1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2011-2015 Freescale Semiconductor, Inc.
9 #include <fdt_support.h>
11 #ifdef CONFIG_FSL_LAYERSCAPE
12 #include <asm/arch/fsl_serdes.h>
14 #include <asm/fsl_serdes.h>
20 struct fm_eth_info fm_info
[] = {
21 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 1)
22 FM_DTSEC_INFO_INITIALIZER(1, 1),
24 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 2)
25 FM_DTSEC_INFO_INITIALIZER(1, 2),
27 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 3)
28 FM_DTSEC_INFO_INITIALIZER(1, 3),
30 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 4)
31 FM_DTSEC_INFO_INITIALIZER(1, 4),
33 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 5)
34 FM_DTSEC_INFO_INITIALIZER(1, 5),
36 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 6)
37 FM_DTSEC_INFO_INITIALIZER(1, 6),
39 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 7)
40 FM_DTSEC_INFO_INITIALIZER(1, 9),
42 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 8)
43 FM_DTSEC_INFO_INITIALIZER(1, 10),
45 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 1)
46 FM_DTSEC_INFO_INITIALIZER(2, 1),
48 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 2)
49 FM_DTSEC_INFO_INITIALIZER(2, 2),
51 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 3)
52 FM_DTSEC_INFO_INITIALIZER(2, 3),
54 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 4)
55 FM_DTSEC_INFO_INITIALIZER(2, 4),
57 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 5)
58 FM_DTSEC_INFO_INITIALIZER(2, 5),
60 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 6)
61 FM_DTSEC_INFO_INITIALIZER(2, 6),
63 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 7)
64 FM_DTSEC_INFO_INITIALIZER(2, 9),
66 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 8)
67 FM_DTSEC_INFO_INITIALIZER(2, 10),
69 #if (CONFIG_SYS_NUM_FM1_10GEC >= 1)
70 FM_TGEC_INFO_INITIALIZER(1, 1),
72 #if (CONFIG_SYS_NUM_FM1_10GEC >= 2)
73 FM_TGEC_INFO_INITIALIZER(1, 2),
75 #if (CONFIG_SYS_NUM_FM1_10GEC >= 3)
76 FM_TGEC_INFO_INITIALIZER2(1, 3),
78 #if (CONFIG_SYS_NUM_FM1_10GEC >= 4)
79 FM_TGEC_INFO_INITIALIZER2(1, 4),
81 #if (CONFIG_SYS_NUM_FM2_10GEC >= 1)
82 FM_TGEC_INFO_INITIALIZER(2, 1),
84 #if (CONFIG_SYS_NUM_FM2_10GEC >= 2)
85 FM_TGEC_INFO_INITIALIZER(2, 2),
89 int fm_standard_init(bd_t
*bis
)
92 struct ccsr_fman
*reg
;
94 reg
= (void *)CONFIG_SYS_FSL_FM1_ADDR
;
95 if (fm_init_common(0, reg
))
98 for (i
= 0; i
< ARRAY_SIZE(fm_info
); i
++) {
99 if ((fm_info
[i
].enabled
) && (fm_info
[i
].index
== 1))
100 fm_eth_initialize(reg
, &fm_info
[i
]);
103 #if (CONFIG_SYS_NUM_FMAN == 2)
104 reg
= (void *)CONFIG_SYS_FSL_FM2_ADDR
;
105 if (fm_init_common(1, reg
))
108 for (i
= 0; i
< ARRAY_SIZE(fm_info
); i
++) {
109 if ((fm_info
[i
].enabled
) && (fm_info
[i
].index
== 2))
110 fm_eth_initialize(reg
, &fm_info
[i
]);
117 /* simple linear search to map from port to array index */
118 static int fm_port_to_index(enum fm_port port
)
122 for (i
= 0; i
< ARRAY_SIZE(fm_info
); i
++) {
123 if (fm_info
[i
].port
== port
)
131 * Determine if an interface is actually active based on HW config
132 * we expect fman_port_enet_if() to report PHY_INTERFACE_MODE_NONE if
133 * the interface is not active based on HW cfg of the SoC
135 void fman_enet_init(void)
139 for (i
= 0; i
< ARRAY_SIZE(fm_info
); i
++) {
140 phy_interface_t enet_if
;
142 enet_if
= fman_port_enet_if(fm_info
[i
].port
);
143 if (enet_if
!= PHY_INTERFACE_MODE_NONE
) {
144 fm_info
[i
].enabled
= 1;
145 fm_info
[i
].enet_if
= enet_if
;
147 fm_info
[i
].enabled
= 0;
154 void fm_disable_port(enum fm_port port
)
156 int i
= fm_port_to_index(port
);
161 fm_info
[i
].enabled
= 0;
162 #ifndef CONFIG_SYS_FMAN_V3
163 fman_disable_port(port
);
167 void fm_enable_port(enum fm_port port
)
169 int i
= fm_port_to_index(port
);
174 fm_info
[i
].enabled
= 1;
175 fman_enable_port(port
);
178 void fm_info_set_mdio(enum fm_port port
, struct mii_dev
*bus
)
180 int i
= fm_port_to_index(port
);
185 fm_info
[i
].bus
= bus
;
188 void fm_info_set_phy_address(enum fm_port port
, int address
)
190 int i
= fm_port_to_index(port
);
195 fm_info
[i
].phy_addr
= address
;
199 * Returns the PHY address for a given Fman port
201 * The port must be set via a prior call to fm_info_set_phy_address().
202 * A negative error code is returned if the port is invalid.
204 int fm_info_get_phy_address(enum fm_port port
)
206 int i
= fm_port_to_index(port
);
211 return fm_info
[i
].phy_addr
;
215 * Returns the type of the data interface between the given MAC and its PHY.
216 * This is typically determined by the RCW.
218 phy_interface_t
fm_info_get_enet_if(enum fm_port port
)
220 int i
= fm_port_to_index(port
);
223 return PHY_INTERFACE_MODE_NONE
;
225 if (fm_info
[i
].enabled
)
226 return fm_info
[i
].enet_if
;
228 return PHY_INTERFACE_MODE_NONE
;
232 __def_board_ft_fman_fixup_port(void *blob
, char * prop
, phys_addr_t pa
,
233 enum fm_port port
, int offset
)
238 void board_ft_fman_fixup_port(void *blob
, char * prop
, phys_addr_t pa
,
239 enum fm_port port
, int offset
)
240 __attribute__((weak
, alias("__def_board_ft_fman_fixup_port")));
242 int ft_fixup_port(void *blob
, struct fm_eth_info
*info
, char *prop
)
246 phys_addr_t paddr
= CONFIG_SYS_CCSRBAR_PHYS
+ info
->compat_offset
;
247 #ifndef CONFIG_SYS_FMAN_V3
248 u64 dtsec1_addr
= (u64
)CONFIG_SYS_CCSRBAR_PHYS
+
249 CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET
;
252 off
= fdt_node_offset_by_compat_reg(blob
, prop
, paddr
);
253 if (off
== -FDT_ERR_NOTFOUND
)
257 fdt_fixup_phy_connection(blob
, off
, info
->enet_if
);
258 board_ft_fman_fixup_port(blob
, prop
, paddr
, info
->port
, off
);
262 #ifdef CONFIG_SYS_FMAN_V3
263 #ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
265 * On T2/T4 SoCs, physically FM1_DTSEC9 and FM1_10GEC1 use the same
266 * dual-role MAC, when FM1_10GEC1 is enabled and FM1_DTSEC9
267 * is disabled, ensure that the dual-role MAC is not disabled,
268 * ditto for other dual-role MACs.
270 if (((info
->port
== FM1_DTSEC9
) && (PORT_IS_ENABLED(FM1_10GEC1
))) ||
271 ((info
->port
== FM1_DTSEC10
) && (PORT_IS_ENABLED(FM1_10GEC2
))) ||
272 ((info
->port
== FM1_DTSEC1
) && (PORT_IS_ENABLED(FM1_10GEC3
))) ||
273 ((info
->port
== FM1_DTSEC2
) && (PORT_IS_ENABLED(FM1_10GEC4
))) ||
274 ((info
->port
== FM1_10GEC1
) && (PORT_IS_ENABLED(FM1_DTSEC9
))) ||
275 ((info
->port
== FM1_10GEC2
) && (PORT_IS_ENABLED(FM1_DTSEC10
))) ||
276 ((info
->port
== FM1_10GEC3
) && (PORT_IS_ENABLED(FM1_DTSEC1
))) ||
277 ((info
->port
== FM1_10GEC4
) && (PORT_IS_ENABLED(FM1_DTSEC2
)))
278 #if (CONFIG_SYS_NUM_FMAN == 2)
280 ((info
->port
== FM2_DTSEC9
) && (PORT_IS_ENABLED(FM2_10GEC1
))) ||
281 ((info
->port
== FM2_DTSEC10
) && (PORT_IS_ENABLED(FM2_10GEC2
))) ||
282 ((info
->port
== FM2_10GEC1
) && (PORT_IS_ENABLED(FM2_DTSEC9
))) ||
283 ((info
->port
== FM2_10GEC2
) && (PORT_IS_ENABLED(FM2_DTSEC10
)))
286 /* FM1_DTSECx and FM1_10GECx use the same dual-role MAC */
287 if (((info
->port
== FM1_DTSEC1
) && (PORT_IS_ENABLED(FM1_10GEC1
))) ||
288 ((info
->port
== FM1_DTSEC2
) && (PORT_IS_ENABLED(FM1_10GEC2
))) ||
289 ((info
->port
== FM1_DTSEC3
) && (PORT_IS_ENABLED(FM1_10GEC3
))) ||
290 ((info
->port
== FM1_DTSEC4
) && (PORT_IS_ENABLED(FM1_10GEC4
))) ||
291 ((info
->port
== FM1_10GEC1
) && (PORT_IS_ENABLED(FM1_DTSEC1
))) ||
292 ((info
->port
== FM1_10GEC2
) && (PORT_IS_ENABLED(FM1_DTSEC2
))) ||
293 ((info
->port
== FM1_10GEC3
) && (PORT_IS_ENABLED(FM1_DTSEC3
))) ||
294 ((info
->port
== FM1_10GEC4
) && (PORT_IS_ENABLED(FM1_DTSEC4
)))
299 /* board code might have caused offset to change */
300 off
= fdt_node_offset_by_compat_reg(blob
, prop
, paddr
);
302 #ifndef CONFIG_SYS_FMAN_V3
303 /* Don't disable FM1-DTSEC1 MAC as its used for MDIO */
304 if (paddr
!= dtsec1_addr
)
306 fdt_status_disabled(blob
, off
); /* disable the MAC node */
308 /* disable the fsl,dpa-ethernet node that points to the MAC */
309 ph
= fdt_get_phandle(blob
, off
);
310 do_fixup_by_prop(blob
, "fsl,fman-mac", &ph
, sizeof(ph
),
311 "status", "disabled", strlen("disabled") + 1, 1);
316 void fdt_fixup_fman_ethernet(void *blob
)
320 #ifdef CONFIG_SYS_FMAN_V3
321 for (i
= 0; i
< ARRAY_SIZE(fm_info
); i
++)
322 ft_fixup_port(blob
, &fm_info
[i
], "fsl,fman-memac");
324 for (i
= 0; i
< ARRAY_SIZE(fm_info
); i
++) {
325 /* Try the new compatible first.
326 * If the node is missing, try the old.
328 if (fm_info
[i
].type
== FM_ETH_1G_E
) {
329 if (ft_fixup_port(blob
, &fm_info
[i
], "fsl,fman-dtsec"))
330 ft_fixup_port(blob
, &fm_info
[i
],
333 if (ft_fixup_port(blob
, &fm_info
[i
], "fsl,fman-xgec") &&
334 ft_fixup_port(blob
, &fm_info
[i
], "fsl,fman-tgec"))
335 ft_fixup_port(blob
, &fm_info
[i
],
342 /*QSGMII Riser Card can work in SGMII mode, but the PHY address is different.
343 *This function scans which Riser Card being used(QSGMII or SGMII Riser Card),
344 *then set the correct PHY address
346 void set_sgmii_phy(struct mii_dev
*bus
, enum fm_port base_port
,
347 unsigned int port_num
, int phy_base_addr
)
349 unsigned int regnum
= 0;
354 qsgmii
= is_qsgmii_riser_card(bus
, phy_base_addr
, port_num
, regnum
);
359 for (i
= base_port
; i
< base_port
+ port_num
; i
++) {
360 if (fm_info_get_enet_if(i
) == PHY_INTERFACE_MODE_SGMII
) {
361 phy_real_addr
= phy_base_addr
+ i
- base_port
;
362 fm_info_set_phy_address(i
, phy_real_addr
);
367 /*to check whether qsgmii riser card is used*/
368 int is_qsgmii_riser_card(struct mii_dev
*bus
, int phy_base_addr
,
369 unsigned int port_num
, unsigned regnum
)
377 for (i
= phy_base_addr
; i
< phy_base_addr
+ port_num
; i
++) {
378 val
= bus
->read(bus
, i
, MDIO_DEVAD_NONE
, regnum
);
379 if (val
!= MIIM_TIMEOUT
)
385 #endif /* CONFIG_DM_ETH */