]>
Commit | Line | Data |
---|---|---|
2915609a AF |
1 | /* |
2 | * Copyright 2009-2011 Freescale Semiconductor, Inc. | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
2915609a AF |
5 | */ |
6 | ||
7 | #include <common.h> | |
8 | #include <command.h> | |
9 | #include <netdev.h> | |
10 | #include <asm/mmu.h> | |
11 | #include <asm/processor.h> | |
12 | #include <asm/cache.h> | |
13 | #include <asm/immap_85xx.h> | |
14 | #include <asm/fsl_law.h> | |
15 | #include <asm/fsl_ddr_sdram.h> | |
16 | #include <asm/fsl_serdes.h> | |
17 | #include <asm/fsl_portals.h> | |
18 | #include <asm/fsl_liodn.h> | |
19 | #include <malloc.h> | |
20 | #include <fm_eth.h> | |
21 | #include <fsl_mdio.h> | |
22 | #include <miiphy.h> | |
23 | #include <phy.h> | |
24 | ||
25 | #include "../common/ngpixis.h" | |
26 | #include "../common/fman.h" | |
27 | #include <asm/fsl_dtsec.h> | |
28 | ||
29 | #define EMI_NONE 0xffffffff | |
30 | #define EMI_MASK 0xf0000000 | |
31 | #define EMI1_RGMII 0x0 | |
32 | #define EMI1_SLOT3 0x80000000 /* bank1 EFGH */ | |
33 | #define EMI1_SLOT4 0x40000000 /* bank2 ABCD */ | |
34 | #define EMI1_SLOT5 0xc0000000 /* bank3 ABCD */ | |
35 | #define EMI2_SLOT4 0x10000000 /* bank2 ABCD */ | |
36 | #define EMI2_SLOT5 0x30000000 /* bank3 ABCD */ | |
37 | #define EMI1_MASK 0xc0000000 | |
38 | #define EMI2_MASK 0x30000000 | |
39 | ||
40 | static int mdio_mux[NUM_FM_PORTS]; | |
41 | ||
42 | static char *mdio_names[16] = { | |
43 | "P4080DS_MDIO0", | |
44 | "P4080DS_MDIO1", | |
45 | NULL, | |
46 | "P4080DS_MDIO3", | |
47 | "P4080DS_MDIO4", | |
48 | NULL, NULL, NULL, | |
49 | "P4080DS_MDIO8", | |
50 | NULL, NULL, NULL, | |
51 | "P4080DS_MDIO12", | |
52 | NULL, NULL, NULL, | |
53 | }; | |
54 | ||
61fc52b6 TT |
55 | /* |
56 | * Mapping of all 18 SERDES lanes to board slots. A value of '0' here means | |
57 | * that the mapping must be determined dynamically, or that the lane maps to | |
58 | * something other than a board slot. | |
59 | */ | |
60 | static u8 lane_to_slot[] = { | |
61 | 1, 1, 2, 2, 3, 3, 3, 3, 6, 6, 4, 4, 4, 4, 5, 5, 5, 5 | |
62 | }; | |
63 | ||
2915609a AF |
64 | static char *p4080ds_mdio_name_for_muxval(u32 muxval) |
65 | { | |
66 | return mdio_names[(muxval & EMI_MASK) >> 28]; | |
67 | } | |
68 | ||
69 | struct mii_dev *mii_dev_for_muxval(u32 muxval) | |
70 | { | |
71 | struct mii_dev *bus; | |
72 | char *name = p4080ds_mdio_name_for_muxval(muxval); | |
73 | ||
74 | if (!name) { | |
75 | printf("No bus for muxval %x\n", muxval); | |
76 | return NULL; | |
77 | } | |
78 | ||
79 | bus = miiphy_get_dev_by_name(name); | |
80 | ||
81 | if (!bus) { | |
82 | printf("No bus by name %s\n", name); | |
83 | return NULL; | |
84 | } | |
85 | ||
86 | return bus; | |
87 | } | |
88 | ||
a836626c | 89 | #if defined(CONFIG_SYS_P4080_ERRATUM_SERDES9) && defined(CONFIG_PHY_TERANETICS) |
2915609a AF |
90 | int board_phy_config(struct phy_device *phydev) |
91 | { | |
9fafe7da TK |
92 | if (phydev->drv->config) |
93 | phydev->drv->config(phydev); | |
a836626c TT |
94 | if (phydev->drv->uid == PHY_UID_TN2020) { |
95 | unsigned long timeout = 1 * 1000; /* 1 seconds */ | |
2915609a AF |
96 | enum srds_prtcl device; |
97 | ||
a836626c TT |
98 | /* |
99 | * Wait for the XAUI to come out of reset. This is when it | |
100 | * starts transmitting alignment signals. | |
101 | */ | |
102 | while (--timeout) { | |
103 | int reg = phy_read(phydev, MDIO_MMD_PHYXS, MDIO_CTRL1); | |
104 | if (reg < 0) { | |
105 | printf("TN2020: Error reading from PHY at " | |
106 | "address %u\n", phydev->addr); | |
107 | break; | |
108 | } | |
109 | /* | |
110 | * Note that we've never actually seen | |
111 | * MDIO_CTRL1_RESET set to 1. | |
112 | */ | |
113 | if ((reg & MDIO_CTRL1_RESET) == 0) | |
114 | break; | |
115 | udelay(1000); | |
116 | } | |
117 | ||
118 | if (!timeout) { | |
119 | printf("TN2020: Timeout waiting for PHY at address %u " | |
120 | " to reset.\n", phydev->addr); | |
121 | } | |
122 | ||
2915609a | 123 | switch (phydev->addr) { |
a836626c | 124 | case CONFIG_SYS_FM1_10GEC1_PHY_ADDR: |
2915609a AF |
125 | device = XAUI_FM1; |
126 | break; | |
a836626c | 127 | case CONFIG_SYS_FM2_10GEC1_PHY_ADDR: |
2915609a AF |
128 | device = XAUI_FM2; |
129 | break; | |
130 | default: | |
131 | device = NONE; | |
132 | } | |
133 | ||
134 | serdes_reset_rx(device); | |
135 | } | |
136 | ||
137 | return 0; | |
138 | } | |
139 | #endif | |
140 | ||
141 | struct p4080ds_mdio { | |
142 | u32 muxval; | |
143 | struct mii_dev *realbus; | |
144 | }; | |
145 | ||
146 | static void p4080ds_mux_mdio(u32 muxval) | |
147 | { | |
148 | ccsr_gpio_t *pgpio = (void *)(CONFIG_SYS_MPC85xx_GPIO_ADDR); | |
149 | uint gpioval = in_be32(&pgpio->gpdat) & ~(EMI_MASK); | |
150 | gpioval |= muxval; | |
151 | ||
152 | out_be32(&pgpio->gpdat, gpioval); | |
153 | } | |
154 | ||
155 | static int p4080ds_mdio_read(struct mii_dev *bus, int addr, int devad, | |
156 | int regnum) | |
157 | { | |
158 | struct p4080ds_mdio *priv = bus->priv; | |
159 | ||
160 | p4080ds_mux_mdio(priv->muxval); | |
161 | ||
162 | return priv->realbus->read(priv->realbus, addr, devad, regnum); | |
163 | } | |
164 | ||
165 | static int p4080ds_mdio_write(struct mii_dev *bus, int addr, int devad, | |
166 | int regnum, u16 value) | |
167 | { | |
168 | struct p4080ds_mdio *priv = bus->priv; | |
169 | ||
170 | p4080ds_mux_mdio(priv->muxval); | |
171 | ||
172 | return priv->realbus->write(priv->realbus, addr, devad, regnum, value); | |
173 | } | |
174 | ||
175 | static int p4080ds_mdio_reset(struct mii_dev *bus) | |
176 | { | |
177 | struct p4080ds_mdio *priv = bus->priv; | |
178 | ||
179 | return priv->realbus->reset(priv->realbus); | |
180 | } | |
181 | ||
182 | static int p4080ds_mdio_init(char *realbusname, u32 muxval) | |
183 | { | |
184 | struct p4080ds_mdio *pmdio; | |
185 | struct mii_dev *bus = mdio_alloc(); | |
186 | ||
187 | if (!bus) { | |
188 | printf("Failed to allocate P4080DS MDIO bus\n"); | |
189 | return -1; | |
190 | } | |
191 | ||
192 | pmdio = malloc(sizeof(*pmdio)); | |
193 | if (!pmdio) { | |
194 | printf("Failed to allocate P4080DS private data\n"); | |
195 | free(bus); | |
196 | return -1; | |
197 | } | |
198 | ||
199 | bus->read = p4080ds_mdio_read; | |
200 | bus->write = p4080ds_mdio_write; | |
201 | bus->reset = p4080ds_mdio_reset; | |
202 | sprintf(bus->name, p4080ds_mdio_name_for_muxval(muxval)); | |
203 | ||
204 | pmdio->realbus = miiphy_get_dev_by_name(realbusname); | |
205 | ||
206 | if (!pmdio->realbus) { | |
207 | printf("No bus with name %s\n", realbusname); | |
208 | free(bus); | |
209 | free(pmdio); | |
210 | return -1; | |
211 | } | |
212 | ||
213 | pmdio->muxval = muxval; | |
214 | bus->priv = pmdio; | |
215 | ||
216 | return mdio_register(bus); | |
217 | } | |
218 | ||
2915609a AF |
219 | void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, |
220 | enum fm_port port, int offset) | |
221 | { | |
222 | if (mdio_mux[port] == EMI1_RGMII) | |
223 | fdt_set_phy_handle(blob, prop, pa, "phy_rgmii"); | |
224 | ||
225 | if (mdio_mux[port] == EMI1_SLOT3) { | |
226 | int idx = port - FM2_DTSEC1 + 5; | |
227 | char phy[16]; | |
228 | ||
229 | sprintf(phy, "phy%d_slot3", idx); | |
230 | ||
231 | fdt_set_phy_handle(blob, prop, pa, phy); | |
232 | } | |
233 | } | |
234 | ||
235 | void fdt_fixup_board_enet(void *fdt) | |
236 | { | |
237 | int i; | |
238 | ||
239 | /* | |
240 | * P4080DS can be configured in many different ways, supporting a number | |
241 | * of combinations of ethernet devices and phy types. In order to | |
242 | * have just one device tree for all of those configurations, we fix up | |
243 | * the tree here. By default, the device tree configures FM1 and FM2 | |
244 | * for SGMII, and configures XAUI on both 10G interfaces. So we have | |
245 | * a number of different variables to track: | |
246 | * | |
247 | * 1) Whether the device is configured at all. Whichever devices are | |
248 | * not enabled should be disabled by setting the "status" property | |
249 | * to "disabled". | |
250 | * 2) What the PHY interface is. If this is an RGMII connection, | |
251 | * we should change the "phy-connection-type" property to | |
252 | * "rgmii" | |
253 | * 3) Which PHY is being used. Because the MDIO buses are muxed, | |
254 | * we need to redirect the "phy-handle" property to point at the | |
255 | * PHY on the right slot/bus. | |
256 | */ | |
257 | ||
258 | /* We've got six MDIO nodes that may or may not need to exist */ | |
2a523f52 SL |
259 | fdt_status_disabled_by_alias(fdt, "emi1_slot3"); |
260 | fdt_status_disabled_by_alias(fdt, "emi1_slot4"); | |
261 | fdt_status_disabled_by_alias(fdt, "emi1_slot5"); | |
262 | fdt_status_disabled_by_alias(fdt, "emi2_slot4"); | |
263 | fdt_status_disabled_by_alias(fdt, "emi2_slot5"); | |
2915609a AF |
264 | |
265 | for (i = 0; i < NUM_FM_PORTS; i++) { | |
266 | switch (mdio_mux[i]) { | |
267 | case EMI1_SLOT3: | |
2a523f52 | 268 | fdt_status_okay_by_alias(fdt, "emi1_slot3"); |
2915609a AF |
269 | break; |
270 | case EMI1_SLOT4: | |
2a523f52 | 271 | fdt_status_okay_by_alias(fdt, "emi1_slot4"); |
2915609a AF |
272 | break; |
273 | case EMI1_SLOT5: | |
2a523f52 | 274 | fdt_status_okay_by_alias(fdt, "emi1_slot5"); |
2915609a AF |
275 | break; |
276 | case EMI2_SLOT4: | |
2a523f52 | 277 | fdt_status_okay_by_alias(fdt, "emi2_slot4"); |
2915609a AF |
278 | break; |
279 | case EMI2_SLOT5: | |
2a523f52 | 280 | fdt_status_okay_by_alias(fdt, "emi2_slot5"); |
2915609a AF |
281 | break; |
282 | } | |
283 | } | |
284 | } | |
285 | ||
2915609a AF |
286 | int board_eth_init(bd_t *bis) |
287 | { | |
288 | #ifdef CONFIG_FMAN_ENET | |
289 | ccsr_gpio_t *pgpio = (void *)(CONFIG_SYS_MPC85xx_GPIO_ADDR); | |
2915609a AF |
290 | int i; |
291 | struct fsl_pq_mdio_info dtsec_mdio_info; | |
292 | struct tgec_mdio_info tgec_mdio_info; | |
293 | ||
2915609a AF |
294 | /* Initialize the mdio_mux array so we can recognize empty elements */ |
295 | for (i = 0; i < NUM_FM_PORTS; i++) | |
296 | mdio_mux[i] = EMI_NONE; | |
297 | ||
298 | /* The first 4 GPIOs are outputs to control MDIO bus muxing */ | |
299 | out_be32(&pgpio->gpdir, EMI_MASK); | |
300 | ||
301 | dtsec_mdio_info.regs = | |
302 | (struct tsec_mii_mng *)CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR; | |
303 | dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME; | |
304 | ||
305 | /* Register the 1G MDIO bus */ | |
306 | fsl_pq_mdio_init(bis, &dtsec_mdio_info); | |
307 | ||
308 | tgec_mdio_info.regs = | |
309 | (struct tgec_mdio_controller *)CONFIG_SYS_FM1_TGEC_MDIO_ADDR; | |
310 | tgec_mdio_info.name = DEFAULT_FM_TGEC_MDIO_NAME; | |
311 | ||
312 | /* Register the 10G MDIO bus */ | |
313 | fm_tgec_mdio_init(bis, &tgec_mdio_info); | |
314 | ||
315 | /* Register the 6 muxing front-ends to the MDIO buses */ | |
316 | p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_RGMII); | |
317 | p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT3); | |
318 | p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT4); | |
319 | p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT5); | |
320 | p4080ds_mdio_init(DEFAULT_FM_TGEC_MDIO_NAME, EMI2_SLOT4); | |
321 | p4080ds_mdio_init(DEFAULT_FM_TGEC_MDIO_NAME, EMI2_SLOT5); | |
322 | ||
323 | fm_info_set_phy_address(FM1_DTSEC1, CONFIG_SYS_FM1_DTSEC1_PHY_ADDR); | |
324 | fm_info_set_phy_address(FM1_DTSEC2, CONFIG_SYS_FM1_DTSEC2_PHY_ADDR); | |
325 | fm_info_set_phy_address(FM1_DTSEC3, CONFIG_SYS_FM1_DTSEC3_PHY_ADDR); | |
326 | fm_info_set_phy_address(FM1_DTSEC4, CONFIG_SYS_FM1_DTSEC4_PHY_ADDR); | |
327 | fm_info_set_phy_address(FM1_10GEC1, CONFIG_SYS_FM1_10GEC1_PHY_ADDR); | |
328 | ||
329 | #if (CONFIG_SYS_NUM_FMAN == 2) | |
330 | fm_info_set_phy_address(FM2_DTSEC1, CONFIG_SYS_FM2_DTSEC1_PHY_ADDR); | |
331 | fm_info_set_phy_address(FM2_DTSEC2, CONFIG_SYS_FM2_DTSEC2_PHY_ADDR); | |
332 | fm_info_set_phy_address(FM2_DTSEC3, CONFIG_SYS_FM2_DTSEC3_PHY_ADDR); | |
333 | fm_info_set_phy_address(FM2_DTSEC4, CONFIG_SYS_FM2_DTSEC4_PHY_ADDR); | |
334 | fm_info_set_phy_address(FM2_10GEC1, CONFIG_SYS_FM2_10GEC1_PHY_ADDR); | |
335 | #endif | |
336 | ||
337 | for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) { | |
338 | int idx = i - FM1_DTSEC1, lane, slot; | |
339 | switch (fm_info_get_enet_if(i)) { | |
340 | case PHY_INTERFACE_MODE_SGMII: | |
341 | lane = serdes_get_first_lane(SGMII_FM1_DTSEC1 + idx); | |
342 | if (lane < 0) | |
343 | break; | |
344 | slot = lane_to_slot[lane]; | |
345 | switch (slot) { | |
61fc52b6 | 346 | case 3: |
2915609a AF |
347 | mdio_mux[i] = EMI1_SLOT3; |
348 | fm_info_set_mdio(i, | |
349 | mii_dev_for_muxval(mdio_mux[i])); | |
350 | break; | |
61fc52b6 | 351 | case 4: |
2915609a AF |
352 | mdio_mux[i] = EMI1_SLOT4; |
353 | fm_info_set_mdio(i, | |
354 | mii_dev_for_muxval(mdio_mux[i])); | |
355 | break; | |
61fc52b6 | 356 | case 5: |
2915609a AF |
357 | mdio_mux[i] = EMI1_SLOT5; |
358 | fm_info_set_mdio(i, | |
359 | mii_dev_for_muxval(mdio_mux[i])); | |
360 | break; | |
361 | }; | |
362 | break; | |
363 | case PHY_INTERFACE_MODE_RGMII: | |
364 | fm_info_set_phy_address(i, 0); | |
365 | mdio_mux[i] = EMI1_RGMII; | |
366 | fm_info_set_mdio(i, | |
367 | mii_dev_for_muxval(mdio_mux[i])); | |
368 | break; | |
369 | default: | |
370 | break; | |
371 | } | |
372 | } | |
373 | ||
374 | for (i = FM1_10GEC1; i < FM1_10GEC1 + CONFIG_SYS_NUM_FM1_10GEC; i++) { | |
375 | int idx = i - FM1_10GEC1, lane, slot; | |
376 | switch (fm_info_get_enet_if(i)) { | |
377 | case PHY_INTERFACE_MODE_XGMII: | |
378 | lane = serdes_get_first_lane(XAUI_FM1 + idx); | |
379 | if (lane < 0) | |
380 | break; | |
381 | slot = lane_to_slot[lane]; | |
382 | switch (slot) { | |
61fc52b6 | 383 | case 4: |
2915609a AF |
384 | mdio_mux[i] = EMI2_SLOT4; |
385 | fm_info_set_mdio(i, | |
386 | mii_dev_for_muxval(mdio_mux[i])); | |
387 | break; | |
61fc52b6 | 388 | case 5: |
2915609a AF |
389 | mdio_mux[i] = EMI2_SLOT5; |
390 | fm_info_set_mdio(i, | |
391 | mii_dev_for_muxval(mdio_mux[i])); | |
392 | break; | |
393 | }; | |
394 | break; | |
395 | default: | |
396 | break; | |
397 | } | |
398 | } | |
399 | ||
400 | #if (CONFIG_SYS_NUM_FMAN == 2) | |
401 | for (i = FM2_DTSEC1; i < FM2_DTSEC1 + CONFIG_SYS_NUM_FM2_DTSEC; i++) { | |
402 | int idx = i - FM2_DTSEC1, lane, slot; | |
403 | switch (fm_info_get_enet_if(i)) { | |
404 | case PHY_INTERFACE_MODE_SGMII: | |
405 | lane = serdes_get_first_lane(SGMII_FM2_DTSEC1 + idx); | |
406 | if (lane < 0) | |
407 | break; | |
408 | slot = lane_to_slot[lane]; | |
409 | switch (slot) { | |
61fc52b6 | 410 | case 3: |
2915609a AF |
411 | mdio_mux[i] = EMI1_SLOT3; |
412 | fm_info_set_mdio(i, | |
413 | mii_dev_for_muxval(mdio_mux[i])); | |
414 | break; | |
61fc52b6 | 415 | case 4: |
2915609a AF |
416 | mdio_mux[i] = EMI1_SLOT4; |
417 | fm_info_set_mdio(i, | |
418 | mii_dev_for_muxval(mdio_mux[i])); | |
419 | break; | |
61fc52b6 | 420 | case 5: |
2915609a AF |
421 | mdio_mux[i] = EMI1_SLOT5; |
422 | fm_info_set_mdio(i, | |
423 | mii_dev_for_muxval(mdio_mux[i])); | |
424 | break; | |
425 | }; | |
426 | break; | |
427 | case PHY_INTERFACE_MODE_RGMII: | |
428 | fm_info_set_phy_address(i, 0); | |
429 | mdio_mux[i] = EMI1_RGMII; | |
430 | fm_info_set_mdio(i, | |
431 | mii_dev_for_muxval(mdio_mux[i])); | |
432 | break; | |
433 | default: | |
434 | break; | |
435 | } | |
436 | } | |
437 | ||
438 | for (i = FM2_10GEC1; i < FM2_10GEC1 + CONFIG_SYS_NUM_FM2_10GEC; i++) { | |
439 | int idx = i - FM2_10GEC1, lane, slot; | |
440 | switch (fm_info_get_enet_if(i)) { | |
441 | case PHY_INTERFACE_MODE_XGMII: | |
442 | lane = serdes_get_first_lane(XAUI_FM2 + idx); | |
443 | if (lane < 0) | |
444 | break; | |
445 | slot = lane_to_slot[lane]; | |
446 | switch (slot) { | |
61fc52b6 | 447 | case 4: |
2915609a AF |
448 | mdio_mux[i] = EMI2_SLOT4; |
449 | fm_info_set_mdio(i, | |
450 | mii_dev_for_muxval(mdio_mux[i])); | |
451 | break; | |
61fc52b6 | 452 | case 5: |
2915609a AF |
453 | mdio_mux[i] = EMI2_SLOT5; |
454 | fm_info_set_mdio(i, | |
455 | mii_dev_for_muxval(mdio_mux[i])); | |
456 | break; | |
457 | }; | |
458 | break; | |
459 | default: | |
460 | break; | |
461 | } | |
462 | } | |
463 | #endif | |
464 | ||
465 | cpu_eth_init(bis); | |
466 | #endif /* CONFIG_FMAN_ENET */ | |
467 | ||
468 | return pci_eth_init(bis); | |
469 | } |