broadcom.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*
  2. * drivers/net/phy/broadcom.c
  3. *
  4. * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
  5. * transceivers.
  6. *
  7. * Copyright (c) 2006 Maciej W. Rozycki
  8. *
  9. * Inspired by code written by Amy Fong.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version
  14. * 2 of the License, or (at your option) any later version.
  15. */
  16. #include <linux/module.h>
  17. #include <linux/phy.h>
  18. #include <linux/brcmphy.h>
  19. #define BRCM_PHY_MODEL(phydev) \
  20. ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
  21. #define BRCM_PHY_REV(phydev) \
  22. ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
  23. /*
  24. * Broadcom LED source encodings. These are used in BCM5461, BCM5481,
  25. * BCM5482, and possibly some others.
  26. */
  27. #define BCM_LED_SRC_LINKSPD1 0x0
  28. #define BCM_LED_SRC_LINKSPD2 0x1
  29. #define BCM_LED_SRC_XMITLED 0x2
  30. #define BCM_LED_SRC_ACTIVITYLED 0x3
  31. #define BCM_LED_SRC_FDXLED 0x4
  32. #define BCM_LED_SRC_SLAVE 0x5
  33. #define BCM_LED_SRC_INTR 0x6
  34. #define BCM_LED_SRC_QUALITY 0x7
  35. #define BCM_LED_SRC_RCVLED 0x8
  36. #define BCM_LED_SRC_MULTICOLOR1 0xa
  37. #define BCM_LED_SRC_OPENSHORT 0xb
  38. #define BCM_LED_SRC_OFF 0xe /* Tied high */
  39. #define BCM_LED_SRC_ON 0xf /* Tied low */
  40. /*
  41. * BCM5482: Shadow registers
  42. * Shadow values go into bits [14:10] of register 0x1c to select a shadow
  43. * register to access.
  44. */
  45. /* 00101: Spare Control Register 3 */
  46. #define BCM54XX_SHD_SCR3 0x05
  47. #define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001
  48. #define BCM54XX_SHD_SCR3_DLLAPD_DIS 0x0002
  49. #define BCM54XX_SHD_SCR3_TRDDAPD 0x0004
  50. /* 01010: Auto Power-Down */
  51. #define BCM54XX_SHD_APD 0x0a
  52. #define BCM54XX_SHD_APD_EN 0x0020
  53. #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */
  54. /* LED3 / ~LINKSPD[2] selector */
  55. #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4)
  56. /* LED1 / ~LINKSPD[1] selector */
  57. #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0)
  58. #define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */
  59. #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */
  60. #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */
  61. #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */
  62. #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */
  63. #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */
  64. /*
  65. * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17)
  66. */
  67. #define MII_BCM54XX_EXP_AADJ1CH0 0x001f
  68. #define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
  69. #define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100
  70. #define MII_BCM54XX_EXP_AADJ1CH3 0x601f
  71. #define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002
  72. #define MII_BCM54XX_EXP_EXP08 0x0F08
  73. #define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001
  74. #define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200
  75. #define MII_BCM54XX_EXP_EXP75 0x0f75
  76. #define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c
  77. #define MII_BCM54XX_EXP_EXP75_CM_OSC 0x0001
  78. #define MII_BCM54XX_EXP_EXP96 0x0f96
  79. #define MII_BCM54XX_EXP_EXP96_MYST 0x0010
  80. #define MII_BCM54XX_EXP_EXP97 0x0f97
  81. #define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c
  82. /*
  83. * BCM5482: Secondary SerDes registers
  84. */
  85. #define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */
  86. #define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */
  87. #define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */
  88. #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
  89. #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */
  90. /*****************************************************************************/
  91. /* Fast Ethernet Transceiver definitions. */
  92. /*****************************************************************************/
  93. #define MII_BRCM_FET_INTREG 0x1a /* Interrupt register */
  94. #define MII_BRCM_FET_IR_MASK 0x0100 /* Mask all interrupts */
  95. #define MII_BRCM_FET_IR_LINK_EN 0x0200 /* Link status change enable */
  96. #define MII_BRCM_FET_IR_SPEED_EN 0x0400 /* Link speed change enable */
  97. #define MII_BRCM_FET_IR_DUPLEX_EN 0x0800 /* Duplex mode change enable */
  98. #define MII_BRCM_FET_IR_ENABLE 0x4000 /* Interrupt enable */
  99. #define MII_BRCM_FET_BRCMTEST 0x1f /* Brcm test register */
  100. #define MII_BRCM_FET_BT_SRE 0x0080 /* Shadow register enable */
  101. /*** Shadow register definitions ***/
  102. #define MII_BRCM_FET_SHDW_MISCCTRL 0x10 /* Shadow misc ctrl */
  103. #define MII_BRCM_FET_SHDW_MC_FAME 0x4000 /* Force Auto MDIX enable */
  104. #define MII_BRCM_FET_SHDW_AUXMODE4 0x1a /* Auxiliary mode 4 */
  105. #define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
  106. #define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
  107. #define MII_BRCM_FET_SHDW_AUXSTAT2 0x1b /* Auxiliary status 2 */
  108. #define MII_BRCM_FET_SHDW_AS2_APDE 0x0020 /* Auto power down enable */
  109. MODULE_DESCRIPTION("Broadcom PHY driver");
  110. MODULE_AUTHOR("Maciej W. Rozycki");
  111. MODULE_LICENSE("GPL");
  112. /*
  113. * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
  114. * 0x1c shadow registers.
  115. */
  116. static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
  117. {
  118. phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
  119. return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
  120. }
  121. static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
  122. {
  123. return phy_write(phydev, MII_BCM54XX_SHD,
  124. MII_BCM54XX_SHD_WRITE |
  125. MII_BCM54XX_SHD_VAL(shadow) |
  126. MII_BCM54XX_SHD_DATA(val));
  127. }
  128. /* Indirect register access functions for the Expansion Registers */
  129. static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
  130. {
  131. int val;
  132. val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
  133. if (val < 0)
  134. return val;
  135. val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
  136. /* Restore default value. It's O.K. if this write fails. */
  137. phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
  138. return val;
  139. }
  140. static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
  141. {
  142. int ret;
  143. ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
  144. if (ret < 0)
  145. return ret;
  146. ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
  147. /* Restore default value. It's O.K. if this write fails. */
  148. phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
  149. return ret;
  150. }
  151. static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
  152. {
  153. return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
  154. }
  155. /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
  156. static int bcm50610_a0_workaround(struct phy_device *phydev)
  157. {
  158. int err;
  159. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
  160. MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
  161. MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
  162. if (err < 0)
  163. return err;
  164. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
  165. MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
  166. if (err < 0)
  167. return err;
  168. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
  169. MII_BCM54XX_EXP_EXP75_VDACCTRL);
  170. if (err < 0)
  171. return err;
  172. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
  173. MII_BCM54XX_EXP_EXP96_MYST);
  174. if (err < 0)
  175. return err;
  176. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
  177. MII_BCM54XX_EXP_EXP97_MYST);
  178. return err;
  179. }
  180. static int bcm54xx_phydsp_config(struct phy_device *phydev)
  181. {
  182. int err, err2;
  183. /* Enable the SMDSP clock */
  184. err = bcm54xx_auxctl_write(phydev,
  185. MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
  186. MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
  187. MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
  188. if (err < 0)
  189. return err;
  190. if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
  191. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
  192. /* Clear bit 9 to fix a phy interop issue. */
  193. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
  194. MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
  195. if (err < 0)
  196. goto error;
  197. if (phydev->drv->phy_id == PHY_ID_BCM50610) {
  198. err = bcm50610_a0_workaround(phydev);
  199. if (err < 0)
  200. goto error;
  201. }
  202. }
  203. if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
  204. int val;
  205. val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
  206. if (val < 0)
  207. goto error;
  208. val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
  209. err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
  210. }
  211. error:
  212. /* Disable the SMDSP clock */
  213. err2 = bcm54xx_auxctl_write(phydev,
  214. MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
  215. MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
  216. /* Return the first error reported. */
  217. return err ? err : err2;
  218. }
  219. static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
  220. {
  221. u32 orig;
  222. int val;
  223. bool clk125en = true;
  224. /* Abort if we are using an untested phy. */
  225. if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
  226. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
  227. BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
  228. return;
  229. val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
  230. if (val < 0)
  231. return;
  232. orig = val;
  233. if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
  234. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
  235. BRCM_PHY_REV(phydev) >= 0x3) {
  236. /*
  237. * Here, bit 0 _disables_ CLK125 when set.
  238. * This bit is set by default.
  239. */
  240. clk125en = false;
  241. } else {
  242. if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
  243. /* Here, bit 0 _enables_ CLK125 when set */
  244. val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
  245. clk125en = false;
  246. }
  247. }
  248. if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
  249. val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
  250. else
  251. val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
  252. if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
  253. val |= BCM54XX_SHD_SCR3_TRDDAPD;
  254. if (orig != val)
  255. bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
  256. val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
  257. if (val < 0)
  258. return;
  259. orig = val;
  260. if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
  261. val |= BCM54XX_SHD_APD_EN;
  262. else
  263. val &= ~BCM54XX_SHD_APD_EN;
  264. if (orig != val)
  265. bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
  266. }
  267. static int bcm54xx_config_init(struct phy_device *phydev)
  268. {
  269. int reg, err;
  270. reg = phy_read(phydev, MII_BCM54XX_ECR);
  271. if (reg < 0)
  272. return reg;
  273. /* Mask interrupts globally. */
  274. reg |= MII_BCM54XX_ECR_IM;
  275. err = phy_write(phydev, MII_BCM54XX_ECR, reg);
  276. if (err < 0)
  277. return err;
  278. /* Unmask events we are interested in. */
  279. reg = ~(MII_BCM54XX_INT_DUPLEX |
  280. MII_BCM54XX_INT_SPEED |
  281. MII_BCM54XX_INT_LINK);
  282. err = phy_write(phydev, MII_BCM54XX_IMR, reg);
  283. if (err < 0)
  284. return err;
  285. if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
  286. BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
  287. (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
  288. bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
  289. if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
  290. (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
  291. (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
  292. bcm54xx_adjust_rxrefclk(phydev);
  293. bcm54xx_phydsp_config(phydev);
  294. return 0;
  295. }
  296. static int bcm5482_config_init(struct phy_device *phydev)
  297. {
  298. int err, reg;
  299. err = bcm54xx_config_init(phydev);
  300. if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
  301. /*
  302. * Enable secondary SerDes and its use as an LED source
  303. */
  304. reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
  305. bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
  306. reg |
  307. BCM5482_SHD_SSD_LEDM |
  308. BCM5482_SHD_SSD_EN);
  309. /*
  310. * Enable SGMII slave mode and auto-detection
  311. */
  312. reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
  313. err = bcm54xx_exp_read(phydev, reg);
  314. if (err < 0)
  315. return err;
  316. err = bcm54xx_exp_write(phydev, reg, err |
  317. BCM5482_SSD_SGMII_SLAVE_EN |
  318. BCM5482_SSD_SGMII_SLAVE_AD);
  319. if (err < 0)
  320. return err;
  321. /*
  322. * Disable secondary SerDes powerdown
  323. */
  324. reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
  325. err = bcm54xx_exp_read(phydev, reg);
  326. if (err < 0)
  327. return err;
  328. err = bcm54xx_exp_write(phydev, reg,
  329. err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
  330. if (err < 0)
  331. return err;
  332. /*
  333. * Select 1000BASE-X register set (primary SerDes)
  334. */
  335. reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
  336. bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
  337. reg | BCM5482_SHD_MODE_1000BX);
  338. /*
  339. * LED1=ACTIVITYLED, LED3=LINKSPD[2]
  340. * (Use LED1 as secondary SerDes ACTIVITY LED)
  341. */
  342. bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
  343. BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
  344. BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
  345. /*
  346. * Auto-negotiation doesn't seem to work quite right
  347. * in this mode, so we disable it and force it to the
  348. * right speed/duplex setting. Only 'link status'
  349. * is important.
  350. */
  351. phydev->autoneg = AUTONEG_DISABLE;
  352. phydev->speed = SPEED_1000;
  353. phydev->duplex = DUPLEX_FULL;
  354. }
  355. return err;
  356. }
  357. static int bcm5482_read_status(struct phy_device *phydev)
  358. {
  359. int err;
  360. err = genphy_read_status(phydev);
  361. if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
  362. /*
  363. * Only link status matters for 1000Base-X mode, so force
  364. * 1000 Mbit/s full-duplex status
  365. */
  366. if (phydev->link) {
  367. phydev->speed = SPEED_1000;
  368. phydev->duplex = DUPLEX_FULL;
  369. }
  370. }
  371. return err;
  372. }
  373. static int bcm54xx_ack_interrupt(struct phy_device *phydev)
  374. {
  375. int reg;
  376. /* Clear pending interrupts. */
  377. reg = phy_read(phydev, MII_BCM54XX_ISR);
  378. if (reg < 0)
  379. return reg;
  380. return 0;
  381. }
  382. static int bcm54xx_config_intr(struct phy_device *phydev)
  383. {
  384. int reg, err;
  385. reg = phy_read(phydev, MII_BCM54XX_ECR);
  386. if (reg < 0)
  387. return reg;
  388. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  389. reg &= ~MII_BCM54XX_ECR_IM;
  390. else
  391. reg |= MII_BCM54XX_ECR_IM;
  392. err = phy_write(phydev, MII_BCM54XX_ECR, reg);
  393. return err;
  394. }
  395. static int bcm5481_config_aneg(struct phy_device *phydev)
  396. {
  397. int ret;
  398. /* Aneg firsly. */
  399. ret = genphy_config_aneg(phydev);
  400. /* Then we can set up the delay. */
  401. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
  402. u16 reg;
  403. /*
  404. * There is no BCM5481 specification available, so down
  405. * here is everything we know about "register 0x18". This
  406. * at least helps BCM5481 to successfully receive packets
  407. * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
  408. * says: "This sets delay between the RXD and RXC signals
  409. * instead of using trace lengths to achieve timing".
  410. */
  411. /* Set RDX clk delay. */
  412. reg = 0x7 | (0x7 << 12);
  413. phy_write(phydev, 0x18, reg);
  414. reg = phy_read(phydev, 0x18);
  415. /* Set RDX-RXC skew. */
  416. reg |= (1 << 8);
  417. /* Write bits 14:0. */
  418. reg |= (1 << 15);
  419. phy_write(phydev, 0x18, reg);
  420. }
  421. return ret;
  422. }
  423. static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
  424. {
  425. int val;
  426. val = phy_read(phydev, reg);
  427. if (val < 0)
  428. return val;
  429. return phy_write(phydev, reg, val | set);
  430. }
  431. static int brcm_fet_config_init(struct phy_device *phydev)
  432. {
  433. int reg, err, err2, brcmtest;
  434. /* Reset the PHY to bring it to a known state. */
  435. err = phy_write(phydev, MII_BMCR, BMCR_RESET);
  436. if (err < 0)
  437. return err;
  438. reg = phy_read(phydev, MII_BRCM_FET_INTREG);
  439. if (reg < 0)
  440. return reg;
  441. /* Unmask events we are interested in and mask interrupts globally. */
  442. reg = MII_BRCM_FET_IR_DUPLEX_EN |
  443. MII_BRCM_FET_IR_SPEED_EN |
  444. MII_BRCM_FET_IR_LINK_EN |
  445. MII_BRCM_FET_IR_ENABLE |
  446. MII_BRCM_FET_IR_MASK;
  447. err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
  448. if (err < 0)
  449. return err;
  450. /* Enable shadow register access */
  451. brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
  452. if (brcmtest < 0)
  453. return brcmtest;
  454. reg = brcmtest | MII_BRCM_FET_BT_SRE;
  455. err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
  456. if (err < 0)
  457. return err;
  458. /* Set the LED mode */
  459. reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
  460. if (reg < 0) {
  461. err = reg;
  462. goto done;
  463. }
  464. reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
  465. reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
  466. err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
  467. if (err < 0)
  468. goto done;
  469. /* Enable auto MDIX */
  470. err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
  471. MII_BRCM_FET_SHDW_MC_FAME);
  472. if (err < 0)
  473. goto done;
  474. if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
  475. /* Enable auto power down */
  476. err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
  477. MII_BRCM_FET_SHDW_AS2_APDE);
  478. }
  479. done:
  480. /* Disable shadow register access */
  481. err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
  482. if (!err)
  483. err = err2;
  484. return err;
  485. }
  486. static int brcm_fet_ack_interrupt(struct phy_device *phydev)
  487. {
  488. int reg;
  489. /* Clear pending interrupts. */
  490. reg = phy_read(phydev, MII_BRCM_FET_INTREG);
  491. if (reg < 0)
  492. return reg;
  493. return 0;
  494. }
  495. static int brcm_fet_config_intr(struct phy_device *phydev)
  496. {
  497. int reg, err;
  498. reg = phy_read(phydev, MII_BRCM_FET_INTREG);
  499. if (reg < 0)
  500. return reg;
  501. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  502. reg &= ~MII_BRCM_FET_IR_MASK;
  503. else
  504. reg |= MII_BRCM_FET_IR_MASK;
  505. err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
  506. return err;
  507. }
  508. static struct phy_driver broadcom_drivers[] = {
  509. {
  510. .phy_id = PHY_ID_BCM5411,
  511. .phy_id_mask = 0xfffffff0,
  512. .name = "Broadcom BCM5411",
  513. .features = PHY_GBIT_FEATURES |
  514. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  515. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  516. .config_init = bcm54xx_config_init,
  517. .config_aneg = genphy_config_aneg,
  518. .read_status = genphy_read_status,
  519. .ack_interrupt = bcm54xx_ack_interrupt,
  520. .config_intr = bcm54xx_config_intr,
  521. .driver = { .owner = THIS_MODULE },
  522. }, {
  523. .phy_id = PHY_ID_BCM5421,
  524. .phy_id_mask = 0xfffffff0,
  525. .name = "Broadcom BCM5421",
  526. .features = PHY_GBIT_FEATURES |
  527. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  528. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  529. .config_init = bcm54xx_config_init,
  530. .config_aneg = genphy_config_aneg,
  531. .read_status = genphy_read_status,
  532. .ack_interrupt = bcm54xx_ack_interrupt,
  533. .config_intr = bcm54xx_config_intr,
  534. .driver = { .owner = THIS_MODULE },
  535. }, {
  536. .phy_id = PHY_ID_BCM5461,
  537. .phy_id_mask = 0xfffffff0,
  538. .name = "Broadcom BCM5461",
  539. .features = PHY_GBIT_FEATURES |
  540. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  541. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  542. .config_init = bcm54xx_config_init,
  543. .config_aneg = genphy_config_aneg,
  544. .read_status = genphy_read_status,
  545. .ack_interrupt = bcm54xx_ack_interrupt,
  546. .config_intr = bcm54xx_config_intr,
  547. .driver = { .owner = THIS_MODULE },
  548. }, {
  549. .phy_id = PHY_ID_BCM5464,
  550. .phy_id_mask = 0xfffffff0,
  551. .name = "Broadcom BCM5464",
  552. .features = PHY_GBIT_FEATURES |
  553. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  554. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  555. .config_init = bcm54xx_config_init,
  556. .config_aneg = genphy_config_aneg,
  557. .read_status = genphy_read_status,
  558. .ack_interrupt = bcm54xx_ack_interrupt,
  559. .config_intr = bcm54xx_config_intr,
  560. .driver = { .owner = THIS_MODULE },
  561. }, {
  562. .phy_id = PHY_ID_BCM5481,
  563. .phy_id_mask = 0xfffffff0,
  564. .name = "Broadcom BCM5481",
  565. .features = PHY_GBIT_FEATURES |
  566. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  567. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  568. .config_init = bcm54xx_config_init,
  569. .config_aneg = bcm5481_config_aneg,
  570. .read_status = genphy_read_status,
  571. .ack_interrupt = bcm54xx_ack_interrupt,
  572. .config_intr = bcm54xx_config_intr,
  573. .driver = { .owner = THIS_MODULE },
  574. }, {
  575. .phy_id = PHY_ID_BCM5482,
  576. .phy_id_mask = 0xfffffff0,
  577. .name = "Broadcom BCM5482",
  578. .features = PHY_GBIT_FEATURES |
  579. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  580. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  581. .config_init = bcm5482_config_init,
  582. .config_aneg = genphy_config_aneg,
  583. .read_status = bcm5482_read_status,
  584. .ack_interrupt = bcm54xx_ack_interrupt,
  585. .config_intr = bcm54xx_config_intr,
  586. .driver = { .owner = THIS_MODULE },
  587. }, {
  588. .phy_id = PHY_ID_BCM50610,
  589. .phy_id_mask = 0xfffffff0,
  590. .name = "Broadcom BCM50610",
  591. .features = PHY_GBIT_FEATURES |
  592. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  593. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  594. .config_init = bcm54xx_config_init,
  595. .config_aneg = genphy_config_aneg,
  596. .read_status = genphy_read_status,
  597. .ack_interrupt = bcm54xx_ack_interrupt,
  598. .config_intr = bcm54xx_config_intr,
  599. .driver = { .owner = THIS_MODULE },
  600. }, {
  601. .phy_id = PHY_ID_BCM50610M,
  602. .phy_id_mask = 0xfffffff0,
  603. .name = "Broadcom BCM50610M",
  604. .features = PHY_GBIT_FEATURES |
  605. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  606. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  607. .config_init = bcm54xx_config_init,
  608. .config_aneg = genphy_config_aneg,
  609. .read_status = genphy_read_status,
  610. .ack_interrupt = bcm54xx_ack_interrupt,
  611. .config_intr = bcm54xx_config_intr,
  612. .driver = { .owner = THIS_MODULE },
  613. }, {
  614. .phy_id = PHY_ID_BCM57780,
  615. .phy_id_mask = 0xfffffff0,
  616. .name = "Broadcom BCM57780",
  617. .features = PHY_GBIT_FEATURES |
  618. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  619. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  620. .config_init = bcm54xx_config_init,
  621. .config_aneg = genphy_config_aneg,
  622. .read_status = genphy_read_status,
  623. .ack_interrupt = bcm54xx_ack_interrupt,
  624. .config_intr = bcm54xx_config_intr,
  625. .driver = { .owner = THIS_MODULE },
  626. }, {
  627. .phy_id = PHY_ID_BCMAC131,
  628. .phy_id_mask = 0xfffffff0,
  629. .name = "Broadcom BCMAC131",
  630. .features = PHY_BASIC_FEATURES |
  631. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  632. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  633. .config_init = brcm_fet_config_init,
  634. .config_aneg = genphy_config_aneg,
  635. .read_status = genphy_read_status,
  636. .ack_interrupt = brcm_fet_ack_interrupt,
  637. .config_intr = brcm_fet_config_intr,
  638. .driver = { .owner = THIS_MODULE },
  639. }, {
  640. .phy_id = PHY_ID_BCM5241,
  641. .phy_id_mask = 0xfffffff0,
  642. .name = "Broadcom BCM5241",
  643. .features = PHY_BASIC_FEATURES |
  644. SUPPORTED_Pause | SUPPORTED_Asym_Pause,
  645. .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
  646. .config_init = brcm_fet_config_init,
  647. .config_aneg = genphy_config_aneg,
  648. .read_status = genphy_read_status,
  649. .ack_interrupt = brcm_fet_ack_interrupt,
  650. .config_intr = brcm_fet_config_intr,
  651. .driver = { .owner = THIS_MODULE },
  652. } };
  653. static int __init broadcom_init(void)
  654. {
  655. return phy_drivers_register(broadcom_drivers,
  656. ARRAY_SIZE(broadcom_drivers));
  657. }
  658. static void __exit broadcom_exit(void)
  659. {
  660. phy_drivers_unregister(broadcom_drivers,
  661. ARRAY_SIZE(broadcom_drivers));
  662. }
  663. module_init(broadcom_init);
  664. module_exit(broadcom_exit);
  665. static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
  666. { PHY_ID_BCM5411, 0xfffffff0 },
  667. { PHY_ID_BCM5421, 0xfffffff0 },
  668. { PHY_ID_BCM5461, 0xfffffff0 },
  669. { PHY_ID_BCM5464, 0xfffffff0 },
  670. { PHY_ID_BCM5482, 0xfffffff0 },
  671. { PHY_ID_BCM5482, 0xfffffff0 },
  672. { PHY_ID_BCM50610, 0xfffffff0 },
  673. { PHY_ID_BCM50610M, 0xfffffff0 },
  674. { PHY_ID_BCM57780, 0xfffffff0 },
  675. { PHY_ID_BCMAC131, 0xfffffff0 },
  676. { PHY_ID_BCM5241, 0xfffffff0 },
  677. { }
  678. };
  679. MODULE_DEVICE_TABLE(mdio, broadcom_tbl);