rockchip.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /**
  2. * drivers/net/phy/rockchip.c
  3. *
  4. * Driver for ROCKCHIP Ethernet PHYs
  5. *
  6. * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
  7. *
  8. * David Wu <david.wu@rock-chips.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. */
  16. #include <linux/ethtool.h>
  17. #include <linux/kernel.h>
  18. #include <linux/module.h>
  19. #include <linux/mii.h>
  20. #include <linux/netdevice.h>
  21. #include <linux/phy.h>
  22. #define INTERNAL_EPHY_ID 0x1234d400
  23. #define MII_INTERNAL_CTRL_STATUS 17
  24. #define SMI_ADDR_TSTCNTL 20
  25. #define SMI_ADDR_TSTREAD1 21
  26. #define SMI_ADDR_TSTREAD2 22
  27. #define SMI_ADDR_TSTWRITE 23
  28. #define MII_SPECIAL_CONTROL_STATUS 31
  29. #define MII_AUTO_MDIX_EN BIT(7)
  30. #define MII_MDIX_EN BIT(6)
  31. #define MII_SPEED_10 BIT(2)
  32. #define MII_SPEED_100 BIT(3)
  33. #define TSTCNTL_RD (BIT(15) | BIT(10))
  34. #define TSTCNTL_WR (BIT(14) | BIT(10))
  35. #define TSTMODE_ENABLE 0x400
  36. #define TSTMODE_DISABLE 0x0
  37. #define WR_ADDR_A7CFG 0x18
  38. static int rockchip_init_tstmode(struct phy_device *phydev)
  39. {
  40. int ret;
  41. /* Enable access to Analog and DSP register banks */
  42. ret = phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_ENABLE);
  43. if (ret)
  44. return ret;
  45. ret = phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_DISABLE);
  46. if (ret)
  47. return ret;
  48. return phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_ENABLE);
  49. }
  50. static int rockchip_close_tstmode(struct phy_device *phydev)
  51. {
  52. /* Back to basic register bank */
  53. return phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_DISABLE);
  54. }
  55. static int rockchip_integrated_phy_analog_init(struct phy_device *phydev)
  56. {
  57. int ret;
  58. ret = rockchip_init_tstmode(phydev);
  59. if (ret)
  60. return ret;
  61. /*
  62. * Adjust tx amplitude to make sginal better,
  63. * the default value is 0x8.
  64. */
  65. ret = phy_write(phydev, SMI_ADDR_TSTWRITE, 0xB);
  66. if (ret)
  67. return ret;
  68. ret = phy_write(phydev, SMI_ADDR_TSTCNTL, TSTCNTL_WR | WR_ADDR_A7CFG);
  69. if (ret)
  70. return ret;
  71. return rockchip_close_tstmode(phydev);
  72. }
  73. static int rockchip_integrated_phy_config_init(struct phy_device *phydev)
  74. {
  75. int val, ret;
  76. /*
  77. * The auto MIDX has linked problem on some board,
  78. * workround to disable auto MDIX.
  79. */
  80. val = phy_read(phydev, MII_INTERNAL_CTRL_STATUS);
  81. if (val < 0)
  82. return val;
  83. val &= ~MII_AUTO_MDIX_EN;
  84. ret = phy_write(phydev, MII_INTERNAL_CTRL_STATUS, val);
  85. if (ret)
  86. return ret;
  87. return rockchip_integrated_phy_analog_init(phydev);
  88. }
  89. static void rockchip_link_change_notify(struct phy_device *phydev)
  90. {
  91. int speed = SPEED_10;
  92. if (phydev->autoneg == AUTONEG_ENABLE) {
  93. int reg = phy_read(phydev, MII_SPECIAL_CONTROL_STATUS);
  94. if (reg < 0) {
  95. phydev_err(phydev, "phy_read err: %d.\n", reg);
  96. return;
  97. }
  98. if (reg & MII_SPEED_100)
  99. speed = SPEED_100;
  100. else if (reg & MII_SPEED_10)
  101. speed = SPEED_10;
  102. } else {
  103. int bmcr = phy_read(phydev, MII_BMCR);
  104. if (bmcr < 0) {
  105. phydev_err(phydev, "phy_read err: %d.\n", bmcr);
  106. return;
  107. }
  108. if (bmcr & BMCR_SPEED100)
  109. speed = SPEED_100;
  110. else
  111. speed = SPEED_10;
  112. }
  113. /*
  114. * If mode switch happens from 10BT to 100BT, all DSP/AFE
  115. * registers are set to default values. So any AFE/DSP
  116. * registers have to be re-initialized in this case.
  117. */
  118. if ((phydev->speed == SPEED_10) && (speed == SPEED_100)) {
  119. int ret = rockchip_integrated_phy_analog_init(phydev);
  120. if (ret)
  121. phydev_err(phydev, "rockchip_integrated_phy_analog_init err: %d.\n",
  122. ret);
  123. }
  124. }
  125. static int rockchip_set_polarity(struct phy_device *phydev, int polarity)
  126. {
  127. int reg, err, val;
  128. /* get the current settings */
  129. reg = phy_read(phydev, MII_INTERNAL_CTRL_STATUS);
  130. if (reg < 0)
  131. return reg;
  132. reg &= ~MII_AUTO_MDIX_EN;
  133. val = reg;
  134. switch (polarity) {
  135. case ETH_TP_MDI:
  136. val &= ~MII_MDIX_EN;
  137. break;
  138. case ETH_TP_MDI_X:
  139. val |= MII_MDIX_EN;
  140. break;
  141. case ETH_TP_MDI_AUTO:
  142. case ETH_TP_MDI_INVALID:
  143. default:
  144. return 0;
  145. }
  146. if (val != reg) {
  147. /* Set the new polarity value in the register */
  148. err = phy_write(phydev, MII_INTERNAL_CTRL_STATUS, val);
  149. if (err)
  150. return err;
  151. }
  152. return 0;
  153. }
  154. static int rockchip_config_aneg(struct phy_device *phydev)
  155. {
  156. int err;
  157. err = rockchip_set_polarity(phydev, phydev->mdix);
  158. if (err < 0)
  159. return err;
  160. return genphy_config_aneg(phydev);
  161. }
  162. static int rockchip_phy_resume(struct phy_device *phydev)
  163. {
  164. genphy_resume(phydev);
  165. return rockchip_integrated_phy_config_init(phydev);
  166. }
  167. static struct phy_driver rockchip_phy_driver[] = {
  168. {
  169. .phy_id = INTERNAL_EPHY_ID,
  170. .phy_id_mask = 0xfffffff0,
  171. .name = "Rockchip integrated EPHY",
  172. .features = PHY_BASIC_FEATURES,
  173. .flags = 0,
  174. .link_change_notify = rockchip_link_change_notify,
  175. .soft_reset = genphy_soft_reset,
  176. .config_init = rockchip_integrated_phy_config_init,
  177. .config_aneg = rockchip_config_aneg,
  178. .suspend = genphy_suspend,
  179. .resume = rockchip_phy_resume,
  180. },
  181. };
  182. module_phy_driver(rockchip_phy_driver);
  183. static struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = {
  184. { INTERNAL_EPHY_ID, 0xfffffff0 },
  185. { }
  186. };
  187. MODULE_DEVICE_TABLE(mdio, rockchip_phy_tbl);
  188. MODULE_AUTHOR("David Wu <david.wu@rock-chips.com>");
  189. MODULE_DESCRIPTION("Rockchip Ethernet PHY driver");
  190. MODULE_LICENSE("GPL v2");