b53.c 18 KB

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