phy.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * (C) Copyright 2014
  3. * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <miiphy.h>
  9. enum {
  10. MIICMD_SET,
  11. MIICMD_MODIFY,
  12. MIICMD_VERIFY_VALUE,
  13. MIICMD_WAIT_FOR_VALUE,
  14. };
  15. struct mii_setupcmd {
  16. u8 token;
  17. u8 reg;
  18. u16 data;
  19. u16 mask;
  20. u32 timeout;
  21. };
  22. /*
  23. * verify we are talking to a 88e1518
  24. */
  25. struct mii_setupcmd verify_88e1518[] = {
  26. { MIICMD_SET, 22, 0x0000 },
  27. { MIICMD_VERIFY_VALUE, 2, 0x0141, 0xffff },
  28. { MIICMD_VERIFY_VALUE, 3, 0x0dd0, 0xfff0 },
  29. };
  30. /*
  31. * workaround for erratum mentioned in 88E1518 release notes
  32. */
  33. struct mii_setupcmd fixup_88e1518[] = {
  34. { MIICMD_SET, 22, 0x00ff },
  35. { MIICMD_SET, 17, 0x214b },
  36. { MIICMD_SET, 16, 0x2144 },
  37. { MIICMD_SET, 17, 0x0c28 },
  38. { MIICMD_SET, 16, 0x2146 },
  39. { MIICMD_SET, 17, 0xb233 },
  40. { MIICMD_SET, 16, 0x214d },
  41. { MIICMD_SET, 17, 0xcc0c },
  42. { MIICMD_SET, 16, 0x2159 },
  43. { MIICMD_SET, 22, 0x00fb },
  44. { MIICMD_SET, 7, 0xc00d },
  45. { MIICMD_SET, 22, 0x0000 },
  46. };
  47. /*
  48. * default initialization:
  49. * - set RGMII receive timing to "receive clock transition when data stable"
  50. * - set RGMII transmit timing to "transmit clock internally delayed"
  51. * - set RGMII output impedance target to 78,8 Ohm
  52. * - run output impedance calibration
  53. * - set autonegotiation advertise to 1000FD only
  54. */
  55. struct mii_setupcmd default_88e1518[] = {
  56. { MIICMD_SET, 22, 0x0002 },
  57. { MIICMD_MODIFY, 21, 0x0030, 0x0030 },
  58. { MIICMD_MODIFY, 25, 0x0000, 0x0003 },
  59. { MIICMD_MODIFY, 24, 0x8000, 0x8000 },
  60. { MIICMD_WAIT_FOR_VALUE, 24, 0x4000, 0x4000, 2000 },
  61. { MIICMD_SET, 22, 0x0000 },
  62. { MIICMD_MODIFY, 4, 0x0000, 0x01e0 },
  63. { MIICMD_MODIFY, 9, 0x0200, 0x0300 },
  64. };
  65. /*
  66. * turn off CLK125 for PHY daughterboard
  67. */
  68. struct mii_setupcmd ch1fix_88e1518[] = {
  69. { MIICMD_SET, 22, 0x0002 },
  70. { MIICMD_MODIFY, 16, 0x0006, 0x0006 },
  71. { MIICMD_SET, 22, 0x0000 },
  72. };
  73. /*
  74. * perform copper software reset
  75. */
  76. struct mii_setupcmd swreset_88e1518[] = {
  77. { MIICMD_SET, 22, 0x0000 },
  78. { MIICMD_MODIFY, 0, 0x8000, 0x8000 },
  79. { MIICMD_WAIT_FOR_VALUE, 0, 0x0000, 0x8000, 2000 },
  80. };
  81. /*
  82. * special one for 88E1514:
  83. * Force SGMII to Copper mode
  84. */
  85. struct mii_setupcmd mii_to_copper_88e1514[] = {
  86. { MIICMD_SET, 22, 0x0012 },
  87. { MIICMD_MODIFY, 20, 0x0001, 0x0007 },
  88. { MIICMD_MODIFY, 20, 0x8000, 0x8000 },
  89. { MIICMD_SET, 22, 0x0000 },
  90. };
  91. /*
  92. * turn off SGMII auto-negotiation
  93. */
  94. struct mii_setupcmd sgmii_autoneg_off_88e1518[] = {
  95. { MIICMD_SET, 22, 0x0001 },
  96. { MIICMD_MODIFY, 0, 0x0000, 0x1000 },
  97. { MIICMD_MODIFY, 0, 0x8000, 0x8000 },
  98. { MIICMD_SET, 22, 0x0000 },
  99. };
  100. /*
  101. * invert LED2 polarity
  102. */
  103. struct mii_setupcmd invert_led2_88e1514[] = {
  104. { MIICMD_SET, 22, 0x0003 },
  105. { MIICMD_MODIFY, 17, 0x0030, 0x0010 },
  106. { MIICMD_SET, 22, 0x0000 },
  107. };
  108. static int process_setupcmd(const char *bus, unsigned char addr,
  109. struct mii_setupcmd *setupcmd)
  110. {
  111. int res;
  112. u8 reg = setupcmd->reg;
  113. u16 data = setupcmd->data;
  114. u16 mask = setupcmd->mask;
  115. u32 timeout = setupcmd->timeout;
  116. u16 orig_data;
  117. unsigned long start;
  118. debug("mii %s:%u reg %2u ", bus, addr, reg);
  119. switch (setupcmd->token) {
  120. case MIICMD_MODIFY:
  121. res = miiphy_read(bus, addr, reg, &orig_data);
  122. if (res)
  123. break;
  124. debug("is %04x. (value %04x mask %04x) ", orig_data, data,
  125. mask);
  126. data = (orig_data & ~mask) | (data & mask);
  127. /* fallthrough */
  128. case MIICMD_SET:
  129. debug("=> %04x\n", data);
  130. res = miiphy_write(bus, addr, reg, data);
  131. break;
  132. case MIICMD_VERIFY_VALUE:
  133. res = miiphy_read(bus, addr, reg, &orig_data);
  134. if (res)
  135. break;
  136. if ((orig_data & mask) != (data & mask))
  137. res = -1;
  138. debug("(value %04x mask %04x) == %04x? %s\n", data, mask,
  139. orig_data, res ? "FAIL" : "PASS");
  140. break;
  141. case MIICMD_WAIT_FOR_VALUE:
  142. res = -1;
  143. start = get_timer(0);
  144. while ((res != 0) && (get_timer(start) < timeout)) {
  145. res = miiphy_read(bus, addr, reg, &orig_data);
  146. if (res)
  147. continue;
  148. if ((orig_data & mask) != (data & mask))
  149. res = -1;
  150. }
  151. debug("(value %04x mask %04x) == %04x? %s after %lu ms\n", data,
  152. mask, orig_data, res ? "FAIL" : "PASS",
  153. get_timer(start));
  154. break;
  155. default:
  156. res = -1;
  157. break;
  158. }
  159. return res;
  160. }
  161. static int process_setup(const char *bus, unsigned char addr,
  162. struct mii_setupcmd *setupcmd, unsigned int count)
  163. {
  164. int res = 0;
  165. unsigned int k;
  166. for (k = 0; k < count; ++k) {
  167. res = process_setupcmd(bus, addr, &setupcmd[k]);
  168. if (res) {
  169. printf("mii cmd %u on bus %s addr %u failed, aborting setup\n",
  170. setupcmd[k].token, bus, addr);
  171. break;
  172. }
  173. }
  174. return res;
  175. }
  176. int setup_88e1518(const char *bus, unsigned char addr)
  177. {
  178. int res;
  179. res = process_setup(bus, addr,
  180. verify_88e1518, ARRAY_SIZE(verify_88e1518));
  181. if (res)
  182. return res;
  183. res = process_setup(bus, addr,
  184. fixup_88e1518, ARRAY_SIZE(fixup_88e1518));
  185. if (res)
  186. return res;
  187. res = process_setup(bus, addr,
  188. default_88e1518, ARRAY_SIZE(default_88e1518));
  189. if (res)
  190. return res;
  191. if (addr) {
  192. res = process_setup(bus, addr,
  193. ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518));
  194. if (res)
  195. return res;
  196. }
  197. res = process_setup(bus, addr,
  198. swreset_88e1518, ARRAY_SIZE(swreset_88e1518));
  199. if (res)
  200. return res;
  201. return 0;
  202. }
  203. int setup_88e1514(const char *bus, unsigned char addr)
  204. {
  205. int res;
  206. res = process_setup(bus, addr,
  207. verify_88e1518, ARRAY_SIZE(verify_88e1518));
  208. if (res)
  209. return res;
  210. res = process_setup(bus, addr,
  211. fixup_88e1518, ARRAY_SIZE(fixup_88e1518));
  212. if (res)
  213. return res;
  214. res = process_setup(bus, addr,
  215. mii_to_copper_88e1514,
  216. ARRAY_SIZE(mii_to_copper_88e1514));
  217. if (res)
  218. return res;
  219. res = process_setup(bus, addr,
  220. sgmii_autoneg_off_88e1518,
  221. ARRAY_SIZE(sgmii_autoneg_off_88e1518));
  222. if (res)
  223. return res;
  224. res = process_setup(bus, addr,
  225. invert_led2_88e1514,
  226. ARRAY_SIZE(invert_led2_88e1514));
  227. if (res)
  228. return res;
  229. res = process_setup(bus, addr,
  230. default_88e1518, ARRAY_SIZE(default_88e1518));
  231. if (res)
  232. return res;
  233. if (addr) {
  234. res = process_setup(bus, addr,
  235. ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518));
  236. if (res)
  237. return res;
  238. }
  239. res = process_setup(bus, addr,
  240. swreset_88e1518, ARRAY_SIZE(swreset_88e1518));
  241. if (res)
  242. return res;
  243. return 0;
  244. }