summaryrefslogtreecommitdiff
path: root/zap-phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'zap-phy.c')
-rw-r--r--zap-phy.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/zap-phy.c b/zap-phy.c
new file mode 100644
index 0000000..c4dc7eb
--- /dev/null
+++ b/zap-phy.c
@@ -0,0 +1,172 @@
+#include <curses.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#include "zap.h"
+
+extern int mdio_read(long ioaddr, int phy_id, int mii_reg_num);
+extern void mdio_write(int ioaddr, int phy_id, int location, int value);
+
+struct zap_phy {
+ long ioaddr;
+ int phy_id;
+ int devad;
+ int irq_fd;
+ char aux_buf[16];
+};
+
+static bool phy_read(void *private, u32 addr, u32 *val)
+{
+ struct zap_phy *phy = private;
+ int v;
+
+ v = mdio_read(phy->ioaddr, phy->phy_id | phy->devad, addr);
+
+ *val = v >= 0 ? v : 0;
+
+ return v >= 0;
+}
+
+static void phy_write(void *private, u32 addr, u32 val)
+{
+ struct zap_phy *phy = private;
+
+ mdio_write(phy->ioaddr, phy->phy_id | phy->devad, addr, val);
+}
+
+static void phy_c45_key(struct zap_private *priv, void *private, int key)
+{
+ struct zap_phy *phy = private;
+ int val;
+
+ switch (key) {
+ case 'r':
+ val = mdio_read(phy->ioaddr, phy->phy_id | 7, 0);
+ if (val < 0)
+ return;
+ mdio_write(phy->ioaddr, phy->phy_id | 7, 0, val | 0x200);
+ break;
+
+ case 'p':
+ zap_prompt_input(priv, 'p', "PHY devad");
+ break;
+ }
+}
+
+static void phy_c45_print_unit(void *private)
+{
+ struct zap_phy *phy = private;
+ const char *dev = "";
+
+ switch (phy->devad) {
+ case 1: dev = " PMA/PMD"; break;
+ case 2: dev = " WIS"; break;
+ case 3: dev = " PCS"; break;
+ case 4: dev = " PHYXS"; break;
+ case 5: dev = " DTEXS"; break;
+ case 7: dev = " AN"; break;
+ }
+
+ printw("PHY #%u.%-2u%s", (phy->phy_id >> 5) & 31, phy->devad, dev);
+ clrtoeol();
+}
+
+static void phy_c45_update_aux(void *private)
+{
+ struct zap_phy *phy = private;
+ char new[16];
+ int len;
+
+ if (phy->irq_fd == -1)
+ return;
+
+ lseek(phy->irq_fd, 0, SEEK_SET);
+ len = read(phy->irq_fd, new, sizeof(new));
+ if (len < 0 || len >= sizeof(new))
+ return;
+
+ len -= 1;
+
+ if (!memcmp(phy->aux_buf, new, len))
+ return;
+
+ memcpy(phy->aux_buf, new, len);
+ mvprintw(1, 41, "IRQ ");
+ mvaddnstr(1, 45, new, len);
+ clrtoeol();
+}
+
+static void phy_c45_input(void *private, char mode, const char *buf)
+{
+ struct zap_phy *phy = private;
+ unsigned long unit;
+
+ errno = 0;
+ unit = strtoul(buf, NULL, 0);
+ if (unit == ULONG_MAX && errno == ERANGE)
+ return;
+ if (unit > 31)
+ return;
+
+ phy->devad = unit;
+}
+
+static const struct zap phy_c45_zap = {
+ .val_width = 4,
+ .max_addr = 0xffff,
+ .read = phy_read,
+ .write = phy_write,
+ .key = phy_c45_key,
+ .print_header = phy_c45_print_unit,
+ .update_aux = phy_c45_update_aux,
+ .input = phy_c45_input,
+};
+
+static void phy_print_c22_unit(void *private)
+{
+ struct zap_phy *phy = private;
+
+ printw("PHY #%u", phy->phy_id);
+}
+
+static const struct zap phy_c22_zap = {
+ .val_width = 4,
+ .max_addr = 0x1f,
+ .read = phy_read,
+ .write = phy_write,
+ .print_header = phy_print_c22_unit,
+};
+
+
+void phy_zap(long ioaddr, int phy_id, unsigned long start)
+{
+ const struct zap *z;
+ struct zap_phy phy = {
+ .ioaddr = ioaddr,
+ .irq_fd = -1,
+ };
+
+ if (phy_id & 0x8000) {
+ phy.phy_id = phy_id & ~31;
+ phy.devad = phy_id & 31;
+
+ if (phy_id == 0x8000)
+ phy.irq_fd = open("/sys/class/gpio/gpio82/value", O_RDONLY);
+ else if (phy_id == 0x8000 + 8 * 32)
+ phy.irq_fd = open("/sys/class/gpio/gpio81/value", O_RDONLY);
+
+ z = &phy_c45_zap;
+ } else {
+ phy.phy_id = phy_id;
+ phy.devad = 0;
+
+ z = &phy_c22_zap;
+ }
+ if (start >= z->max_addr)
+ start = z->max_addr;
+ zap(z, start, &phy);
+}