mscc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /*
  2. * Driver for Microsemi VSC85xx PHYs
  3. *
  4. * Author: Nagaraju Lakkaraju
  5. * License: Dual MIT/GPL
  6. * Copyright (c) 2016 Microsemi Corporation
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/mdio.h>
  11. #include <linux/mii.h>
  12. #include <linux/phy.h>
  13. #include <linux/of.h>
  14. #include <linux/netdevice.h>
  15. #include <dt-bindings/net/mscc-phy-vsc8531.h>
  16. enum rgmii_rx_clock_delay {
  17. RGMII_RX_CLK_DELAY_0_2_NS = 0,
  18. RGMII_RX_CLK_DELAY_0_8_NS = 1,
  19. RGMII_RX_CLK_DELAY_1_1_NS = 2,
  20. RGMII_RX_CLK_DELAY_1_7_NS = 3,
  21. RGMII_RX_CLK_DELAY_2_0_NS = 4,
  22. RGMII_RX_CLK_DELAY_2_3_NS = 5,
  23. RGMII_RX_CLK_DELAY_2_6_NS = 6,
  24. RGMII_RX_CLK_DELAY_3_4_NS = 7
  25. };
  26. /* Microsemi VSC85xx PHY registers */
  27. /* IEEE 802. Std Registers */
  28. #define MSCC_PHY_BYPASS_CONTROL 18
  29. #define DISABLE_HP_AUTO_MDIX_MASK 0x0080
  30. #define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
  31. #define DISABLE_POLARITY_CORR_MASK 0x0010
  32. #define MSCC_PHY_EXT_PHY_CNTL_1 23
  33. #define MAC_IF_SELECTION_MASK 0x1800
  34. #define MAC_IF_SELECTION_GMII 0
  35. #define MAC_IF_SELECTION_RMII 1
  36. #define MAC_IF_SELECTION_RGMII 2
  37. #define MAC_IF_SELECTION_POS 11
  38. #define FAR_END_LOOPBACK_MODE_MASK 0x0008
  39. #define MII_VSC85XX_INT_MASK 25
  40. #define MII_VSC85XX_INT_MASK_MASK 0xa000
  41. #define MII_VSC85XX_INT_MASK_WOL 0x0040
  42. #define MII_VSC85XX_INT_STATUS 26
  43. #define MSCC_PHY_WOL_MAC_CONTROL 27
  44. #define EDGE_RATE_CNTL_POS 5
  45. #define EDGE_RATE_CNTL_MASK 0x00E0
  46. #define MSCC_PHY_DEV_AUX_CNTL 28
  47. #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
  48. #define MSCC_PHY_LED_MODE_SEL 29
  49. #define LED_1_MODE_SEL_MASK 0x00F0
  50. #define LED_0_MODE_SEL_MASK 0x000F
  51. #define LED_1_MODE_SEL_POS 4
  52. #define MSCC_EXT_PAGE_ACCESS 31
  53. #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
  54. #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
  55. #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
  56. /* Extended Page 1 Registers */
  57. #define MSCC_PHY_EXT_MODE_CNTL 19
  58. #define FORCE_MDI_CROSSOVER_MASK 0x000C
  59. #define FORCE_MDI_CROSSOVER_MDIX 0x000C
  60. #define FORCE_MDI_CROSSOVER_MDI 0x0008
  61. #define MSCC_PHY_ACTIPHY_CNTL 20
  62. #define DOWNSHIFT_CNTL_MASK 0x001C
  63. #define DOWNSHIFT_EN 0x0010
  64. #define DOWNSHIFT_CNTL_POS 2
  65. /* Extended Page 2 Registers */
  66. #define MSCC_PHY_RGMII_CNTL 20
  67. #define RGMII_RX_CLK_DELAY_MASK 0x0070
  68. #define RGMII_RX_CLK_DELAY_POS 4
  69. #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
  70. #define MSCC_PHY_WOL_MID_MAC_ADDR 22
  71. #define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
  72. #define MSCC_PHY_WOL_LOWER_PASSWD 24
  73. #define MSCC_PHY_WOL_MID_PASSWD 25
  74. #define MSCC_PHY_WOL_UPPER_PASSWD 26
  75. #define MSCC_PHY_WOL_MAC_CONTROL 27
  76. #define SECURE_ON_ENABLE 0x8000
  77. #define SECURE_ON_PASSWD_LEN_4 0x4000
  78. /* Microsemi PHY ID's */
  79. #define PHY_ID_VSC8530 0x00070560
  80. #define PHY_ID_VSC8531 0x00070570
  81. #define PHY_ID_VSC8540 0x00070760
  82. #define PHY_ID_VSC8541 0x00070770
  83. #define MSCC_VDDMAC_1500 1500
  84. #define MSCC_VDDMAC_1800 1800
  85. #define MSCC_VDDMAC_2500 2500
  86. #define MSCC_VDDMAC_3300 3300
  87. #define DOWNSHIFT_COUNT_MAX 5
  88. struct vsc8531_private {
  89. int rate_magic;
  90. u8 led_0_mode;
  91. u8 led_1_mode;
  92. };
  93. #ifdef CONFIG_OF_MDIO
  94. struct vsc8531_edge_rate_table {
  95. u16 vddmac;
  96. u8 slowdown[8];
  97. };
  98. static const struct vsc8531_edge_rate_table edge_table[] = {
  99. {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },
  100. {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },
  101. {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },
  102. {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
  103. };
  104. #endif /* CONFIG_OF_MDIO */
  105. static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
  106. {
  107. int rc;
  108. rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
  109. return rc;
  110. }
  111. static int vsc85xx_led_cntl_set(struct phy_device *phydev,
  112. u8 led_num,
  113. u8 mode)
  114. {
  115. int rc;
  116. u16 reg_val;
  117. mutex_lock(&phydev->lock);
  118. reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
  119. if (led_num) {
  120. reg_val &= ~LED_1_MODE_SEL_MASK;
  121. reg_val |= (((u16)mode << LED_1_MODE_SEL_POS) &
  122. LED_1_MODE_SEL_MASK);
  123. } else {
  124. reg_val &= ~LED_0_MODE_SEL_MASK;
  125. reg_val |= ((u16)mode & LED_0_MODE_SEL_MASK);
  126. }
  127. rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
  128. mutex_unlock(&phydev->lock);
  129. return rc;
  130. }
  131. static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
  132. {
  133. u16 reg_val;
  134. reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
  135. if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
  136. *mdix = ETH_TP_MDI_X;
  137. else
  138. *mdix = ETH_TP_MDI;
  139. return 0;
  140. }
  141. static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
  142. {
  143. int rc;
  144. u16 reg_val;
  145. reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
  146. if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) {
  147. reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
  148. DISABLE_POLARITY_CORR_MASK |
  149. DISABLE_HP_AUTO_MDIX_MASK);
  150. } else {
  151. reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
  152. DISABLE_POLARITY_CORR_MASK |
  153. DISABLE_HP_AUTO_MDIX_MASK);
  154. }
  155. rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
  156. if (rc != 0)
  157. return rc;
  158. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
  159. if (rc != 0)
  160. return rc;
  161. reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL);
  162. reg_val &= ~(FORCE_MDI_CROSSOVER_MASK);
  163. if (mdix == ETH_TP_MDI)
  164. reg_val |= FORCE_MDI_CROSSOVER_MDI;
  165. else if (mdix == ETH_TP_MDI_X)
  166. reg_val |= FORCE_MDI_CROSSOVER_MDIX;
  167. rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val);
  168. if (rc != 0)
  169. return rc;
  170. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  171. if (rc != 0)
  172. return rc;
  173. return genphy_restart_aneg(phydev);
  174. }
  175. static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
  176. {
  177. int rc;
  178. u16 reg_val;
  179. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
  180. if (rc != 0)
  181. goto out;
  182. reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
  183. reg_val &= DOWNSHIFT_CNTL_MASK;
  184. if (!(reg_val & DOWNSHIFT_EN))
  185. *count = DOWNSHIFT_DEV_DISABLE;
  186. else
  187. *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
  188. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  189. out:
  190. return rc;
  191. }
  192. static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
  193. {
  194. int rc;
  195. u16 reg_val;
  196. if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
  197. /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
  198. count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
  199. } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
  200. phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
  201. return -ERANGE;
  202. } else if (count) {
  203. /* Downshift count is either 2,3,4 or 5 */
  204. count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
  205. }
  206. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
  207. if (rc != 0)
  208. goto out;
  209. reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
  210. reg_val &= ~(DOWNSHIFT_CNTL_MASK);
  211. reg_val |= count;
  212. rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val);
  213. if (rc != 0)
  214. goto out;
  215. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  216. out:
  217. return rc;
  218. }
  219. static int vsc85xx_wol_set(struct phy_device *phydev,
  220. struct ethtool_wolinfo *wol)
  221. {
  222. int rc;
  223. u16 reg_val;
  224. u8 i;
  225. u16 pwd[3] = {0, 0, 0};
  226. struct ethtool_wolinfo *wol_conf = wol;
  227. u8 *mac_addr = phydev->attached_dev->dev_addr;
  228. mutex_lock(&phydev->lock);
  229. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  230. if (rc != 0)
  231. goto out_unlock;
  232. if (wol->wolopts & WAKE_MAGIC) {
  233. /* Store the device address for the magic packet */
  234. for (i = 0; i < ARRAY_SIZE(pwd); i++)
  235. pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
  236. mac_addr[5 - i * 2];
  237. phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
  238. phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
  239. phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
  240. } else {
  241. phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
  242. phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
  243. phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
  244. }
  245. if (wol_conf->wolopts & WAKE_MAGICSECURE) {
  246. for (i = 0; i < ARRAY_SIZE(pwd); i++)
  247. pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
  248. wol_conf->sopass[5 - i * 2];
  249. phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
  250. phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
  251. phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
  252. } else {
  253. phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
  254. phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
  255. phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
  256. }
  257. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  258. if (wol_conf->wolopts & WAKE_MAGICSECURE)
  259. reg_val |= SECURE_ON_ENABLE;
  260. else
  261. reg_val &= ~SECURE_ON_ENABLE;
  262. phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
  263. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  264. if (rc != 0)
  265. goto out_unlock;
  266. if (wol->wolopts & WAKE_MAGIC) {
  267. /* Enable the WOL interrupt */
  268. reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
  269. reg_val |= MII_VSC85XX_INT_MASK_WOL;
  270. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
  271. if (rc != 0)
  272. goto out_unlock;
  273. } else {
  274. /* Disable the WOL interrupt */
  275. reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
  276. reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
  277. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
  278. if (rc != 0)
  279. goto out_unlock;
  280. }
  281. /* Clear WOL iterrupt status */
  282. reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  283. out_unlock:
  284. mutex_unlock(&phydev->lock);
  285. return rc;
  286. }
  287. static void vsc85xx_wol_get(struct phy_device *phydev,
  288. struct ethtool_wolinfo *wol)
  289. {
  290. int rc;
  291. u16 reg_val;
  292. u8 i;
  293. u16 pwd[3] = {0, 0, 0};
  294. struct ethtool_wolinfo *wol_conf = wol;
  295. mutex_lock(&phydev->lock);
  296. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  297. if (rc != 0)
  298. goto out_unlock;
  299. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  300. if (reg_val & SECURE_ON_ENABLE)
  301. wol_conf->wolopts |= WAKE_MAGICSECURE;
  302. if (wol_conf->wolopts & WAKE_MAGICSECURE) {
  303. pwd[0] = phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
  304. pwd[1] = phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
  305. pwd[2] = phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
  306. for (i = 0; i < ARRAY_SIZE(pwd); i++) {
  307. wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
  308. wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
  309. >> 8;
  310. }
  311. }
  312. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  313. out_unlock:
  314. mutex_unlock(&phydev->lock);
  315. }
  316. #ifdef CONFIG_OF_MDIO
  317. static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
  318. {
  319. u8 sd;
  320. u16 vdd;
  321. int rc, i, j;
  322. struct device *dev = &phydev->mdio.dev;
  323. struct device_node *of_node = dev->of_node;
  324. u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
  325. if (!of_node)
  326. return -ENODEV;
  327. rc = of_property_read_u16(of_node, "vsc8531,vddmac", &vdd);
  328. if (rc != 0)
  329. vdd = MSCC_VDDMAC_3300;
  330. rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown", &sd);
  331. if (rc != 0)
  332. sd = 0;
  333. for (i = 0; i < ARRAY_SIZE(edge_table); i++)
  334. if (edge_table[i].vddmac == vdd)
  335. for (j = 0; j < sd_array_size; j++)
  336. if (edge_table[i].slowdown[j] == sd)
  337. return (sd_array_size - j - 1);
  338. return -EINVAL;
  339. }
  340. static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
  341. char *led,
  342. u8 default_mode)
  343. {
  344. struct device *dev = &phydev->mdio.dev;
  345. struct device_node *of_node = dev->of_node;
  346. u8 led_mode;
  347. int err;
  348. if (!of_node)
  349. return -ENODEV;
  350. led_mode = default_mode;
  351. err = of_property_read_u8(of_node, led, &led_mode);
  352. if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) {
  353. phydev_err(phydev, "DT %s invalid\n", led);
  354. return -EINVAL;
  355. }
  356. return led_mode;
  357. }
  358. #else
  359. static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
  360. {
  361. return 0;
  362. }
  363. static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
  364. char *led,
  365. u8 default_mode)
  366. {
  367. return default_mode;
  368. }
  369. #endif /* CONFIG_OF_MDIO */
  370. static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
  371. {
  372. int rc;
  373. u16 reg_val;
  374. mutex_lock(&phydev->lock);
  375. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  376. if (rc != 0)
  377. goto out_unlock;
  378. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  379. reg_val &= ~(EDGE_RATE_CNTL_MASK);
  380. reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
  381. rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
  382. if (rc != 0)
  383. goto out_unlock;
  384. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  385. out_unlock:
  386. mutex_unlock(&phydev->lock);
  387. return rc;
  388. }
  389. static int vsc85xx_mac_if_set(struct phy_device *phydev,
  390. phy_interface_t interface)
  391. {
  392. int rc;
  393. u16 reg_val;
  394. mutex_lock(&phydev->lock);
  395. reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
  396. reg_val &= ~(MAC_IF_SELECTION_MASK);
  397. switch (interface) {
  398. case PHY_INTERFACE_MODE_RGMII:
  399. reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
  400. break;
  401. case PHY_INTERFACE_MODE_RMII:
  402. reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
  403. break;
  404. case PHY_INTERFACE_MODE_MII:
  405. case PHY_INTERFACE_MODE_GMII:
  406. reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
  407. break;
  408. default:
  409. rc = -EINVAL;
  410. goto out_unlock;
  411. }
  412. rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
  413. if (rc != 0)
  414. goto out_unlock;
  415. rc = genphy_soft_reset(phydev);
  416. out_unlock:
  417. mutex_unlock(&phydev->lock);
  418. return rc;
  419. }
  420. static int vsc85xx_default_config(struct phy_device *phydev)
  421. {
  422. int rc;
  423. u16 reg_val;
  424. phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
  425. mutex_lock(&phydev->lock);
  426. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  427. if (rc != 0)
  428. goto out_unlock;
  429. reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
  430. reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
  431. reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
  432. phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
  433. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  434. out_unlock:
  435. mutex_unlock(&phydev->lock);
  436. return rc;
  437. }
  438. static int vsc85xx_get_tunable(struct phy_device *phydev,
  439. struct ethtool_tunable *tuna, void *data)
  440. {
  441. switch (tuna->id) {
  442. case ETHTOOL_PHY_DOWNSHIFT:
  443. return vsc85xx_downshift_get(phydev, (u8 *)data);
  444. default:
  445. return -EINVAL;
  446. }
  447. }
  448. static int vsc85xx_set_tunable(struct phy_device *phydev,
  449. struct ethtool_tunable *tuna,
  450. const void *data)
  451. {
  452. switch (tuna->id) {
  453. case ETHTOOL_PHY_DOWNSHIFT:
  454. return vsc85xx_downshift_set(phydev, *(u8 *)data);
  455. default:
  456. return -EINVAL;
  457. }
  458. }
  459. static int vsc85xx_config_init(struct phy_device *phydev)
  460. {
  461. int rc;
  462. struct vsc8531_private *vsc8531 = phydev->priv;
  463. rc = vsc85xx_default_config(phydev);
  464. if (rc)
  465. return rc;
  466. rc = vsc85xx_mac_if_set(phydev, phydev->interface);
  467. if (rc)
  468. return rc;
  469. rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
  470. if (rc)
  471. return rc;
  472. rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode);
  473. if (rc)
  474. return rc;
  475. rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode);
  476. if (rc)
  477. return rc;
  478. rc = genphy_config_init(phydev);
  479. return rc;
  480. }
  481. static int vsc85xx_ack_interrupt(struct phy_device *phydev)
  482. {
  483. int rc = 0;
  484. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  485. rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  486. return (rc < 0) ? rc : 0;
  487. }
  488. static int vsc85xx_config_intr(struct phy_device *phydev)
  489. {
  490. int rc;
  491. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  492. rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
  493. MII_VSC85XX_INT_MASK_MASK);
  494. } else {
  495. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
  496. if (rc < 0)
  497. return rc;
  498. rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  499. }
  500. return rc;
  501. }
  502. static int vsc85xx_config_aneg(struct phy_device *phydev)
  503. {
  504. int rc;
  505. rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
  506. if (rc < 0)
  507. return rc;
  508. return genphy_config_aneg(phydev);
  509. }
  510. static int vsc85xx_read_status(struct phy_device *phydev)
  511. {
  512. int rc;
  513. rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
  514. if (rc < 0)
  515. return rc;
  516. return genphy_read_status(phydev);
  517. }
  518. static int vsc85xx_probe(struct phy_device *phydev)
  519. {
  520. struct vsc8531_private *vsc8531;
  521. int rate_magic;
  522. int led_mode;
  523. rate_magic = vsc85xx_edge_rate_magic_get(phydev);
  524. if (rate_magic < 0)
  525. return rate_magic;
  526. vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
  527. if (!vsc8531)
  528. return -ENOMEM;
  529. phydev->priv = vsc8531;
  530. vsc8531->rate_magic = rate_magic;
  531. /* LED[0] and LED[1] mode */
  532. led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode",
  533. VSC8531_LINK_1000_ACTIVITY);
  534. if (led_mode < 0)
  535. return led_mode;
  536. vsc8531->led_0_mode = led_mode;
  537. led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode",
  538. VSC8531_LINK_100_ACTIVITY);
  539. if (led_mode < 0)
  540. return led_mode;
  541. vsc8531->led_1_mode = led_mode;
  542. return 0;
  543. }
  544. /* Microsemi VSC85xx PHYs */
  545. static struct phy_driver vsc85xx_driver[] = {
  546. {
  547. .phy_id = PHY_ID_VSC8530,
  548. .name = "Microsemi FE VSC8530",
  549. .phy_id_mask = 0xfffffff0,
  550. .features = PHY_BASIC_FEATURES,
  551. .flags = PHY_HAS_INTERRUPT,
  552. .soft_reset = &genphy_soft_reset,
  553. .config_init = &vsc85xx_config_init,
  554. .config_aneg = &vsc85xx_config_aneg,
  555. .aneg_done = &genphy_aneg_done,
  556. .read_status = &vsc85xx_read_status,
  557. .ack_interrupt = &vsc85xx_ack_interrupt,
  558. .config_intr = &vsc85xx_config_intr,
  559. .suspend = &genphy_suspend,
  560. .resume = &genphy_resume,
  561. .probe = &vsc85xx_probe,
  562. .set_wol = &vsc85xx_wol_set,
  563. .get_wol = &vsc85xx_wol_get,
  564. .get_tunable = &vsc85xx_get_tunable,
  565. .set_tunable = &vsc85xx_set_tunable,
  566. },
  567. {
  568. .phy_id = PHY_ID_VSC8531,
  569. .name = "Microsemi VSC8531",
  570. .phy_id_mask = 0xfffffff0,
  571. .features = PHY_GBIT_FEATURES,
  572. .flags = PHY_HAS_INTERRUPT,
  573. .soft_reset = &genphy_soft_reset,
  574. .config_init = &vsc85xx_config_init,
  575. .config_aneg = &vsc85xx_config_aneg,
  576. .aneg_done = &genphy_aneg_done,
  577. .read_status = &vsc85xx_read_status,
  578. .ack_interrupt = &vsc85xx_ack_interrupt,
  579. .config_intr = &vsc85xx_config_intr,
  580. .suspend = &genphy_suspend,
  581. .resume = &genphy_resume,
  582. .probe = &vsc85xx_probe,
  583. .set_wol = &vsc85xx_wol_set,
  584. .get_wol = &vsc85xx_wol_get,
  585. .get_tunable = &vsc85xx_get_tunable,
  586. .set_tunable = &vsc85xx_set_tunable,
  587. },
  588. {
  589. .phy_id = PHY_ID_VSC8540,
  590. .name = "Microsemi FE VSC8540 SyncE",
  591. .phy_id_mask = 0xfffffff0,
  592. .features = PHY_BASIC_FEATURES,
  593. .flags = PHY_HAS_INTERRUPT,
  594. .soft_reset = &genphy_soft_reset,
  595. .config_init = &vsc85xx_config_init,
  596. .config_aneg = &vsc85xx_config_aneg,
  597. .aneg_done = &genphy_aneg_done,
  598. .read_status = &vsc85xx_read_status,
  599. .ack_interrupt = &vsc85xx_ack_interrupt,
  600. .config_intr = &vsc85xx_config_intr,
  601. .suspend = &genphy_suspend,
  602. .resume = &genphy_resume,
  603. .probe = &vsc85xx_probe,
  604. .set_wol = &vsc85xx_wol_set,
  605. .get_wol = &vsc85xx_wol_get,
  606. .get_tunable = &vsc85xx_get_tunable,
  607. .set_tunable = &vsc85xx_set_tunable,
  608. },
  609. {
  610. .phy_id = PHY_ID_VSC8541,
  611. .name = "Microsemi VSC8541 SyncE",
  612. .phy_id_mask = 0xfffffff0,
  613. .features = PHY_GBIT_FEATURES,
  614. .flags = PHY_HAS_INTERRUPT,
  615. .soft_reset = &genphy_soft_reset,
  616. .config_init = &vsc85xx_config_init,
  617. .config_aneg = &vsc85xx_config_aneg,
  618. .aneg_done = &genphy_aneg_done,
  619. .read_status = &vsc85xx_read_status,
  620. .ack_interrupt = &vsc85xx_ack_interrupt,
  621. .config_intr = &vsc85xx_config_intr,
  622. .suspend = &genphy_suspend,
  623. .resume = &genphy_resume,
  624. .probe = &vsc85xx_probe,
  625. .set_wol = &vsc85xx_wol_set,
  626. .get_wol = &vsc85xx_wol_get,
  627. .get_tunable = &vsc85xx_get_tunable,
  628. .set_tunable = &vsc85xx_set_tunable,
  629. }
  630. };
  631. module_phy_driver(vsc85xx_driver);
  632. static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
  633. { PHY_ID_VSC8530, 0xfffffff0, },
  634. { PHY_ID_VSC8531, 0xfffffff0, },
  635. { PHY_ID_VSC8540, 0xfffffff0, },
  636. { PHY_ID_VSC8541, 0xfffffff0, },
  637. { }
  638. };
  639. MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
  640. MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
  641. MODULE_AUTHOR("Nagaraju Lakkaraju");
  642. MODULE_LICENSE("Dual MIT/GPL");