marvell.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * Marvell PHY drivers
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  17. * MA 02111-1307 USA
  18. *
  19. * Copyright 2010-2011 Freescale Semiconductor, Inc.
  20. * author Andy Fleming
  21. *
  22. */
  23. #include <config.h>
  24. #include <common.h>
  25. #include <phy.h>
  26. #define PHY_AUTONEGOTIATE_TIMEOUT 5000
  27. /* 88E1011 PHY Status Register */
  28. #define MIIM_88E1xxx_PHY_STATUS 0x11
  29. #define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000
  30. #define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000
  31. #define MIIM_88E1xxx_PHYSTAT_100 0x4000
  32. #define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000
  33. #define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800
  34. #define MIIM_88E1xxx_PHYSTAT_LINK 0x0400
  35. #define MIIM_88E1xxx_PHY_SCR 0x10
  36. #define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060
  37. /* 88E1111 PHY LED Control Register */
  38. #define MIIM_88E1111_PHY_LED_CONTROL 24
  39. #define MIIM_88E1111_PHY_LED_DIRECT 0x4100
  40. #define MIIM_88E1111_PHY_LED_COMBINE 0x411C
  41. /* 88E1118 PHY defines */
  42. #define MIIM_88E1118_PHY_PAGE 22
  43. #define MIIM_88E1118_PHY_LED_PAGE 3
  44. /* 88E1121 PHY LED Control Register */
  45. #define MIIM_88E1121_PHY_LED_CTRL 16
  46. #define MIIM_88E1121_PHY_LED_PAGE 3
  47. #define MIIM_88E1121_PHY_LED_DEF 0x0030
  48. /* 88E1121 PHY IRQ Enable/Status Register */
  49. #define MIIM_88E1121_PHY_IRQ_EN 18
  50. #define MIIM_88E1121_PHY_IRQ_STATUS 19
  51. #define MIIM_88E1121_PHY_PAGE 22
  52. /* 88E1145 Extended PHY Specific Control Register */
  53. #define MIIM_88E1145_PHY_EXT_CR 20
  54. #define MIIM_M88E1145_RGMII_RX_DELAY 0x0080
  55. #define MIIM_M88E1145_RGMII_TX_DELAY 0x0002
  56. #define MIIM_88E1145_PHY_LED_CONTROL 24
  57. #define MIIM_88E1145_PHY_LED_DIRECT 0x4100
  58. #define MIIM_88E1145_PHY_PAGE 29
  59. #define MIIM_88E1145_PHY_CAL_OV 30
  60. #define MIIM_88E1149_PHY_PAGE 29
  61. /* Marvell 88E1011S */
  62. static int m88e1011s_config(struct phy_device *phydev)
  63. {
  64. /* Reset and configure the PHY */
  65. phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
  66. phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
  67. phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
  68. phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5);
  69. phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0);
  70. phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
  71. phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
  72. genphy_config_aneg(phydev);
  73. return 0;
  74. }
  75. /* Parse the 88E1011's status register for speed and duplex
  76. * information
  77. */
  78. static uint m88e1xxx_parse_status(struct phy_device *phydev)
  79. {
  80. unsigned int speed;
  81. unsigned int mii_reg;
  82. mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS);
  83. if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) &&
  84. !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
  85. int i = 0;
  86. puts("Waiting for PHY realtime link");
  87. while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) {
  88. /* Timeout reached ? */
  89. if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
  90. puts(" TIMEOUT !\n");
  91. phydev->link = 0;
  92. break;
  93. }
  94. if ((i++ % 1000) == 0)
  95. putc('.');
  96. udelay(1000);
  97. mii_reg = phy_read(phydev, MDIO_DEVAD_NONE,
  98. MIIM_88E1xxx_PHY_STATUS);
  99. }
  100. puts(" done\n");
  101. udelay(500000); /* another 500 ms (results in faster booting) */
  102. } else {
  103. if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK)
  104. phydev->link = 1;
  105. else
  106. phydev->link = 0;
  107. }
  108. if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX)
  109. phydev->duplex = DUPLEX_FULL;
  110. else
  111. phydev->duplex = DUPLEX_HALF;
  112. speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED;
  113. switch (speed) {
  114. case MIIM_88E1xxx_PHYSTAT_GBIT:
  115. phydev->speed = SPEED_1000;
  116. break;
  117. case MIIM_88E1xxx_PHYSTAT_100:
  118. phydev->speed = SPEED_100;
  119. break;
  120. default:
  121. phydev->speed = SPEED_10;
  122. break;
  123. }
  124. return 0;
  125. }
  126. static int m88e1011s_startup(struct phy_device *phydev)
  127. {
  128. genphy_update_link(phydev);
  129. m88e1xxx_parse_status(phydev);
  130. return 0;
  131. }
  132. /* Marvell 88E1111S */
  133. static int m88e1111s_config(struct phy_device *phydev)
  134. {
  135. int reg;
  136. if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
  137. (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
  138. (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
  139. (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
  140. reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1b);
  141. reg = (reg & 0xfff0) | 0xb;
  142. phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, reg);
  143. } else {
  144. phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, 0x1f);
  145. }
  146. phy_write(phydev, MDIO_DEVAD_NONE, 0x14, 0x0cd2);
  147. genphy_config_aneg(phydev);
  148. phy_reset(phydev);
  149. return 0;
  150. }
  151. /* Marvell 88E1118 */
  152. static int m88e1118_config(struct phy_device *phydev)
  153. {
  154. /* Change Page Number */
  155. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002);
  156. /* Delay RGMII TX and RX */
  157. phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070);
  158. /* Change Page Number */
  159. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003);
  160. /* Adjust LED control */
  161. phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e);
  162. /* Change Page Number */
  163. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
  164. genphy_config_aneg(phydev);
  165. phy_reset(phydev);
  166. return 0;
  167. }
  168. static int m88e1118_startup(struct phy_device *phydev)
  169. {
  170. /* Change Page Number */
  171. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000);
  172. genphy_update_link(phydev);
  173. m88e1xxx_parse_status(phydev);
  174. return 0;
  175. }
  176. /* Marvell 88E1121R */
  177. static int m88e1121_config(struct phy_device *phydev)
  178. {
  179. int pg;
  180. /* Configure the PHY */
  181. genphy_config_aneg(phydev);
  182. /* Switch the page to access the led register */
  183. pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE);
  184. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE,
  185. MIIM_88E1121_PHY_LED_PAGE);
  186. /* Configure leds */
  187. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL,
  188. MIIM_88E1121_PHY_LED_DEF);
  189. /* Restore the page pointer */
  190. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg);
  191. /* Disable IRQs and de-assert interrupt */
  192. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0);
  193. phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS);
  194. return 0;
  195. }
  196. /* Marvell 88E1145 */
  197. static int m88e1145_config(struct phy_device *phydev)
  198. {
  199. int reg;
  200. /* Errata E0, E1 */
  201. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b);
  202. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f);
  203. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016);
  204. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da);
  205. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR,
  206. MIIM_88E1xxx_PHY_MDI_X_AUTO);
  207. reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR);
  208. if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
  209. reg |= MIIM_M88E1145_RGMII_RX_DELAY |
  210. MIIM_M88E1145_RGMII_TX_DELAY;
  211. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg);
  212. genphy_config_aneg(phydev);
  213. phy_reset(phydev);
  214. return 0;
  215. }
  216. static int m88e1145_startup(struct phy_device *phydev)
  217. {
  218. genphy_update_link(phydev);
  219. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL,
  220. MIIM_88E1145_PHY_LED_DIRECT);
  221. m88e1xxx_parse_status(phydev);
  222. return 0;
  223. }
  224. /* Marvell 88E1149S */
  225. static int m88e1149_config(struct phy_device *phydev)
  226. {
  227. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f);
  228. phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c);
  229. phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5);
  230. phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0);
  231. phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
  232. genphy_config_aneg(phydev);
  233. phy_reset(phydev);
  234. return 0;
  235. }
  236. static struct phy_driver M88E1011S_driver = {
  237. .name = "Marvell 88E1011S",
  238. .uid = 0x1410c60,
  239. .mask = 0xffffff0,
  240. .features = PHY_GBIT_FEATURES,
  241. .config = &m88e1011s_config,
  242. .startup = &m88e1011s_startup,
  243. .shutdown = &genphy_shutdown,
  244. };
  245. static struct phy_driver M88E1111S_driver = {
  246. .name = "Marvell 88E1111S",
  247. .uid = 0x1410cc0,
  248. .mask = 0xffffff0,
  249. .features = PHY_GBIT_FEATURES,
  250. .config = &m88e1111s_config,
  251. .startup = &m88e1011s_startup,
  252. .shutdown = &genphy_shutdown,
  253. };
  254. static struct phy_driver M88E1118_driver = {
  255. .name = "Marvell 88E1118",
  256. .uid = 0x1410e10,
  257. .mask = 0xffffff0,
  258. .features = PHY_GBIT_FEATURES,
  259. .config = &m88e1118_config,
  260. .startup = &m88e1118_startup,
  261. .shutdown = &genphy_shutdown,
  262. };
  263. static struct phy_driver M88E1121R_driver = {
  264. .name = "Marvell 88E1121R",
  265. .uid = 0x1410cb0,
  266. .mask = 0xffffff0,
  267. .features = PHY_GBIT_FEATURES,
  268. .config = &m88e1121_config,
  269. .startup = &genphy_startup,
  270. .shutdown = &genphy_shutdown,
  271. };
  272. static struct phy_driver M88E1145_driver = {
  273. .name = "Marvell 88E1145",
  274. .uid = 0x1410cd0,
  275. .mask = 0xffffff0,
  276. .features = PHY_GBIT_FEATURES,
  277. .config = &m88e1145_config,
  278. .startup = &m88e1145_startup,
  279. .shutdown = &genphy_shutdown,
  280. };
  281. static struct phy_driver M88E1149S_driver = {
  282. .name = "Marvell 88E1149S",
  283. .uid = 0x1410ca0,
  284. .mask = 0xffffff0,
  285. .features = PHY_GBIT_FEATURES,
  286. .config = &m88e1149_config,
  287. .startup = &m88e1011s_startup,
  288. .shutdown = &genphy_shutdown,
  289. };
  290. int phy_marvell_init(void)
  291. {
  292. phy_register(&M88E1149S_driver);
  293. phy_register(&M88E1145_driver);
  294. phy_register(&M88E1121R_driver);
  295. phy_register(&M88E1118_driver);
  296. phy_register(&M88E1111S_driver);
  297. phy_register(&M88E1011S_driver);
  298. return 0;
  299. }