realtek.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * drivers/net/phy/realtek.c
  3. *
  4. * Driver for Realtek PHYs
  5. *
  6. * Author: Johnson Leung <r58129@freescale.com>
  7. *
  8. * Copyright (c) 2004 Freescale Semiconductor, Inc.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2 of the License, or (at your
  13. * option) any later version.
  14. *
  15. */
  16. #include <linux/bitops.h>
  17. #include <linux/phy.h>
  18. #include <linux/module.h>
  19. #define RTL821x_PHYSR 0x11
  20. #define RTL821x_PHYSR_DUPLEX BIT(13)
  21. #define RTL821x_PHYSR_SPEED GENMASK(15, 14)
  22. #define RTL821x_INER 0x12
  23. #define RTL8211B_INER_INIT 0x6400
  24. #define RTL8211E_INER_LINK_STATUS BIT(10)
  25. #define RTL8211F_INER_LINK_STATUS BIT(4)
  26. #define RTL821x_INSR 0x13
  27. #define RTL821x_PAGE_SELECT 0x1f
  28. #define RTL8211F_INSR 0x1d
  29. #define RTL8211F_TX_DELAY BIT(8)
  30. #define RTL8201F_ISR 0x1e
  31. #define RTL8201F_IER 0x13
  32. #define RTL8366RB_POWER_SAVE 0x15
  33. #define RTL8366RB_POWER_SAVE_ON BIT(12)
  34. MODULE_DESCRIPTION("Realtek PHY driver");
  35. MODULE_AUTHOR("Johnson Leung");
  36. MODULE_LICENSE("GPL");
  37. static int rtl821x_read_page(struct phy_device *phydev)
  38. {
  39. return __phy_read(phydev, RTL821x_PAGE_SELECT);
  40. }
  41. static int rtl821x_write_page(struct phy_device *phydev, int page)
  42. {
  43. return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
  44. }
  45. static int rtl8201_ack_interrupt(struct phy_device *phydev)
  46. {
  47. int err;
  48. err = phy_read(phydev, RTL8201F_ISR);
  49. return (err < 0) ? err : 0;
  50. }
  51. static int rtl821x_ack_interrupt(struct phy_device *phydev)
  52. {
  53. int err;
  54. err = phy_read(phydev, RTL821x_INSR);
  55. return (err < 0) ? err : 0;
  56. }
  57. static int rtl8211f_ack_interrupt(struct phy_device *phydev)
  58. {
  59. int err;
  60. err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
  61. return (err < 0) ? err : 0;
  62. }
  63. static int rtl8201_config_intr(struct phy_device *phydev)
  64. {
  65. u16 val;
  66. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  67. val = BIT(13) | BIT(12) | BIT(11);
  68. else
  69. val = 0;
  70. return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
  71. }
  72. static int rtl8211b_config_intr(struct phy_device *phydev)
  73. {
  74. int err;
  75. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  76. err = phy_write(phydev, RTL821x_INER,
  77. RTL8211B_INER_INIT);
  78. else
  79. err = phy_write(phydev, RTL821x_INER, 0);
  80. return err;
  81. }
  82. static int rtl8211e_config_intr(struct phy_device *phydev)
  83. {
  84. int err;
  85. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  86. err = phy_write(phydev, RTL821x_INER,
  87. RTL8211E_INER_LINK_STATUS);
  88. else
  89. err = phy_write(phydev, RTL821x_INER, 0);
  90. return err;
  91. }
  92. static int rtl8211f_config_intr(struct phy_device *phydev)
  93. {
  94. u16 val;
  95. if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  96. val = RTL8211F_INER_LINK_STATUS;
  97. else
  98. val = 0;
  99. return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
  100. }
  101. static int rtl8211_config_aneg(struct phy_device *phydev)
  102. {
  103. int ret;
  104. ret = genphy_config_aneg(phydev);
  105. if (ret < 0)
  106. return ret;
  107. /* Quirk was copied from vendor driver. Unfortunately it includes no
  108. * description of the magic numbers.
  109. */
  110. if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
  111. phy_write(phydev, 0x17, 0x2138);
  112. phy_write(phydev, 0x0e, 0x0260);
  113. } else {
  114. phy_write(phydev, 0x17, 0x2108);
  115. phy_write(phydev, 0x0e, 0x0000);
  116. }
  117. return 0;
  118. }
  119. static int rtl8211c_config_init(struct phy_device *phydev)
  120. {
  121. /* RTL8211C has an issue when operating in Gigabit slave mode */
  122. phy_set_bits(phydev, MII_CTRL1000,
  123. CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
  124. return genphy_config_init(phydev);
  125. }
  126. static int rtl8211f_config_init(struct phy_device *phydev)
  127. {
  128. int ret;
  129. u16 val = 0;
  130. ret = genphy_config_init(phydev);
  131. if (ret < 0)
  132. return ret;
  133. /* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
  134. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  135. phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
  136. val = RTL8211F_TX_DELAY;
  137. return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val);
  138. }
  139. static int rtl8211b_suspend(struct phy_device *phydev)
  140. {
  141. phy_write(phydev, MII_MMD_DATA, BIT(9));
  142. return genphy_suspend(phydev);
  143. }
  144. static int rtl8211b_resume(struct phy_device *phydev)
  145. {
  146. phy_write(phydev, MII_MMD_DATA, 0);
  147. return genphy_resume(phydev);
  148. }
  149. static int rtl8366rb_config_init(struct phy_device *phydev)
  150. {
  151. int ret;
  152. ret = genphy_config_init(phydev);
  153. if (ret < 0)
  154. return ret;
  155. ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
  156. RTL8366RB_POWER_SAVE_ON);
  157. if (ret) {
  158. dev_err(&phydev->mdio.dev,
  159. "error enabling power management\n");
  160. }
  161. return ret;
  162. }
  163. static struct phy_driver realtek_drvs[] = {
  164. {
  165. .phy_id = 0x00008201,
  166. .name = "RTL8201CP Ethernet",
  167. .phy_id_mask = 0x0000ffff,
  168. .features = PHY_BASIC_FEATURES,
  169. .flags = PHY_HAS_INTERRUPT,
  170. }, {
  171. .phy_id = 0x001cc816,
  172. .name = "RTL8201F Fast Ethernet",
  173. .phy_id_mask = 0x001fffff,
  174. .features = PHY_BASIC_FEATURES,
  175. .flags = PHY_HAS_INTERRUPT,
  176. .ack_interrupt = &rtl8201_ack_interrupt,
  177. .config_intr = &rtl8201_config_intr,
  178. .suspend = genphy_suspend,
  179. .resume = genphy_resume,
  180. .read_page = rtl821x_read_page,
  181. .write_page = rtl821x_write_page,
  182. }, {
  183. .phy_id = 0x001cc910,
  184. .name = "RTL8211 Gigabit Ethernet",
  185. .phy_id_mask = 0x001fffff,
  186. .features = PHY_GBIT_FEATURES,
  187. .config_aneg = rtl8211_config_aneg,
  188. .read_mmd = &genphy_read_mmd_unsupported,
  189. .write_mmd = &genphy_write_mmd_unsupported,
  190. }, {
  191. .phy_id = 0x001cc912,
  192. .name = "RTL8211B Gigabit Ethernet",
  193. .phy_id_mask = 0x001fffff,
  194. .features = PHY_GBIT_FEATURES,
  195. .flags = PHY_HAS_INTERRUPT,
  196. .ack_interrupt = &rtl821x_ack_interrupt,
  197. .config_intr = &rtl8211b_config_intr,
  198. .read_mmd = &genphy_read_mmd_unsupported,
  199. .write_mmd = &genphy_write_mmd_unsupported,
  200. .suspend = rtl8211b_suspend,
  201. .resume = rtl8211b_resume,
  202. }, {
  203. .phy_id = 0x001cc913,
  204. .name = "RTL8211C Gigabit Ethernet",
  205. .phy_id_mask = 0x001fffff,
  206. .features = PHY_GBIT_FEATURES,
  207. .config_init = rtl8211c_config_init,
  208. .read_mmd = &genphy_read_mmd_unsupported,
  209. .write_mmd = &genphy_write_mmd_unsupported,
  210. }, {
  211. .phy_id = 0x001cc914,
  212. .name = "RTL8211DN Gigabit Ethernet",
  213. .phy_id_mask = 0x001fffff,
  214. .features = PHY_GBIT_FEATURES,
  215. .flags = PHY_HAS_INTERRUPT,
  216. .ack_interrupt = rtl821x_ack_interrupt,
  217. .config_intr = rtl8211e_config_intr,
  218. .suspend = genphy_suspend,
  219. .resume = genphy_resume,
  220. }, {
  221. .phy_id = 0x001cc915,
  222. .name = "RTL8211E Gigabit Ethernet",
  223. .phy_id_mask = 0x001fffff,
  224. .features = PHY_GBIT_FEATURES,
  225. .flags = PHY_HAS_INTERRUPT,
  226. .ack_interrupt = &rtl821x_ack_interrupt,
  227. .config_intr = &rtl8211e_config_intr,
  228. .suspend = genphy_suspend,
  229. .resume = genphy_resume,
  230. }, {
  231. .phy_id = 0x001cc916,
  232. .name = "RTL8211F Gigabit Ethernet",
  233. .phy_id_mask = 0x001fffff,
  234. .features = PHY_GBIT_FEATURES,
  235. .flags = PHY_HAS_INTERRUPT,
  236. .config_init = &rtl8211f_config_init,
  237. .ack_interrupt = &rtl8211f_ack_interrupt,
  238. .config_intr = &rtl8211f_config_intr,
  239. .suspend = genphy_suspend,
  240. .resume = genphy_resume,
  241. .read_page = rtl821x_read_page,
  242. .write_page = rtl821x_write_page,
  243. }, {
  244. .phy_id = 0x001cc961,
  245. .name = "RTL8366RB Gigabit Ethernet",
  246. .phy_id_mask = 0x001fffff,
  247. .features = PHY_GBIT_FEATURES,
  248. .flags = PHY_HAS_INTERRUPT,
  249. .config_init = &rtl8366rb_config_init,
  250. .suspend = genphy_suspend,
  251. .resume = genphy_resume,
  252. },
  253. };
  254. module_phy_driver(realtek_drvs);
  255. static struct mdio_device_id __maybe_unused realtek_tbl[] = {
  256. { 0x001cc816, 0x001fffff },
  257. { 0x001cc910, 0x001fffff },
  258. { 0x001cc912, 0x001fffff },
  259. { 0x001cc913, 0x001fffff },
  260. { 0x001cc914, 0x001fffff },
  261. { 0x001cc915, 0x001fffff },
  262. { 0x001cc916, 0x001fffff },
  263. { 0x001cc961, 0x001fffff },
  264. { }
  265. };
  266. MODULE_DEVICE_TABLE(mdio, realtek_tbl);