mscc.c 12 KB

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