diff options
Diffstat (limited to 'common/cmd_mii.c')
-rw-r--r-- | common/cmd_mii.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/common/cmd_mii.c b/common/cmd_mii.c index ef53e13f7b4..4a848297723 100644 --- a/common/cmd_mii.c +++ b/common/cmd_mii.c @@ -28,9 +28,11 @@ #include <common.h> #include <command.h> #include <miiphy.h> +#include <miivals.h> #if (CONFIG_COMMANDS & CFG_CMD_MII) +#ifdef CONFIG_TERSE_MII /* * Display values from last command. */ @@ -143,6 +145,417 @@ U_BOOT_CMD( "mii read <addr> <reg> - read MII PHY <addr> register <reg>\n" "mii write <addr> <reg> <data> - write MII PHY <addr> register <reg>\n" ); +#else /* CONFIG_TERSE_MII */ +typedef struct _MII_reg_desc_t { + ushort regno; + char * name; +} MII_reg_desc_t; + +MII_reg_desc_t reg_0_5_desc_tbl[] = { + { 0, "PHY control register" }, + { 1, "PHY status register" }, + { 2, "PHY ID 1 register" }, + { 3, "PHY ID 2 register" }, + { 4, "Autonegotiation advertisement register" }, + { 5, "Autonegotiation partner abilities register" }, +}; + +typedef struct _MII_field_desc_t { + ushort hi; + ushort lo; + ushort mask; + char * name; +} MII_field_desc_t; + +MII_field_desc_t reg_0_desc_tbl[] = { + { 15, 15, 0x01, "reset" }, + { 14, 14, 0x01, "loopback" }, + { 13, 6, 0x81, "speed selection" }, /* special */ + { 12, 12, 0x01, "A/N enable" }, + { 11, 11, 0x01, "power-down" }, + { 10, 10, 0x01, "isolate" }, + { 9, 9, 0x01, "restart A/N" }, + { 8, 8, 0x01, "duplex" }, /* special */ + { 7, 7, 0x01, "collision test enable" }, + { 5, 0, 0x3f, "(reserved)" } +}; + +MII_field_desc_t reg_1_desc_tbl[] = { + { 15, 15, 0x01, "100BASE-T4 able" }, + { 14, 14, 0x01, "100BASE-X full duplex able" }, + { 13, 13, 0x01, "100BASE-X half duplex able" }, + { 12, 12, 0x01, "10 Mbps full duplex able" }, + { 11, 11, 0x01, "10 Mbps half duplex able" }, + { 10, 10, 0x01, "100BASE-T2 full duplex able" }, + { 9, 9, 0x01, "100BASE-T2 half duplex able" }, + { 8, 8, 0x01, "extended status" }, + { 7, 7, 0x01, "(reserved)" }, + { 6, 6, 0x01, "MF preamble suppression" }, + { 5, 5, 0x01, "A/N complete" }, + { 4, 4, 0x01, "remote fault" }, + { 3, 3, 0x01, "A/N able" }, + { 2, 2, 0x01, "link status" }, + { 1, 1, 0x01, "jabber detect" }, + { 0, 0, 0x01, "extended capabilities" }, +}; + +MII_field_desc_t reg_2_desc_tbl[] = { + { 15, 0, 0xffff, "OUI portion" }, +}; + +MII_field_desc_t reg_3_desc_tbl[] = { + { 15, 10, 0x3f, "OUI portion" }, + { 9, 4, 0x3f, "manufacturer part number" }, + { 3, 0, 0x0f, "manufacturer rev. number" }, +}; + +MII_field_desc_t reg_4_desc_tbl[] = { + { 15, 15, 0x01, "next page able" }, + { 14, 14, 0x01, "reserved" }, + { 13, 13, 0x01, "remote fault" }, + { 12, 12, 0x01, "reserved" }, + { 11, 11, 0x01, "asymmetric pause" }, + { 10, 10, 0x01, "pause enable" }, + { 9, 9, 0x01, "100BASE-T4 able" }, + { 8, 8, 0x01, "100BASE-TX full duplex able" }, + { 7, 7, 0x01, "100BASE-TX able" }, + { 6, 6, 0x01, "10BASE-T full duplex able" }, + { 5, 5, 0x01, "10BASE-T able" }, + { 4, 0, 0x1f, "xxx to do" }, +}; + +MII_field_desc_t reg_5_desc_tbl[] = { + { 15, 15, 0x01, "next page able" }, + { 14, 14, 0x01, "acknowledge" }, + { 13, 13, 0x01, "remote fault" }, + { 12, 12, 0x01, "(reserved)" }, + { 11, 11, 0x01, "asymmetric pause able" }, + { 10, 10, 0x01, "pause able" }, + { 9, 9, 0x01, "100BASE-T4 able" }, + { 8, 8, 0x01, "100BASE-X full duplex able" }, + { 7, 7, 0x01, "100BASE-TX able" }, + { 6, 6, 0x01, "10BASE-T full duplex able" }, + { 5, 5, 0x01, "10BASE-T able" }, + { 4, 0, 0x1f, "xxx to do" }, +}; + +#define DESC0LEN (sizeof(reg_0_desc_tbl)/sizeof(reg_0_desc_tbl[0])) +#define DESC1LEN (sizeof(reg_1_desc_tbl)/sizeof(reg_1_desc_tbl[0])) +#define DESC2LEN (sizeof(reg_2_desc_tbl)/sizeof(reg_2_desc_tbl[0])) +#define DESC3LEN (sizeof(reg_3_desc_tbl)/sizeof(reg_3_desc_tbl[0])) +#define DESC4LEN (sizeof(reg_4_desc_tbl)/sizeof(reg_4_desc_tbl[0])) +#define DESC5LEN (sizeof(reg_5_desc_tbl)/sizeof(reg_5_desc_tbl[0])) + +typedef struct _MII_field_desc_and_len_t { + MII_field_desc_t * pdesc; + ushort len; +} MII_field_desc_and_len_t; + +MII_field_desc_and_len_t desc_and_len_tbl[] = { + { reg_0_desc_tbl, DESC0LEN }, + { reg_1_desc_tbl, DESC1LEN }, + { reg_2_desc_tbl, DESC2LEN }, + { reg_3_desc_tbl, DESC3LEN }, + { reg_4_desc_tbl, DESC4LEN }, + { reg_5_desc_tbl, DESC5LEN }, +}; + +static void dump_reg( + ushort regval, + MII_reg_desc_t * prd, + MII_field_desc_and_len_t * pdl); + +static int special_field( + ushort regno, + MII_field_desc_t * pdesc, + ushort regval); + +void MII_dump_0_to_5( + ushort regvals[6], + uchar reglo, + uchar reghi) +{ + ulong i; + + for (i = 0; i < 6; i++) { + if ((reglo <= i) && (i <= reghi)) + dump_reg(regvals[i], ®_0_5_desc_tbl[i], + &desc_and_len_tbl[i]); + } +} + +static void dump_reg( + ushort regval, + MII_reg_desc_t * prd, + MII_field_desc_and_len_t * pdl) +{ + ulong i; + ushort mask_in_place; + MII_field_desc_t * pdesc; + + printf("%u. (%04hx) -- %s --\n", + prd->regno, regval, prd->name); + + for (i = 0; i < pdl->len; i++) { + pdesc = &pdl->pdesc[i]; + + mask_in_place = pdesc->mask << pdesc->lo; + + printf(" (%04hx:%04hx) %u.", + mask_in_place, + regval & mask_in_place, + prd->regno); + + if (special_field(prd->regno, pdesc, regval)) { + } + else { + if (pdesc->hi == pdesc->lo) + printf("%2u ", pdesc->lo); + else + printf("%2u-%2u", pdesc->hi, pdesc->lo); + printf(" = %5u %s", + (regval & mask_in_place) >> pdesc->lo, + pdesc->name); + } + printf("\n"); + + } + printf("\n"); +} + +/* Special fields: +** 0.6,13 +** 0.8 +** 2.15-0 +** 3.15-0 +** 4.4-0 +** 5.4-0 +*/ + +static int special_field( + ushort regno, + MII_field_desc_t * pdesc, + ushort regval) +{ + if ((regno == 0) && (pdesc->lo == 6)) { + ushort speed_bits = regval & MII_CTL_SPEED_MASK; + printf("%2u,%2u = b%u%u speed selection = %s Mbps", + 6, 13, + (regval >> 6) & 1, + (regval >> 13) & 1, + speed_bits == MII_CTL_SPEED_1000_MBPS ? "1000" : + speed_bits == MII_CTL_SPEED_100_MBPS ? "100" : + speed_bits == MII_CTL_SPEED_10_MBPS ? "10" : + "???"); + return 1; + } + + else if ((regno == 0) && (pdesc->lo == 8)) { + printf("%2u = %5u duplex = %s", + pdesc->lo, + (regval >> pdesc->lo) & 1, + ((regval >> pdesc->lo) & 1) ? "full" : "half"); + return 1; + } + + else if ((regno == 4) && (pdesc->lo == 0)) { + ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask; + printf("%2u-%2u = %5u selector = %s", + pdesc->hi, pdesc->lo, sel_bits, + sel_bits == MII_AN_ADV_IEEE_802_3 ? + "IEEE 802.3" : + sel_bits == MII_AN_ADV_IEEE_802_9_ISLAN_16T ? + "IEEE 802.9 ISLAN-16T" : + "???"); + return 1; + } + + else if ((regno == 5) && (pdesc->lo == 0)) { + ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask; + printf("%2u-%2u = %u selector = %s", + pdesc->hi, pdesc->lo, sel_bits, + sel_bits == MII_AN_PARTNER_IEEE_802_3 ? + "IEEE 802.3" : + sel_bits == MII_AN_PARTNER_IEEE_802_9_ISLAN_16T ? + "IEEE 802.9 ISLAN-16T" : + "???"); + return 1; + } + + return 0; +} + +uint last_op; +uint last_data; +uint last_addr_lo; +uint last_addr_hi; +uint last_reg_lo; +uint last_reg_hi; + +static void extract_range( + char * input, + unsigned char * plo, + unsigned char * phi) +{ + char * end; + *plo = simple_strtoul(input, &end, 16); + if (*end == '-') { + end++; + *phi = simple_strtoul(end, NULL, 16); + } + else { + *phi = *plo; + } +} + +// ---------------------------------------------------------------- +int do_mii (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + char op; + unsigned char addrlo, addrhi, reglo, reghi; + unsigned char addr, reg; + unsigned short data; + int rcode = 0; + +#ifdef CONFIG_8xx + mii_init (); +#endif + + /* + * We use the last specified parameters, unless new ones are + * entered. + */ + op = last_op; + addrlo = last_addr_lo; + addrhi = last_addr_hi; + reglo = last_reg_lo; + reghi = last_reg_hi; + data = last_data; + + if ((flag & CMD_FLAG_REPEAT) == 0) { + op = argv[1][0]; + if (argc >= 3) + extract_range(argv[2], &addrlo, &addrhi); + if (argc >= 4) + extract_range(argv[3], ®lo, ®hi); + if (argc >= 5) + data = simple_strtoul (argv[4], NULL, 16); + } + + /* + * check info/read/write. + */ + if (op == 'i') { + unsigned char j, start, end; + unsigned int oui; + unsigned char model; + unsigned char rev; + + /* + * Look for any and all PHYs. Valid addresses are 0..31. + */ + if (argc >= 3) { + start = addr; end = addr + 1; + } else { + start = 0; end = 32; + } + + for (j = start; j < end; j++) { + if (miiphy_info (j, &oui, &model, &rev) == 0) { + printf("PHY 0x%02X: " + "OUI = 0x%04X, " + "Model = 0x%02X, " + "Rev = 0x%02X, " + "%3dbaseT, %s\n", + j, oui, model, rev, + miiphy_speed (j), + miiphy_duplex (j) == FULL ? "FDX" : "HDX"); + } + } + } else if (op == 'r') { + for (addr = addrlo; addr <= addrhi; addr++) { + for (reg = reglo; reg <= reghi; reg++) { + data = 0xffff; + if (miiphy_read (addr, reg, &data) != 0) { + printf( + "Error reading from the PHY addr=%02x reg=%02x\n", + addr, reg); + rcode = 1; + } + else { + if ((addrlo != addrhi) || (reglo != reghi)) + printf("addr=%02x reg=%02x data=", + (uint)addr, (uint)reg); + printf("%04X\n", data & 0x0000FFFF); + } + } + if ((addrlo != addrhi) && (reglo != reghi)) + printf("\n"); + } + } else if (op == 'w') { + for (addr = addrlo; addr <= addrhi; addr++) { + for (reg = reglo; reg <= reghi; reg++) { + if (miiphy_write (addr, reg, data) != 0) { + printf("Error writing to the PHY addr=%02x reg=%02x\n", + addr, reg); + rcode = 1; + } + } + } + } else if (op == 'd') { + ushort regs[6]; + int ok = 1; + if ((reglo > 5) || (reghi > 5)) { + printf( + "The MII dump command only formats the " + "standard MII registers, 0-5.\n"); + return 1; + } + for (addr = addrlo; addr <= addrhi; addr++) { + for (reg = 0; reg < 6; reg++) { + if (miiphy_read(addr, reg, ®s[reg]) != 0) { + ok = 0; + printf( + "Error reading from the PHY addr=%02x reg=%02x\n", + addr, reg); + rcode = 1; + } + } + if (ok) + MII_dump_0_to_5(regs, reglo, reghi); + printf("\n"); + } + } else { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* + * Save the parameters for repeats. + */ + last_op = op; + last_addr_lo = addrlo; + last_addr_hi = addrhi; + last_reg_lo = reglo; + last_reg_hi = reghi; + last_data = data; + + return rcode; +} + +/***************************************************/ + +U_BOOT_CMD( + mii, 5, 1, do_mii, + "mii - MII utility commands\n", + "info <addr> - display MII PHY info\n" + "mii read <addr> <reg> - read MII PHY <addr> register <reg>\n" + "mii write <addr> <reg> <data> - write MII PHY <addr> register <reg>\n" + "mii dump <addr> <reg> - pretty-print <addr> <reg> (0-5 only)\n" + "Addr and/or reg may be ranges, e.g. 2-7.\n" +); + +#endif /* CONFIG_TERSE_MII */ #endif /* CFG_CMD_MII */ |