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