broadcom.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * drivers/net/phy/broadcom.c
  4. *
  5. * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
  6. * transceivers.
  7. *
  8. * Copyright (c) 2006 Maciej W. Rozycki
  9. *
  10. * Inspired by code written by Amy Fong.
  11. */
  12. #include "bcm-phy-lib.h"
  13. #include <linux/delay.h>
  14. #include <linux/module.h>
  15. #include <linux/phy.h>
  16. #include <linux/brcmphy.h>
  17. #include <linux/of.h>
  18. #define BRCM_PHY_MODEL(phydev) \
  19. ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
  20. #define BRCM_PHY_REV(phydev) \
  21. ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
  22. MODULE_DESCRIPTION("Broadcom PHY driver");
  23. MODULE_AUTHOR("Maciej W. Rozycki");
  24. MODULE_LICENSE("GPL");
  25. struct bcm54xx_phy_priv {
  26. u64 *stats;
  27. struct bcm_ptp_private *ptp;
  28. };
  29. static int bcm54xx_config_clock_delay(struct phy_device *phydev)
  30. {
  31. int rc, val;
  32. /* handling PHY's internal RX clock delay */
  33. val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  34. val |= MII_BCM54XX_AUXCTL_MISC_WREN;
  35. if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
  36. phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
  37. /* Disable RGMII RXC-RXD skew */
  38. val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  39. }
  40. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  41. phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
  42. /* Enable RGMII RXC-RXD skew */
  43. val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
  44. }
  45. rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  46. val);
  47. if (rc < 0)
  48. return rc;
  49. /* handling PHY's internal TX clock delay */
  50. val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
  51. if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
  52. phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
  53. /* Disable internal TX clock delay */
  54. val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
  55. }
  56. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  57. phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
  58. /* Enable internal TX clock delay */
  59. val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
  60. }
  61. rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
  62. if (rc < 0)
  63. return rc;
  64. return 0;
  65. }
  66. static int bcm54210e_config_init(struct phy_device *phydev)
  67. {
  68. int val;
  69. bcm54xx_config_clock_delay(phydev);
  70. if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
  71. val = phy_read(phydev, MII_CTRL1000);
  72. val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
  73. phy_write(phydev, MII_CTRL1000, val);
  74. }
  75. return 0;
  76. }
  77. static int bcm54612e_config_init(struct phy_device *phydev)
  78. {
  79. int reg;
  80. bcm54xx_config_clock_delay(phydev);
  81. /* Enable CLK125 MUX on LED4 if ref clock is enabled. */
  82. if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
  83. int err;
  84. reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
  85. err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
  86. BCM54612E_LED4_CLK125OUT_EN | reg);
  87. if (err < 0)
  88. return err;
  89. }
  90. return 0;
  91. }
  92. static int bcm54616s_config_init(struct phy_device *phydev)
  93. {
  94. int rc, val;
  95. if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
  96. phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
  97. return 0;
  98. /* Ensure proper interface mode is selected. */
  99. /* Disable RGMII mode */
  100. val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  101. if (val < 0)
  102. return val;
  103. val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
  104. val |= MII_BCM54XX_AUXCTL_MISC_WREN;
  105. rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  106. val);
  107. if (rc < 0)
  108. return rc;
  109. /* Select 1000BASE-X register set (primary SerDes) */
  110. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
  111. if (val < 0)
  112. return val;
  113. val |= BCM54XX_SHD_MODE_1000BX;
  114. rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
  115. if (rc < 0)
  116. return rc;
  117. /* Power down SerDes interface */
  118. rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
  119. if (rc < 0)
  120. return rc;
  121. /* Select proper interface mode */
  122. val &= ~BCM54XX_SHD_INTF_SEL_MASK;
  123. val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
  124. BCM54XX_SHD_INTF_SEL_SGMII :
  125. BCM54XX_SHD_INTF_SEL_GBIC;
  126. rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
  127. if (rc < 0)
  128. return rc;
  129. /* Power up SerDes interface */
  130. rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
  131. if (rc < 0)
  132. return rc;
  133. /* Select copper register set */
  134. val &= ~BCM54XX_SHD_MODE_1000BX;
  135. rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
  136. if (rc < 0)
  137. return rc;
  138. /* Power up copper interface */
  139. return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
  140. }
  141. /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
  142. static int bcm50610_a0_workaround(struct phy_device *phydev)
  143. {
  144. int err;
  145. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
  146. MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
  147. MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
  148. if (err < 0)
  149. return err;
  150. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
  151. MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
  152. if (err < 0)
  153. return err;
  154. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
  155. MII_BCM54XX_EXP_EXP75_VDACCTRL);
  156. if (err < 0)
  157. return err;
  158. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
  159. MII_BCM54XX_EXP_EXP96_MYST);
  160. if (err < 0)
  161. return err;
  162. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
  163. MII_BCM54XX_EXP_EXP97_MYST);
  164. return err;
  165. }
  166. static int bcm54xx_phydsp_config(struct phy_device *phydev)
  167. {
  168. int err, err2;
  169. /* Enable the SMDSP clock */
  170. err = bcm54xx_auxctl_write(phydev,
  171. MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
  172. MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
  173. MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
  174. if (err < 0)
  175. return err;
  176. if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
  177. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
  178. /* Clear bit 9 to fix a phy interop issue. */
  179. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
  180. MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
  181. if (err < 0)
  182. goto error;
  183. if (phydev->drv->phy_id == PHY_ID_BCM50610) {
  184. err = bcm50610_a0_workaround(phydev);
  185. if (err < 0)
  186. goto error;
  187. }
  188. }
  189. if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
  190. int val;
  191. val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
  192. if (val < 0)
  193. goto error;
  194. val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
  195. err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
  196. }
  197. error:
  198. /* Disable the SMDSP clock */
  199. err2 = bcm54xx_auxctl_write(phydev,
  200. MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
  201. MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
  202. /* Return the first error reported. */
  203. return err ? err : err2;
  204. }
  205. static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
  206. {
  207. u32 orig;
  208. int val;
  209. bool clk125en = true;
  210. /* Abort if we are using an untested phy. */
  211. if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
  212. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
  213. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
  214. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E &&
  215. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
  216. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
  217. return;
  218. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
  219. if (val < 0)
  220. return;
  221. orig = val;
  222. if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
  223. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
  224. BRCM_PHY_REV(phydev) >= 0x3) {
  225. /*
  226. * Here, bit 0 _disables_ CLK125 when set.
  227. * This bit is set by default.
  228. */
  229. clk125en = false;
  230. } else {
  231. if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
  232. if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) {
  233. /* Here, bit 0 _enables_ CLK125 when set */
  234. val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
  235. }
  236. clk125en = false;
  237. }
  238. }
  239. if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
  240. val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
  241. else
  242. val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
  243. if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
  244. if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
  245. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
  246. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
  247. val |= BCM54XX_SHD_SCR3_RXCTXC_DIS;
  248. else
  249. val |= BCM54XX_SHD_SCR3_TRDDAPD;
  250. }
  251. if (orig != val)
  252. bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
  253. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
  254. if (val < 0)
  255. return;
  256. orig = val;
  257. if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
  258. val |= BCM54XX_SHD_APD_EN;
  259. else
  260. val &= ~BCM54XX_SHD_APD_EN;
  261. if (orig != val)
  262. bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
  263. }
  264. static void bcm54xx_ptp_stop(struct phy_device *phydev)
  265. {
  266. struct bcm54xx_phy_priv *priv = phydev->priv;
  267. if (priv->ptp)
  268. bcm_ptp_stop(priv->ptp);
  269. }
  270. static void bcm54xx_ptp_config_init(struct phy_device *phydev)
  271. {
  272. struct bcm54xx_phy_priv *priv = phydev->priv;
  273. if (priv->ptp)
  274. bcm_ptp_config_init(phydev);
  275. }
  276. static int bcm54xx_config_init(struct phy_device *phydev)
  277. {
  278. int reg, err, val;
  279. reg = phy_read(phydev, MII_BCM54XX_ECR);
  280. if (reg < 0)
  281. return reg;
  282. /* Mask interrupts globally. */
  283. reg |= MII_BCM54XX_ECR_IM;
  284. err = phy_write(phydev, MII_BCM54XX_ECR, reg);
  285. if (err < 0)
  286. return err;
  287. /* Unmask events we are interested in. */
  288. reg = ~(MII_BCM54XX_INT_DUPLEX |
  289. MII_BCM54XX_INT_SPEED |
  290. MII_BCM54XX_INT_LINK);
  291. err = phy_write(phydev, MII_BCM54XX_IMR, reg);
  292. if (err < 0)
  293. return err;
  294. if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
  295. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
  296. (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
  297. bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
  298. bcm54xx_adjust_rxrefclk(phydev);
  299. switch (BRCM_PHY_MODEL(phydev)) {
  300. case PHY_ID_BCM50610:
  301. case PHY_ID_BCM50610M:
  302. err = bcm54xx_config_clock_delay(phydev);
  303. break;
  304. case PHY_ID_BCM54210E:
  305. err = bcm54210e_config_init(phydev);
  306. break;
  307. case PHY_ID_BCM54612E:
  308. err = bcm54612e_config_init(phydev);
  309. break;
  310. case PHY_ID_BCM54616S:
  311. err = bcm54616s_config_init(phydev);
  312. break;
  313. case PHY_ID_BCM54810:
  314. /* For BCM54810, we need to disable BroadR-Reach function */
  315. val = bcm_phy_read_exp(phydev,
  316. BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
  317. val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
  318. err = bcm_phy_write_exp(phydev,
  319. BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
  320. val);
  321. break;
  322. }
  323. if (err)
  324. return err;
  325. bcm54xx_phydsp_config(phydev);
  326. /* For non-SFP setups, encode link speed into LED1 and LED3 pair
  327. * (green/amber).
  328. * Also flash these two LEDs on activity. This means configuring
  329. * them for MULTICOLOR and encoding link/activity into them.
  330. * Don't do this for devices on an SFP module, since some of these
  331. * use the LED outputs to control the SFP LOS signal, and changing
  332. * these settings will cause LOS to malfunction.
  333. */
  334. if (!phy_on_sfp(phydev)) {
  335. val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
  336. BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
  337. bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
  338. val = BCM_LED_MULTICOLOR_IN_PHASE |
  339. BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
  340. BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
  341. bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
  342. }
  343. bcm54xx_ptp_config_init(phydev);
  344. return 0;
  345. }
  346. static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable)
  347. {
  348. int ret = 0;
  349. if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND))
  350. return ret;
  351. ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL);
  352. if (ret < 0)
  353. goto out;
  354. if (enable)
  355. ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP;
  356. else
  357. ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP);
  358. ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret);
  359. out:
  360. return ret;
  361. }
  362. static int bcm54xx_suspend(struct phy_device *phydev)
  363. {
  364. int ret;
  365. bcm54xx_ptp_stop(phydev);
  366. /* We cannot use a read/modify/write here otherwise the PHY gets into
  367. * a bad state where its LEDs keep flashing, thus defeating the purpose
  368. * of low power mode.
  369. */
  370. ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN);
  371. if (ret < 0)
  372. return ret;
  373. return bcm54xx_iddq_set(phydev, true);
  374. }
  375. static int bcm54xx_resume(struct phy_device *phydev)
  376. {
  377. int ret;
  378. ret = bcm54xx_iddq_set(phydev, false);
  379. if (ret < 0)
  380. return ret;
  381. /* Writes to register other than BMCR would be ignored
  382. * unless we clear the PDOWN bit first
  383. */
  384. ret = genphy_resume(phydev);
  385. if (ret < 0)
  386. return ret;
  387. /* Upon exiting power down, the PHY remains in an internal reset state
  388. * for 40us
  389. */
  390. fsleep(40);
  391. /* Issue a soft reset after clearing the power down bit
  392. * and before doing any other configuration.
  393. */
  394. if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) {
  395. ret = genphy_soft_reset(phydev);
  396. if (ret < 0)
  397. return ret;
  398. }
  399. return bcm54xx_config_init(phydev);
  400. }
  401. static int bcm54810_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
  402. {
  403. return -EOPNOTSUPP;
  404. }
  405. static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
  406. u16 val)
  407. {
  408. return -EOPNOTSUPP;
  409. }
  410. static int bcm54811_config_init(struct phy_device *phydev)
  411. {
  412. int err, reg;
  413. /* Disable BroadR-Reach function. */
  414. reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
  415. reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
  416. err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
  417. reg);
  418. if (err < 0)
  419. return err;
  420. err = bcm54xx_config_init(phydev);
  421. /* Enable CLK125 MUX on LED4 if ref clock is enabled. */
  422. if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
  423. reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
  424. err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
  425. BCM54612E_LED4_CLK125OUT_EN | reg);
  426. if (err < 0)
  427. return err;
  428. }
  429. return err;
  430. }
  431. static int bcm5481_config_aneg(struct phy_device *phydev)
  432. {
  433. struct device_node *np = phydev->mdio.dev.of_node;
  434. int ret;
  435. /* Aneg firstly. */
  436. ret = genphy_config_aneg(phydev);
  437. /* Then we can set up the delay. */
  438. bcm54xx_config_clock_delay(phydev);
  439. if (of_property_read_bool(np, "enet-phy-lane-swap")) {
  440. /* Lane Swap - Undocumented register...magic! */
  441. ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
  442. 0x11B);
  443. if (ret < 0)
  444. return ret;
  445. }
  446. return ret;
  447. }
  448. struct bcm54616s_phy_priv {
  449. bool mode_1000bx_en;
  450. };
  451. static int bcm54616s_probe(struct phy_device *phydev)
  452. {
  453. struct bcm54616s_phy_priv *priv;
  454. int val;
  455. priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
  456. if (!priv)
  457. return -ENOMEM;
  458. phydev->priv = priv;
  459. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
  460. if (val < 0)
  461. return val;
  462. /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0]
  463. * is 01b, and the link between PHY and its link partner can be
  464. * either 1000Base-X or 100Base-FX.
  465. * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
  466. * support is still missing as of now.
  467. */
  468. if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
  469. val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
  470. if (val < 0)
  471. return val;
  472. /* Bit 0 of the SerDes 100-FX Control register, when set
  473. * to 1, sets the MII/RGMII -> 100BASE-FX configuration.
  474. * When this bit is set to 0, it sets the GMII/RGMII ->
  475. * 1000BASE-X configuration.
  476. */
  477. if (!(val & BCM54616S_100FX_MODE))
  478. priv->mode_1000bx_en = true;
  479. phydev->port = PORT_FIBRE;
  480. }
  481. return 0;
  482. }
  483. static int bcm54616s_config_aneg(struct phy_device *phydev)
  484. {
  485. struct bcm54616s_phy_priv *priv = phydev->priv;
  486. int ret;
  487. /* Aneg firstly. */
  488. if (priv->mode_1000bx_en)
  489. ret = genphy_c37_config_aneg(phydev);
  490. else
  491. ret = genphy_config_aneg(phydev);
  492. /* Then we can set up the delay. */
  493. bcm54xx_config_clock_delay(phydev);
  494. return ret;
  495. }
  496. static int bcm54616s_read_status(struct phy_device *phydev)
  497. {
  498. struct bcm54616s_phy_priv *priv = phydev->priv;
  499. int err;
  500. if (priv->mode_1000bx_en)
  501. err = genphy_c37_read_status(phydev);
  502. else
  503. err = genphy_read_status(phydev);
  504. return err;
  505. }
  506. static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
  507. {
  508. int val;
  509. val = phy_read(phydev, reg);
  510. if (val < 0)
  511. return val;
  512. return phy_write(phydev, reg, val | set);
  513. }
  514. static int brcm_fet_config_init(struct phy_device *phydev)
  515. {
  516. int reg, err, err2, brcmtest;
  517. /* Reset the PHY to bring it to a known state. */
  518. err = phy_write(phydev, MII_BMCR, BMCR_RESET);
  519. if (err < 0)
  520. return err;
  521. /* The datasheet indicates the PHY needs up to 1us to complete a reset,
  522. * build some slack here.
  523. */
  524. usleep_range(1000, 2000);
  525. /* The PHY requires 65 MDC clock cycles to complete a write operation
  526. * and turnaround the line properly.
  527. *
  528. * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac)
  529. * may flag the lack of turn-around as a read failure. This is
  530. * particularly true with this combination since the MDIO controller
  531. * only used 64 MDC cycles. This is not a critical failure in this
  532. * specific case and it has no functional impact otherwise, so we let
  533. * that one go through. If there is a genuine bus error, the next read
  534. * of MII_BRCM_FET_INTREG will error out.
  535. */
  536. err = phy_read(phydev, MII_BMCR);
  537. if (err < 0 && err != -EIO)
  538. return err;
  539. reg = phy_read(phydev, MII_BRCM_FET_INTREG);
  540. if (reg < 0)
  541. return reg;
  542. /* Unmask events we are interested in and mask interrupts globally. */
  543. reg = MII_BRCM_FET_IR_DUPLEX_EN |
  544. MII_BRCM_FET_IR_SPEED_EN |
  545. MII_BRCM_FET_IR_LINK_EN |
  546. MII_BRCM_FET_IR_ENABLE |
  547. MII_BRCM_FET_IR_MASK;
  548. err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
  549. if (err < 0)
  550. return err;
  551. /* Enable shadow register access */
  552. brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
  553. if (brcmtest < 0)
  554. return brcmtest;
  555. reg = brcmtest | MII_BRCM_FET_BT_SRE;
  556. err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
  557. if (err < 0)
  558. return err;
  559. /* Set the LED mode */
  560. reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
  561. if (reg < 0) {
  562. err = reg;
  563. goto done;
  564. }
  565. reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
  566. reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
  567. err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
  568. if (err < 0)
  569. goto done;
  570. /* Enable auto MDIX */
  571. err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
  572. MII_BRCM_FET_SHDW_MC_FAME);
  573. if (err < 0)
  574. goto done;
  575. if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
  576. /* Enable auto power down */
  577. err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
  578. MII_BRCM_FET_SHDW_AS2_APDE);
  579. }
  580. done:
  581. /* Disable shadow register access */
  582. err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
  583. if (!err)
  584. err = err2;
  585. return err;
  586. }
  587. static int brcm_fet_ack_interrupt(struct phy_device *phydev)
  588. {
  589. int reg;
  590. /* Clear pending interrupts. */
  591. reg = phy_read(phydev, MII_BRCM_FET_INTREG);
  592. if (reg < 0)
  593. return reg;
  594. return 0;
  595. }
  596. static int brcm_fet_config_intr(struct phy_device *phydev)
  597. {
  598. int reg, err;
  599. reg = phy_read(phydev, MII_BRCM_FET_INTREG);
  600. if (reg < 0)
  601. return reg;
  602. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  603. err = brcm_fet_ack_interrupt(phydev);
  604. if (err)
  605. return err;
  606. reg &= ~MII_BRCM_FET_IR_MASK;
  607. err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
  608. } else {
  609. reg |= MII_BRCM_FET_IR_MASK;
  610. err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
  611. if (err)
  612. return err;
  613. err = brcm_fet_ack_interrupt(phydev);
  614. }
  615. return err;
  616. }
  617. static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
  618. {
  619. int irq_status;
  620. irq_status = phy_read(phydev, MII_BRCM_FET_INTREG);
  621. if (irq_status < 0) {
  622. phy_error(phydev);
  623. return IRQ_NONE;
  624. }
  625. if (irq_status == 0)
  626. return IRQ_NONE;
  627. phy_trigger_machine(phydev);
  628. return IRQ_HANDLED;
  629. }
  630. static int brcm_fet_suspend(struct phy_device *phydev)
  631. {
  632. int reg, err, err2, brcmtest;
  633. /* We cannot use a read/modify/write here otherwise the PHY continues
  634. * to drive LEDs which defeats the purpose of low power mode.
  635. */
  636. err = phy_write(phydev, MII_BMCR, BMCR_PDOWN);
  637. if (err < 0)
  638. return err;
  639. /* Enable shadow register access */
  640. brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
  641. if (brcmtest < 0)
  642. return brcmtest;
  643. reg = brcmtest | MII_BRCM_FET_BT_SRE;
  644. err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
  645. if (err < 0)
  646. return err;
  647. /* Set standby mode */
  648. err = phy_modify(phydev, MII_BRCM_FET_SHDW_AUXMODE4,
  649. MII_BRCM_FET_SHDW_AM4_STANDBY,
  650. MII_BRCM_FET_SHDW_AM4_STANDBY);
  651. /* Disable shadow register access */
  652. err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
  653. if (!err)
  654. err = err2;
  655. return err;
  656. }
  657. static int bcm54xx_phy_probe(struct phy_device *phydev)
  658. {
  659. struct bcm54xx_phy_priv *priv;
  660. priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
  661. if (!priv)
  662. return -ENOMEM;
  663. phydev->priv = priv;
  664. priv->stats = devm_kcalloc(&phydev->mdio.dev,
  665. bcm_phy_get_sset_count(phydev), sizeof(u64),
  666. GFP_KERNEL);
  667. if (!priv->stats)
  668. return -ENOMEM;
  669. priv->ptp = bcm_ptp_probe(phydev);
  670. if (IS_ERR(priv->ptp))
  671. return PTR_ERR(priv->ptp);
  672. return 0;
  673. }
  674. static void bcm54xx_get_stats(struct phy_device *phydev,
  675. struct ethtool_stats *stats, u64 *data)
  676. {
  677. struct bcm54xx_phy_priv *priv = phydev->priv;
  678. bcm_phy_get_stats(phydev, priv->stats, stats, data);
  679. }
  680. static void bcm54xx_link_change_notify(struct phy_device *phydev)
  681. {
  682. u16 mask = MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE |
  683. MII_BCM54XX_EXP_EXP08_FORCE_DAC_WAKE;
  684. int ret;
  685. if (phydev->state != PHY_RUNNING)
  686. return;
  687. /* Don't change the DAC wake settings if auto power down
  688. * is not requested.
  689. */
  690. if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
  691. return;
  692. ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08);
  693. if (ret < 0)
  694. return;
  695. /* Enable/disable 10BaseT auto and forced early DAC wake depending
  696. * on the negotiated speed, those settings should only be done
  697. * for 10Mbits/sec.
  698. */
  699. if (phydev->speed == SPEED_10)
  700. ret |= mask;
  701. else
  702. ret &= ~mask;
  703. bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret);
  704. }
  705. static struct phy_driver broadcom_drivers[] = {
  706. {
  707. .phy_id = PHY_ID_BCM5411,
  708. .phy_id_mask = 0xfffffff0,
  709. .name = "Broadcom BCM5411",
  710. /* PHY_GBIT_FEATURES */
  711. .get_sset_count = bcm_phy_get_sset_count,
  712. .get_strings = bcm_phy_get_strings,
  713. .get_stats = bcm54xx_get_stats,
  714. .probe = bcm54xx_phy_probe,
  715. .config_init = bcm54xx_config_init,
  716. .config_intr = bcm_phy_config_intr,
  717. .handle_interrupt = bcm_phy_handle_interrupt,
  718. .link_change_notify = bcm54xx_link_change_notify,
  719. }, {
  720. .phy_id = PHY_ID_BCM5421,
  721. .phy_id_mask = 0xfffffff0,
  722. .name = "Broadcom BCM5421",
  723. /* PHY_GBIT_FEATURES */
  724. .get_sset_count = bcm_phy_get_sset_count,
  725. .get_strings = bcm_phy_get_strings,
  726. .get_stats = bcm54xx_get_stats,
  727. .probe = bcm54xx_phy_probe,
  728. .config_init = bcm54xx_config_init,
  729. .config_intr = bcm_phy_config_intr,
  730. .handle_interrupt = bcm_phy_handle_interrupt,
  731. .link_change_notify = bcm54xx_link_change_notify,
  732. }, {
  733. .phy_id = PHY_ID_BCM54210E,
  734. .phy_id_mask = 0xfffffff0,
  735. .name = "Broadcom BCM54210E",
  736. /* PHY_GBIT_FEATURES */
  737. .get_sset_count = bcm_phy_get_sset_count,
  738. .get_strings = bcm_phy_get_strings,
  739. .get_stats = bcm54xx_get_stats,
  740. .probe = bcm54xx_phy_probe,
  741. .config_init = bcm54xx_config_init,
  742. .config_intr = bcm_phy_config_intr,
  743. .handle_interrupt = bcm_phy_handle_interrupt,
  744. .link_change_notify = bcm54xx_link_change_notify,
  745. .suspend = bcm54xx_suspend,
  746. .resume = bcm54xx_resume,
  747. }, {
  748. .phy_id = PHY_ID_BCM5461,
  749. .phy_id_mask = 0xfffffff0,
  750. .name = "Broadcom BCM5461",
  751. /* PHY_GBIT_FEATURES */
  752. .get_sset_count = bcm_phy_get_sset_count,
  753. .get_strings = bcm_phy_get_strings,
  754. .get_stats = bcm54xx_get_stats,
  755. .probe = bcm54xx_phy_probe,
  756. .config_init = bcm54xx_config_init,
  757. .config_intr = bcm_phy_config_intr,
  758. .handle_interrupt = bcm_phy_handle_interrupt,
  759. .link_change_notify = bcm54xx_link_change_notify,
  760. }, {
  761. .phy_id = PHY_ID_BCM54612E,
  762. .phy_id_mask = 0xfffffff0,
  763. .name = "Broadcom BCM54612E",
  764. /* PHY_GBIT_FEATURES */
  765. .get_sset_count = bcm_phy_get_sset_count,
  766. .get_strings = bcm_phy_get_strings,
  767. .get_stats = bcm54xx_get_stats,
  768. .probe = bcm54xx_phy_probe,
  769. .config_init = bcm54xx_config_init,
  770. .config_intr = bcm_phy_config_intr,
  771. .handle_interrupt = bcm_phy_handle_interrupt,
  772. .link_change_notify = bcm54xx_link_change_notify,
  773. }, {
  774. .phy_id = PHY_ID_BCM54616S,
  775. .phy_id_mask = 0xfffffff0,
  776. .name = "Broadcom BCM54616S",
  777. /* PHY_GBIT_FEATURES */
  778. .soft_reset = genphy_soft_reset,
  779. .config_init = bcm54xx_config_init,
  780. .config_aneg = bcm54616s_config_aneg,
  781. .config_intr = bcm_phy_config_intr,
  782. .handle_interrupt = bcm_phy_handle_interrupt,
  783. .read_status = bcm54616s_read_status,
  784. .probe = bcm54616s_probe,
  785. .link_change_notify = bcm54xx_link_change_notify,
  786. }, {
  787. .phy_id = PHY_ID_BCM5464,
  788. .phy_id_mask = 0xfffffff0,
  789. .name = "Broadcom BCM5464",
  790. /* PHY_GBIT_FEATURES */
  791. .get_sset_count = bcm_phy_get_sset_count,
  792. .get_strings = bcm_phy_get_strings,
  793. .get_stats = bcm54xx_get_stats,
  794. .probe = bcm54xx_phy_probe,
  795. .config_init = bcm54xx_config_init,
  796. .config_intr = bcm_phy_config_intr,
  797. .handle_interrupt = bcm_phy_handle_interrupt,
  798. .suspend = genphy_suspend,
  799. .resume = genphy_resume,
  800. .link_change_notify = bcm54xx_link_change_notify,
  801. }, {
  802. .phy_id = PHY_ID_BCM5481,
  803. .phy_id_mask = 0xfffffff0,
  804. .name = "Broadcom BCM5481",
  805. /* PHY_GBIT_FEATURES */
  806. .get_sset_count = bcm_phy_get_sset_count,
  807. .get_strings = bcm_phy_get_strings,
  808. .get_stats = bcm54xx_get_stats,
  809. .probe = bcm54xx_phy_probe,
  810. .config_init = bcm54xx_config_init,
  811. .config_aneg = bcm5481_config_aneg,
  812. .config_intr = bcm_phy_config_intr,
  813. .handle_interrupt = bcm_phy_handle_interrupt,
  814. .link_change_notify = bcm54xx_link_change_notify,
  815. }, {
  816. .phy_id = PHY_ID_BCM54810,
  817. .phy_id_mask = 0xfffffff0,
  818. .name = "Broadcom BCM54810",
  819. /* PHY_GBIT_FEATURES */
  820. .get_sset_count = bcm_phy_get_sset_count,
  821. .get_strings = bcm_phy_get_strings,
  822. .get_stats = bcm54xx_get_stats,
  823. .probe = bcm54xx_phy_probe,
  824. .read_mmd = bcm54810_read_mmd,
  825. .write_mmd = bcm54810_write_mmd,
  826. .config_init = bcm54xx_config_init,
  827. .config_aneg = bcm5481_config_aneg,
  828. .config_intr = bcm_phy_config_intr,
  829. .handle_interrupt = bcm_phy_handle_interrupt,
  830. .suspend = bcm54xx_suspend,
  831. .resume = bcm54xx_resume,
  832. .link_change_notify = bcm54xx_link_change_notify,
  833. }, {
  834. .phy_id = PHY_ID_BCM54811,
  835. .phy_id_mask = 0xfffffff0,
  836. .name = "Broadcom BCM54811",
  837. /* PHY_GBIT_FEATURES */
  838. .get_sset_count = bcm_phy_get_sset_count,
  839. .get_strings = bcm_phy_get_strings,
  840. .get_stats = bcm54xx_get_stats,
  841. .probe = bcm54xx_phy_probe,
  842. .config_init = bcm54811_config_init,
  843. .config_aneg = bcm5481_config_aneg,
  844. .config_intr = bcm_phy_config_intr,
  845. .handle_interrupt = bcm_phy_handle_interrupt,
  846. .suspend = bcm54xx_suspend,
  847. .resume = bcm54xx_resume,
  848. .link_change_notify = bcm54xx_link_change_notify,
  849. }, {
  850. .phy_id = PHY_ID_BCM5482,
  851. .phy_id_mask = 0xfffffff0,
  852. .name = "Broadcom BCM5482",
  853. /* PHY_GBIT_FEATURES */
  854. .get_sset_count = bcm_phy_get_sset_count,
  855. .get_strings = bcm_phy_get_strings,
  856. .get_stats = bcm54xx_get_stats,
  857. .probe = bcm54xx_phy_probe,
  858. .config_init = bcm54xx_config_init,
  859. .config_intr = bcm_phy_config_intr,
  860. .handle_interrupt = bcm_phy_handle_interrupt,
  861. .link_change_notify = bcm54xx_link_change_notify,
  862. }, {
  863. .phy_id = PHY_ID_BCM50610,
  864. .phy_id_mask = 0xfffffff0,
  865. .name = "Broadcom BCM50610",
  866. /* PHY_GBIT_FEATURES */
  867. .get_sset_count = bcm_phy_get_sset_count,
  868. .get_strings = bcm_phy_get_strings,
  869. .get_stats = bcm54xx_get_stats,
  870. .probe = bcm54xx_phy_probe,
  871. .config_init = bcm54xx_config_init,
  872. .config_intr = bcm_phy_config_intr,
  873. .handle_interrupt = bcm_phy_handle_interrupt,
  874. .link_change_notify = bcm54xx_link_change_notify,
  875. .suspend = bcm54xx_suspend,
  876. .resume = bcm54xx_resume,
  877. }, {
  878. .phy_id = PHY_ID_BCM50610M,
  879. .phy_id_mask = 0xfffffff0,
  880. .name = "Broadcom BCM50610M",
  881. /* PHY_GBIT_FEATURES */
  882. .get_sset_count = bcm_phy_get_sset_count,
  883. .get_strings = bcm_phy_get_strings,
  884. .get_stats = bcm54xx_get_stats,
  885. .probe = bcm54xx_phy_probe,
  886. .config_init = bcm54xx_config_init,
  887. .config_intr = bcm_phy_config_intr,
  888. .handle_interrupt = bcm_phy_handle_interrupt,
  889. .link_change_notify = bcm54xx_link_change_notify,
  890. .suspend = bcm54xx_suspend,
  891. .resume = bcm54xx_resume,
  892. }, {
  893. .phy_id = PHY_ID_BCM57780,
  894. .phy_id_mask = 0xfffffff0,
  895. .name = "Broadcom BCM57780",
  896. /* PHY_GBIT_FEATURES */
  897. .get_sset_count = bcm_phy_get_sset_count,
  898. .get_strings = bcm_phy_get_strings,
  899. .get_stats = bcm54xx_get_stats,
  900. .probe = bcm54xx_phy_probe,
  901. .config_init = bcm54xx_config_init,
  902. .config_intr = bcm_phy_config_intr,
  903. .handle_interrupt = bcm_phy_handle_interrupt,
  904. .link_change_notify = bcm54xx_link_change_notify,
  905. }, {
  906. .phy_id = PHY_ID_BCMAC131,
  907. .phy_id_mask = 0xfffffff0,
  908. .name = "Broadcom BCMAC131",
  909. /* PHY_BASIC_FEATURES */
  910. .config_init = brcm_fet_config_init,
  911. .config_intr = brcm_fet_config_intr,
  912. .handle_interrupt = brcm_fet_handle_interrupt,
  913. .suspend = brcm_fet_suspend,
  914. .resume = brcm_fet_config_init,
  915. }, {
  916. .phy_id = PHY_ID_BCM5241,
  917. .phy_id_mask = 0xfffffff0,
  918. .name = "Broadcom BCM5241",
  919. /* PHY_BASIC_FEATURES */
  920. .config_init = brcm_fet_config_init,
  921. .config_intr = brcm_fet_config_intr,
  922. .handle_interrupt = brcm_fet_handle_interrupt,
  923. .suspend = brcm_fet_suspend,
  924. .resume = brcm_fet_config_init,
  925. }, {
  926. .phy_id = PHY_ID_BCM5395,
  927. .phy_id_mask = 0xfffffff0,
  928. .name = "Broadcom BCM5395",
  929. .flags = PHY_IS_INTERNAL,
  930. /* PHY_GBIT_FEATURES */
  931. .get_sset_count = bcm_phy_get_sset_count,
  932. .get_strings = bcm_phy_get_strings,
  933. .get_stats = bcm54xx_get_stats,
  934. .probe = bcm54xx_phy_probe,
  935. .link_change_notify = bcm54xx_link_change_notify,
  936. }, {
  937. .phy_id = PHY_ID_BCM53125,
  938. .phy_id_mask = 0xfffffff0,
  939. .name = "Broadcom BCM53125",
  940. .flags = PHY_IS_INTERNAL,
  941. /* PHY_GBIT_FEATURES */
  942. .get_sset_count = bcm_phy_get_sset_count,
  943. .get_strings = bcm_phy_get_strings,
  944. .get_stats = bcm54xx_get_stats,
  945. .probe = bcm54xx_phy_probe,
  946. .config_init = bcm54xx_config_init,
  947. .config_intr = bcm_phy_config_intr,
  948. .handle_interrupt = bcm_phy_handle_interrupt,
  949. .link_change_notify = bcm54xx_link_change_notify,
  950. }, {
  951. .phy_id = PHY_ID_BCM53128,
  952. .phy_id_mask = 0xfffffff0,
  953. .name = "Broadcom BCM53128",
  954. .flags = PHY_IS_INTERNAL,
  955. /* PHY_GBIT_FEATURES */
  956. .get_sset_count = bcm_phy_get_sset_count,
  957. .get_strings = bcm_phy_get_strings,
  958. .get_stats = bcm54xx_get_stats,
  959. .probe = bcm54xx_phy_probe,
  960. .config_init = bcm54xx_config_init,
  961. .config_intr = bcm_phy_config_intr,
  962. .handle_interrupt = bcm_phy_handle_interrupt,
  963. .link_change_notify = bcm54xx_link_change_notify,
  964. }, {
  965. .phy_id = PHY_ID_BCM89610,
  966. .phy_id_mask = 0xfffffff0,
  967. .name = "Broadcom BCM89610",
  968. /* PHY_GBIT_FEATURES */
  969. .get_sset_count = bcm_phy_get_sset_count,
  970. .get_strings = bcm_phy_get_strings,
  971. .get_stats = bcm54xx_get_stats,
  972. .probe = bcm54xx_phy_probe,
  973. .config_init = bcm54xx_config_init,
  974. .config_intr = bcm_phy_config_intr,
  975. .handle_interrupt = bcm_phy_handle_interrupt,
  976. .link_change_notify = bcm54xx_link_change_notify,
  977. } };
  978. module_phy_driver(broadcom_drivers);
  979. static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
  980. { PHY_ID_BCM5411, 0xfffffff0 },
  981. { PHY_ID_BCM5421, 0xfffffff0 },
  982. { PHY_ID_BCM54210E, 0xfffffff0 },
  983. { PHY_ID_BCM5461, 0xfffffff0 },
  984. { PHY_ID_BCM54612E, 0xfffffff0 },
  985. { PHY_ID_BCM54616S, 0xfffffff0 },
  986. { PHY_ID_BCM5464, 0xfffffff0 },
  987. { PHY_ID_BCM5481, 0xfffffff0 },
  988. { PHY_ID_BCM54810, 0xfffffff0 },
  989. { PHY_ID_BCM54811, 0xfffffff0 },
  990. { PHY_ID_BCM5482, 0xfffffff0 },
  991. { PHY_ID_BCM50610, 0xfffffff0 },
  992. { PHY_ID_BCM50610M, 0xfffffff0 },
  993. { PHY_ID_BCM57780, 0xfffffff0 },
  994. { PHY_ID_BCMAC131, 0xfffffff0 },
  995. { PHY_ID_BCM5241, 0xfffffff0 },
  996. { PHY_ID_BCM5395, 0xfffffff0 },
  997. { PHY_ID_BCM53125, 0xfffffff0 },
  998. { PHY_ID_BCM53128, 0xfffffff0 },
  999. { PHY_ID_BCM89610, 0xfffffff0 },
  1000. { }
  1001. };
  1002. MODULE_DEVICE_TABLE(mdio, broadcom_tbl);