command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / drivers / net / phy / b53.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017
4  * Broadcom
5  * Florian Fainelli <f.fainelli@gmail.com>
6  */
7
8 /*
9  * PHY driver for Broadcom BCM53xx (roboswitch) Ethernet switches.
10  *
11  * This driver configures the b53 for basic use as a PHY. The switch supports
12  * vendor tags and VLAN configuration that can affect the switching decisions.
13  * This driver uses a simple configuration in which all ports are only allowed
14  * to send frames to the CPU port and receive frames from the CPU port this
15  * providing port isolation (no cross talk).
16  *
17  * The configuration determines which PHY ports to activate using the
18  * CONFIG_B53_PHY_PORTS bitmask. Set bit N will active port N and so on.
19  *
20  * This driver was written primarily for the Lamobo R1 platform using a BCM53152
21  * switch but the BCM53xx being largely register compatible, extending it to
22  * cover other switches would be trivial.
23  */
24
25 #include <common.h>
26 #include <command.h>
27
28 #include <errno.h>
29 #include <malloc.h>
30 #include <miiphy.h>
31 #include <netdev.h>
32
33 /* Pseudo-PHY address (non configurable) to access internal registers */
34 #define BRCM_PSEUDO_PHY_ADDR            30
35
36 /* Maximum number of ports possible */
37 #define B53_N_PORTS                     9
38
39 #define B53_CTRL_PAGE                   0x00 /* Control */
40 #define B53_MGMT_PAGE                   0x02 /* Management Mode */
41 /* Port VLAN Page */
42 #define B53_PVLAN_PAGE                  0x31
43
44 /* Control Page registers */
45 #define B53_PORT_CTRL(i)                (0x00 + (i))
46 #define   PORT_CTRL_RX_DISABLE          BIT(0)
47 #define   PORT_CTRL_TX_DISABLE          BIT(1)
48 #define   PORT_CTRL_RX_BCST_EN          BIT(2) /* Broadcast RX (P8 only) */
49 #define   PORT_CTRL_RX_MCST_EN          BIT(3) /* Multicast RX (P8 only) */
50 #define   PORT_CTRL_RX_UCST_EN          BIT(4) /* Unicast RX (P8 only) */
51
52 /* Switch Mode Control Register (8 bit) */
53 #define B53_SWITCH_MODE                 0x0b
54 #define   SM_SW_FWD_MODE                BIT(0)  /* 1 = Managed Mode */
55 #define   SM_SW_FWD_EN                  BIT(1)  /* Forwarding Enable */
56
57 /* IMP Port state override register (8 bit) */
58 #define B53_PORT_OVERRIDE_CTRL          0x0e
59 #define   PORT_OVERRIDE_LINK            BIT(0)
60 #define   PORT_OVERRIDE_FULL_DUPLEX     BIT(1) /* 0 = Half Duplex */
61 #define   PORT_OVERRIDE_SPEED_S         2
62 #define   PORT_OVERRIDE_SPEED_10M       (0 << PORT_OVERRIDE_SPEED_S)
63 #define   PORT_OVERRIDE_SPEED_100M      (1 << PORT_OVERRIDE_SPEED_S)
64 #define   PORT_OVERRIDE_SPEED_1000M     (2 << PORT_OVERRIDE_SPEED_S)
65 /* BCM5325 only */
66 #define   PORT_OVERRIDE_RV_MII_25       BIT(4)
67 #define   PORT_OVERRIDE_RX_FLOW         BIT(4)
68 #define   PORT_OVERRIDE_TX_FLOW         BIT(5)
69 /* BCM5301X only, requires setting 1000M */
70 #define   PORT_OVERRIDE_SPEED_2000M     BIT(6)
71 #define   PORT_OVERRIDE_EN              BIT(7) /* Use the register contents */
72
73 #define B53_RGMII_CTRL_IMP              0x60
74 #define   RGMII_CTRL_ENABLE_GMII        BIT(7)
75 #define   RGMII_CTRL_TIMING_SEL         BIT(2)
76 #define   RGMII_CTRL_DLL_RXC            BIT(1)
77 #define   RGMII_CTRL_DLL_TXC            BIT(0)
78
79 /* Switch control (8 bit) */
80 #define B53_SWITCH_CTRL                 0x22
81 #define  B53_MII_DUMB_FWDG_EN           BIT(6)
82
83 /* Software reset register (8 bit) */
84 #define B53_SOFTRESET                   0x79
85 #define   SW_RST                        BIT(7)
86 #define   EN_CH_RST                     BIT(6)
87 #define   EN_SW_RST                     BIT(4)
88
89 /* Fast Aging Control register (8 bit) */
90 #define B53_FAST_AGE_CTRL               0x88
91 #define   FAST_AGE_STATIC               BIT(0)
92 #define   FAST_AGE_DYNAMIC              BIT(1)
93 #define   FAST_AGE_PORT                 BIT(2)
94 #define   FAST_AGE_VLAN                 BIT(3)
95 #define   FAST_AGE_STP                  BIT(4)
96 #define   FAST_AGE_MC                   BIT(5)
97 #define   FAST_AGE_DONE                 BIT(7)
98
99 /* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
100 #define B53_PVLAN_PORT_MASK(i)          ((i) * 2)
101
102 /* MII registers */
103 #define REG_MII_PAGE    0x10    /* MII Page register */
104 #define REG_MII_ADDR    0x11    /* MII Address register */
105 #define REG_MII_DATA0   0x18    /* MII Data register 0 */
106 #define REG_MII_DATA1   0x19    /* MII Data register 1 */
107 #define REG_MII_DATA2   0x1a    /* MII Data register 2 */
108 #define REG_MII_DATA3   0x1b    /* MII Data register 3 */
109
110 #define REG_MII_PAGE_ENABLE     BIT(0)
111 #define REG_MII_ADDR_WRITE      BIT(0)
112 #define REG_MII_ADDR_READ       BIT(1)
113
114 struct b53_device {
115         struct mii_dev  *bus;
116         unsigned int cpu_port;
117 };
118
119 static int b53_mdio_op(struct mii_dev *bus, u8 page, u8 reg, u16 op)
120 {
121         int ret;
122         int i;
123         u16 v;
124
125         /* set page number */
126         v = (page << 8) | REG_MII_PAGE_ENABLE;
127         ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
128                          REG_MII_PAGE, v);
129         if (ret)
130                 return ret;
131
132         /* set register address */
133         v = (reg << 8) | op;
134         ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
135                          REG_MII_ADDR, v);
136         if (ret)
137                 return ret;
138
139         /* check if operation completed */
140         for (i = 0; i < 5; ++i) {
141                 v = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
142                               REG_MII_ADDR);
143                 if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
144                         break;
145
146                 udelay(100);
147         }
148
149         if (i == 5)
150                 return -EIO;
151
152         return 0;
153 }
154
155 static int b53_mdio_read8(struct mii_dev *bus, u8 page, u8 reg, u8 *val)
156 {
157         int ret;
158
159         ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
160         if (ret)
161                 return ret;
162
163         *val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
164                          REG_MII_DATA0) & 0xff;
165
166         return 0;
167 }
168
169 static int b53_mdio_read16(struct mii_dev *bus, u8 page, u8 reg, u16 *val)
170 {
171         int ret;
172
173         ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
174         if (ret)
175                 return ret;
176
177         *val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
178                          REG_MII_DATA0);
179
180         return 0;
181 }
182
183 static int b53_mdio_read32(struct mii_dev *bus, u8 page, u8 reg, u32 *val)
184 {
185         int ret;
186
187         ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
188         if (ret)
189                 return ret;
190
191         *val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
192                          REG_MII_DATA0);
193         *val |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
194                           REG_MII_DATA1) << 16;
195
196         return 0;
197 }
198
199 static int b53_mdio_read48(struct mii_dev *bus, u8 page, u8 reg, u64 *val)
200 {
201         u64 temp = 0;
202         int i;
203         int ret;
204
205         ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
206         if (ret)
207                 return ret;
208
209         for (i = 2; i >= 0; i--) {
210                 temp <<= 16;
211                 temp |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
212                                   REG_MII_DATA0 + i);
213         }
214
215         *val = temp;
216
217         return 0;
218 }
219
220 static int b53_mdio_read64(struct mii_dev *bus, u8 page, u8 reg, u64 *val)
221 {
222         u64 temp = 0;
223         int i;
224         int ret;
225
226         ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ);
227         if (ret)
228                 return ret;
229
230         for (i = 3; i >= 0; i--) {
231                 temp <<= 16;
232                 temp |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
233                                   REG_MII_DATA0 + i);
234         }
235
236         *val = temp;
237
238         return 0;
239 }
240
241 static int b53_mdio_write8(struct mii_dev *bus, u8 page, u8 reg, u8 value)
242 {
243         int ret;
244
245         ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
246                          REG_MII_DATA0, value);
247         if (ret)
248                 return ret;
249
250         return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
251 }
252
253 static int b53_mdio_write16(struct mii_dev *bus, u8 page, u8 reg,
254                             u16 value)
255 {
256         int ret;
257
258         ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE,
259                          REG_MII_DATA0, value);
260         if (ret)
261                 return ret;
262
263         return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
264 }
265
266 static int b53_mdio_write32(struct mii_dev *bus, u8 page, u8 reg,
267                             u32 value)
268 {
269         unsigned int i;
270         u32 temp = value;
271
272         for (i = 0; i < 2; i++) {
273                 int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR,
274                                      MDIO_DEVAD_NONE,
275                                      REG_MII_DATA0 + i, temp & 0xffff);
276                 if (ret)
277                         return ret;
278                 temp >>= 16;
279         }
280
281         return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
282 }
283
284 static int b53_mdio_write48(struct mii_dev *bus, u8 page, u8 reg,
285                             u64 value)
286 {
287         unsigned int i;
288         u64 temp = value;
289
290         for (i = 0; i < 3; i++) {
291                 int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR,
292                                      MDIO_DEVAD_NONE,
293                                      REG_MII_DATA0 + i, temp & 0xffff);
294                 if (ret)
295                         return ret;
296                 temp >>= 16;
297         }
298
299         return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
300 }
301
302 static int b53_mdio_write64(struct mii_dev *bus, u8 page, u8 reg,
303                             u64 value)
304 {
305         unsigned int i;
306         u64 temp = value;
307
308         for (i = 0; i < 4; i++) {
309                 int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR,
310                                      MDIO_DEVAD_NONE,
311                                      REG_MII_DATA0 + i, temp & 0xffff);
312                 if (ret)
313                         return ret;
314                 temp >>= 16;
315         }
316
317         return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE);
318 }
319
320 static inline int b53_read8(struct b53_device *dev, u8 page,
321                             u8 reg, u8 *value)
322 {
323         return b53_mdio_read8(dev->bus, page, reg, value);
324 }
325
326 static inline int b53_read16(struct b53_device *dev, u8 page,
327                              u8 reg, u16 *value)
328 {
329         return b53_mdio_read16(dev->bus, page, reg, value);
330 }
331
332 static inline int b53_read32(struct b53_device *dev, u8 page,
333                              u8 reg, u32 *value)
334 {
335         return b53_mdio_read32(dev->bus, page, reg, value);
336 }
337
338 static inline int b53_read48(struct b53_device *dev, u8 page,
339                              u8 reg, u64 *value)
340 {
341         return b53_mdio_read48(dev->bus, page, reg, value);
342 }
343
344 static inline int b53_read64(struct b53_device *dev, u8 page,
345                              u8 reg, u64 *value)
346 {
347         return b53_mdio_read64(dev->bus, page, reg, value);
348 }
349
350 static inline int b53_write8(struct b53_device *dev, u8 page,
351                              u8 reg, u8 value)
352 {
353         return b53_mdio_write8(dev->bus, page, reg, value);
354 }
355
356 static inline int b53_write16(struct b53_device *dev, u8 page,
357                               u8 reg, u16 value)
358 {
359         return b53_mdio_write16(dev->bus, page, reg, value);
360 }
361
362 static inline int b53_write32(struct b53_device *dev, u8 page,
363                               u8 reg, u32 value)
364 {
365         return b53_mdio_write32(dev->bus, page, reg, value);
366 }
367
368 static inline int b53_write48(struct b53_device *dev, u8 page,
369                               u8 reg, u64 value)
370 {
371         return b53_mdio_write48(dev->bus, page, reg, value);
372 }
373
374 static inline int b53_write64(struct b53_device *dev, u8 page,
375                               u8 reg, u64 value)
376 {
377         return b53_mdio_write64(dev->bus, page, reg, value);
378 }
379
380 static int b53_flush_arl(struct b53_device *dev, u8 mask)
381 {
382         unsigned int i;
383
384         b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
385                    FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask);
386
387         for (i = 0; i < 10; i++) {
388                 u8 fast_age_ctrl;
389
390                 b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
391                           &fast_age_ctrl);
392
393                 if (!(fast_age_ctrl & FAST_AGE_DONE))
394                         goto out;
395
396                 mdelay(1);
397         }
398
399         return -ETIMEDOUT;
400 out:
401         /* Only age dynamic entries (default behavior) */
402         b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DYNAMIC);
403         return 0;
404 }
405
406 static int b53_switch_reset(struct phy_device *phydev)
407 {
408         struct b53_device *dev = phydev->priv;
409         unsigned int timeout = 1000;
410         u8 mgmt;
411         u8 reg;
412
413         b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, &reg);
414         reg |= SW_RST | EN_SW_RST | EN_CH_RST;
415         b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, reg);
416
417         do {
418                 b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, &reg);
419                 if (!(reg & SW_RST))
420                         break;
421
422                 mdelay(1);
423         } while (timeout-- > 0);
424
425         if (timeout == 0)
426                 return -ETIMEDOUT;
427
428         b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
429
430         if (!(mgmt & SM_SW_FWD_EN)) {
431                 mgmt &= ~SM_SW_FWD_MODE;
432                 mgmt |= SM_SW_FWD_EN;
433
434                 b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
435                 b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
436
437                 if (!(mgmt & SM_SW_FWD_EN)) {
438                         printf("Failed to enable switch!\n");
439                         return -EINVAL;
440                 }
441         }
442
443         /* Include IMP port in dumb forwarding mode when no tagging protocol
444          * is configured
445          */
446         b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt);
447         mgmt |= B53_MII_DUMB_FWDG_EN;
448         b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
449
450         return b53_flush_arl(dev, FAST_AGE_STATIC);
451 }
452
453 static void b53_enable_cpu_port(struct phy_device *phydev)
454 {
455         struct b53_device *dev = phydev->priv;
456         u8 port_ctrl;
457
458         port_ctrl = PORT_CTRL_RX_BCST_EN |
459                     PORT_CTRL_RX_MCST_EN |
460                     PORT_CTRL_RX_UCST_EN;
461         b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(dev->cpu_port), port_ctrl);
462
463         port_ctrl = PORT_OVERRIDE_EN | PORT_OVERRIDE_LINK |
464                     PORT_OVERRIDE_FULL_DUPLEX | PORT_OVERRIDE_SPEED_1000M;
465         b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, port_ctrl);
466
467         b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_IMP, &port_ctrl);
468 }
469
470 static void b53_imp_vlan_setup(struct b53_device *dev, int cpu_port)
471 {
472         unsigned int port;
473         u16 pvlan;
474
475         /* Enable the IMP port to be in the same VLAN as the other ports
476          * on a per-port basis such that we only have Port i and IMP in
477          * the same VLAN.
478          */
479         for (port = 0; port < B53_N_PORTS; port++) {
480                 if (!((1 << port) & CONFIG_B53_PHY_PORTS))
481                         continue;
482
483                 b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port),
484                            &pvlan);
485                 pvlan |= BIT(cpu_port);
486                 b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port),
487                             pvlan);
488         }
489 }
490
491 static int b53_port_enable(struct phy_device *phydev, unsigned int port)
492 {
493         struct b53_device *dev = phydev->priv;
494         unsigned int cpu_port = dev->cpu_port;
495         u16 pvlan;
496
497         /* Clear the Rx and Tx disable bits and set to no spanning tree */
498         b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0);
499
500         /* Set this port, and only this one to be in the default VLAN */
501         b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);
502         pvlan &= ~0x1ff;
503         pvlan |= BIT(port);
504         b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan);
505
506         b53_imp_vlan_setup(dev, cpu_port);
507
508         return 0;
509 }
510
511 static int b53_switch_init(struct phy_device *phydev)
512 {
513         static int init;
514         int ret;
515
516         if (init)
517                 return 0;
518
519         ret = b53_switch_reset(phydev);
520         if (ret < 0)
521                 return ret;
522
523         b53_enable_cpu_port(phydev);
524
525         init = 1;
526
527         return 0;
528 }
529
530 static int b53_probe(struct phy_device *phydev)
531 {
532         struct b53_device *dev;
533         int ret;
534
535         dev = malloc(sizeof(*dev));
536         if (!dev)
537                 return -ENOMEM;
538
539         memset(dev, 0, sizeof(*dev));
540
541         phydev->priv = dev;
542         dev->bus = phydev->bus;
543         dev->cpu_port = CONFIG_B53_CPU_PORT;
544
545         ret = b53_switch_reset(phydev);
546         if (ret < 0)
547                 return ret;
548
549         return 0;
550 }
551
552 static int b53_phy_config(struct phy_device *phydev)
553 {
554         unsigned int port;
555         int res;
556
557         res = b53_switch_init(phydev);
558         if (res < 0)
559                 return res;
560
561         for (port = 0; port < B53_N_PORTS; port++) {
562                 if (!((1 << port) & CONFIG_B53_PHY_PORTS))
563                         continue;
564
565                 res = b53_port_enable(phydev, port);
566                 if (res < 0) {
567                         printf("Error enabling port %i\n", port);
568                         continue;
569                 }
570
571                 res = genphy_config_aneg(phydev);
572                 if (res < 0) {
573                         printf("Error setting PHY %i autoneg\n", port);
574                         continue;
575                 }
576
577                 res = 0;
578         }
579
580         return res;
581 }
582
583 static int b53_phy_startup(struct phy_device *phydev)
584 {
585         unsigned int port;
586         int res;
587
588         for (port = 0; port < B53_N_PORTS; port++) {
589                 if (!((1 << port) & CONFIG_B53_PHY_PORTS))
590                         continue;
591
592                 phydev->addr = port;
593
594                 res = genphy_startup(phydev);
595                 if (res < 0)
596                         continue;
597                 else
598                         break;
599         }
600
601         /* Since we are connected directly to the switch, hardcode the link
602          * parameters to match those of the CPU port configured in
603          * b53_enable_cpu_port, we cannot be dependent on the user-facing port
604          * settings (e.g: 100Mbits/sec would not work here)
605          */
606         phydev->speed = 1000;
607         phydev->duplex = 1;
608         phydev->link = 1;
609
610         return 0;
611 }
612
613 static struct phy_driver b53_driver = {
614         .name = "Broadcom BCM53125",
615         .uid = 0x03625c00,
616         .mask = 0xfffffc00,
617         .features = PHY_GBIT_FEATURES,
618         .probe = b53_probe,
619         .config = b53_phy_config,
620         .startup = b53_phy_startup,
621         .shutdown = &genphy_shutdown,
622 };
623
624 int phy_b53_init(void)
625 {
626         phy_register(&b53_driver);
627
628         return 0;
629 }
630
631 int do_b53_reg_read(const char *name, int argc, char *const argv[])
632 {
633         u8 page, offset, width;
634         struct mii_dev *bus;
635         int ret = -EINVAL;
636         u64 value64 = 0;
637         u32 value32 = 0;
638         u16 value16 = 0;
639         u8 value8 = 0;
640
641         bus = miiphy_get_dev_by_name(name);
642         if (!bus) {
643                 printf("unable to find MDIO bus: %s\n", name);
644                 return ret;
645         }
646
647         page = simple_strtoul(argv[1], NULL, 16);
648         offset = simple_strtoul(argv[2], NULL, 16);
649         width = simple_strtoul(argv[3], NULL, 10);
650
651         switch (width) {
652         case 8:
653                 ret = b53_mdio_read8(bus, page, offset, &value8);
654                 printf("page=0x%02x, offset=0x%02x, value=0x%02x\n",
655                        page, offset, value8);
656                 break;
657         case 16:
658                 ret = b53_mdio_read16(bus, page, offset, &value16);
659                 printf("page=0x%02x, offset=0x%02x, value=0x%04x\n",
660                        page, offset, value16);
661                 break;
662         case 32:
663                 ret = b53_mdio_read32(bus, page, offset, &value32);
664                 printf("page=0x%02x, offset=0x%02x, value=0x%08x\n",
665                        page, offset, value32);
666                 break;
667         case 48:
668                 ret = b53_mdio_read48(bus, page, offset, &value64);
669                 printf("page=0x%02x, offset=0x%02x, value=0x%012llx\n",
670                        page, offset, value64);
671                 break;
672         case 64:
673                 ret = b53_mdio_read48(bus, page, offset, &value64);
674                 printf("page=0x%02x, offset=0x%02x, value=0x%016llx\n",
675                        page, offset, value64);
676                 break;
677         default:
678                 printf("Unsupported width: %d\n", width);
679                 break;
680         }
681
682         return ret;
683 }
684
685 int do_b53_reg_write(const char *name, int argc, char *const argv[])
686 {
687         u8 page, offset, width;
688         struct mii_dev *bus;
689         int ret = -EINVAL;
690         u64 value64 = 0;
691         u32 value = 0;
692
693         bus = miiphy_get_dev_by_name(name);
694         if (!bus) {
695                 printf("unable to find MDIO bus: %s\n", name);
696                 return ret;
697         }
698
699         page = simple_strtoul(argv[1], NULL, 16);
700         offset = simple_strtoul(argv[2], NULL, 16);
701         width = simple_strtoul(argv[3], NULL, 10);
702         if (width == 48 || width == 64)
703                 value64 = simple_strtoull(argv[4], NULL, 16);
704         else
705                 value = simple_strtoul(argv[4], NULL, 16);
706
707         switch (width) {
708         case 8:
709                 ret = b53_mdio_write8(bus, page, offset, value & 0xff);
710                 break;
711         case 16:
712                 ret = b53_mdio_write16(bus, page, offset, value);
713                 break;
714         case 32:
715                 ret = b53_mdio_write32(bus, page, offset, value);
716                 break;
717         case 48:
718                 ret = b53_mdio_write48(bus, page, offset, value64);
719                 break;
720         case 64:
721                 ret = b53_mdio_write64(bus, page, offset, value64);
722                 break;
723         default:
724                 printf("Unsupported width: %d\n", width);
725                 break;
726         }
727
728         return ret;
729 }
730
731 int do_b53_reg(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
732 {
733         const char *cmd, *mdioname;
734         int ret = 0;
735
736         if (argc < 2)
737                 return cmd_usage(cmdtp);
738
739         cmd = argv[1];
740         --argc;
741         ++argv;
742
743         if (!strcmp(cmd, "write")) {
744                 if (argc < 4)
745                         return cmd_usage(cmdtp);
746                 mdioname = argv[1];
747                 --argc;
748                 ++argv;
749                 ret = do_b53_reg_write(mdioname, argc, argv);
750         } else if (!strcmp(cmd, "read")) {
751                 if (argc < 5)
752                         return cmd_usage(cmdtp);
753                 mdioname = argv[1];
754                 --argc;
755                 ++argv;
756                 ret = do_b53_reg_read(mdioname, argc, argv);
757         } else {
758                 return cmd_usage(cmdtp);
759         }
760
761         return ret;
762 }
763
764 U_BOOT_CMD(b53_reg, 7, 1, do_b53_reg,
765            "Broadcom B53 switch register access",
766            "write mdioname page (hex) offset (hex) width (dec) value (hex)\n"
767            "read mdioname page (hex) offset (hex) width (dec)\n"
768           );