bcm-phy-lib.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2015-2017 Broadcom
  4. */
  5. #include "bcm-phy-lib.h"
  6. #include <linux/bitfield.h>
  7. #include <linux/brcmphy.h>
  8. #include <linux/export.h>
  9. #include <linux/mdio.h>
  10. #include <linux/module.h>
  11. #include <linux/phy.h>
  12. #include <linux/ethtool.h>
  13. #include <linux/ethtool_netlink.h>
  14. #define MII_BCM_CHANNEL_WIDTH 0x2000
  15. #define BCM_CL45VEN_EEE_ADV 0x3c
  16. int __bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
  17. {
  18. int rc;
  19. rc = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
  20. if (rc < 0)
  21. return rc;
  22. return __phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
  23. }
  24. EXPORT_SYMBOL_GPL(__bcm_phy_write_exp);
  25. int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
  26. {
  27. int rc;
  28. phy_lock_mdio_bus(phydev);
  29. rc = __bcm_phy_write_exp(phydev, reg, val);
  30. phy_unlock_mdio_bus(phydev);
  31. return rc;
  32. }
  33. EXPORT_SYMBOL_GPL(bcm_phy_write_exp);
  34. int __bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
  35. {
  36. int val;
  37. val = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
  38. if (val < 0)
  39. return val;
  40. val = __phy_read(phydev, MII_BCM54XX_EXP_DATA);
  41. /* Restore default value. It's O.K. if this write fails. */
  42. __phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
  43. return val;
  44. }
  45. EXPORT_SYMBOL_GPL(__bcm_phy_read_exp);
  46. int bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
  47. {
  48. int rc;
  49. phy_lock_mdio_bus(phydev);
  50. rc = __bcm_phy_read_exp(phydev, reg);
  51. phy_unlock_mdio_bus(phydev);
  52. return rc;
  53. }
  54. EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
  55. int __bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set)
  56. {
  57. int new, ret;
  58. ret = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
  59. if (ret < 0)
  60. return ret;
  61. ret = __phy_read(phydev, MII_BCM54XX_EXP_DATA);
  62. if (ret < 0)
  63. return ret;
  64. new = (ret & ~mask) | set;
  65. if (new == ret)
  66. return 0;
  67. return __phy_write(phydev, MII_BCM54XX_EXP_DATA, new);
  68. }
  69. EXPORT_SYMBOL_GPL(__bcm_phy_modify_exp);
  70. int bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set)
  71. {
  72. int ret;
  73. phy_lock_mdio_bus(phydev);
  74. ret = __bcm_phy_modify_exp(phydev, reg, mask, set);
  75. phy_unlock_mdio_bus(phydev);
  76. return ret;
  77. }
  78. EXPORT_SYMBOL_GPL(bcm_phy_modify_exp);
  79. int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
  80. {
  81. /* The register must be written to both the Shadow Register Select and
  82. * the Shadow Read Register Selector
  83. */
  84. phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MASK |
  85. regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT);
  86. return phy_read(phydev, MII_BCM54XX_AUX_CTL);
  87. }
  88. EXPORT_SYMBOL_GPL(bcm54xx_auxctl_read);
  89. int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
  90. {
  91. return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
  92. }
  93. EXPORT_SYMBOL(bcm54xx_auxctl_write);
  94. int bcm_phy_write_misc(struct phy_device *phydev,
  95. u16 reg, u16 chl, u16 val)
  96. {
  97. int rc;
  98. int tmp;
  99. rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
  100. MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  101. if (rc < 0)
  102. return rc;
  103. tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
  104. tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
  105. rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
  106. if (rc < 0)
  107. return rc;
  108. tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
  109. rc = bcm_phy_write_exp(phydev, tmp, val);
  110. return rc;
  111. }
  112. EXPORT_SYMBOL_GPL(bcm_phy_write_misc);
  113. int bcm_phy_read_misc(struct phy_device *phydev,
  114. u16 reg, u16 chl)
  115. {
  116. int rc;
  117. int tmp;
  118. rc = phy_write(phydev, MII_BCM54XX_AUX_CTL,
  119. MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  120. if (rc < 0)
  121. return rc;
  122. tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
  123. tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
  124. rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
  125. if (rc < 0)
  126. return rc;
  127. tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg;
  128. rc = bcm_phy_read_exp(phydev, tmp);
  129. return rc;
  130. }
  131. EXPORT_SYMBOL_GPL(bcm_phy_read_misc);
  132. int bcm_phy_ack_intr(struct phy_device *phydev)
  133. {
  134. int reg;
  135. /* Clear pending interrupts. */
  136. reg = phy_read(phydev, MII_BCM54XX_ISR);
  137. if (reg < 0)
  138. return reg;
  139. return 0;
  140. }
  141. EXPORT_SYMBOL_GPL(bcm_phy_ack_intr);
  142. int bcm_phy_config_intr(struct phy_device *phydev)
  143. {
  144. int reg, err;
  145. reg = phy_read(phydev, MII_BCM54XX_ECR);
  146. if (reg < 0)
  147. return reg;
  148. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  149. err = bcm_phy_ack_intr(phydev);
  150. if (err)
  151. return err;
  152. reg &= ~MII_BCM54XX_ECR_IM;
  153. err = phy_write(phydev, MII_BCM54XX_ECR, reg);
  154. } else {
  155. reg |= MII_BCM54XX_ECR_IM;
  156. err = phy_write(phydev, MII_BCM54XX_ECR, reg);
  157. if (err)
  158. return err;
  159. err = bcm_phy_ack_intr(phydev);
  160. }
  161. return err;
  162. }
  163. EXPORT_SYMBOL_GPL(bcm_phy_config_intr);
  164. irqreturn_t bcm_phy_handle_interrupt(struct phy_device *phydev)
  165. {
  166. int irq_status, irq_mask;
  167. irq_status = phy_read(phydev, MII_BCM54XX_ISR);
  168. if (irq_status < 0) {
  169. phy_error(phydev);
  170. return IRQ_NONE;
  171. }
  172. /* If a bit from the Interrupt Mask register is set, the corresponding
  173. * bit from the Interrupt Status register is masked. So read the IMR
  174. * and then flip the bits to get the list of possible interrupt
  175. * sources.
  176. */
  177. irq_mask = phy_read(phydev, MII_BCM54XX_IMR);
  178. if (irq_mask < 0) {
  179. phy_error(phydev);
  180. return IRQ_NONE;
  181. }
  182. irq_mask = ~irq_mask;
  183. if (!(irq_status & irq_mask))
  184. return IRQ_NONE;
  185. phy_trigger_machine(phydev);
  186. return IRQ_HANDLED;
  187. }
  188. EXPORT_SYMBOL_GPL(bcm_phy_handle_interrupt);
  189. int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow)
  190. {
  191. phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
  192. return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
  193. }
  194. EXPORT_SYMBOL_GPL(bcm_phy_read_shadow);
  195. int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow,
  196. u16 val)
  197. {
  198. return phy_write(phydev, MII_BCM54XX_SHD,
  199. MII_BCM54XX_SHD_WRITE |
  200. MII_BCM54XX_SHD_VAL(shadow) |
  201. MII_BCM54XX_SHD_DATA(val));
  202. }
  203. EXPORT_SYMBOL_GPL(bcm_phy_write_shadow);
  204. int __bcm_phy_read_rdb(struct phy_device *phydev, u16 rdb)
  205. {
  206. int val;
  207. val = __phy_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
  208. if (val < 0)
  209. return val;
  210. return __phy_read(phydev, MII_BCM54XX_RDB_DATA);
  211. }
  212. EXPORT_SYMBOL_GPL(__bcm_phy_read_rdb);
  213. int bcm_phy_read_rdb(struct phy_device *phydev, u16 rdb)
  214. {
  215. int ret;
  216. phy_lock_mdio_bus(phydev);
  217. ret = __bcm_phy_read_rdb(phydev, rdb);
  218. phy_unlock_mdio_bus(phydev);
  219. return ret;
  220. }
  221. EXPORT_SYMBOL_GPL(bcm_phy_read_rdb);
  222. int __bcm_phy_write_rdb(struct phy_device *phydev, u16 rdb, u16 val)
  223. {
  224. int ret;
  225. ret = __phy_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
  226. if (ret < 0)
  227. return ret;
  228. return __phy_write(phydev, MII_BCM54XX_RDB_DATA, val);
  229. }
  230. EXPORT_SYMBOL_GPL(__bcm_phy_write_rdb);
  231. int bcm_phy_write_rdb(struct phy_device *phydev, u16 rdb, u16 val)
  232. {
  233. int ret;
  234. phy_lock_mdio_bus(phydev);
  235. ret = __bcm_phy_write_rdb(phydev, rdb, val);
  236. phy_unlock_mdio_bus(phydev);
  237. return ret;
  238. }
  239. EXPORT_SYMBOL_GPL(bcm_phy_write_rdb);
  240. int __bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask, u16 set)
  241. {
  242. int new, ret;
  243. ret = __phy_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
  244. if (ret < 0)
  245. return ret;
  246. ret = __phy_read(phydev, MII_BCM54XX_RDB_DATA);
  247. if (ret < 0)
  248. return ret;
  249. new = (ret & ~mask) | set;
  250. if (new == ret)
  251. return 0;
  252. return __phy_write(phydev, MII_BCM54XX_RDB_DATA, new);
  253. }
  254. EXPORT_SYMBOL_GPL(__bcm_phy_modify_rdb);
  255. int bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask, u16 set)
  256. {
  257. int ret;
  258. phy_lock_mdio_bus(phydev);
  259. ret = __bcm_phy_modify_rdb(phydev, rdb, mask, set);
  260. phy_unlock_mdio_bus(phydev);
  261. return ret;
  262. }
  263. EXPORT_SYMBOL_GPL(bcm_phy_modify_rdb);
  264. int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down)
  265. {
  266. int val;
  267. if (dll_pwr_down) {
  268. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
  269. if (val < 0)
  270. return val;
  271. val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
  272. bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
  273. }
  274. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
  275. if (val < 0)
  276. return val;
  277. /* Clear APD bits */
  278. val &= BCM_APD_CLR_MASK;
  279. if (phydev->autoneg == AUTONEG_ENABLE)
  280. val |= BCM54XX_SHD_APD_EN;
  281. else
  282. val |= BCM_NO_ANEG_APD_EN;
  283. /* Enable energy detect single link pulse for easy wakeup */
  284. val |= BCM_APD_SINGLELP_EN;
  285. /* Enable Auto Power-Down (APD) for the PHY */
  286. return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
  287. }
  288. EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);
  289. int bcm_phy_set_eee(struct phy_device *phydev, bool enable)
  290. {
  291. int val, mask = 0;
  292. /* Enable EEE at PHY level */
  293. val = phy_read_mmd(phydev, MDIO_MMD_AN, BRCM_CL45VEN_EEE_CONTROL);
  294. if (val < 0)
  295. return val;
  296. if (enable)
  297. val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
  298. else
  299. val &= ~(LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X);
  300. phy_write_mmd(phydev, MDIO_MMD_AN, BRCM_CL45VEN_EEE_CONTROL, (u32)val);
  301. /* Advertise EEE */
  302. val = phy_read_mmd(phydev, MDIO_MMD_AN, BCM_CL45VEN_EEE_ADV);
  303. if (val < 0)
  304. return val;
  305. if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
  306. phydev->supported))
  307. mask |= MDIO_EEE_1000T;
  308. if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
  309. phydev->supported))
  310. mask |= MDIO_EEE_100TX;
  311. if (enable)
  312. val |= mask;
  313. else
  314. val &= ~mask;
  315. phy_write_mmd(phydev, MDIO_MMD_AN, BCM_CL45VEN_EEE_ADV, (u32)val);
  316. return 0;
  317. }
  318. EXPORT_SYMBOL_GPL(bcm_phy_set_eee);
  319. int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count)
  320. {
  321. int val;
  322. val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  323. if (val < 0)
  324. return val;
  325. /* Check if wirespeed is enabled or not */
  326. if (!(val & MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN)) {
  327. *count = DOWNSHIFT_DEV_DISABLE;
  328. return 0;
  329. }
  330. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2);
  331. if (val < 0)
  332. return val;
  333. /* Downgrade after one link attempt */
  334. if (val & BCM54XX_SHD_SCR2_WSPD_RTRY_DIS) {
  335. *count = 1;
  336. } else {
  337. /* Downgrade after configured retry count */
  338. val >>= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
  339. val &= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK;
  340. *count = val + BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET;
  341. }
  342. return 0;
  343. }
  344. EXPORT_SYMBOL_GPL(bcm_phy_downshift_get);
  345. int bcm_phy_downshift_set(struct phy_device *phydev, u8 count)
  346. {
  347. int val = 0, ret = 0;
  348. /* Range check the number given */
  349. if (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET >
  350. BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK &&
  351. count != DOWNSHIFT_DEV_DEFAULT_COUNT) {
  352. return -ERANGE;
  353. }
  354. val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
  355. if (val < 0)
  356. return val;
  357. /* Se the write enable bit */
  358. val |= MII_BCM54XX_AUXCTL_MISC_WREN;
  359. if (count == DOWNSHIFT_DEV_DISABLE) {
  360. val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN;
  361. return bcm54xx_auxctl_write(phydev,
  362. MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  363. val);
  364. } else {
  365. val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN;
  366. ret = bcm54xx_auxctl_write(phydev,
  367. MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
  368. val);
  369. if (ret < 0)
  370. return ret;
  371. }
  372. val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2);
  373. val &= ~(BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK <<
  374. BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT |
  375. BCM54XX_SHD_SCR2_WSPD_RTRY_DIS);
  376. switch (count) {
  377. case 1:
  378. val |= BCM54XX_SHD_SCR2_WSPD_RTRY_DIS;
  379. break;
  380. case DOWNSHIFT_DEV_DEFAULT_COUNT:
  381. val |= 1 << BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
  382. break;
  383. default:
  384. val |= (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET) <<
  385. BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
  386. break;
  387. }
  388. return bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR2, val);
  389. }
  390. EXPORT_SYMBOL_GPL(bcm_phy_downshift_set);
  391. struct bcm_phy_hw_stat {
  392. const char *string;
  393. u8 reg;
  394. u8 shift;
  395. u8 bits;
  396. };
  397. /* Counters freeze at either 0xffff or 0xff, better than nothing */
  398. static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = {
  399. { "phy_receive_errors", MII_BRCM_CORE_BASE12, 0, 16 },
  400. { "phy_serdes_ber_errors", MII_BRCM_CORE_BASE13, 8, 8 },
  401. { "phy_false_carrier_sense_errors", MII_BRCM_CORE_BASE13, 0, 8 },
  402. { "phy_local_rcvr_nok", MII_BRCM_CORE_BASE14, 8, 8 },
  403. { "phy_remote_rcv_nok", MII_BRCM_CORE_BASE14, 0, 8 },
  404. };
  405. int bcm_phy_get_sset_count(struct phy_device *phydev)
  406. {
  407. return ARRAY_SIZE(bcm_phy_hw_stats);
  408. }
  409. EXPORT_SYMBOL_GPL(bcm_phy_get_sset_count);
  410. void bcm_phy_get_strings(struct phy_device *phydev, u8 *data)
  411. {
  412. unsigned int i;
  413. for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
  414. strscpy(data + i * ETH_GSTRING_LEN,
  415. bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
  416. }
  417. EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
  418. /* Caller is supposed to provide appropriate storage for the library code to
  419. * access the shadow copy
  420. */
  421. static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow,
  422. unsigned int i)
  423. {
  424. struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i];
  425. int val;
  426. u64 ret;
  427. val = phy_read(phydev, stat.reg);
  428. if (val < 0) {
  429. ret = U64_MAX;
  430. } else {
  431. val >>= stat.shift;
  432. val = val & ((1 << stat.bits) - 1);
  433. shadow[i] += val;
  434. ret = shadow[i];
  435. }
  436. return ret;
  437. }
  438. void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
  439. struct ethtool_stats *stats, u64 *data)
  440. {
  441. unsigned int i;
  442. for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
  443. data[i] = bcm_phy_get_stat(phydev, shadow, i);
  444. }
  445. EXPORT_SYMBOL_GPL(bcm_phy_get_stats);
  446. void bcm_phy_r_rc_cal_reset(struct phy_device *phydev)
  447. {
  448. /* Reset R_CAL/RC_CAL Engine */
  449. bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010);
  450. /* Disable Reset R_AL/RC_CAL Engine */
  451. bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000);
  452. }
  453. EXPORT_SYMBOL_GPL(bcm_phy_r_rc_cal_reset);
  454. int bcm_phy_28nm_a0b0_afe_config_init(struct phy_device *phydev)
  455. {
  456. /* Increase VCO range to prevent unlocking problem of PLL at low
  457. * temp
  458. */
  459. bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
  460. /* Change Ki to 011 */
  461. bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
  462. /* Disable loading of TVCO buffer to bandgap, set bandgap trim
  463. * to 111
  464. */
  465. bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
  466. /* Adjust bias current trim by -3 */
  467. bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
  468. /* Switch to CORE_BASE1E */
  469. phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd);
  470. bcm_phy_r_rc_cal_reset(phydev);
  471. /* write AFE_RXCONFIG_0 */
  472. bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
  473. /* write AFE_RXCONFIG_1 */
  474. bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
  475. /* write AFE_RX_LP_COUNTER */
  476. bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
  477. /* write AFE_HPF_TRIM_OTHERS */
  478. bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
  479. /* write AFTE_TX_CONFIG */
  480. bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
  481. return 0;
  482. }
  483. EXPORT_SYMBOL_GPL(bcm_phy_28nm_a0b0_afe_config_init);
  484. int bcm_phy_enable_jumbo(struct phy_device *phydev)
  485. {
  486. int ret;
  487. ret = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL);
  488. if (ret < 0)
  489. return ret;
  490. /* Enable extended length packet reception */
  491. ret = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
  492. ret | MII_BCM54XX_AUXCTL_ACTL_EXT_PKT_LEN);
  493. if (ret < 0)
  494. return ret;
  495. /* Enable the elastic FIFO for raising the transmission limit from
  496. * 4.5KB to 10KB, at the expense of an additional 16 ns in propagation
  497. * latency.
  498. */
  499. return phy_set_bits(phydev, MII_BCM54XX_ECR, MII_BCM54XX_ECR_FIFOE);
  500. }
  501. EXPORT_SYMBOL_GPL(bcm_phy_enable_jumbo);
  502. static int __bcm_phy_enable_rdb_access(struct phy_device *phydev)
  503. {
  504. return __bcm_phy_write_exp(phydev, BCM54XX_EXP_REG7E, 0);
  505. }
  506. static int __bcm_phy_enable_legacy_access(struct phy_device *phydev)
  507. {
  508. return __bcm_phy_write_rdb(phydev, BCM54XX_RDB_REG0087,
  509. BCM54XX_ACCESS_MODE_LEGACY_EN);
  510. }
  511. static int _bcm_phy_cable_test_start(struct phy_device *phydev, bool is_rdb)
  512. {
  513. u16 mask, set;
  514. int ret;
  515. /* Auto-negotiation must be enabled for cable diagnostics to work, but
  516. * don't advertise any capabilities.
  517. */
  518. phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
  519. phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
  520. phy_write(phydev, MII_CTRL1000, 0);
  521. phy_lock_mdio_bus(phydev);
  522. if (is_rdb) {
  523. ret = __bcm_phy_enable_legacy_access(phydev);
  524. if (ret)
  525. goto out;
  526. }
  527. mask = BCM54XX_ECD_CTRL_CROSS_SHORT_DIS | BCM54XX_ECD_CTRL_UNIT_MASK;
  528. set = BCM54XX_ECD_CTRL_RUN | BCM54XX_ECD_CTRL_BREAK_LINK |
  529. FIELD_PREP(BCM54XX_ECD_CTRL_UNIT_MASK,
  530. BCM54XX_ECD_CTRL_UNIT_CM);
  531. ret = __bcm_phy_modify_exp(phydev, BCM54XX_EXP_ECD_CTRL, mask, set);
  532. out:
  533. /* re-enable the RDB access even if there was an error */
  534. if (is_rdb)
  535. ret = __bcm_phy_enable_rdb_access(phydev) ? : ret;
  536. phy_unlock_mdio_bus(phydev);
  537. return ret;
  538. }
  539. static int bcm_phy_cable_test_report_trans(int result)
  540. {
  541. switch (result) {
  542. case BCM54XX_ECD_FAULT_TYPE_OK:
  543. return ETHTOOL_A_CABLE_RESULT_CODE_OK;
  544. case BCM54XX_ECD_FAULT_TYPE_OPEN:
  545. return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
  546. case BCM54XX_ECD_FAULT_TYPE_SAME_SHORT:
  547. return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
  548. case BCM54XX_ECD_FAULT_TYPE_CROSS_SHORT:
  549. return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
  550. case BCM54XX_ECD_FAULT_TYPE_INVALID:
  551. case BCM54XX_ECD_FAULT_TYPE_BUSY:
  552. default:
  553. return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
  554. }
  555. }
  556. static bool bcm_phy_distance_valid(int result)
  557. {
  558. switch (result) {
  559. case BCM54XX_ECD_FAULT_TYPE_OPEN:
  560. case BCM54XX_ECD_FAULT_TYPE_SAME_SHORT:
  561. case BCM54XX_ECD_FAULT_TYPE_CROSS_SHORT:
  562. return true;
  563. }
  564. return false;
  565. }
  566. static int bcm_phy_report_length(struct phy_device *phydev, int pair)
  567. {
  568. int val;
  569. val = __bcm_phy_read_exp(phydev,
  570. BCM54XX_EXP_ECD_PAIR_A_LENGTH_RESULTS + pair);
  571. if (val < 0)
  572. return val;
  573. if (val == BCM54XX_ECD_LENGTH_RESULTS_INVALID)
  574. return 0;
  575. ethnl_cable_test_fault_length(phydev, pair, val);
  576. return 0;
  577. }
  578. static int _bcm_phy_cable_test_get_status(struct phy_device *phydev,
  579. bool *finished, bool is_rdb)
  580. {
  581. int pair_a, pair_b, pair_c, pair_d, ret;
  582. *finished = false;
  583. phy_lock_mdio_bus(phydev);
  584. if (is_rdb) {
  585. ret = __bcm_phy_enable_legacy_access(phydev);
  586. if (ret)
  587. goto out;
  588. }
  589. ret = __bcm_phy_read_exp(phydev, BCM54XX_EXP_ECD_CTRL);
  590. if (ret < 0)
  591. goto out;
  592. if (ret & BCM54XX_ECD_CTRL_IN_PROGRESS) {
  593. ret = 0;
  594. goto out;
  595. }
  596. ret = __bcm_phy_read_exp(phydev, BCM54XX_EXP_ECD_FAULT_TYPE);
  597. if (ret < 0)
  598. goto out;
  599. pair_a = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_A_MASK, ret);
  600. pair_b = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_B_MASK, ret);
  601. pair_c = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_C_MASK, ret);
  602. pair_d = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_D_MASK, ret);
  603. ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
  604. bcm_phy_cable_test_report_trans(pair_a));
  605. ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
  606. bcm_phy_cable_test_report_trans(pair_b));
  607. ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
  608. bcm_phy_cable_test_report_trans(pair_c));
  609. ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
  610. bcm_phy_cable_test_report_trans(pair_d));
  611. if (bcm_phy_distance_valid(pair_a))
  612. bcm_phy_report_length(phydev, 0);
  613. if (bcm_phy_distance_valid(pair_b))
  614. bcm_phy_report_length(phydev, 1);
  615. if (bcm_phy_distance_valid(pair_c))
  616. bcm_phy_report_length(phydev, 2);
  617. if (bcm_phy_distance_valid(pair_d))
  618. bcm_phy_report_length(phydev, 3);
  619. ret = 0;
  620. *finished = true;
  621. out:
  622. /* re-enable the RDB access even if there was an error */
  623. if (is_rdb)
  624. ret = __bcm_phy_enable_rdb_access(phydev) ? : ret;
  625. phy_unlock_mdio_bus(phydev);
  626. return ret;
  627. }
  628. int bcm_phy_cable_test_start(struct phy_device *phydev)
  629. {
  630. return _bcm_phy_cable_test_start(phydev, false);
  631. }
  632. EXPORT_SYMBOL_GPL(bcm_phy_cable_test_start);
  633. int bcm_phy_cable_test_get_status(struct phy_device *phydev, bool *finished)
  634. {
  635. return _bcm_phy_cable_test_get_status(phydev, finished, false);
  636. }
  637. EXPORT_SYMBOL_GPL(bcm_phy_cable_test_get_status);
  638. /* We assume that all PHYs which support RDB access can be switched to legacy
  639. * mode. If, in the future, this is not true anymore, we have to re-implement
  640. * this with RDB access.
  641. */
  642. int bcm_phy_cable_test_start_rdb(struct phy_device *phydev)
  643. {
  644. return _bcm_phy_cable_test_start(phydev, true);
  645. }
  646. EXPORT_SYMBOL_GPL(bcm_phy_cable_test_start_rdb);
  647. int bcm_phy_cable_test_get_status_rdb(struct phy_device *phydev,
  648. bool *finished)
  649. {
  650. return _bcm_phy_cable_test_get_status(phydev, finished, true);
  651. }
  652. EXPORT_SYMBOL_GPL(bcm_phy_cable_test_get_status_rdb);
  653. MODULE_DESCRIPTION("Broadcom PHY Library");
  654. MODULE_LICENSE("GPL v2");
  655. MODULE_AUTHOR("Broadcom Corporation");