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