mscc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  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. u32 vddmac;
  96. u32 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, u16 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. u32 vdd, sd;
  320. int rc, i, j;
  321. struct device *dev = &phydev->mdio.dev;
  322. struct device_node *of_node = dev->of_node;
  323. u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
  324. if (!of_node)
  325. return -ENODEV;
  326. rc = of_property_read_u32(of_node, "vsc8531,vddmac", &vdd);
  327. if (rc != 0)
  328. vdd = MSCC_VDDMAC_3300;
  329. rc = of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd);
  330. if (rc != 0)
  331. sd = 0;
  332. for (i = 0; i < ARRAY_SIZE(edge_table); i++)
  333. if (edge_table[i].vddmac == vdd)
  334. for (j = 0; j < sd_array_size; j++)
  335. if (edge_table[i].slowdown[j] == sd)
  336. return (sd_array_size - j - 1);
  337. return -EINVAL;
  338. }
  339. static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
  340. char *led,
  341. u8 default_mode)
  342. {
  343. struct device *dev = &phydev->mdio.dev;
  344. struct device_node *of_node = dev->of_node;
  345. u8 led_mode;
  346. int err;
  347. if (!of_node)
  348. return -ENODEV;
  349. led_mode = default_mode;
  350. err = of_property_read_u8(of_node, led, &led_mode);
  351. if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) {
  352. phydev_err(phydev, "DT %s invalid\n", led);
  353. return -EINVAL;
  354. }
  355. return led_mode;
  356. }
  357. #else
  358. static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
  359. {
  360. return 0;
  361. }
  362. static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
  363. char *led,
  364. u8 default_mode)
  365. {
  366. return default_mode;
  367. }
  368. #endif /* CONFIG_OF_MDIO */
  369. static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
  370. {
  371. int rc;
  372. u16 reg_val;
  373. mutex_lock(&phydev->lock);
  374. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  375. if (rc != 0)
  376. goto out_unlock;
  377. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  378. reg_val &= ~(EDGE_RATE_CNTL_MASK);
  379. reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
  380. rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
  381. if (rc != 0)
  382. goto out_unlock;
  383. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  384. out_unlock:
  385. mutex_unlock(&phydev->lock);
  386. return rc;
  387. }
  388. static int vsc85xx_mac_if_set(struct phy_device *phydev,
  389. phy_interface_t interface)
  390. {
  391. int rc;
  392. u16 reg_val;
  393. mutex_lock(&phydev->lock);
  394. reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
  395. reg_val &= ~(MAC_IF_SELECTION_MASK);
  396. switch (interface) {
  397. case PHY_INTERFACE_MODE_RGMII:
  398. reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
  399. break;
  400. case PHY_INTERFACE_MODE_RMII:
  401. reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
  402. break;
  403. case PHY_INTERFACE_MODE_MII:
  404. case PHY_INTERFACE_MODE_GMII:
  405. reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
  406. break;
  407. default:
  408. rc = -EINVAL;
  409. goto out_unlock;
  410. }
  411. rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
  412. if (rc != 0)
  413. goto out_unlock;
  414. rc = genphy_soft_reset(phydev);
  415. out_unlock:
  416. mutex_unlock(&phydev->lock);
  417. return rc;
  418. }
  419. static int vsc85xx_default_config(struct phy_device *phydev)
  420. {
  421. int rc;
  422. u16 reg_val;
  423. phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
  424. mutex_lock(&phydev->lock);
  425. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  426. if (rc != 0)
  427. goto out_unlock;
  428. reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
  429. reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
  430. reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
  431. phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
  432. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  433. out_unlock:
  434. mutex_unlock(&phydev->lock);
  435. return rc;
  436. }
  437. static int vsc85xx_get_tunable(struct phy_device *phydev,
  438. struct ethtool_tunable *tuna, void *data)
  439. {
  440. switch (tuna->id) {
  441. case ETHTOOL_PHY_DOWNSHIFT:
  442. return vsc85xx_downshift_get(phydev, (u8 *)data);
  443. default:
  444. return -EINVAL;
  445. }
  446. }
  447. static int vsc85xx_set_tunable(struct phy_device *phydev,
  448. struct ethtool_tunable *tuna,
  449. const void *data)
  450. {
  451. switch (tuna->id) {
  452. case ETHTOOL_PHY_DOWNSHIFT:
  453. return vsc85xx_downshift_set(phydev, *(u8 *)data);
  454. default:
  455. return -EINVAL;
  456. }
  457. }
  458. static int vsc85xx_config_init(struct phy_device *phydev)
  459. {
  460. int rc;
  461. struct vsc8531_private *vsc8531 = phydev->priv;
  462. rc = vsc85xx_default_config(phydev);
  463. if (rc)
  464. return rc;
  465. rc = vsc85xx_mac_if_set(phydev, phydev->interface);
  466. if (rc)
  467. return rc;
  468. rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
  469. if (rc)
  470. return rc;
  471. rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode);
  472. if (rc)
  473. return rc;
  474. rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode);
  475. if (rc)
  476. return rc;
  477. rc = genphy_config_init(phydev);
  478. return rc;
  479. }
  480. static int vsc85xx_ack_interrupt(struct phy_device *phydev)
  481. {
  482. int rc = 0;
  483. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  484. rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  485. return (rc < 0) ? rc : 0;
  486. }
  487. static int vsc85xx_config_intr(struct phy_device *phydev)
  488. {
  489. int rc;
  490. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  491. rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
  492. MII_VSC85XX_INT_MASK_MASK);
  493. } else {
  494. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
  495. if (rc < 0)
  496. return rc;
  497. rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  498. }
  499. return rc;
  500. }
  501. static int vsc85xx_config_aneg(struct phy_device *phydev)
  502. {
  503. int rc;
  504. rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
  505. if (rc < 0)
  506. return rc;
  507. return genphy_config_aneg(phydev);
  508. }
  509. static int vsc85xx_read_status(struct phy_device *phydev)
  510. {
  511. int rc;
  512. rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
  513. if (rc < 0)
  514. return rc;
  515. return genphy_read_status(phydev);
  516. }
  517. static int vsc85xx_probe(struct phy_device *phydev)
  518. {
  519. struct vsc8531_private *vsc8531;
  520. int rate_magic;
  521. int led_mode;
  522. rate_magic = vsc85xx_edge_rate_magic_get(phydev);
  523. if (rate_magic < 0)
  524. return rate_magic;
  525. vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
  526. if (!vsc8531)
  527. return -ENOMEM;
  528. phydev->priv = vsc8531;
  529. vsc8531->rate_magic = rate_magic;
  530. /* LED[0] and LED[1] mode */
  531. led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode",
  532. VSC8531_LINK_1000_ACTIVITY);
  533. if (led_mode < 0)
  534. return led_mode;
  535. vsc8531->led_0_mode = led_mode;
  536. led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode",
  537. VSC8531_LINK_100_ACTIVITY);
  538. if (led_mode < 0)
  539. return led_mode;
  540. vsc8531->led_1_mode = led_mode;
  541. return 0;
  542. }
  543. /* Microsemi VSC85xx PHYs */
  544. static struct phy_driver vsc85xx_driver[] = {
  545. {
  546. .phy_id = PHY_ID_VSC8530,
  547. .name = "Microsemi FE VSC8530",
  548. .phy_id_mask = 0xfffffff0,
  549. .features = PHY_BASIC_FEATURES,
  550. .flags = PHY_HAS_INTERRUPT,
  551. .soft_reset = &genphy_soft_reset,
  552. .config_init = &vsc85xx_config_init,
  553. .config_aneg = &vsc85xx_config_aneg,
  554. .aneg_done = &genphy_aneg_done,
  555. .read_status = &vsc85xx_read_status,
  556. .ack_interrupt = &vsc85xx_ack_interrupt,
  557. .config_intr = &vsc85xx_config_intr,
  558. .suspend = &genphy_suspend,
  559. .resume = &genphy_resume,
  560. .probe = &vsc85xx_probe,
  561. .set_wol = &vsc85xx_wol_set,
  562. .get_wol = &vsc85xx_wol_get,
  563. .get_tunable = &vsc85xx_get_tunable,
  564. .set_tunable = &vsc85xx_set_tunable,
  565. },
  566. {
  567. .phy_id = PHY_ID_VSC8531,
  568. .name = "Microsemi VSC8531",
  569. .phy_id_mask = 0xfffffff0,
  570. .features = PHY_GBIT_FEATURES,
  571. .flags = PHY_HAS_INTERRUPT,
  572. .soft_reset = &genphy_soft_reset,
  573. .config_init = &vsc85xx_config_init,
  574. .config_aneg = &vsc85xx_config_aneg,
  575. .aneg_done = &genphy_aneg_done,
  576. .read_status = &vsc85xx_read_status,
  577. .ack_interrupt = &vsc85xx_ack_interrupt,
  578. .config_intr = &vsc85xx_config_intr,
  579. .suspend = &genphy_suspend,
  580. .resume = &genphy_resume,
  581. .probe = &vsc85xx_probe,
  582. .set_wol = &vsc85xx_wol_set,
  583. .get_wol = &vsc85xx_wol_get,
  584. .get_tunable = &vsc85xx_get_tunable,
  585. .set_tunable = &vsc85xx_set_tunable,
  586. },
  587. {
  588. .phy_id = PHY_ID_VSC8540,
  589. .name = "Microsemi FE VSC8540 SyncE",
  590. .phy_id_mask = 0xfffffff0,
  591. .features = PHY_BASIC_FEATURES,
  592. .flags = PHY_HAS_INTERRUPT,
  593. .soft_reset = &genphy_soft_reset,
  594. .config_init = &vsc85xx_config_init,
  595. .config_aneg = &vsc85xx_config_aneg,
  596. .aneg_done = &genphy_aneg_done,
  597. .read_status = &vsc85xx_read_status,
  598. .ack_interrupt = &vsc85xx_ack_interrupt,
  599. .config_intr = &vsc85xx_config_intr,
  600. .suspend = &genphy_suspend,
  601. .resume = &genphy_resume,
  602. .probe = &vsc85xx_probe,
  603. .set_wol = &vsc85xx_wol_set,
  604. .get_wol = &vsc85xx_wol_get,
  605. .get_tunable = &vsc85xx_get_tunable,
  606. .set_tunable = &vsc85xx_set_tunable,
  607. },
  608. {
  609. .phy_id = PHY_ID_VSC8541,
  610. .name = "Microsemi VSC8541 SyncE",
  611. .phy_id_mask = 0xfffffff0,
  612. .features = PHY_GBIT_FEATURES,
  613. .flags = PHY_HAS_INTERRUPT,
  614. .soft_reset = &genphy_soft_reset,
  615. .config_init = &vsc85xx_config_init,
  616. .config_aneg = &vsc85xx_config_aneg,
  617. .aneg_done = &genphy_aneg_done,
  618. .read_status = &vsc85xx_read_status,
  619. .ack_interrupt = &vsc85xx_ack_interrupt,
  620. .config_intr = &vsc85xx_config_intr,
  621. .suspend = &genphy_suspend,
  622. .resume = &genphy_resume,
  623. .probe = &vsc85xx_probe,
  624. .set_wol = &vsc85xx_wol_set,
  625. .get_wol = &vsc85xx_wol_get,
  626. .get_tunable = &vsc85xx_get_tunable,
  627. .set_tunable = &vsc85xx_set_tunable,
  628. }
  629. };
  630. module_phy_driver(vsc85xx_driver);
  631. static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
  632. { PHY_ID_VSC8530, 0xfffffff0, },
  633. { PHY_ID_VSC8531, 0xfffffff0, },
  634. { PHY_ID_VSC8540, 0xfffffff0, },
  635. { PHY_ID_VSC8541, 0xfffffff0, },
  636. { }
  637. };
  638. MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
  639. MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
  640. MODULE_AUTHOR("Nagaraju Lakkaraju");
  641. MODULE_LICENSE("Dual MIT/GPL");