mscc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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. enum rgmii_rx_clock_delay {
  16. RGMII_RX_CLK_DELAY_0_2_NS = 0,
  17. RGMII_RX_CLK_DELAY_0_8_NS = 1,
  18. RGMII_RX_CLK_DELAY_1_1_NS = 2,
  19. RGMII_RX_CLK_DELAY_1_7_NS = 3,
  20. RGMII_RX_CLK_DELAY_2_0_NS = 4,
  21. RGMII_RX_CLK_DELAY_2_3_NS = 5,
  22. RGMII_RX_CLK_DELAY_2_6_NS = 6,
  23. RGMII_RX_CLK_DELAY_3_4_NS = 7
  24. };
  25. /* Microsemi VSC85xx PHY registers */
  26. /* IEEE 802. Std Registers */
  27. #define MSCC_PHY_EXT_PHY_CNTL_1 23
  28. #define MAC_IF_SELECTION_MASK 0x1800
  29. #define MAC_IF_SELECTION_GMII 0
  30. #define MAC_IF_SELECTION_RMII 1
  31. #define MAC_IF_SELECTION_RGMII 2
  32. #define MAC_IF_SELECTION_POS 11
  33. #define FAR_END_LOOPBACK_MODE_MASK 0x0008
  34. #define MII_VSC85XX_INT_MASK 25
  35. #define MII_VSC85XX_INT_MASK_MASK 0xa000
  36. #define MII_VSC85XX_INT_MASK_WOL 0x0040
  37. #define MII_VSC85XX_INT_STATUS 26
  38. #define MSCC_PHY_WOL_MAC_CONTROL 27
  39. #define EDGE_RATE_CNTL_POS 5
  40. #define EDGE_RATE_CNTL_MASK 0x00E0
  41. #define MSCC_EXT_PAGE_ACCESS 31
  42. #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
  43. #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
  44. /* Extended Page 2 Registers */
  45. #define MSCC_PHY_RGMII_CNTL 20
  46. #define RGMII_RX_CLK_DELAY_MASK 0x0070
  47. #define RGMII_RX_CLK_DELAY_POS 4
  48. #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
  49. #define MSCC_PHY_WOL_MID_MAC_ADDR 22
  50. #define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
  51. #define MSCC_PHY_WOL_LOWER_PASSWD 24
  52. #define MSCC_PHY_WOL_MID_PASSWD 25
  53. #define MSCC_PHY_WOL_UPPER_PASSWD 26
  54. #define MSCC_PHY_WOL_MAC_CONTROL 27
  55. #define SECURE_ON_ENABLE 0x8000
  56. #define SECURE_ON_PASSWD_LEN_4 0x4000
  57. /* Microsemi PHY ID's */
  58. #define PHY_ID_VSC8531 0x00070570
  59. #define PHY_ID_VSC8541 0x00070770
  60. #define MSCC_VDDMAC_1500 1500
  61. #define MSCC_VDDMAC_1800 1800
  62. #define MSCC_VDDMAC_2500 2500
  63. #define MSCC_VDDMAC_3300 3300
  64. struct vsc8531_private {
  65. int rate_magic;
  66. };
  67. #ifdef CONFIG_OF_MDIO
  68. struct vsc8531_edge_rate_table {
  69. u16 vddmac;
  70. u8 slowdown[8];
  71. };
  72. static const struct vsc8531_edge_rate_table edge_table[] = {
  73. {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },
  74. {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },
  75. {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },
  76. {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
  77. };
  78. #endif /* CONFIG_OF_MDIO */
  79. static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
  80. {
  81. int rc;
  82. rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
  83. return rc;
  84. }
  85. static int vsc85xx_wol_set(struct phy_device *phydev,
  86. struct ethtool_wolinfo *wol)
  87. {
  88. int rc;
  89. u16 reg_val;
  90. u8 i;
  91. u16 pwd[3] = {0, 0, 0};
  92. struct ethtool_wolinfo *wol_conf = wol;
  93. u8 *mac_addr = phydev->attached_dev->dev_addr;
  94. mutex_lock(&phydev->lock);
  95. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  96. if (rc != 0)
  97. goto out_unlock;
  98. if (wol->wolopts & WAKE_MAGIC) {
  99. /* Store the device address for the magic packet */
  100. for (i = 0; i < ARRAY_SIZE(pwd); i++)
  101. pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
  102. mac_addr[5 - i * 2];
  103. phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
  104. phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
  105. phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
  106. } else {
  107. phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
  108. phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
  109. phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
  110. }
  111. if (wol_conf->wolopts & WAKE_MAGICSECURE) {
  112. for (i = 0; i < ARRAY_SIZE(pwd); i++)
  113. pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
  114. wol_conf->sopass[5 - i * 2];
  115. phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
  116. phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
  117. phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
  118. } else {
  119. phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
  120. phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
  121. phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
  122. }
  123. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  124. if (wol_conf->wolopts & WAKE_MAGICSECURE)
  125. reg_val |= SECURE_ON_ENABLE;
  126. else
  127. reg_val &= ~SECURE_ON_ENABLE;
  128. phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
  129. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  130. if (rc != 0)
  131. goto out_unlock;
  132. if (wol->wolopts & WAKE_MAGIC) {
  133. /* Enable the WOL interrupt */
  134. reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
  135. reg_val |= MII_VSC85XX_INT_MASK_WOL;
  136. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
  137. if (rc != 0)
  138. goto out_unlock;
  139. } else {
  140. /* Disable the WOL interrupt */
  141. reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
  142. reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
  143. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
  144. if (rc != 0)
  145. goto out_unlock;
  146. }
  147. /* Clear WOL iterrupt status */
  148. reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  149. out_unlock:
  150. mutex_unlock(&phydev->lock);
  151. return rc;
  152. }
  153. static void vsc85xx_wol_get(struct phy_device *phydev,
  154. struct ethtool_wolinfo *wol)
  155. {
  156. int rc;
  157. u16 reg_val;
  158. u8 i;
  159. u16 pwd[3] = {0, 0, 0};
  160. struct ethtool_wolinfo *wol_conf = wol;
  161. mutex_lock(&phydev->lock);
  162. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  163. if (rc != 0)
  164. goto out_unlock;
  165. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  166. if (reg_val & SECURE_ON_ENABLE)
  167. wol_conf->wolopts |= WAKE_MAGICSECURE;
  168. if (wol_conf->wolopts & WAKE_MAGICSECURE) {
  169. pwd[0] = phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
  170. pwd[1] = phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
  171. pwd[2] = phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
  172. for (i = 0; i < ARRAY_SIZE(pwd); i++) {
  173. wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
  174. wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
  175. >> 8;
  176. }
  177. }
  178. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  179. out_unlock:
  180. mutex_unlock(&phydev->lock);
  181. }
  182. #ifdef CONFIG_OF_MDIO
  183. static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
  184. {
  185. u8 sd;
  186. u16 vdd;
  187. int rc, i, j;
  188. struct device *dev = &phydev->mdio.dev;
  189. struct device_node *of_node = dev->of_node;
  190. u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
  191. if (!of_node)
  192. return -ENODEV;
  193. rc = of_property_read_u16(of_node, "vsc8531,vddmac", &vdd);
  194. if (rc != 0)
  195. vdd = MSCC_VDDMAC_3300;
  196. rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown", &sd);
  197. if (rc != 0)
  198. sd = 0;
  199. for (i = 0; i < ARRAY_SIZE(edge_table); i++)
  200. if (edge_table[i].vddmac == vdd)
  201. for (j = 0; j < sd_array_size; j++)
  202. if (edge_table[i].slowdown[j] == sd)
  203. return (sd_array_size - j - 1);
  204. return -EINVAL;
  205. }
  206. #else
  207. static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
  208. {
  209. return 0;
  210. }
  211. #endif /* CONFIG_OF_MDIO */
  212. static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
  213. {
  214. int rc;
  215. u16 reg_val;
  216. mutex_lock(&phydev->lock);
  217. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  218. if (rc != 0)
  219. goto out_unlock;
  220. reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
  221. reg_val &= ~(EDGE_RATE_CNTL_MASK);
  222. reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
  223. rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
  224. if (rc != 0)
  225. goto out_unlock;
  226. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  227. out_unlock:
  228. mutex_unlock(&phydev->lock);
  229. return rc;
  230. }
  231. static int vsc85xx_mac_if_set(struct phy_device *phydev,
  232. phy_interface_t interface)
  233. {
  234. int rc;
  235. u16 reg_val;
  236. mutex_lock(&phydev->lock);
  237. reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
  238. reg_val &= ~(MAC_IF_SELECTION_MASK);
  239. switch (interface) {
  240. case PHY_INTERFACE_MODE_RGMII:
  241. reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
  242. break;
  243. case PHY_INTERFACE_MODE_RMII:
  244. reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
  245. break;
  246. case PHY_INTERFACE_MODE_MII:
  247. case PHY_INTERFACE_MODE_GMII:
  248. reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
  249. break;
  250. default:
  251. rc = -EINVAL;
  252. goto out_unlock;
  253. }
  254. rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
  255. if (rc != 0)
  256. goto out_unlock;
  257. rc = genphy_soft_reset(phydev);
  258. out_unlock:
  259. mutex_unlock(&phydev->lock);
  260. return rc;
  261. }
  262. static int vsc85xx_default_config(struct phy_device *phydev)
  263. {
  264. int rc;
  265. u16 reg_val;
  266. mutex_lock(&phydev->lock);
  267. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
  268. if (rc != 0)
  269. goto out_unlock;
  270. reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
  271. reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
  272. reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
  273. phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
  274. rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
  275. out_unlock:
  276. mutex_unlock(&phydev->lock);
  277. return rc;
  278. }
  279. static int vsc85xx_config_init(struct phy_device *phydev)
  280. {
  281. int rc;
  282. struct vsc8531_private *vsc8531 = phydev->priv;
  283. rc = vsc85xx_default_config(phydev);
  284. if (rc)
  285. return rc;
  286. rc = vsc85xx_mac_if_set(phydev, phydev->interface);
  287. if (rc)
  288. return rc;
  289. rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
  290. if (rc)
  291. return rc;
  292. rc = genphy_config_init(phydev);
  293. return rc;
  294. }
  295. static int vsc85xx_ack_interrupt(struct phy_device *phydev)
  296. {
  297. int rc = 0;
  298. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  299. rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  300. return (rc < 0) ? rc : 0;
  301. }
  302. static int vsc85xx_config_intr(struct phy_device *phydev)
  303. {
  304. int rc;
  305. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  306. rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
  307. MII_VSC85XX_INT_MASK_MASK);
  308. } else {
  309. rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
  310. if (rc < 0)
  311. return rc;
  312. rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
  313. }
  314. return rc;
  315. }
  316. static int vsc85xx_probe(struct phy_device *phydev)
  317. {
  318. int rate_magic;
  319. struct vsc8531_private *vsc8531;
  320. rate_magic = vsc85xx_edge_rate_magic_get(phydev);
  321. if (rate_magic < 0)
  322. return rate_magic;
  323. vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
  324. if (!vsc8531)
  325. return -ENOMEM;
  326. phydev->priv = vsc8531;
  327. vsc8531->rate_magic = rate_magic;
  328. return 0;
  329. }
  330. /* Microsemi VSC85xx PHYs */
  331. static struct phy_driver vsc85xx_driver[] = {
  332. {
  333. .phy_id = PHY_ID_VSC8531,
  334. .name = "Microsemi VSC8531",
  335. .phy_id_mask = 0xfffffff0,
  336. .features = PHY_GBIT_FEATURES,
  337. .flags = PHY_HAS_INTERRUPT,
  338. .soft_reset = &genphy_soft_reset,
  339. .config_init = &vsc85xx_config_init,
  340. .config_aneg = &genphy_config_aneg,
  341. .aneg_done = &genphy_aneg_done,
  342. .read_status = &genphy_read_status,
  343. .ack_interrupt = &vsc85xx_ack_interrupt,
  344. .config_intr = &vsc85xx_config_intr,
  345. .suspend = &genphy_suspend,
  346. .resume = &genphy_resume,
  347. .probe = &vsc85xx_probe,
  348. .set_wol = &vsc85xx_wol_set,
  349. .get_wol = &vsc85xx_wol_get,
  350. },
  351. {
  352. .phy_id = PHY_ID_VSC8541,
  353. .name = "Microsemi VSC8541 SyncE",
  354. .phy_id_mask = 0xfffffff0,
  355. .features = PHY_GBIT_FEATURES,
  356. .flags = PHY_HAS_INTERRUPT,
  357. .soft_reset = &genphy_soft_reset,
  358. .config_init = &vsc85xx_config_init,
  359. .config_aneg = &genphy_config_aneg,
  360. .aneg_done = &genphy_aneg_done,
  361. .read_status = &genphy_read_status,
  362. .ack_interrupt = &vsc85xx_ack_interrupt,
  363. .config_intr = &vsc85xx_config_intr,
  364. .suspend = &genphy_suspend,
  365. .resume = &genphy_resume,
  366. .probe = &vsc85xx_probe,
  367. .set_wol = &vsc85xx_wol_set,
  368. .get_wol = &vsc85xx_wol_get,
  369. }
  370. };
  371. module_phy_driver(vsc85xx_driver);
  372. static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
  373. { PHY_ID_VSC8531, 0xfffffff0, },
  374. { PHY_ID_VSC8541, 0xfffffff0, },
  375. { }
  376. };
  377. MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
  378. MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
  379. MODULE_AUTHOR("Nagaraju Lakkaraju");
  380. MODULE_LICENSE("Dual MIT/GPL");