]>
Commit | Line | Data |
---|---|---|
126fe70d SX |
1 | /* |
2 | * Copyright 2016 Freescale Semiconductor, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <asm/io.h> | |
9 | #include <netdev.h> | |
10 | #include <fdt_support.h> | |
11 | #include <fm_eth.h> | |
12 | #include <fsl_mdio.h> | |
13 | #include <fsl_dtsec.h> | |
14 | #include <malloc.h> | |
15 | #include <asm/arch/fsl_serdes.h> | |
16 | ||
17 | #include "../common/qixis.h" | |
18 | #include "../common/fman.h" | |
19 | #include "ls1046aqds_qixis.h" | |
20 | ||
21 | #define EMI_NONE 0xFF | |
22 | #define EMI1_RGMII1 0 | |
23 | #define EMI1_RGMII2 1 | |
24 | #define EMI1_SLOT1 2 | |
25 | #define EMI1_SLOT2 3 | |
26 | #define EMI1_SLOT4 4 | |
27 | ||
28 | static int mdio_mux[NUM_FM_PORTS]; | |
29 | ||
30 | static const char * const mdio_names[] = { | |
31 | "LS1046AQDS_MDIO_RGMII1", | |
32 | "LS1046AQDS_MDIO_RGMII2", | |
33 | "LS1046AQDS_MDIO_SLOT1", | |
34 | "LS1046AQDS_MDIO_SLOT2", | |
35 | "LS1046AQDS_MDIO_SLOT4", | |
36 | "NULL", | |
37 | }; | |
38 | ||
39 | /* Map SerDes 1 & 2 lanes to default slot. */ | |
40 | static u8 lane_to_slot[] = {1, 1, 1, 1, 0, 4, 0 , 0}; | |
41 | ||
42 | static const char *ls1046aqds_mdio_name_for_muxval(u8 muxval) | |
43 | { | |
44 | return mdio_names[muxval]; | |
45 | } | |
46 | ||
47 | struct mii_dev *mii_dev_for_muxval(u8 muxval) | |
48 | { | |
49 | struct mii_dev *bus; | |
50 | const char *name; | |
51 | ||
52 | if (muxval > EMI1_SLOT4) | |
53 | return NULL; | |
54 | ||
55 | name = ls1046aqds_mdio_name_for_muxval(muxval); | |
56 | ||
57 | if (!name) { | |
58 | printf("No bus for muxval %x\n", muxval); | |
59 | return NULL; | |
60 | } | |
61 | ||
62 | bus = miiphy_get_dev_by_name(name); | |
63 | ||
64 | if (!bus) { | |
65 | printf("No bus by name %s\n", name); | |
66 | return NULL; | |
67 | } | |
68 | ||
69 | return bus; | |
70 | } | |
71 | ||
72 | struct ls1046aqds_mdio { | |
73 | u8 muxval; | |
74 | struct mii_dev *realbus; | |
75 | }; | |
76 | ||
77 | static void ls1046aqds_mux_mdio(u8 muxval) | |
78 | { | |
79 | u8 brdcfg4; | |
80 | ||
81 | if (muxval < 7) { | |
82 | brdcfg4 = QIXIS_READ(brdcfg[4]); | |
83 | brdcfg4 &= ~BRDCFG4_EMISEL_MASK; | |
84 | brdcfg4 |= (muxval << BRDCFG4_EMISEL_SHIFT); | |
85 | QIXIS_WRITE(brdcfg[4], brdcfg4); | |
86 | } | |
87 | } | |
88 | ||
89 | static int ls1046aqds_mdio_read(struct mii_dev *bus, int addr, int devad, | |
90 | int regnum) | |
91 | { | |
92 | struct ls1046aqds_mdio *priv = bus->priv; | |
93 | ||
94 | ls1046aqds_mux_mdio(priv->muxval); | |
95 | ||
96 | return priv->realbus->read(priv->realbus, addr, devad, regnum); | |
97 | } | |
98 | ||
99 | static int ls1046aqds_mdio_write(struct mii_dev *bus, int addr, int devad, | |
100 | int regnum, u16 value) | |
101 | { | |
102 | struct ls1046aqds_mdio *priv = bus->priv; | |
103 | ||
104 | ls1046aqds_mux_mdio(priv->muxval); | |
105 | ||
106 | return priv->realbus->write(priv->realbus, addr, devad, | |
107 | regnum, value); | |
108 | } | |
109 | ||
110 | static int ls1046aqds_mdio_reset(struct mii_dev *bus) | |
111 | { | |
112 | struct ls1046aqds_mdio *priv = bus->priv; | |
113 | ||
114 | return priv->realbus->reset(priv->realbus); | |
115 | } | |
116 | ||
117 | static int ls1046aqds_mdio_init(char *realbusname, u8 muxval) | |
118 | { | |
119 | struct ls1046aqds_mdio *pmdio; | |
120 | struct mii_dev *bus = mdio_alloc(); | |
121 | ||
122 | if (!bus) { | |
123 | printf("Failed to allocate ls1046aqds MDIO bus\n"); | |
124 | return -1; | |
125 | } | |
126 | ||
127 | pmdio = malloc(sizeof(*pmdio)); | |
128 | if (!pmdio) { | |
129 | printf("Failed to allocate ls1046aqds private data\n"); | |
130 | free(bus); | |
131 | return -1; | |
132 | } | |
133 | ||
134 | bus->read = ls1046aqds_mdio_read; | |
135 | bus->write = ls1046aqds_mdio_write; | |
136 | bus->reset = ls1046aqds_mdio_reset; | |
137 | sprintf(bus->name, ls1046aqds_mdio_name_for_muxval(muxval)); | |
138 | ||
139 | pmdio->realbus = miiphy_get_dev_by_name(realbusname); | |
140 | ||
141 | if (!pmdio->realbus) { | |
142 | printf("No bus with name %s\n", realbusname); | |
143 | free(bus); | |
144 | free(pmdio); | |
145 | return -1; | |
146 | } | |
147 | ||
148 | pmdio->muxval = muxval; | |
149 | bus->priv = pmdio; | |
150 | return mdio_register(bus); | |
151 | } | |
152 | ||
153 | void board_ft_fman_fixup_port(void *fdt, char *compat, phys_addr_t addr, | |
154 | enum fm_port port, int offset) | |
155 | { | |
156 | struct fixed_link f_link; | |
157 | ||
158 | if (fm_info_get_enet_if(port) == PHY_INTERFACE_MODE_SGMII) { | |
159 | switch (port) { | |
160 | case FM1_DTSEC9: | |
161 | fdt_set_phy_handle(fdt, compat, addr, "sgmii_s1_p1"); | |
162 | break; | |
163 | case FM1_DTSEC10: | |
164 | fdt_set_phy_handle(fdt, compat, addr, "sgmii_s1_p2"); | |
165 | break; | |
166 | case FM1_DTSEC5: | |
167 | fdt_set_phy_handle(fdt, compat, addr, "sgmii_s1_p3"); | |
168 | break; | |
169 | case FM1_DTSEC6: | |
170 | fdt_set_phy_handle(fdt, compat, addr, "sgmii_s1_p4"); | |
171 | break; | |
172 | case FM1_DTSEC2: | |
173 | fdt_set_phy_handle(fdt, compat, addr, "sgmii_s4_p1"); | |
174 | break; | |
175 | default: | |
176 | break; | |
177 | } | |
178 | } else if (fm_info_get_enet_if(port) == PHY_INTERFACE_MODE_SGMII_2500) { | |
179 | /* 2.5G SGMII interface */ | |
180 | f_link.phy_id = cpu_to_fdt32(port); | |
181 | f_link.duplex = cpu_to_fdt32(1); | |
182 | f_link.link_speed = cpu_to_fdt32(1000); | |
183 | f_link.pause = 0; | |
184 | f_link.asym_pause = 0; | |
185 | /* no PHY for 2.5G SGMII on QDS */ | |
186 | fdt_delprop(fdt, offset, "phy-handle"); | |
187 | fdt_setprop(fdt, offset, "fixed-link", &f_link, sizeof(f_link)); | |
188 | fdt_setprop_string(fdt, offset, "phy-connection-type", | |
189 | "sgmii-2500"); | |
190 | } else if (fm_info_get_enet_if(port) == PHY_INTERFACE_MODE_QSGMII) { | |
191 | switch (port) { | |
192 | case FM1_DTSEC1: | |
193 | fdt_set_phy_handle(fdt, compat, addr, "qsgmii_s2_p4"); | |
194 | break; | |
195 | case FM1_DTSEC5: | |
196 | fdt_set_phy_handle(fdt, compat, addr, "qsgmii_s2_p2"); | |
197 | break; | |
198 | case FM1_DTSEC6: | |
199 | fdt_set_phy_handle(fdt, compat, addr, "qsgmii_s2_p1"); | |
200 | break; | |
201 | case FM1_DTSEC10: | |
202 | fdt_set_phy_handle(fdt, compat, addr, "qsgmii_s2_p3"); | |
203 | break; | |
204 | default: | |
205 | break; | |
206 | } | |
207 | fdt_delprop(fdt, offset, "phy-connection-type"); | |
208 | fdt_setprop_string(fdt, offset, "phy-connection-type", | |
209 | "qsgmii"); | |
210 | } else if (fm_info_get_enet_if(port) == PHY_INTERFACE_MODE_XGMII && | |
211 | (port == FM1_10GEC1 || port == FM1_10GEC2)) { | |
212 | /* XFI interface */ | |
213 | f_link.phy_id = cpu_to_fdt32(port); | |
214 | f_link.duplex = cpu_to_fdt32(1); | |
215 | f_link.link_speed = cpu_to_fdt32(10000); | |
216 | f_link.pause = 0; | |
217 | f_link.asym_pause = 0; | |
218 | /* no PHY for XFI */ | |
219 | fdt_delprop(fdt, offset, "phy-handle"); | |
220 | fdt_setprop(fdt, offset, "fixed-link", &f_link, sizeof(f_link)); | |
221 | fdt_setprop_string(fdt, offset, "phy-connection-type", "xgmii"); | |
222 | } | |
223 | } | |
224 | ||
225 | void fdt_fixup_board_enet(void *fdt) | |
226 | { | |
227 | int i; | |
228 | ||
229 | for (i = FM1_DTSEC1; i < NUM_FM_PORTS; i++) { | |
230 | switch (fm_info_get_enet_if(i)) { | |
231 | case PHY_INTERFACE_MODE_SGMII: | |
232 | case PHY_INTERFACE_MODE_QSGMII: | |
233 | switch (mdio_mux[i]) { | |
234 | case EMI1_SLOT1: | |
235 | fdt_status_okay_by_alias(fdt, "emi1_slot1"); | |
236 | break; | |
237 | case EMI1_SLOT2: | |
238 | fdt_status_okay_by_alias(fdt, "emi1_slot2"); | |
239 | break; | |
240 | case EMI1_SLOT4: | |
241 | fdt_status_okay_by_alias(fdt, "emi1_slot4"); | |
242 | break; | |
243 | default: | |
244 | break; | |
245 | } | |
246 | break; | |
247 | default: | |
248 | break; | |
249 | } | |
250 | } | |
251 | } | |
252 | ||
253 | int board_eth_init(bd_t *bis) | |
254 | { | |
255 | #ifdef CONFIG_FMAN_ENET | |
256 | int i, idx, lane, slot, interface; | |
257 | struct memac_mdio_info dtsec_mdio_info; | |
258 | struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); | |
259 | u32 srds_s1, srds_s2; | |
260 | u8 brdcfg12; | |
261 | ||
262 | srds_s1 = in_be32(&gur->rcwsr[4]) & | |
263 | FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; | |
264 | srds_s1 >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT; | |
265 | ||
266 | srds_s2 = in_be32(&gur->rcwsr[4]) & | |
267 | FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_MASK; | |
268 | srds_s2 >>= FSL_CHASSIS2_RCWSR4_SRDS2_PRTCL_SHIFT; | |
269 | ||
270 | /* Initialize the mdio_mux array so we can recognize empty elements */ | |
271 | for (i = 0; i < NUM_FM_PORTS; i++) | |
272 | mdio_mux[i] = EMI_NONE; | |
273 | ||
274 | dtsec_mdio_info.regs = | |
275 | (struct memac_mdio_controller *)CONFIG_SYS_FM1_DTSEC_MDIO_ADDR; | |
276 | ||
277 | dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME; | |
278 | ||
279 | /* Register the 1G MDIO bus */ | |
280 | fm_memac_mdio_init(bis, &dtsec_mdio_info); | |
281 | ||
282 | /* Register the muxing front-ends to the MDIO buses */ | |
283 | ls1046aqds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_RGMII1); | |
284 | ls1046aqds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_RGMII2); | |
285 | ls1046aqds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT1); | |
286 | ls1046aqds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT2); | |
287 | ls1046aqds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT4); | |
288 | ||
289 | /* Set the two on-board RGMII PHY address */ | |
290 | fm_info_set_phy_address(FM1_DTSEC3, RGMII_PHY1_ADDR); | |
291 | fm_info_set_phy_address(FM1_DTSEC4, RGMII_PHY2_ADDR); | |
292 | ||
293 | switch (srds_s1) { | |
294 | case 0x3333: | |
295 | /* SGMII on slot 1, MAC 9 */ | |
296 | fm_info_set_phy_address(FM1_DTSEC9, SGMII_CARD_PORT1_PHY_ADDR); | |
297 | case 0x1333: | |
298 | case 0x2333: | |
299 | /* SGMII on slot 1, MAC 10 */ | |
300 | fm_info_set_phy_address(FM1_DTSEC10, SGMII_CARD_PORT2_PHY_ADDR); | |
301 | case 0x1133: | |
302 | case 0x2233: | |
303 | /* SGMII on slot 1, MAC 5/6 */ | |
304 | fm_info_set_phy_address(FM1_DTSEC5, SGMII_CARD_PORT3_PHY_ADDR); | |
305 | fm_info_set_phy_address(FM1_DTSEC6, SGMII_CARD_PORT4_PHY_ADDR); | |
306 | break; | |
307 | case 0x1040: | |
308 | case 0x2040: | |
309 | /* QSGMII on lane B, MAC 6/5/10/1 */ | |
310 | fm_info_set_phy_address(FM1_DTSEC6, | |
311 | QSGMII_CARD_PORT1_PHY_ADDR_S2); | |
312 | fm_info_set_phy_address(FM1_DTSEC5, | |
313 | QSGMII_CARD_PORT2_PHY_ADDR_S2); | |
314 | fm_info_set_phy_address(FM1_DTSEC10, | |
315 | QSGMII_CARD_PORT3_PHY_ADDR_S2); | |
316 | fm_info_set_phy_address(FM1_DTSEC1, | |
317 | QSGMII_CARD_PORT4_PHY_ADDR_S2); | |
318 | break; | |
319 | case 0x3363: | |
320 | /* SGMII on slot 1, MAC 9/10 */ | |
321 | fm_info_set_phy_address(FM1_DTSEC9, SGMII_CARD_PORT1_PHY_ADDR); | |
322 | fm_info_set_phy_address(FM1_DTSEC10, SGMII_CARD_PORT2_PHY_ADDR); | |
323 | case 0x1163: | |
324 | case 0x2263: | |
325 | case 0x2223: | |
326 | /* SGMII on slot 1, MAC 6 */ | |
327 | fm_info_set_phy_address(FM1_DTSEC6, SGMII_CARD_PORT4_PHY_ADDR); | |
328 | break; | |
329 | default: | |
330 | printf("Invalid SerDes protocol 0x%x for LS1046AQDS\n", | |
331 | srds_s1); | |
332 | break; | |
333 | } | |
334 | ||
335 | if (srds_s2 == 0x5a59 || srds_s2 == 0x5a06) | |
336 | /* SGMII on slot 4, MAC 2 */ | |
337 | fm_info_set_phy_address(FM1_DTSEC2, SGMII_CARD_PORT1_PHY_ADDR); | |
338 | ||
339 | for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) { | |
340 | idx = i - FM1_DTSEC1; | |
341 | interface = fm_info_get_enet_if(i); | |
342 | switch (interface) { | |
343 | case PHY_INTERFACE_MODE_SGMII: | |
344 | case PHY_INTERFACE_MODE_QSGMII: | |
345 | if (interface == PHY_INTERFACE_MODE_SGMII) { | |
346 | if (i == FM1_DTSEC5) { | |
347 | /* route lane 2 to slot1 so to have | |
348 | * one sgmii riser card supports | |
349 | * MAC5 and MAC6. | |
350 | */ | |
351 | brdcfg12 = QIXIS_READ(brdcfg[12]); | |
352 | QIXIS_WRITE(brdcfg[12], | |
353 | brdcfg12 | 0x80); | |
354 | } | |
355 | lane = serdes_get_first_lane(FSL_SRDS_1, | |
356 | SGMII_FM1_DTSEC1 + idx); | |
357 | } else { | |
358 | /* clear the bit 7 to route lane B on slot2. */ | |
359 | brdcfg12 = QIXIS_READ(brdcfg[12]); | |
360 | QIXIS_WRITE(brdcfg[12], brdcfg12 & 0x7f); | |
361 | ||
362 | lane = serdes_get_first_lane(FSL_SRDS_1, | |
363 | QSGMII_FM1_A); | |
364 | lane_to_slot[lane] = 2; | |
365 | } | |
366 | ||
367 | if (i == FM1_DTSEC2) | |
368 | lane = 5; | |
369 | ||
370 | if (lane < 0) | |
371 | break; | |
372 | ||
373 | slot = lane_to_slot[lane]; | |
374 | debug("FM1@DTSEC%u expects SGMII in slot %u\n", | |
375 | idx + 1, slot); | |
376 | if (QIXIS_READ(present2) & (1 << (slot - 1))) | |
377 | fm_disable_port(i); | |
378 | ||
379 | switch (slot) { | |
380 | case 1: | |
381 | mdio_mux[i] = EMI1_SLOT1; | |
382 | fm_info_set_mdio(i, mii_dev_for_muxval( | |
383 | mdio_mux[i])); | |
384 | break; | |
385 | case 2: | |
386 | mdio_mux[i] = EMI1_SLOT2; | |
387 | fm_info_set_mdio(i, mii_dev_for_muxval( | |
388 | mdio_mux[i])); | |
389 | break; | |
390 | case 4: | |
391 | mdio_mux[i] = EMI1_SLOT4; | |
392 | fm_info_set_mdio(i, mii_dev_for_muxval( | |
393 | mdio_mux[i])); | |
394 | break; | |
395 | default: | |
396 | break; | |
397 | } | |
398 | break; | |
399 | case PHY_INTERFACE_MODE_RGMII: | |
400 | if (i == FM1_DTSEC3) | |
401 | mdio_mux[i] = EMI1_RGMII1; | |
402 | else if (i == FM1_DTSEC4) | |
403 | mdio_mux[i] = EMI1_RGMII2; | |
404 | fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); | |
405 | break; | |
406 | default: | |
407 | break; | |
408 | } | |
409 | } | |
410 | ||
411 | cpu_eth_init(bis); | |
412 | #endif /* CONFIG_FMAN_ENET */ | |
413 | ||
414 | return pci_eth_init(bis); | |
415 | } |