]>
Commit | Line | Data |
---|---|---|
0787ecc0 MH |
1 | /* |
2 | * Copyright 2011 Freescale Semiconductor, Inc. | |
3 | * Author: Mingkai Hu <Mingkai.hu@freescale.com> | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
0787ecc0 MH |
6 | */ |
7 | ||
8 | /* | |
9 | * The RGMII PHYs are provided by the two on-board PHY. The SGMII PHYs | |
10 | * are provided by the three on-board PHY or by the standard Freescale | |
11 | * four-port SGMII riser card. We need to change the phy-handle in the | |
12 | * kernel dts file to point to the correct PHY according to serdes mux | |
13 | * and serdes protocol selection. | |
14 | */ | |
15 | ||
16 | #include <common.h> | |
17 | #include <netdev.h> | |
18 | #include <asm/fsl_serdes.h> | |
19 | #include <fm_eth.h> | |
20 | #include <fsl_mdio.h> | |
21 | #include <malloc.h> | |
22 | #include <asm/fsl_dtsec.h> | |
23 | ||
24 | #include "cpld.h" | |
25 | #include "../common/fman.h" | |
26 | ||
27 | #ifdef CONFIG_FMAN_ENET | |
28 | /* | |
29 | * Mapping of all 18 SERDES lanes to board slots. A value of '0' here means | |
30 | * that the mapping must be determined dynamically, or that the lane maps to | |
31 | * something other than a board slot | |
32 | */ | |
33 | static u8 lane_to_slot[] = { | |
34 | 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0 | |
35 | }; | |
36 | ||
37 | static int riser_phy_addr[] = { | |
38 | CONFIG_SYS_FM1_DTSEC1_RISER_PHY_ADDR, | |
39 | CONFIG_SYS_FM1_DTSEC2_RISER_PHY_ADDR, | |
40 | CONFIG_SYS_FM1_DTSEC3_RISER_PHY_ADDR, | |
41 | CONFIG_SYS_FM1_DTSEC4_RISER_PHY_ADDR, | |
42 | }; | |
43 | ||
44 | /* | |
45 | * Initialize the lane_to_slot[] array. | |
46 | * | |
47 | * On the P2040RDB board the mapping is controlled by CPLD register. | |
48 | */ | |
49 | static void initialize_lane_to_slot(void) | |
50 | { | |
51 | u8 mux = CPLD_READ(serdes_mux); | |
52 | ||
53 | lane_to_slot[6] = (mux & SERDES_MUX_LANE_6_MASK) ? 0 : 1; | |
54 | lane_to_slot[10] = (mux & SERDES_MUX_LANE_A_MASK) ? 0 : 2; | |
55 | lane_to_slot[12] = (mux & SERDES_MUX_LANE_C_MASK) ? 0 : 2; | |
56 | lane_to_slot[13] = (mux & SERDES_MUX_LANE_D_MASK) ? 0 : 2; | |
57 | } | |
58 | ||
59 | /* | |
60 | * Given the following ... | |
61 | * | |
62 | * 1) A pointer to an Fman Ethernet node (as identified by the 'compat' | |
63 | * compatible string and 'addr' physical address) | |
64 | * | |
65 | * 2) An Fman port | |
66 | * | |
67 | * ... update the phy-handle property of the Ethernet node to point to the | |
68 | * right PHY. This assumes that we already know the PHY for each port. | |
69 | * | |
70 | * The offset of the Fman Ethernet node is also passed in for convenience, but | |
71 | * it is not used, and we recalculate the offset anyway. | |
72 | * | |
73 | * Note that what we call "Fman ports" (enum fm_port) is really an Fman MAC. | |
74 | * Inside the Fman, "ports" are things that connect to MACs. We only call them | |
75 | * ports in U-Boot because on previous Ethernet devices (e.g. Gianfar), MACs | |
76 | * and ports are the same thing. | |
77 | * | |
78 | */ | |
79 | void board_ft_fman_fixup_port(void *fdt, char *compat, phys_addr_t addr, | |
80 | enum fm_port port, int offset) | |
81 | { | |
82 | phy_interface_t intf = fm_info_get_enet_if(port); | |
83 | char phy[16]; | |
84 | ||
85 | /* The RGMII PHY is identified by the MAC connected to it */ | |
86 | if (intf == PHY_INTERFACE_MODE_RGMII) { | |
87 | sprintf(phy, "phy_rgmii_%u", port == FM1_DTSEC5 ? 0 : 1); | |
88 | fdt_set_phy_handle(fdt, compat, addr, phy); | |
89 | } | |
90 | ||
91 | /* The SGMII PHY is identified by the MAC connected to it */ | |
92 | if (intf == PHY_INTERFACE_MODE_SGMII) { | |
93 | int lane = serdes_get_first_lane(SGMII_FM1_DTSEC1 + port); | |
94 | u8 slot; | |
95 | if (lane < 0) | |
96 | return; | |
97 | slot = lane_to_slot[lane]; | |
98 | if (slot) { | |
99 | sprintf(phy, "phy_sgmii_%x", | |
100 | CONFIG_SYS_FM1_DTSEC1_RISER_PHY_ADDR | |
101 | + (port - FM1_DTSEC1)); | |
102 | fdt_set_phy_handle(fdt, compat, addr, phy); | |
103 | } else { | |
104 | sprintf(phy, "phy_sgmii_%x", | |
105 | CONFIG_SYS_FM1_DTSEC1_PHY_ADDR | |
106 | + (port - FM1_DTSEC1)); | |
107 | fdt_set_phy_handle(fdt, compat, addr, phy); | |
108 | } | |
109 | } | |
110 | ||
111 | if (intf == PHY_INTERFACE_MODE_XGMII) { | |
112 | /* XAUI */ | |
113 | int lane = serdes_get_first_lane(XAUI_FM1); | |
114 | if (lane >= 0) { | |
115 | /* The XAUI PHY is identified by the slot */ | |
116 | sprintf(phy, "phy_xgmii_%u", lane_to_slot[lane]); | |
117 | fdt_set_phy_handle(fdt, compat, addr, phy); | |
118 | } | |
119 | } | |
120 | } | |
121 | #endif /* #ifdef CONFIG_FMAN_ENET */ | |
122 | ||
123 | int board_eth_init(bd_t *bis) | |
124 | { | |
125 | #ifdef CONFIG_FMAN_ENET | |
0787ecc0 MH |
126 | struct fsl_pq_mdio_info dtsec_mdio_info; |
127 | struct tgec_mdio_info tgec_mdio_info; | |
128 | unsigned int i, slot; | |
129 | int lane; | |
130 | ||
131 | printf("Initializing Fman\n"); | |
132 | ||
133 | initialize_lane_to_slot(); | |
134 | ||
0787ecc0 MH |
135 | dtsec_mdio_info.regs = |
136 | (struct tsec_mii_mng *)CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR; | |
137 | dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME; | |
138 | ||
139 | /* Register the real 1G MDIO bus */ | |
140 | fsl_pq_mdio_init(bis, &dtsec_mdio_info); | |
141 | ||
142 | tgec_mdio_info.regs = | |
143 | (struct tgec_mdio_controller *)CONFIG_SYS_FM1_TGEC_MDIO_ADDR; | |
144 | tgec_mdio_info.name = DEFAULT_FM_TGEC_MDIO_NAME; | |
145 | ||
146 | /* Register the real 10G MDIO bus */ | |
147 | fm_tgec_mdio_init(bis, &tgec_mdio_info); | |
148 | ||
149 | /* | |
150 | * Program the three on-board SGMII PHY addresses. If the SGMII Riser | |
151 | * card used, we'll override the PHY address later. For any DTSEC that | |
152 | * is RGMII, we'll also override its PHY address later. We assume that | |
153 | * DTSEC4 and DTSEC5 are used for RGMII. | |
154 | */ | |
155 | fm_info_set_phy_address(FM1_DTSEC1, CONFIG_SYS_FM1_DTSEC1_PHY_ADDR); | |
156 | fm_info_set_phy_address(FM1_DTSEC2, CONFIG_SYS_FM1_DTSEC2_PHY_ADDR); | |
157 | fm_info_set_phy_address(FM1_DTSEC3, CONFIG_SYS_FM1_DTSEC3_PHY_ADDR); | |
158 | ||
159 | for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) { | |
160 | int idx = i - FM1_DTSEC1; | |
161 | ||
162 | switch (fm_info_get_enet_if(i)) { | |
163 | case PHY_INTERFACE_MODE_SGMII: | |
164 | lane = serdes_get_first_lane(SGMII_FM1_DTSEC1 + idx); | |
165 | if (lane < 0) | |
166 | break; | |
167 | slot = lane_to_slot[lane]; | |
168 | if (slot) | |
169 | fm_info_set_phy_address(i, riser_phy_addr[i]); | |
170 | break; | |
171 | case PHY_INTERFACE_MODE_RGMII: | |
172 | /* Only DTSEC4 and DTSEC5 can be routed to RGMII */ | |
173 | fm_info_set_phy_address(i, i == FM1_DTSEC5 ? | |
174 | CONFIG_SYS_FM1_DTSEC5_PHY_ADDR : | |
175 | CONFIG_SYS_FM1_DTSEC4_PHY_ADDR); | |
176 | break; | |
177 | default: | |
178 | printf("Fman1: DTSEC%u set to unknown interface %i\n", | |
179 | idx + 1, fm_info_get_enet_if(i)); | |
180 | break; | |
181 | } | |
182 | ||
183 | fm_info_set_mdio(i, | |
184 | miiphy_get_dev_by_name(DEFAULT_FM_MDIO_NAME)); | |
185 | } | |
186 | ||
187 | lane = serdes_get_first_lane(XAUI_FM1); | |
188 | if (lane >= 0) { | |
189 | slot = lane_to_slot[lane]; | |
190 | if (slot) | |
191 | fm_info_set_phy_address(FM1_10GEC1, | |
192 | CONFIG_SYS_FM1_10GEC1_PHY_ADDR); | |
193 | } | |
194 | ||
195 | fm_info_set_mdio(FM1_10GEC1, | |
196 | miiphy_get_dev_by_name(DEFAULT_FM_TGEC_MDIO_NAME)); | |
197 | cpu_eth_init(bis); | |
198 | #endif | |
199 | ||
200 | return pci_eth_init(bis); | |
201 | } |