b53.c 18 KB

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