1 /* 2 * Copyright 2011 Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <errno.h> 7 #include <common.h> 8 #include <asm/io.h> 9 #include <asm/fsl_serdes.h> 10 #include <fsl_mdio.h> 11 12 #include "fm.h" 13 14 struct fm_eth_info fm_info[] = { 15 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 1) 16 FM_DTSEC_INFO_INITIALIZER(1, 1), 17 #endif 18 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 2) 19 FM_DTSEC_INFO_INITIALIZER(1, 2), 20 #endif 21 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 3) 22 FM_DTSEC_INFO_INITIALIZER(1, 3), 23 #endif 24 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 4) 25 FM_DTSEC_INFO_INITIALIZER(1, 4), 26 #endif 27 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 5) 28 FM_DTSEC_INFO_INITIALIZER(1, 5), 29 #endif 30 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 6) 31 FM_DTSEC_INFO_INITIALIZER(1, 6), 32 #endif 33 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 7) 34 FM_DTSEC_INFO_INITIALIZER(1, 9), 35 #endif 36 #if (CONFIG_SYS_NUM_FM1_DTSEC >= 8) 37 FM_DTSEC_INFO_INITIALIZER(1, 10), 38 #endif 39 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 1) 40 FM_DTSEC_INFO_INITIALIZER(2, 1), 41 #endif 42 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 2) 43 FM_DTSEC_INFO_INITIALIZER(2, 2), 44 #endif 45 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 3) 46 FM_DTSEC_INFO_INITIALIZER(2, 3), 47 #endif 48 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 4) 49 FM_DTSEC_INFO_INITIALIZER(2, 4), 50 #endif 51 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 5) 52 FM_DTSEC_INFO_INITIALIZER(2, 5), 53 #endif 54 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 6) 55 FM_DTSEC_INFO_INITIALIZER(2, 6), 56 #endif 57 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 7) 58 FM_DTSEC_INFO_INITIALIZER(2, 9), 59 #endif 60 #if (CONFIG_SYS_NUM_FM2_DTSEC >= 8) 61 FM_DTSEC_INFO_INITIALIZER(2, 10), 62 #endif 63 #if (CONFIG_SYS_NUM_FM1_10GEC >= 1) 64 FM_TGEC_INFO_INITIALIZER(1, 1), 65 #endif 66 #if (CONFIG_SYS_NUM_FM1_10GEC >= 2) 67 FM_TGEC_INFO_INITIALIZER(1, 2), 68 #endif 69 #if (CONFIG_SYS_NUM_FM1_10GEC >= 3) 70 FM_TGEC_INFO_INITIALIZER2(1, 3), 71 #endif 72 #if (CONFIG_SYS_NUM_FM1_10GEC >= 4) 73 FM_TGEC_INFO_INITIALIZER2(1, 4), 74 #endif 75 #if (CONFIG_SYS_NUM_FM2_10GEC >= 1) 76 FM_TGEC_INFO_INITIALIZER(2, 1), 77 #endif 78 #if (CONFIG_SYS_NUM_FM2_10GEC >= 2) 79 FM_TGEC_INFO_INITIALIZER(2, 2), 80 #endif 81 }; 82 83 int fm_standard_init(bd_t *bis) 84 { 85 int i; 86 struct ccsr_fman *reg; 87 88 reg = (void *)CONFIG_SYS_FSL_FM1_ADDR; 89 if (fm_init_common(0, reg)) 90 return 0; 91 92 for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 93 if ((fm_info[i].enabled) && (fm_info[i].index == 1)) 94 fm_eth_initialize(reg, &fm_info[i]); 95 } 96 97 #if (CONFIG_SYS_NUM_FMAN == 2) 98 reg = (void *)CONFIG_SYS_FSL_FM2_ADDR; 99 if (fm_init_common(1, reg)) 100 return 0; 101 102 for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 103 if ((fm_info[i].enabled) && (fm_info[i].index == 2)) 104 fm_eth_initialize(reg, &fm_info[i]); 105 } 106 #endif 107 108 return 1; 109 } 110 111 /* simple linear search to map from port to array index */ 112 static int fm_port_to_index(enum fm_port port) 113 { 114 int i; 115 116 for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 117 if (fm_info[i].port == port) 118 return i; 119 } 120 121 return -1; 122 } 123 124 /* 125 * Determine if an interface is actually active based on HW config 126 * we expect fman_port_enet_if() to report PHY_INTERFACE_MODE_NONE if 127 * the interface is not active based on HW cfg of the SoC 128 */ 129 void fman_enet_init(void) 130 { 131 int i; 132 133 for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 134 phy_interface_t enet_if; 135 136 enet_if = fman_port_enet_if(fm_info[i].port); 137 if (enet_if != PHY_INTERFACE_MODE_NONE) { 138 fm_info[i].enabled = 1; 139 fm_info[i].enet_if = enet_if; 140 } else { 141 fm_info[i].enabled = 0; 142 } 143 } 144 145 return ; 146 } 147 148 void fm_disable_port(enum fm_port port) 149 { 150 int i = fm_port_to_index(port); 151 152 if (i == -1) 153 return; 154 155 fm_info[i].enabled = 0; 156 fman_disable_port(port); 157 } 158 159 void fm_enable_port(enum fm_port port) 160 { 161 int i = fm_port_to_index(port); 162 163 if (i == -1) 164 return; 165 166 fm_info[i].enabled = 1; 167 fman_enable_port(port); 168 } 169 170 void fm_info_set_mdio(enum fm_port port, struct mii_dev *bus) 171 { 172 int i = fm_port_to_index(port); 173 174 if (i == -1) 175 return; 176 177 fm_info[i].bus = bus; 178 } 179 180 void fm_info_set_phy_address(enum fm_port port, int address) 181 { 182 int i = fm_port_to_index(port); 183 184 if (i == -1) 185 return; 186 187 fm_info[i].phy_addr = address; 188 } 189 190 /* 191 * Returns the PHY address for a given Fman port 192 * 193 * The port must be set via a prior call to fm_info_set_phy_address(). 194 * A negative error code is returned if the port is invalid. 195 */ 196 int fm_info_get_phy_address(enum fm_port port) 197 { 198 int i = fm_port_to_index(port); 199 200 if (i == -1) 201 return -1; 202 203 return fm_info[i].phy_addr; 204 } 205 206 /* 207 * Returns the type of the data interface between the given MAC and its PHY. 208 * This is typically determined by the RCW. 209 */ 210 phy_interface_t fm_info_get_enet_if(enum fm_port port) 211 { 212 int i = fm_port_to_index(port); 213 214 if (i == -1) 215 return PHY_INTERFACE_MODE_NONE; 216 217 if (fm_info[i].enabled) 218 return fm_info[i].enet_if; 219 220 return PHY_INTERFACE_MODE_NONE; 221 } 222 223 static void 224 __def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, 225 enum fm_port port, int offset) 226 { 227 return ; 228 } 229 230 void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, 231 enum fm_port port, int offset) 232 __attribute__((weak, alias("__def_board_ft_fman_fixup_port"))); 233 234 int ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) 235 { 236 int off; 237 uint32_t ph; 238 phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset; 239 u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS + 240 CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET; 241 242 off = fdt_node_offset_by_compat_reg(blob, prop, paddr); 243 if (off == -FDT_ERR_NOTFOUND) 244 return -EINVAL; 245 246 if (info->enabled) { 247 fdt_fixup_phy_connection(blob, off, info->enet_if); 248 board_ft_fman_fixup_port(blob, prop, paddr, info->port, off); 249 return 0; 250 } 251 252 #ifdef CONFIG_SYS_FMAN_V3 253 #ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION 254 /* 255 * On T2/T4 SoCs, physically FM1_DTSEC9 and FM1_10GEC1 use the same 256 * dual-role MAC, when FM1_10GEC1 is enabled and FM1_DTSEC9 257 * is disabled, ensure that the dual-role MAC is not disabled, 258 * ditto for other dual-role MACs. 259 */ 260 if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) || 261 ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) || 262 ((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC3))) || 263 ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC4))) || 264 ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) || 265 ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) || 266 ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC1))) || 267 ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC2))) 268 #if (CONFIG_SYS_NUM_FMAN == 2) 269 || 270 ((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) || 271 ((info->port == FM2_DTSEC10) && (PORT_IS_ENABLED(FM2_10GEC2))) || 272 ((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) || 273 ((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10))) 274 #endif 275 #else 276 /* FM1_DTSECx and FM1_10GECx use the same dual-role MAC */ 277 if (((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC1))) || 278 ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC2))) || 279 ((info->port == FM1_DTSEC3) && (PORT_IS_ENABLED(FM1_10GEC3))) || 280 ((info->port == FM1_DTSEC4) && (PORT_IS_ENABLED(FM1_10GEC4))) || 281 ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC1))) || 282 ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC2))) || 283 ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC3))) || 284 ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC4))) 285 #endif 286 ) 287 return 0; 288 #endif 289 /* board code might have caused offset to change */ 290 off = fdt_node_offset_by_compat_reg(blob, prop, paddr); 291 292 /* Don't disable FM1-DTSEC1 MAC as its used for MDIO */ 293 if (paddr != dtsec1_addr) 294 fdt_status_disabled(blob, off); /* disable the MAC node */ 295 296 /* disable the fsl,dpa-ethernet node that points to the MAC */ 297 ph = fdt_get_phandle(blob, off); 298 do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph), 299 "status", "disabled", strlen("disabled") + 1, 1); 300 301 return 0; 302 } 303 304 void fdt_fixup_fman_ethernet(void *blob) 305 { 306 int i; 307 308 #ifdef CONFIG_SYS_FMAN_V3 309 for (i = 0; i < ARRAY_SIZE(fm_info); i++) 310 ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac"); 311 #else 312 for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 313 /* Try the new compatible first. 314 * If the node is missing, try the old. 315 */ 316 if (fm_info[i].type == FM_ETH_1G_E) { 317 if (ft_fixup_port(blob, &fm_info[i], "fsl,fman-dtsec")) 318 ft_fixup_port(blob, &fm_info[i], 319 "fsl,fman-1g-mac"); 320 } else { 321 if (ft_fixup_port(blob, &fm_info[i], "fsl,fman-tgec")) 322 ft_fixup_port(blob, &fm_info[i], 323 "fsl,fman-10g-mac"); 324 } 325 } 326 #endif 327 } 328 329 /*QSGMII Riser Card can work in SGMII mode, but the PHY address is different. 330 *This function scans which Riser Card being used(QSGMII or SGMII Riser Card), 331 *then set the correct PHY address 332 */ 333 void set_sgmii_phy(struct mii_dev *bus, enum fm_port base_port, 334 unsigned int port_num, int phy_base_addr) 335 { 336 unsigned int regnum = 0; 337 int qsgmii; 338 int i; 339 int phy_real_addr; 340 341 qsgmii = is_qsgmii_riser_card(bus, phy_base_addr, port_num, regnum); 342 343 if (!qsgmii) 344 return; 345 346 for (i = base_port; i < base_port + port_num; i++) { 347 if (fm_info_get_enet_if(i) == PHY_INTERFACE_MODE_SGMII) { 348 phy_real_addr = phy_base_addr + i - base_port; 349 fm_info_set_phy_address(i, phy_real_addr); 350 } 351 } 352 } 353 354 /*to check whether qsgmii riser card is used*/ 355 int is_qsgmii_riser_card(struct mii_dev *bus, int phy_base_addr, 356 unsigned int port_num, unsigned regnum) 357 { 358 int i; 359 int val; 360 361 if (!bus) 362 return 0; 363 364 for (i = phy_base_addr; i < phy_base_addr + port_num; i++) { 365 val = bus->read(bus, i, MDIO_DEVAD_NONE, regnum); 366 if (val != MIIM_TIMEOUT) 367 return 1; 368 } 369 370 return 0; 371 } 372