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