ihs_phys.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #include <common.h>
  2. #include <dm.h>
  3. #include <miiphy.h>
  4. #include <asm-generic/gpio.h>
  5. #include "ihs_phys.h"
  6. #include "dt_helpers.h"
  7. enum {
  8. PORTTYPE_MAIN_CAT,
  9. PORTTYPE_TOP_CAT,
  10. PORTTYPE_16C_16F,
  11. PORTTYPE_UNKNOWN
  12. };
  13. static struct porttype {
  14. bool phy_invert_in_pol;
  15. bool phy_invert_out_pol;
  16. } porttypes[] = {
  17. { true, false },
  18. { false, true },
  19. { false, false },
  20. };
  21. static void ihs_phy_config(struct phy_device *phydev, bool qinpn, bool qoutpn)
  22. {
  23. u16 reg;
  24. phy_config(phydev);
  25. /* enable QSGMII autonegotiation with flow control */
  26. phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004);
  27. reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
  28. reg |= (3 << 6);
  29. phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
  30. /*
  31. * invert QSGMII Q_INP/N and Q_OUTP/N if required
  32. * and perform global reset
  33. */
  34. reg = phy_read(phydev, MDIO_DEVAD_NONE, 26);
  35. if (qinpn)
  36. reg |= (1 << 13);
  37. if (qoutpn)
  38. reg |= (1 << 12);
  39. reg |= (1 << 15);
  40. phy_write(phydev, MDIO_DEVAD_NONE, 26, reg);
  41. /* advertise 1000BASE-T full-duplex only */
  42. phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
  43. reg = phy_read(phydev, MDIO_DEVAD_NONE, 4);
  44. reg &= ~0x1e0;
  45. phy_write(phydev, MDIO_DEVAD_NONE, 4, reg);
  46. reg = phy_read(phydev, MDIO_DEVAD_NONE, 9);
  47. reg = (reg & ~0x300) | 0x200;
  48. phy_write(phydev, MDIO_DEVAD_NONE, 9, reg);
  49. /* copper power up */
  50. reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
  51. reg &= ~0x0004;
  52. phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
  53. }
  54. uint calculate_octo_phy_mask(void)
  55. {
  56. uint k;
  57. uint octo_phy_mask = 0;
  58. struct gpio_desc gpio = {};
  59. char gpio_name[64];
  60. static const char * const dev_name[] = {"pca9698@23", "pca9698@21",
  61. "pca9698@24", "pca9698@25",
  62. "pca9698@26"};
  63. /* mark all octo phys that should be present */
  64. for (k = 0; k < 5; ++k) {
  65. snprintf(gpio_name, 64, "cat-gpio-%u", k);
  66. if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name))
  67. continue;
  68. /* check CAT flag */
  69. if (dm_gpio_get_value(&gpio))
  70. octo_phy_mask |= (1 << (k * 2));
  71. else
  72. /* If CAT == 0, there's no second octo phy -> skip */
  73. continue;
  74. snprintf(gpio_name, 64, "second-octo-gpio-%u", k);
  75. if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) {
  76. /* default: second octo phy is present */
  77. octo_phy_mask |= (1 << (k * 2 + 1));
  78. continue;
  79. }
  80. if (dm_gpio_get_value(&gpio) == 0)
  81. octo_phy_mask |= (1 << (k * 2 + 1));
  82. }
  83. return octo_phy_mask;
  84. }
  85. int register_miiphy_bus(uint k, struct mii_dev **bus)
  86. {
  87. int retval;
  88. struct mii_dev *mdiodev = mdio_alloc();
  89. char *name = bb_miiphy_buses[k].name;
  90. if (!mdiodev)
  91. return -ENOMEM;
  92. strncpy(mdiodev->name,
  93. name,
  94. MDIO_NAME_LEN);
  95. mdiodev->read = bb_miiphy_read;
  96. mdiodev->write = bb_miiphy_write;
  97. retval = mdio_register(mdiodev);
  98. if (retval < 0)
  99. return retval;
  100. *bus = miiphy_get_dev_by_name(name);
  101. return 0;
  102. }
  103. struct porttype *get_porttype(uint octo_phy_mask, uint k)
  104. {
  105. uint octo_index = k * 4;
  106. if (!k) {
  107. if (octo_phy_mask & 0x01)
  108. return &porttypes[PORTTYPE_MAIN_CAT];
  109. else if (!(octo_phy_mask & 0x03))
  110. return &porttypes[PORTTYPE_16C_16F];
  111. } else {
  112. if (octo_phy_mask & (1 << octo_index))
  113. return &porttypes[PORTTYPE_TOP_CAT];
  114. }
  115. return NULL;
  116. }
  117. int init_single_phy(struct porttype *porttype, struct mii_dev *bus,
  118. uint bus_idx, uint m, uint phy_idx)
  119. {
  120. struct phy_device *phydev = phy_find_by_mask(
  121. bus, 1 << (m * 8 + phy_idx),
  122. PHY_INTERFACE_MODE_MII);
  123. printf(" %u", bus_idx * 32 + m * 8 + phy_idx);
  124. if (!phydev)
  125. puts("!");
  126. else
  127. ihs_phy_config(phydev, porttype->phy_invert_in_pol,
  128. porttype->phy_invert_out_pol);
  129. return 0;
  130. }
  131. int init_octo_phys(uint octo_phy_mask)
  132. {
  133. uint bus_idx;
  134. /* there are up to four octo-phys on each mdio bus */
  135. for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) {
  136. uint m;
  137. uint octo_index = bus_idx * 4;
  138. struct mii_dev *bus = NULL;
  139. struct porttype *porttype = NULL;
  140. int ret;
  141. porttype = get_porttype(octo_phy_mask, bus_idx);
  142. if (!porttype)
  143. continue;
  144. for (m = 0; m < 4; ++m) {
  145. uint phy_idx;
  146. /**
  147. * Register a bus device if there is at least one phy
  148. * on the current bus
  149. */
  150. if (!m && octo_phy_mask & (0xf << octo_index)) {
  151. ret = register_miiphy_bus(bus_idx, &bus);
  152. if (ret)
  153. return ret;
  154. }
  155. if (!(octo_phy_mask & BIT(octo_index + m)))
  156. continue;
  157. for (phy_idx = 0; phy_idx < 8; ++phy_idx)
  158. init_single_phy(porttype, bus, bus_idx, m,
  159. phy_idx);
  160. }
  161. }
  162. return 0;
  163. }
  164. /*
  165. * MII GPIO bitbang implementation
  166. * MDC MDIO bus
  167. * 13 14 PHY1-4
  168. * 25 45 PHY5-8
  169. * 46 24 PHY9-10
  170. */
  171. struct gpio_mii {
  172. int index;
  173. struct gpio_desc mdc_gpio;
  174. struct gpio_desc mdio_gpio;
  175. int mdc_num;
  176. int mdio_num;
  177. int mdio_value;
  178. } gpio_mii_set[] = {
  179. { 0, {}, {}, 13, 14, 1 },
  180. { 1, {}, {}, 25, 45, 1 },
  181. { 2, {}, {}, 46, 24, 1 },
  182. };
  183. static int mii_mdio_init(struct bb_miiphy_bus *bus)
  184. {
  185. struct gpio_mii *gpio_mii = bus->priv;
  186. char name[32] = {};
  187. struct udevice *gpio_dev1 = NULL;
  188. struct udevice *gpio_dev2 = NULL;
  189. if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) ||
  190. uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) {
  191. printf("Could not get GPIO device.\n");
  192. return 1;
  193. }
  194. if (gpio_mii->mdc_num > 31) {
  195. gpio_mii->mdc_gpio.dev = gpio_dev2;
  196. gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32;
  197. } else {
  198. gpio_mii->mdc_gpio.dev = gpio_dev1;
  199. gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num;
  200. }
  201. gpio_mii->mdc_gpio.flags = 0;
  202. snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index);
  203. dm_gpio_request(&gpio_mii->mdc_gpio, name);
  204. if (gpio_mii->mdio_num > 31) {
  205. gpio_mii->mdio_gpio.dev = gpio_dev2;
  206. gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32;
  207. } else {
  208. gpio_mii->mdio_gpio.dev = gpio_dev1;
  209. gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num;
  210. }
  211. gpio_mii->mdio_gpio.flags = 0;
  212. snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index);
  213. dm_gpio_request(&gpio_mii->mdio_gpio, name);
  214. dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT);
  215. dm_gpio_set_value(&gpio_mii->mdc_gpio, 1);
  216. return 0;
  217. }
  218. static int mii_mdio_active(struct bb_miiphy_bus *bus)
  219. {
  220. struct gpio_mii *gpio_mii = bus->priv;
  221. dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value);
  222. return 0;
  223. }
  224. static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
  225. {
  226. struct gpio_mii *gpio_mii = bus->priv;
  227. dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
  228. return 0;
  229. }
  230. static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
  231. {
  232. struct gpio_mii *gpio_mii = bus->priv;
  233. dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT);
  234. dm_gpio_set_value(&gpio_mii->mdio_gpio, v);
  235. gpio_mii->mdio_value = v;
  236. return 0;
  237. }
  238. static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
  239. {
  240. struct gpio_mii *gpio_mii = bus->priv;
  241. dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
  242. *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio));
  243. return 0;
  244. }
  245. static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
  246. {
  247. struct gpio_mii *gpio_mii = bus->priv;
  248. dm_gpio_set_value(&gpio_mii->mdc_gpio, v);
  249. return 0;
  250. }
  251. static int mii_delay(struct bb_miiphy_bus *bus)
  252. {
  253. udelay(1);
  254. return 0;
  255. }
  256. struct bb_miiphy_bus bb_miiphy_buses[] = {
  257. {
  258. .name = "ihs0",
  259. .init = mii_mdio_init,
  260. .mdio_active = mii_mdio_active,
  261. .mdio_tristate = mii_mdio_tristate,
  262. .set_mdio = mii_set_mdio,
  263. .get_mdio = mii_get_mdio,
  264. .set_mdc = mii_set_mdc,
  265. .delay = mii_delay,
  266. .priv = &gpio_mii_set[0],
  267. },
  268. {
  269. .name = "ihs1",
  270. .init = mii_mdio_init,
  271. .mdio_active = mii_mdio_active,
  272. .mdio_tristate = mii_mdio_tristate,
  273. .set_mdio = mii_set_mdio,
  274. .get_mdio = mii_get_mdio,
  275. .set_mdc = mii_set_mdc,
  276. .delay = mii_delay,
  277. .priv = &gpio_mii_set[1],
  278. },
  279. {
  280. .name = "ihs2",
  281. .init = mii_mdio_init,
  282. .mdio_active = mii_mdio_active,
  283. .mdio_tristate = mii_mdio_tristate,
  284. .set_mdio = mii_set_mdio,
  285. .get_mdio = mii_get_mdio,
  286. .set_mdc = mii_set_mdc,
  287. .delay = mii_delay,
  288. .priv = &gpio_mii_set[2],
  289. },
  290. };
  291. int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);