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