bcm7xxx.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. * Broadcom BCM7xxx internal transceivers support.
  3. *
  4. * Copyright (C) 2014, Broadcom Corporation
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/phy.h>
  13. #include <linux/delay.h>
  14. #include "bcm-phy-lib.h"
  15. #include <linux/bitops.h>
  16. #include <linux/brcmphy.h>
  17. #include <linux/mdio.h>
  18. /* Broadcom BCM7xxx internal PHY registers */
  19. /* 40nm only register definitions */
  20. #define MII_BCM7XXX_100TX_AUX_CTL 0x10
  21. #define MII_BCM7XXX_100TX_FALSE_CAR 0x13
  22. #define MII_BCM7XXX_100TX_DISC 0x14
  23. #define MII_BCM7XXX_AUX_MODE 0x1d
  24. #define MII_BCM7XXX_64CLK_MDIO BIT(12)
  25. #define MII_BCM7XXX_TEST 0x1f
  26. #define MII_BCM7XXX_SHD_MODE_2 BIT(2)
  27. /* 28nm only register definitions */
  28. #define MISC_ADDR(base, channel) base, channel
  29. #define DSP_TAP10 MISC_ADDR(0x0a, 0)
  30. #define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1)
  31. #define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2)
  32. #define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0)
  33. #define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0)
  34. #define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1)
  35. #define AFE_RXCONFIG_2 MISC_ADDR(0x38, 2)
  36. #define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3)
  37. #define AFE_TX_CONFIG MISC_ADDR(0x39, 0)
  38. #define AFE_VDCA_ICTRL_0 MISC_ADDR(0x39, 1)
  39. #define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3)
  40. #define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0)
  41. struct bcm7xxx_phy_priv {
  42. u64 *stats;
  43. };
  44. static void r_rc_cal_reset(struct phy_device *phydev)
  45. {
  46. /* Reset R_CAL/RC_CAL Engine */
  47. bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
  48. /* Disable Reset R_AL/RC_CAL Engine */
  49. bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
  50. }
  51. static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
  52. {
  53. /* Increase VCO range to prevent unlocking problem of PLL at low
  54. * temp
  55. */
  56. bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
  57. /* Change Ki to 011 */
  58. bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
  59. /* Disable loading of TVCO buffer to bandgap, set bandgap trim
  60. * to 111
  61. */
  62. bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
  63. /* Adjust bias current trim by -3 */
  64. bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
  65. /* Switch to CORE_BASE1E */
  66. phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd);
  67. r_rc_cal_reset(phydev);
  68. /* write AFE_RXCONFIG_0 */
  69. bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
  70. /* write AFE_RXCONFIG_1 */
  71. bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
  72. /* write AFE_RX_LP_COUNTER */
  73. bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
  74. /* write AFE_HPF_TRIM_OTHERS */
  75. bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
  76. /* write AFTE_TX_CONFIG */
  77. bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
  78. return 0;
  79. }
  80. static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
  81. {
  82. /* AFE_RXCONFIG_0 */
  83. bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
  84. /* AFE_RXCONFIG_1 */
  85. bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
  86. /* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
  87. bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
  88. /* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
  89. bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
  90. /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
  91. bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
  92. /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
  93. bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
  94. /* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
  95. bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
  96. /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
  97. * offset for HT=0 code
  98. */
  99. bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
  100. /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
  101. phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
  102. /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
  103. bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
  104. /* Reset R_CAL/RC_CAL engine */
  105. r_rc_cal_reset(phydev);
  106. return 0;
  107. }
  108. static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
  109. {
  110. /* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
  111. bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
  112. /* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
  113. bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
  114. /* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
  115. bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
  116. /* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
  117. * offset for HT=0 code
  118. */
  119. bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
  120. /* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
  121. phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
  122. /* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
  123. bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
  124. /* Reset R_CAL/RC_CAL engine */
  125. r_rc_cal_reset(phydev);
  126. return 0;
  127. }
  128. static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
  129. {
  130. u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
  131. u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
  132. u8 count;
  133. int ret = 0;
  134. pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
  135. phydev_name(phydev), phydev->drv->name, rev, patch);
  136. /* Dummy read to a register to workaround an issue upon reset where the
  137. * internal inverter may not allow the first MDIO transaction to pass
  138. * the MDIO management controller and make us return 0xffff for such
  139. * reads.
  140. */
  141. phy_read(phydev, MII_BMSR);
  142. switch (rev) {
  143. case 0xb0:
  144. ret = bcm7xxx_28nm_b0_afe_config_init(phydev);
  145. break;
  146. case 0xd0:
  147. ret = bcm7xxx_28nm_d0_afe_config_init(phydev);
  148. break;
  149. case 0xe0:
  150. case 0xf0:
  151. /* Rev G0 introduces a roll over */
  152. case 0x10:
  153. ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
  154. break;
  155. default:
  156. break;
  157. }
  158. if (ret)
  159. return ret;
  160. ret = bcm_phy_downshift_get(phydev, &count);
  161. if (ret)
  162. return ret;
  163. /* Only enable EEE if Wirespeed/downshift is disabled */
  164. ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
  165. if (ret)
  166. return ret;
  167. return bcm_phy_enable_apd(phydev, true);
  168. }
  169. static int bcm7xxx_28nm_resume(struct phy_device *phydev)
  170. {
  171. int ret;
  172. /* Re-apply workarounds coming out suspend/resume */
  173. ret = bcm7xxx_28nm_config_init(phydev);
  174. if (ret)
  175. return ret;
  176. /* 28nm Gigabit PHYs come out of reset without any half-duplex
  177. * or "hub" compliant advertised mode, fix that. This does not
  178. * cause any problems with the PHY library since genphy_config_aneg()
  179. * gracefully handles auto-negotiated and forced modes.
  180. */
  181. return genphy_config_aneg(phydev);
  182. }
  183. static int phy_set_clr_bits(struct phy_device *dev, int location,
  184. int set_mask, int clr_mask)
  185. {
  186. int v, ret;
  187. v = phy_read(dev, location);
  188. if (v < 0)
  189. return v;
  190. v &= ~clr_mask;
  191. v |= set_mask;
  192. ret = phy_write(dev, location, v);
  193. if (ret < 0)
  194. return ret;
  195. return v;
  196. }
  197. static int bcm7xxx_config_init(struct phy_device *phydev)
  198. {
  199. int ret;
  200. /* Enable 64 clock MDIO */
  201. phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
  202. phy_read(phydev, MII_BCM7XXX_AUX_MODE);
  203. /* set shadow mode 2 */
  204. ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
  205. MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
  206. if (ret < 0)
  207. return ret;
  208. /* set iddq_clkbias */
  209. phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
  210. udelay(10);
  211. /* reset iddq_clkbias */
  212. phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
  213. phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
  214. /* reset shadow mode 2 */
  215. ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
  216. if (ret < 0)
  217. return ret;
  218. return 0;
  219. }
  220. /* Workaround for putting the PHY in IDDQ mode, required
  221. * for all BCM7XXX 40nm and 65nm PHYs
  222. */
  223. static int bcm7xxx_suspend(struct phy_device *phydev)
  224. {
  225. int ret;
  226. const struct bcm7xxx_regs {
  227. int reg;
  228. u16 value;
  229. } bcm7xxx_suspend_cfg[] = {
  230. { MII_BCM7XXX_TEST, 0x008b },
  231. { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
  232. { MII_BCM7XXX_100TX_DISC, 0x7000 },
  233. { MII_BCM7XXX_TEST, 0x000f },
  234. { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
  235. { MII_BCM7XXX_TEST, 0x000b },
  236. };
  237. unsigned int i;
  238. for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
  239. ret = phy_write(phydev,
  240. bcm7xxx_suspend_cfg[i].reg,
  241. bcm7xxx_suspend_cfg[i].value);
  242. if (ret)
  243. return ret;
  244. }
  245. return 0;
  246. }
  247. static int bcm7xxx_28nm_get_tunable(struct phy_device *phydev,
  248. struct ethtool_tunable *tuna,
  249. void *data)
  250. {
  251. switch (tuna->id) {
  252. case ETHTOOL_PHY_DOWNSHIFT:
  253. return bcm_phy_downshift_get(phydev, (u8 *)data);
  254. default:
  255. return -EOPNOTSUPP;
  256. }
  257. }
  258. static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
  259. struct ethtool_tunable *tuna,
  260. const void *data)
  261. {
  262. u8 count = *(u8 *)data;
  263. int ret;
  264. switch (tuna->id) {
  265. case ETHTOOL_PHY_DOWNSHIFT:
  266. ret = bcm_phy_downshift_set(phydev, count);
  267. break;
  268. default:
  269. return -EOPNOTSUPP;
  270. }
  271. if (ret)
  272. return ret;
  273. /* Disable EEE advertisment since this prevents the PHY
  274. * from successfully linking up, trigger auto-negotiation restart
  275. * to let the MAC decide what to do.
  276. */
  277. ret = bcm_phy_set_eee(phydev, count == DOWNSHIFT_DEV_DISABLE);
  278. if (ret)
  279. return ret;
  280. return genphy_restart_aneg(phydev);
  281. }
  282. static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
  283. struct ethtool_stats *stats, u64 *data)
  284. {
  285. struct bcm7xxx_phy_priv *priv = phydev->priv;
  286. bcm_phy_get_stats(phydev, priv->stats, stats, data);
  287. }
  288. static int bcm7xxx_28nm_probe(struct phy_device *phydev)
  289. {
  290. struct bcm7xxx_phy_priv *priv;
  291. priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
  292. if (!priv)
  293. return -ENOMEM;
  294. phydev->priv = priv;
  295. priv->stats = devm_kcalloc(&phydev->mdio.dev,
  296. bcm_phy_get_sset_count(phydev), sizeof(u64),
  297. GFP_KERNEL);
  298. if (!priv->stats)
  299. return -ENOMEM;
  300. return 0;
  301. }
  302. #define BCM7XXX_28NM_GPHY(_oui, _name) \
  303. { \
  304. .phy_id = (_oui), \
  305. .phy_id_mask = 0xfffffff0, \
  306. .name = _name, \
  307. .features = PHY_GBIT_FEATURES, \
  308. .flags = PHY_IS_INTERNAL, \
  309. .config_init = bcm7xxx_28nm_config_init, \
  310. .config_aneg = genphy_config_aneg, \
  311. .read_status = genphy_read_status, \
  312. .resume = bcm7xxx_28nm_resume, \
  313. .get_tunable = bcm7xxx_28nm_get_tunable, \
  314. .set_tunable = bcm7xxx_28nm_set_tunable, \
  315. .get_sset_count = bcm_phy_get_sset_count, \
  316. .get_strings = bcm_phy_get_strings, \
  317. .get_stats = bcm7xxx_28nm_get_phy_stats, \
  318. .probe = bcm7xxx_28nm_probe, \
  319. }
  320. #define BCM7XXX_40NM_EPHY(_oui, _name) \
  321. { \
  322. .phy_id = (_oui), \
  323. .phy_id_mask = 0xfffffff0, \
  324. .name = _name, \
  325. .features = PHY_BASIC_FEATURES, \
  326. .flags = PHY_IS_INTERNAL, \
  327. .config_init = bcm7xxx_config_init, \
  328. .config_aneg = genphy_config_aneg, \
  329. .read_status = genphy_read_status, \
  330. .suspend = bcm7xxx_suspend, \
  331. .resume = bcm7xxx_config_init, \
  332. }
  333. static struct phy_driver bcm7xxx_driver[] = {
  334. BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
  335. BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
  336. BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
  337. BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
  338. BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
  339. BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
  340. BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"),
  341. BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"),
  342. BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
  343. BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
  344. BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
  345. };
  346. static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
  347. { PHY_ID_BCM7250, 0xfffffff0, },
  348. { PHY_ID_BCM7364, 0xfffffff0, },
  349. { PHY_ID_BCM7366, 0xfffffff0, },
  350. { PHY_ID_BCM7346, 0xfffffff0, },
  351. { PHY_ID_BCM7362, 0xfffffff0, },
  352. { PHY_ID_BCM7425, 0xfffffff0, },
  353. { PHY_ID_BCM7429, 0xfffffff0, },
  354. { PHY_ID_BCM7439, 0xfffffff0, },
  355. { PHY_ID_BCM7435, 0xfffffff0, },
  356. { PHY_ID_BCM7445, 0xfffffff0, },
  357. { }
  358. };
  359. module_phy_driver(bcm7xxx_driver);
  360. MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
  361. MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
  362. MODULE_LICENSE("GPL");
  363. MODULE_AUTHOR("Broadcom Corporation");