3
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
5
* SPDX-License-Identifier: GPL-2.0+
16
typedef struct _MII_reg_desc_t {
21
static const MII_reg_desc_t reg_0_5_desc_tbl[] = {
22
{ MII_BMCR, "PHY control register" },
23
{ MII_BMSR, "PHY status register" },
24
{ MII_PHYSID1, "PHY ID 1 register" },
25
{ MII_PHYSID2, "PHY ID 2 register" },
26
{ MII_ADVERTISE, "Autonegotiation advertisement register" },
27
{ MII_LPA, "Autonegotiation partner abilities register" },
30
typedef struct _MII_field_desc_t {
37
static const MII_field_desc_t reg_0_desc_tbl[] = {
38
{ 15, 15, 0x01, "reset" },
39
{ 14, 14, 0x01, "loopback" },
40
{ 13, 6, 0x81, "speed selection" }, /* special */
41
{ 12, 12, 0x01, "A/N enable" },
42
{ 11, 11, 0x01, "power-down" },
43
{ 10, 10, 0x01, "isolate" },
44
{ 9, 9, 0x01, "restart A/N" },
45
{ 8, 8, 0x01, "duplex" }, /* special */
46
{ 7, 7, 0x01, "collision test enable" },
47
{ 5, 0, 0x3f, "(reserved)" }
50
static const MII_field_desc_t reg_1_desc_tbl[] = {
51
{ 15, 15, 0x01, "100BASE-T4 able" },
52
{ 14, 14, 0x01, "100BASE-X full duplex able" },
53
{ 13, 13, 0x01, "100BASE-X half duplex able" },
54
{ 12, 12, 0x01, "10 Mbps full duplex able" },
55
{ 11, 11, 0x01, "10 Mbps half duplex able" },
56
{ 10, 10, 0x01, "100BASE-T2 full duplex able" },
57
{ 9, 9, 0x01, "100BASE-T2 half duplex able" },
58
{ 8, 8, 0x01, "extended status" },
59
{ 7, 7, 0x01, "(reserved)" },
60
{ 6, 6, 0x01, "MF preamble suppression" },
61
{ 5, 5, 0x01, "A/N complete" },
62
{ 4, 4, 0x01, "remote fault" },
63
{ 3, 3, 0x01, "A/N able" },
64
{ 2, 2, 0x01, "link status" },
65
{ 1, 1, 0x01, "jabber detect" },
66
{ 0, 0, 0x01, "extended capabilities" },
69
static const MII_field_desc_t reg_2_desc_tbl[] = {
70
{ 15, 0, 0xffff, "OUI portion" },
73
static const MII_field_desc_t reg_3_desc_tbl[] = {
74
{ 15, 10, 0x3f, "OUI portion" },
75
{ 9, 4, 0x3f, "manufacturer part number" },
76
{ 3, 0, 0x0f, "manufacturer rev. number" },
79
static const MII_field_desc_t reg_4_desc_tbl[] = {
80
{ 15, 15, 0x01, "next page able" },
81
{ 14, 14, 0x01, "(reserved)" },
82
{ 13, 13, 0x01, "remote fault" },
83
{ 12, 12, 0x01, "(reserved)" },
84
{ 11, 11, 0x01, "asymmetric pause" },
85
{ 10, 10, 0x01, "pause enable" },
86
{ 9, 9, 0x01, "100BASE-T4 able" },
87
{ 8, 8, 0x01, "100BASE-TX full duplex able" },
88
{ 7, 7, 0x01, "100BASE-TX able" },
89
{ 6, 6, 0x01, "10BASE-T full duplex able" },
90
{ 5, 5, 0x01, "10BASE-T able" },
91
{ 4, 0, 0x1f, "xxx to do" },
94
static const MII_field_desc_t reg_5_desc_tbl[] = {
95
{ 15, 15, 0x01, "next page able" },
96
{ 14, 14, 0x01, "acknowledge" },
97
{ 13, 13, 0x01, "remote fault" },
98
{ 12, 12, 0x01, "(reserved)" },
99
{ 11, 11, 0x01, "asymmetric pause able" },
100
{ 10, 10, 0x01, "pause able" },
101
{ 9, 9, 0x01, "100BASE-T4 able" },
102
{ 8, 8, 0x01, "100BASE-X full duplex able" },
103
{ 7, 7, 0x01, "100BASE-TX able" },
104
{ 6, 6, 0x01, "10BASE-T full duplex able" },
105
{ 5, 5, 0x01, "10BASE-T able" },
106
{ 4, 0, 0x1f, "xxx to do" },
108
typedef struct _MII_field_desc_and_len_t {
109
const MII_field_desc_t *pdesc;
111
} MII_field_desc_and_len_t;
113
static const MII_field_desc_and_len_t desc_and_len_tbl[] = {
114
{ reg_0_desc_tbl, ARRAY_SIZE(reg_0_desc_tbl) },
115
{ reg_1_desc_tbl, ARRAY_SIZE(reg_1_desc_tbl) },
116
{ reg_2_desc_tbl, ARRAY_SIZE(reg_2_desc_tbl) },
117
{ reg_3_desc_tbl, ARRAY_SIZE(reg_3_desc_tbl) },
118
{ reg_4_desc_tbl, ARRAY_SIZE(reg_4_desc_tbl) },
119
{ reg_5_desc_tbl, ARRAY_SIZE(reg_5_desc_tbl) },
122
static void dump_reg(
124
const MII_reg_desc_t *prd,
125
const MII_field_desc_and_len_t *pdl);
127
static int special_field(
129
const MII_field_desc_t *pdesc,
132
static void MII_dump_0_to_5(
139
for (i = 0; i < 6; i++) {
140
if ((reglo <= i) && (i <= reghi))
141
dump_reg(regvals[i], ®_0_5_desc_tbl[i],
142
&desc_and_len_tbl[i]);
146
static void dump_reg(
148
const MII_reg_desc_t *prd,
149
const MII_field_desc_and_len_t *pdl)
152
ushort mask_in_place;
153
const MII_field_desc_t *pdesc;
155
printf("%u. (%04hx) -- %s --\n",
156
prd->regno, regval, prd->name);
158
for (i = 0; i < pdl->len; i++) {
159
pdesc = &pdl->pdesc[i];
161
mask_in_place = pdesc->mask << pdesc->lo;
163
printf(" (%04hx:%04hx) %u.",
165
regval & mask_in_place,
168
if (special_field(prd->regno, pdesc, regval)) {
171
if (pdesc->hi == pdesc->lo)
172
printf("%2u ", pdesc->lo);
174
printf("%2u-%2u", pdesc->hi, pdesc->lo);
176
(regval & mask_in_place) >> pdesc->lo,
194
static int special_field(
196
const MII_field_desc_t *pdesc,
199
if ((regno == MII_BMCR) && (pdesc->lo == 6)) {
200
ushort speed_bits = regval & (BMCR_SPEED1000 | BMCR_SPEED100);
201
printf("%2u,%2u = b%u%u speed selection = %s Mbps",
205
speed_bits == BMCR_SPEED1000 ? "1000" :
206
speed_bits == BMCR_SPEED100 ? "100" :
211
else if ((regno == MII_BMCR) && (pdesc->lo == 8)) {
212
printf("%2u = %5u duplex = %s",
214
(regval >> pdesc->lo) & 1,
215
((regval >> pdesc->lo) & 1) ? "full" : "half");
219
else if ((regno == MII_ADVERTISE) && (pdesc->lo == 0)) {
220
ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
221
printf("%2u-%2u = %5u selector = %s",
222
pdesc->hi, pdesc->lo, sel_bits,
223
sel_bits == PHY_ANLPAR_PSB_802_3 ?
225
sel_bits == PHY_ANLPAR_PSB_802_9 ?
226
"IEEE 802.9 ISLAN-16T" :
231
else if ((regno == MII_LPA) && (pdesc->lo == 0)) {
232
ushort sel_bits = (regval >> pdesc->lo) & pdesc->mask;
233
printf("%2u-%2u = %u selector = %s",
234
pdesc->hi, pdesc->lo, sel_bits,
235
sel_bits == PHY_ANLPAR_PSB_802_3 ?
237
sel_bits == PHY_ANLPAR_PSB_802_9 ?
238
"IEEE 802.9 ISLAN-16T" :
246
static char last_op[2];
247
static uint last_data;
248
static uint last_addr_lo;
249
static uint last_addr_hi;
250
static uint last_reg_lo;
251
static uint last_reg_hi;
253
static void extract_range(
259
*plo = simple_strtoul(input, &end, 16);
262
*phi = simple_strtoul(end, NULL, 16);
269
/* ---------------------------------------------------------------- */
270
static int do_mii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
273
unsigned char addrlo, addrhi, reglo, reghi;
274
unsigned char addr, reg;
280
return CMD_RET_USAGE;
282
#if defined(CONFIG_MII_INIT)
287
* We use the last specified parameters, unless new ones are
292
addrlo = last_addr_lo;
293
addrhi = last_addr_hi;
298
if ((flag & CMD_FLAG_REPEAT) == 0) {
300
if (strlen(argv[1]) > 1)
306
extract_range(argv[2], &addrlo, &addrhi);
308
extract_range(argv[3], ®lo, ®hi);
310
data = simple_strtoul (argv[4], NULL, 16);
313
/* use current device */
314
devname = miiphy_get_current_dev();
317
* check info/read/write.
320
unsigned char j, start, end;
326
* Look for any and all PHYs. Valid addresses are 0..31.
329
start = addrlo; end = addrhi;
334
for (j = start; j <= end; j++) {
335
if (miiphy_info (devname, j, &oui, &model, &rev) == 0) {
336
printf("PHY 0x%02X: "
342
miiphy_speed (devname, j),
343
miiphy_is_1000base_x (devname, j)
345
(miiphy_duplex (devname, j) == FULL)
349
} else if (op[0] == 'r') {
350
for (addr = addrlo; addr <= addrhi; addr++) {
351
for (reg = reglo; reg <= reghi; reg++) {
353
if (miiphy_read (devname, addr, reg, &data) != 0) {
355
"Error reading from the PHY addr=%02x reg=%02x\n",
359
if ((addrlo != addrhi) || (reglo != reghi))
360
printf("addr=%02x reg=%02x data=",
361
(uint)addr, (uint)reg);
362
printf("%04X\n", data & 0x0000FFFF);
365
if ((addrlo != addrhi) && (reglo != reghi))
368
} else if (op[0] == 'w') {
369
for (addr = addrlo; addr <= addrhi; addr++) {
370
for (reg = reglo; reg <= reghi; reg++) {
371
if (miiphy_write (devname, addr, reg, data) != 0) {
372
printf("Error writing to the PHY addr=%02x reg=%02x\n",
378
} else if (strncmp(op, "du", 2) == 0) {
381
if ((reglo > 5) || (reghi > 5)) {
383
"The MII dump command only formats the "
384
"standard MII registers, 0-5.\n");
387
for (addr = addrlo; addr <= addrhi; addr++) {
388
for (reg = reglo; reg < reghi + 1; reg++) {
389
if (miiphy_read(devname, addr, reg, ®s[reg]) != 0) {
392
"Error reading from the PHY addr=%02x reg=%02x\n",
398
MII_dump_0_to_5(regs, reglo, reghi);
401
} else if (strncmp(op, "de", 2) == 0) {
405
miiphy_set_current_dev (argv[2]);
407
return CMD_RET_USAGE;
411
* Save the parameters for repeats.
415
last_addr_lo = addrlo;
416
last_addr_hi = addrhi;
424
/***************************************************/
428
"MII utility commands",
429
"device - list available devices\n"
430
"mii device <devname> - set current device\n"
431
"mii info <addr> - display MII PHY info\n"
432
"mii read <addr> <reg> - read MII PHY <addr> register <reg>\n"
433
"mii write <addr> <reg> <data> - write MII PHY <addr> register <reg>\n"
434
"mii dump <addr> <reg> - pretty-print <addr> <reg> (0-5 only)\n"
435
"Addr and/or reg may be ranges, e.g. 2-7."