eth_lx2160aqds.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2018-2020 NXP
  4. *
  5. */
  6. #include <common.h>
  7. #include <env.h>
  8. #include <fdt_support.h>
  9. #include <hwconfig.h>
  10. #include <command.h>
  11. #include <log.h>
  12. #include <net.h>
  13. #include <netdev.h>
  14. #include <malloc.h>
  15. #include <fsl_mdio.h>
  16. #include <miiphy.h>
  17. #include <phy.h>
  18. #include <fm_eth.h>
  19. #include <asm/global_data.h>
  20. #include <asm/io.h>
  21. #include <exports.h>
  22. #include <asm/arch/fsl_serdes.h>
  23. #include <fsl-mc/fsl_mc.h>
  24. #include <fsl-mc/ldpaa_wriop.h>
  25. #include <linux/libfdt.h>
  26. #include "../common/qixis.h"
  27. DECLARE_GLOBAL_DATA_PTR;
  28. #ifndef CONFIG_DM_ETH
  29. #define EMI_NONE 0
  30. #define EMI1 1 /* Mdio Bus 1 */
  31. #define EMI2 2 /* Mdio Bus 2 */
  32. #if defined(CONFIG_FSL_MC_ENET)
  33. enum io_slot {
  34. IO_SLOT_NONE = 0,
  35. IO_SLOT_1,
  36. IO_SLOT_2,
  37. IO_SLOT_3,
  38. IO_SLOT_4,
  39. IO_SLOT_5,
  40. IO_SLOT_6,
  41. IO_SLOT_7,
  42. IO_SLOT_8,
  43. EMI1_RGMII1,
  44. EMI1_RGMII2,
  45. IO_SLOT_MAX
  46. };
  47. struct lx2160a_qds_mdio {
  48. enum io_slot ioslot : 4;
  49. u8 realbusnum : 4;
  50. struct mii_dev *realbus;
  51. };
  52. /* structure explaining the phy configuration on 8 lanes of a serdes*/
  53. struct serdes_phy_config {
  54. u8 serdes; /* serdes protocol */
  55. struct phy_config {
  56. u8 dpmacid;
  57. /* -1 terminated array */
  58. int phy_address[WRIOP_MAX_PHY_NUM + 1];
  59. u8 mdio_bus;
  60. enum io_slot ioslot;
  61. } phy_config[SRDS_MAX_LANES];
  62. };
  63. /* Table defining the phy configuration on 8 lanes of a serdes.
  64. * Various assumptions have been made while defining this table.
  65. * e.g. for serdes1 protocol 19 it is being assumed that X-M11-USXGMII
  66. * card is being used for dpmac 3-4. (X-M12-XFI could also have been used)
  67. * And also that this card is connected to IO Slot 1 (could have been connected
  68. * to any of the 8 IO slots (IO slot 1 - IO slot 8)).
  69. * similarly, it is also being assumed that MDIO 1 is selected on X-M7-40G card
  70. * used in serdes1 protocol 19 (could have selected MDIO 2)
  71. * To override these settings "dpmac" environment variable can be used after
  72. * defining "dpmac_override" in hwconfig environment variable.
  73. * This table has limited serdes protocol entries. It can be expanded as per
  74. * requirement.
  75. */
  76. static const struct serdes_phy_config serdes1_phy_config[] = {
  77. {3, {{WRIOP1_DPMAC3, {AQ_PHY_ADDR1, -1},
  78. EMI1, IO_SLOT_1},
  79. {WRIOP1_DPMAC4, {AQ_PHY_ADDR2, -1},
  80. EMI1, IO_SLOT_1},
  81. {WRIOP1_DPMAC5, {AQ_PHY_ADDR3, -1},
  82. EMI1, IO_SLOT_1},
  83. {WRIOP1_DPMAC6, {AQ_PHY_ADDR4, -1},
  84. EMI1, IO_SLOT_1} } },
  85. {7, {{WRIOP1_DPMAC3, {AQ_PHY_ADDR1, -1},
  86. EMI1, IO_SLOT_1},
  87. {WRIOP1_DPMAC4, {AQ_PHY_ADDR2, -1},
  88. EMI1, IO_SLOT_1},
  89. {WRIOP1_DPMAC5, {AQ_PHY_ADDR3, -1},
  90. EMI1, IO_SLOT_1},
  91. {WRIOP1_DPMAC6, {AQ_PHY_ADDR4, -1},
  92. EMI1, IO_SLOT_1},
  93. {WRIOP1_DPMAC7, {SGMII_CARD_PORT1_PHY_ADDR, -1},
  94. EMI1, IO_SLOT_2},
  95. {WRIOP1_DPMAC8, {SGMII_CARD_PORT2_PHY_ADDR, -1},
  96. EMI1, IO_SLOT_2},
  97. {WRIOP1_DPMAC9, {SGMII_CARD_PORT3_PHY_ADDR, -1},
  98. EMI1, IO_SLOT_2},
  99. {WRIOP1_DPMAC10, {SGMII_CARD_PORT4_PHY_ADDR, -1},
  100. EMI1, IO_SLOT_2} } },
  101. {8, {} },
  102. {13, {{WRIOP1_DPMAC1, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  103. EMI1, IO_SLOT_1},
  104. {WRIOP1_DPMAC2, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  105. EMI1, IO_SLOT_2} } },
  106. {14, {{WRIOP1_DPMAC1, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  107. EMI1, IO_SLOT_1} } },
  108. {15, {{WRIOP1_DPMAC1, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  109. EMI1, IO_SLOT_1},
  110. {WRIOP1_DPMAC2, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  111. EMI1, IO_SLOT_1} } },
  112. {17, {{WRIOP1_DPMAC3, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  113. EMI1, IO_SLOT_1},
  114. {WRIOP1_DPMAC4, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  115. EMI1, IO_SLOT_1},
  116. {WRIOP1_DPMAC5, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  117. EMI1, IO_SLOT_1},
  118. {WRIOP1_DPMAC6, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  119. EMI1, IO_SLOT_1} } },
  120. {19, {{WRIOP1_DPMAC2, {CORTINA_PHY_ADDR1, -1},
  121. EMI1, IO_SLOT_2},
  122. {WRIOP1_DPMAC3, {AQ_PHY_ADDR1, -1},
  123. EMI1, IO_SLOT_1},
  124. {WRIOP1_DPMAC4, {AQ_PHY_ADDR2, -1},
  125. EMI1, IO_SLOT_1},
  126. {WRIOP1_DPMAC5, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  127. EMI1, IO_SLOT_6},
  128. {WRIOP1_DPMAC6, {INPHI_PHY_ADDR1, INPHI_PHY_ADDR2, -1},
  129. EMI1, IO_SLOT_6} } },
  130. {20, {{WRIOP1_DPMAC1, {CORTINA_PHY_ADDR1, -1},
  131. EMI1, IO_SLOT_1},
  132. {WRIOP1_DPMAC2, {CORTINA_PHY_ADDR1, -1},
  133. EMI1, IO_SLOT_2} } }
  134. };
  135. static const struct serdes_phy_config serdes2_phy_config[] = {
  136. {2, {} },
  137. {3, {} },
  138. {5, {} },
  139. {11, {{WRIOP1_DPMAC12, {SGMII_CARD_PORT2_PHY_ADDR, -1},
  140. EMI1, IO_SLOT_7},
  141. {WRIOP1_DPMAC17, {SGMII_CARD_PORT3_PHY_ADDR, -1},
  142. EMI1, IO_SLOT_7},
  143. {WRIOP1_DPMAC18, {SGMII_CARD_PORT4_PHY_ADDR, -1},
  144. EMI1, IO_SLOT_7},
  145. {WRIOP1_DPMAC16, {SGMII_CARD_PORT2_PHY_ADDR, -1},
  146. EMI1, IO_SLOT_8},
  147. {WRIOP1_DPMAC13, {SGMII_CARD_PORT3_PHY_ADDR, -1},
  148. EMI1, IO_SLOT_8},
  149. {WRIOP1_DPMAC14, {SGMII_CARD_PORT4_PHY_ADDR, -1},
  150. EMI1, IO_SLOT_8} } },
  151. };
  152. static const struct serdes_phy_config serdes3_phy_config[] = {
  153. {2, {} },
  154. {3, {} }
  155. };
  156. static inline
  157. const struct phy_config *get_phy_config(u8 serdes,
  158. const struct serdes_phy_config *table,
  159. u8 table_size)
  160. {
  161. int i;
  162. for (i = 0; i < table_size; i++) {
  163. if (table[i].serdes == serdes)
  164. return table[i].phy_config;
  165. }
  166. return NULL;
  167. }
  168. /* BRDCFG4 controls EMI routing for the board.
  169. * Bits Function
  170. * 7-6 EMI Interface #1 Primary Routing (CFG_MUX1_EMI1) (1.8V):
  171. * EMI1 00= On-board PHY #1
  172. * 01= On-board PHY #2
  173. * 10= (reserved)
  174. * 11= Slots 1..8 multiplexer and translator.
  175. * 5-3 EMI Interface #1 Secondary Routing (CFG_MUX2_EMI1) (2.5V):
  176. * EMI1X 000= Slot #1
  177. * 001= Slot #2
  178. * 010= Slot #3
  179. * 011= Slot #4
  180. * 100= Slot #5
  181. * 101= Slot #6
  182. * 110= Slot #7
  183. * 111= Slot #8
  184. * 2-0 EMI Interface #2 Routing (CFG_MUX_EMI2):
  185. * EMI2 000= Slot #1 (secondary EMI)
  186. * 001= Slot #2 (secondary EMI)
  187. * 010= Slot #3 (secondary EMI)
  188. * 011= Slot #4 (secondary EMI)
  189. * 100= Slot #5 (secondary EMI)
  190. * 101= Slot #6 (secondary EMI)
  191. * 110= Slot #7 (secondary EMI)
  192. * 111= Slot #8 (secondary EMI)
  193. */
  194. static int lx2160a_qds_get_mdio_mux_val(u8 realbusnum, enum io_slot ioslot)
  195. {
  196. switch (realbusnum) {
  197. case EMI1:
  198. switch (ioslot) {
  199. case EMI1_RGMII1:
  200. return 0;
  201. case EMI1_RGMII2:
  202. return 0x40;
  203. default:
  204. return (((ioslot - 1) << BRDCFG4_EMI1SEL_SHIFT) | 0xC0);
  205. }
  206. break;
  207. case EMI2:
  208. return ((ioslot - 1) << BRDCFG4_EMI2SEL_SHIFT);
  209. default:
  210. return -1;
  211. }
  212. }
  213. static void lx2160a_qds_mux_mdio(struct lx2160a_qds_mdio *priv)
  214. {
  215. u8 brdcfg4, mux_val, reg;
  216. brdcfg4 = QIXIS_READ(brdcfg[4]);
  217. reg = brdcfg4;
  218. mux_val = lx2160a_qds_get_mdio_mux_val(priv->realbusnum, priv->ioslot);
  219. switch (priv->realbusnum) {
  220. case EMI1:
  221. brdcfg4 &= ~BRDCFG4_EMI1SEL_MASK;
  222. brdcfg4 |= mux_val;
  223. break;
  224. case EMI2:
  225. brdcfg4 &= ~BRDCFG4_EMI2SEL_MASK;
  226. brdcfg4 |= mux_val;
  227. break;
  228. }
  229. if (brdcfg4 ^ reg)
  230. QIXIS_WRITE(brdcfg[4], brdcfg4);
  231. }
  232. static int lx2160a_qds_mdio_read(struct mii_dev *bus, int addr,
  233. int devad, int regnum)
  234. {
  235. struct lx2160a_qds_mdio *priv = bus->priv;
  236. lx2160a_qds_mux_mdio(priv);
  237. return priv->realbus->read(priv->realbus, addr, devad, regnum);
  238. }
  239. static int lx2160a_qds_mdio_write(struct mii_dev *bus, int addr, int devad,
  240. int regnum, u16 value)
  241. {
  242. struct lx2160a_qds_mdio *priv = bus->priv;
  243. lx2160a_qds_mux_mdio(priv);
  244. return priv->realbus->write(priv->realbus, addr, devad, regnum, value);
  245. }
  246. static int lx2160a_qds_mdio_reset(struct mii_dev *bus)
  247. {
  248. struct lx2160a_qds_mdio *priv = bus->priv;
  249. return priv->realbus->reset(priv->realbus);
  250. }
  251. static struct mii_dev *lx2160a_qds_mdio_init(u8 realbusnum, enum io_slot ioslot)
  252. {
  253. struct lx2160a_qds_mdio *pmdio;
  254. struct mii_dev *bus;
  255. /*should be within MDIO_NAME_LEN*/
  256. char dummy_mdio_name[] = "LX2160A_QDS_MDIO1_IOSLOT1";
  257. if (realbusnum == EMI2) {
  258. if (ioslot < IO_SLOT_1 || ioslot > IO_SLOT_8) {
  259. printf("invalid ioslot %d\n", ioslot);
  260. return NULL;
  261. }
  262. } else if (realbusnum == EMI1) {
  263. if (ioslot < IO_SLOT_1 || ioslot > EMI1_RGMII2) {
  264. printf("invalid ioslot %d\n", ioslot);
  265. return NULL;
  266. }
  267. } else {
  268. printf("not supported real mdio bus %d\n", realbusnum);
  269. return NULL;
  270. }
  271. if (ioslot == EMI1_RGMII1)
  272. strcpy(dummy_mdio_name, "LX2160A_QDS_MDIO1_RGMII1");
  273. else if (ioslot == EMI1_RGMII2)
  274. strcpy(dummy_mdio_name, "LX2160A_QDS_MDIO1_RGMII2");
  275. else
  276. sprintf(dummy_mdio_name, "LX2160A_QDS_MDIO%d_IOSLOT%d",
  277. realbusnum, ioslot);
  278. bus = miiphy_get_dev_by_name(dummy_mdio_name);
  279. if (bus)
  280. return bus;
  281. bus = mdio_alloc();
  282. if (!bus) {
  283. printf("Failed to allocate %s bus\n", dummy_mdio_name);
  284. return NULL;
  285. }
  286. pmdio = malloc(sizeof(*pmdio));
  287. if (!pmdio) {
  288. printf("Failed to allocate %s private data\n", dummy_mdio_name);
  289. free(bus);
  290. return NULL;
  291. }
  292. switch (realbusnum) {
  293. case EMI1:
  294. pmdio->realbus =
  295. miiphy_get_dev_by_name(DEFAULT_WRIOP_MDIO1_NAME);
  296. break;
  297. case EMI2:
  298. pmdio->realbus =
  299. miiphy_get_dev_by_name(DEFAULT_WRIOP_MDIO2_NAME);
  300. break;
  301. }
  302. if (!pmdio->realbus) {
  303. printf("No real mdio bus num %d found\n", realbusnum);
  304. free(bus);
  305. free(pmdio);
  306. return NULL;
  307. }
  308. pmdio->realbusnum = realbusnum;
  309. pmdio->ioslot = ioslot;
  310. bus->read = lx2160a_qds_mdio_read;
  311. bus->write = lx2160a_qds_mdio_write;
  312. bus->reset = lx2160a_qds_mdio_reset;
  313. strcpy(bus->name, dummy_mdio_name);
  314. bus->priv = pmdio;
  315. if (!mdio_register(bus))
  316. return bus;
  317. printf("No bus with name %s\n", dummy_mdio_name);
  318. free(bus);
  319. free(pmdio);
  320. return NULL;
  321. }
  322. static inline void do_phy_config(const struct phy_config *phy_config)
  323. {
  324. struct mii_dev *bus;
  325. int i, phy_num, phy_address;
  326. for (i = 0; i < SRDS_MAX_LANES; i++) {
  327. if (!phy_config[i].dpmacid)
  328. continue;
  329. for (phy_num = 0;
  330. phy_num < ARRAY_SIZE(phy_config[i].phy_address);
  331. phy_num++) {
  332. phy_address = phy_config[i].phy_address[phy_num];
  333. if (phy_address == -1)
  334. break;
  335. wriop_set_phy_address(phy_config[i].dpmacid,
  336. phy_num, phy_address);
  337. }
  338. /*Register the muxing front-ends to the MDIO buses*/
  339. bus = lx2160a_qds_mdio_init(phy_config[i].mdio_bus,
  340. phy_config[i].ioslot);
  341. if (!bus)
  342. printf("could not get bus for mdio %d ioslot %d\n",
  343. phy_config[i].mdio_bus,
  344. phy_config[i].ioslot);
  345. else
  346. wriop_set_mdio(phy_config[i].dpmacid, bus);
  347. }
  348. }
  349. static inline void do_dpmac_config(int dpmac, const char *arg_dpmacid,
  350. char *env_dpmac)
  351. {
  352. const char *ret;
  353. size_t len;
  354. u8 realbusnum, ioslot;
  355. struct mii_dev *bus;
  356. int phy_num;
  357. char *phystr = "phy00";
  358. /*search phy in dpmac arg*/
  359. for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) {
  360. sprintf(phystr, "phy%d", phy_num + 1);
  361. ret = hwconfig_subarg_f(arg_dpmacid, phystr, &len, env_dpmac);
  362. if (!ret) {
  363. /*look for phy instead of phy1*/
  364. if (!phy_num)
  365. ret = hwconfig_subarg_f(arg_dpmacid, "phy",
  366. &len, env_dpmac);
  367. if (!ret)
  368. continue;
  369. }
  370. if (len != 4 || strncmp(ret, "0x", 2))
  371. printf("invalid phy format in %s variable.\n"
  372. "specify phy%d for %s in hex format e.g. 0x12\n",
  373. env_dpmac, phy_num + 1, arg_dpmacid);
  374. else
  375. wriop_set_phy_address(dpmac, phy_num,
  376. hextoul(ret, NULL));
  377. }
  378. /*search mdio in dpmac arg*/
  379. ret = hwconfig_subarg_f(arg_dpmacid, "mdio", &len, env_dpmac);
  380. if (ret)
  381. realbusnum = *ret - '0';
  382. else
  383. realbusnum = EMI_NONE;
  384. if (realbusnum) {
  385. /*search io in dpmac arg*/
  386. ret = hwconfig_subarg_f(arg_dpmacid, "io", &len, env_dpmac);
  387. if (ret)
  388. ioslot = *ret - '0';
  389. else
  390. ioslot = IO_SLOT_NONE;
  391. /*Register the muxing front-ends to the MDIO buses*/
  392. bus = lx2160a_qds_mdio_init(realbusnum, ioslot);
  393. if (!bus)
  394. printf("could not get bus for mdio %d ioslot %d\n",
  395. realbusnum, ioslot);
  396. else
  397. wriop_set_mdio(dpmac, bus);
  398. }
  399. }
  400. #endif
  401. #endif /* !CONFIG_DM_ETH */
  402. int board_eth_init(struct bd_info *bis)
  403. {
  404. #ifndef CONFIG_DM_ETH
  405. #if defined(CONFIG_FSL_MC_ENET)
  406. struct memac_mdio_info mdio_info;
  407. struct memac_mdio_controller *regs;
  408. int i;
  409. const char *ret;
  410. char *env_dpmac;
  411. char dpmacid[] = "dpmac00", srds[] = "00_00_00";
  412. size_t len;
  413. struct mii_dev *bus;
  414. const struct phy_config *phy_config;
  415. struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
  416. u32 srds_s1, srds_s2, srds_s3;
  417. srds_s1 = in_le32(&gur->rcwsr[28]) &
  418. FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK;
  419. srds_s1 >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
  420. srds_s2 = in_le32(&gur->rcwsr[28]) &
  421. FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK;
  422. srds_s2 >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
  423. srds_s3 = in_le32(&gur->rcwsr[28]) &
  424. FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_MASK;
  425. srds_s3 >>= FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_SHIFT;
  426. sprintf(srds, "%d_%d_%d", srds_s1, srds_s2, srds_s3);
  427. regs = (struct memac_mdio_controller *)CONFIG_SYS_FSL_WRIOP1_MDIO1;
  428. mdio_info.regs = regs;
  429. mdio_info.name = DEFAULT_WRIOP_MDIO1_NAME;
  430. /*Register the EMI 1*/
  431. fm_memac_mdio_init(bis, &mdio_info);
  432. regs = (struct memac_mdio_controller *)CONFIG_SYS_FSL_WRIOP1_MDIO2;
  433. mdio_info.regs = regs;
  434. mdio_info.name = DEFAULT_WRIOP_MDIO2_NAME;
  435. /*Register the EMI 2*/
  436. fm_memac_mdio_init(bis, &mdio_info);
  437. /* "dpmac" environment variable can be used after
  438. * defining "dpmac_override" in hwconfig environment variable.
  439. */
  440. if (hwconfig("dpmac_override")) {
  441. env_dpmac = env_get("dpmac");
  442. if (env_dpmac) {
  443. ret = hwconfig_arg_f("srds", &len, env_dpmac);
  444. if (ret) {
  445. if (strncmp(ret, srds, strlen(srds))) {
  446. printf("SERDES configuration changed.\n"
  447. "previous: %.*s, current: %s.\n"
  448. "update dpmac variable.\n",
  449. (int)len, ret, srds);
  450. }
  451. } else {
  452. printf("SERDES configuration not found.\n"
  453. "Please add srds:%s in dpmac variable\n",
  454. srds);
  455. }
  456. for (i = WRIOP1_DPMAC1; i < NUM_WRIOP_PORTS; i++) {
  457. /* Look for dpmac1 to dpmac24(current max) arg
  458. * in dpmac environment variable
  459. */
  460. sprintf(dpmacid, "dpmac%d", i);
  461. ret = hwconfig_arg_f(dpmacid, &len, env_dpmac);
  462. if (ret)
  463. do_dpmac_config(i, dpmacid, env_dpmac);
  464. }
  465. } else {
  466. printf("Warning: environment dpmac not found.\n"
  467. "DPAA network interfaces may not work\n");
  468. }
  469. } else {
  470. /*Look for phy config for serdes1 in phy config table*/
  471. phy_config = get_phy_config(srds_s1, serdes1_phy_config,
  472. ARRAY_SIZE(serdes1_phy_config));
  473. if (!phy_config) {
  474. printf("%s WRIOP: Unsupported SerDes1 Protocol %d\n",
  475. __func__, srds_s1);
  476. } else {
  477. do_phy_config(phy_config);
  478. }
  479. phy_config = get_phy_config(srds_s2, serdes2_phy_config,
  480. ARRAY_SIZE(serdes2_phy_config));
  481. if (!phy_config) {
  482. printf("%s WRIOP: Unsupported SerDes2 Protocol %d\n",
  483. __func__, srds_s2);
  484. } else {
  485. do_phy_config(phy_config);
  486. }
  487. phy_config = get_phy_config(srds_s3, serdes3_phy_config,
  488. ARRAY_SIZE(serdes3_phy_config));
  489. if (!phy_config) {
  490. printf("%s WRIOP: Unsupported SerDes3 Protocol %d\n",
  491. __func__, srds_s3);
  492. } else {
  493. do_phy_config(phy_config);
  494. }
  495. }
  496. if (wriop_get_enet_if(WRIOP1_DPMAC17) == PHY_INTERFACE_MODE_RGMII_ID) {
  497. wriop_set_phy_address(WRIOP1_DPMAC17, 0, RGMII_PHY_ADDR1);
  498. bus = lx2160a_qds_mdio_init(EMI1, EMI1_RGMII1);
  499. if (!bus)
  500. printf("could not get bus for RGMII1\n");
  501. else
  502. wriop_set_mdio(WRIOP1_DPMAC17, bus);
  503. }
  504. if (wriop_get_enet_if(WRIOP1_DPMAC18) == PHY_INTERFACE_MODE_RGMII_ID) {
  505. wriop_set_phy_address(WRIOP1_DPMAC18, 0, RGMII_PHY_ADDR2);
  506. bus = lx2160a_qds_mdio_init(EMI1, EMI1_RGMII2);
  507. if (!bus)
  508. printf("could not get bus for RGMII2\n");
  509. else
  510. wriop_set_mdio(WRIOP1_DPMAC18, bus);
  511. }
  512. cpu_eth_init(bis);
  513. #endif /* CONFIG_FMAN_ENET */
  514. #endif /* !CONFIG_DM_ETH */
  515. #ifdef CONFIG_PHY_AQUANTIA
  516. /*
  517. * Export functions to be used by AQ firmware
  518. * upload application
  519. */
  520. gd->jt->strcpy = strcpy;
  521. gd->jt->mdelay = mdelay;
  522. gd->jt->mdio_get_current_dev = mdio_get_current_dev;
  523. gd->jt->phy_find_by_mask = phy_find_by_mask;
  524. gd->jt->mdio_phydev_for_ethname = mdio_phydev_for_ethname;
  525. gd->jt->miiphy_set_current_dev = miiphy_set_current_dev;
  526. #endif
  527. #ifdef CONFIG_DM_ETH
  528. return 0;
  529. #else
  530. return pci_eth_init(bis);
  531. #endif
  532. }
  533. #if defined(CONFIG_RESET_PHY_R)
  534. void reset_phy(void)
  535. {
  536. #if defined(CONFIG_FSL_MC_ENET)
  537. mc_env_boot();
  538. #endif
  539. }
  540. #endif /* CONFIG_RESET_PHY_R */
  541. #ifndef CONFIG_DM_ETH
  542. #if defined(CONFIG_FSL_MC_ENET)
  543. int fdt_fixup_dpmac_phy_handle(void *fdt, int dpmac_id, int node_phandle)
  544. {
  545. int offset;
  546. int ret;
  547. char dpmac_str[] = "dpmacs@00";
  548. const char *phy_string;
  549. offset = fdt_path_offset(fdt, "/soc/fsl-mc/dpmacs");
  550. if (offset < 0)
  551. offset = fdt_path_offset(fdt, "/fsl-mc/dpmacs");
  552. if (offset < 0) {
  553. printf("dpmacs node not found in device tree\n");
  554. return offset;
  555. }
  556. sprintf(dpmac_str, "dpmac@%x", dpmac_id);
  557. debug("dpmac_str = %s\n", dpmac_str);
  558. offset = fdt_subnode_offset(fdt, offset, dpmac_str);
  559. if (offset < 0) {
  560. printf("%s node not found in device tree\n", dpmac_str);
  561. return offset;
  562. }
  563. phy_string = fdt_getprop(fdt, offset, "phy-connection-type", NULL);
  564. if (is_backplane_mode(phy_string)) {
  565. /* Backplane KR mode: skip fixups */
  566. printf("Interface %d in backplane KR mode\n", dpmac_id);
  567. return 0;
  568. }
  569. ret = fdt_appendprop_cell(fdt, offset, "phy-handle", node_phandle);
  570. if (ret)
  571. printf("%d@%s %d\n", __LINE__, __func__, ret);
  572. phy_string = phy_string_for_interface(wriop_get_enet_if(dpmac_id));
  573. ret = fdt_setprop_string(fdt, offset, "phy-connection-type",
  574. phy_string);
  575. if (ret)
  576. printf("%d@%s %d\n", __LINE__, __func__, ret);
  577. return ret;
  578. }
  579. int fdt_get_ioslot_offset(void *fdt, struct mii_dev *mii_dev, int fpga_offset)
  580. {
  581. char mdio_ioslot_str[] = "mdio@00";
  582. struct lx2160a_qds_mdio *priv;
  583. u64 reg;
  584. u32 phandle;
  585. int offset, mux_val;
  586. /*Test if the MDIO bus is real mdio bus or muxing front end ?*/
  587. if (strncmp(mii_dev->name, "LX2160A_QDS_MDIO",
  588. strlen("LX2160A_QDS_MDIO")))
  589. return -1;
  590. /*Get the real MDIO bus num and ioslot info from bus's priv data*/
  591. priv = mii_dev->priv;
  592. debug("real_bus_num = %d, ioslot = %d\n",
  593. priv->realbusnum, priv->ioslot);
  594. if (priv->realbusnum == EMI1)
  595. reg = CONFIG_SYS_FSL_WRIOP1_MDIO1;
  596. else
  597. reg = CONFIG_SYS_FSL_WRIOP1_MDIO2;
  598. offset = fdt_node_offset_by_compat_reg(fdt, "fsl,fman-memac-mdio", reg);
  599. if (offset < 0) {
  600. printf("mdio@%llx node not found in device tree\n", reg);
  601. return offset;
  602. }
  603. phandle = fdt_get_phandle(fdt, offset);
  604. phandle = cpu_to_fdt32(phandle);
  605. offset = fdt_node_offset_by_prop_value(fdt, -1, "mdio-parent-bus",
  606. &phandle, 4);
  607. if (offset < 0) {
  608. printf("mdio-mux-%d node not found in device tree\n",
  609. priv->realbusnum == EMI1 ? 1 : 2);
  610. return offset;
  611. }
  612. mux_val = lx2160a_qds_get_mdio_mux_val(priv->realbusnum, priv->ioslot);
  613. if (priv->realbusnum == EMI1)
  614. mux_val >>= BRDCFG4_EMI1SEL_SHIFT;
  615. else
  616. mux_val >>= BRDCFG4_EMI2SEL_SHIFT;
  617. sprintf(mdio_ioslot_str, "mdio@%x", (u8)mux_val);
  618. offset = fdt_subnode_offset(fdt, offset, mdio_ioslot_str);
  619. if (offset < 0) {
  620. printf("%s node not found in device tree\n", mdio_ioslot_str);
  621. return offset;
  622. }
  623. return offset;
  624. }
  625. int fdt_create_phy_node(void *fdt, int offset, u8 phyaddr, int *subnodeoffset,
  626. struct phy_device *phy_dev, int phandle)
  627. {
  628. char phy_node_name[] = "ethernet-phy@00";
  629. char phy_id_compatible_str[] = "ethernet-phy-id0000.0000,";
  630. int ret;
  631. sprintf(phy_node_name, "ethernet-phy@%x", phyaddr);
  632. debug("phy_node_name = %s\n", phy_node_name);
  633. *subnodeoffset = fdt_add_subnode(fdt, offset, phy_node_name);
  634. if (*subnodeoffset <= 0) {
  635. printf("Could not add subnode %s inside node %s err = %s\n",
  636. phy_node_name, fdt_get_name(fdt, offset, NULL),
  637. fdt_strerror(*subnodeoffset));
  638. return *subnodeoffset;
  639. }
  640. sprintf(phy_id_compatible_str, "ethernet-phy-id%04x.%04x,",
  641. phy_dev->phy_id >> 16, phy_dev->phy_id & 0xFFFF);
  642. debug("phy_id_compatible_str %s\n", phy_id_compatible_str);
  643. ret = fdt_setprop_string(fdt, *subnodeoffset, "compatible",
  644. phy_id_compatible_str);
  645. if (ret) {
  646. printf("%d@%s %d\n", __LINE__, __func__, ret);
  647. goto out;
  648. }
  649. if (phy_dev->is_c45) {
  650. ret = fdt_appendprop_string(fdt, *subnodeoffset, "compatible",
  651. "ethernet-phy-ieee802.3-c45");
  652. if (ret) {
  653. printf("%d@%s %d\n", __LINE__, __func__, ret);
  654. goto out;
  655. }
  656. } else {
  657. ret = fdt_appendprop_string(fdt, *subnodeoffset, "compatible",
  658. "ethernet-phy-ieee802.3-c22");
  659. if (ret) {
  660. printf("%d@%s %d\n", __LINE__, __func__, ret);
  661. goto out;
  662. }
  663. }
  664. ret = fdt_setprop_cell(fdt, *subnodeoffset, "reg", phyaddr);
  665. if (ret) {
  666. printf("%d@%s %d\n", __LINE__, __func__, ret);
  667. goto out;
  668. }
  669. ret = fdt_set_phandle(fdt, *subnodeoffset, phandle);
  670. if (ret) {
  671. printf("%d@%s %d\n", __LINE__, __func__, ret);
  672. goto out;
  673. }
  674. out:
  675. if (ret)
  676. fdt_del_node(fdt, *subnodeoffset);
  677. return ret;
  678. }
  679. int fdt_fixup_board_phy(void *fdt)
  680. {
  681. int fpga_offset, offset, subnodeoffset;
  682. struct mii_dev *mii_dev;
  683. struct list_head *mii_devs, *entry;
  684. int ret, dpmac_id, phandle, i;
  685. struct phy_device *phy_dev;
  686. char ethname[ETH_NAME_LEN];
  687. phy_interface_t phy_iface;
  688. ret = 0;
  689. /* we know FPGA is connected to i2c0, therefore search path directly,
  690. * instead of compatible property, as it saves time
  691. */
  692. fpga_offset = fdt_path_offset(fdt, "/soc/i2c@2000000/fpga");
  693. if (fpga_offset < 0)
  694. fpga_offset = fdt_path_offset(fdt, "/i2c@2000000/fpga");
  695. if (fpga_offset < 0) {
  696. printf("i2c@2000000/fpga node not found in device tree\n");
  697. return fpga_offset;
  698. }
  699. phandle = fdt_alloc_phandle(fdt);
  700. mii_devs = mdio_get_list_head();
  701. list_for_each(entry, mii_devs) {
  702. mii_dev = list_entry(entry, struct mii_dev, link);
  703. debug("mii_dev name : %s\n", mii_dev->name);
  704. offset = fdt_get_ioslot_offset(fdt, mii_dev, fpga_offset);
  705. if (offset < 0)
  706. continue;
  707. // Look for phy devices attached to MDIO bus muxing front end
  708. // and create their entries with compatible being the device id
  709. for (i = 0; i < PHY_MAX_ADDR; i++) {
  710. phy_dev = mii_dev->phymap[i];
  711. if (!phy_dev)
  712. continue;
  713. // TODO: use sscanf instead of loop
  714. dpmac_id = WRIOP1_DPMAC1;
  715. while (dpmac_id < NUM_WRIOP_PORTS) {
  716. phy_iface = wriop_get_enet_if(dpmac_id);
  717. snprintf(ethname, ETH_NAME_LEN, "DPMAC%d@%s",
  718. dpmac_id,
  719. phy_string_for_interface(phy_iface));
  720. if (strcmp(ethname, phy_dev->dev->name) == 0)
  721. break;
  722. dpmac_id++;
  723. }
  724. if (dpmac_id == NUM_WRIOP_PORTS)
  725. continue;
  726. ret = fdt_create_phy_node(fdt, offset, i,
  727. &subnodeoffset,
  728. phy_dev, phandle);
  729. if (ret)
  730. break;
  731. ret = fdt_fixup_dpmac_phy_handle(fdt,
  732. dpmac_id, phandle);
  733. if (ret) {
  734. fdt_del_node(fdt, subnodeoffset);
  735. break;
  736. }
  737. /* calculate offset again as new node addition may have
  738. * changed offset;
  739. */
  740. offset = fdt_get_ioslot_offset(fdt, mii_dev,
  741. fpga_offset);
  742. phandle++;
  743. }
  744. if (ret)
  745. break;
  746. }
  747. return ret;
  748. }
  749. #endif // CONFIG_FSL_MC_ENET
  750. #endif
  751. #if defined(CONFIG_DM_ETH) && defined(CONFIG_MULTI_DTB_FIT)
  752. /* Structure to hold SERDES protocols supported in case of
  753. * CONFIG_DM_ETH enabled (network interfaces are described in the DTS).
  754. *
  755. * @serdes_block: the index of the SERDES block
  756. * @serdes_protocol: the decimal value of the protocol supported
  757. * @dts_needed: DTS notes describing the current configuration are needed
  758. *
  759. * When dts_needed is true, the board_fit_config_name_match() function
  760. * will try to exactly match the current configuration of the block with a DTS
  761. * name provided.
  762. */
  763. static struct serdes_configuration {
  764. u8 serdes_block;
  765. u32 serdes_protocol;
  766. bool dts_needed;
  767. } supported_protocols[] = {
  768. /* Serdes block #1 */
  769. {1, 3, true},
  770. {1, 7, true},
  771. {1, 19, true},
  772. {1, 20, true},
  773. /* Serdes block #2 */
  774. {2, 2, false},
  775. {2, 3, false},
  776. {2, 5, false},
  777. {2, 11, true},
  778. /* Serdes block #3 */
  779. {3, 2, false},
  780. {3, 3, false},
  781. };
  782. #define SUPPORTED_SERDES_PROTOCOLS ARRAY_SIZE(supported_protocols)
  783. static bool protocol_supported(u8 serdes_block, u32 protocol)
  784. {
  785. struct serdes_configuration serdes_conf;
  786. int i;
  787. for (i = 0; i < SUPPORTED_SERDES_PROTOCOLS; i++) {
  788. serdes_conf = supported_protocols[i];
  789. if (serdes_conf.serdes_block == serdes_block &&
  790. serdes_conf.serdes_protocol == protocol)
  791. return true;
  792. }
  793. return false;
  794. }
  795. static void get_str_protocol(u8 serdes_block, u32 protocol, char *str)
  796. {
  797. struct serdes_configuration serdes_conf;
  798. int i;
  799. for (i = 0; i < SUPPORTED_SERDES_PROTOCOLS; i++) {
  800. serdes_conf = supported_protocols[i];
  801. if (serdes_conf.serdes_block == serdes_block &&
  802. serdes_conf.serdes_protocol == protocol) {
  803. if (serdes_conf.dts_needed == true)
  804. sprintf(str, "%u", protocol);
  805. else
  806. sprintf(str, "x");
  807. return;
  808. }
  809. }
  810. }
  811. int board_fit_config_name_match(const char *name)
  812. {
  813. struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
  814. u32 rcw_status = in_le32(&gur->rcwsr[28]);
  815. char srds_s1_str[2], srds_s2_str[2], srds_s3_str[2];
  816. u32 srds_s1, srds_s2, srds_s3;
  817. char expected_dts[100];
  818. srds_s1 = rcw_status & FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_MASK;
  819. srds_s1 >>= FSL_CHASSIS3_RCWSR28_SRDS1_PRTCL_SHIFT;
  820. srds_s2 = rcw_status & FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_MASK;
  821. srds_s2 >>= FSL_CHASSIS3_RCWSR28_SRDS2_PRTCL_SHIFT;
  822. srds_s3 = rcw_status & FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_MASK;
  823. srds_s3 >>= FSL_CHASSIS3_RCWSR28_SRDS3_PRTCL_SHIFT;
  824. /* Check for supported protocols. The default DTS will be used
  825. * in this case
  826. */
  827. if (!protocol_supported(1, srds_s1) ||
  828. !protocol_supported(2, srds_s2) ||
  829. !protocol_supported(3, srds_s3))
  830. return -1;
  831. get_str_protocol(1, srds_s1, srds_s1_str);
  832. get_str_protocol(2, srds_s2, srds_s2_str);
  833. get_str_protocol(3, srds_s3, srds_s3_str);
  834. sprintf(expected_dts, "fsl-lx2160a-qds-%s-%s-%s",
  835. srds_s1_str, srds_s2_str, srds_s3_str);
  836. if (!strcmp(name, expected_dts))
  837. return 0;
  838. return -1;
  839. }
  840. #endif