1c916d7c9SKumar Gala /* 2c916d7c9SKumar Gala * Copyright 2011 Freescale Semiconductor, Inc. 3c916d7c9SKumar Gala * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 5c916d7c9SKumar Gala */ 6c916d7c9SKumar Gala #include <common.h> 7c916d7c9SKumar Gala #include <asm/io.h> 8c916d7c9SKumar Gala #include <asm/fsl_serdes.h> 9c916d7c9SKumar Gala 10c916d7c9SKumar Gala #include "fm.h" 11c916d7c9SKumar Gala 12c916d7c9SKumar Gala struct fm_eth_info fm_info[] = { 13c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM1_DTSEC >= 1) 14c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(1, 1), 15c916d7c9SKumar Gala #endif 16c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM1_DTSEC >= 2) 17c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(1, 2), 18c916d7c9SKumar Gala #endif 19c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM1_DTSEC >= 3) 20c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(1, 3), 21c916d7c9SKumar Gala #endif 22c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM1_DTSEC >= 4) 23c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(1, 4), 24c916d7c9SKumar Gala #endif 25c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM1_DTSEC >= 5) 26c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(1, 5), 27c916d7c9SKumar Gala #endif 289e758758SYork Sun #if (CONFIG_SYS_NUM_FM1_DTSEC >= 6) 299e758758SYork Sun FM_DTSEC_INFO_INITIALIZER(1, 6), 309e758758SYork Sun #endif 319e758758SYork Sun #if (CONFIG_SYS_NUM_FM1_DTSEC >= 7) 329e758758SYork Sun FM_DTSEC_INFO_INITIALIZER(1, 9), 339e758758SYork Sun #endif 349e758758SYork Sun #if (CONFIG_SYS_NUM_FM1_DTSEC >= 8) 359e758758SYork Sun FM_DTSEC_INFO_INITIALIZER(1, 10), 369e758758SYork Sun #endif 37c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM2_DTSEC >= 1) 38c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(2, 1), 39c916d7c9SKumar Gala #endif 40c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM2_DTSEC >= 2) 41c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(2, 2), 42c916d7c9SKumar Gala #endif 43c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM2_DTSEC >= 3) 44c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(2, 3), 45c916d7c9SKumar Gala #endif 46c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM2_DTSEC >= 4) 47c916d7c9SKumar Gala FM_DTSEC_INFO_INITIALIZER(2, 4), 48c916d7c9SKumar Gala #endif 4999abf7deSTimur Tabi #if (CONFIG_SYS_NUM_FM2_DTSEC >= 5) 5099abf7deSTimur Tabi FM_DTSEC_INFO_INITIALIZER(2, 5), 5199abf7deSTimur Tabi #endif 529e758758SYork Sun #if (CONFIG_SYS_NUM_FM2_DTSEC >= 6) 539e758758SYork Sun FM_DTSEC_INFO_INITIALIZER(2, 6), 549e758758SYork Sun #endif 559e758758SYork Sun #if (CONFIG_SYS_NUM_FM2_DTSEC >= 7) 569e758758SYork Sun FM_DTSEC_INFO_INITIALIZER(2, 9), 579e758758SYork Sun #endif 589e758758SYork Sun #if (CONFIG_SYS_NUM_FM2_DTSEC >= 8) 599e758758SYork Sun FM_DTSEC_INFO_INITIALIZER(2, 10), 609e758758SYork Sun #endif 61c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM1_10GEC >= 1) 62c916d7c9SKumar Gala FM_TGEC_INFO_INITIALIZER(1, 1), 63c916d7c9SKumar Gala #endif 64944b6ccfSShaohui Xie #if (CONFIG_SYS_NUM_FM1_10GEC >= 2) 65944b6ccfSShaohui Xie FM_TGEC_INFO_INITIALIZER(1, 2), 66944b6ccfSShaohui Xie #endif 67*82a55c1eSShengzhou Liu #if (CONFIG_SYS_NUM_FM1_10GEC >= 3) 68*82a55c1eSShengzhou Liu FM_TGEC_INFO_INITIALIZER2(1, 3), 69*82a55c1eSShengzhou Liu #endif 70*82a55c1eSShengzhou Liu #if (CONFIG_SYS_NUM_FM1_10GEC >= 4) 71*82a55c1eSShengzhou Liu FM_TGEC_INFO_INITIALIZER2(1, 4), 72*82a55c1eSShengzhou Liu #endif 73c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM2_10GEC >= 1) 74c916d7c9SKumar Gala FM_TGEC_INFO_INITIALIZER(2, 1), 75c916d7c9SKumar Gala #endif 76944b6ccfSShaohui Xie #if (CONFIG_SYS_NUM_FM2_10GEC >= 2) 77944b6ccfSShaohui Xie FM_TGEC_INFO_INITIALIZER(2, 2), 78944b6ccfSShaohui Xie #endif 79c916d7c9SKumar Gala }; 80c916d7c9SKumar Gala 81c916d7c9SKumar Gala int fm_standard_init(bd_t *bis) 82c916d7c9SKumar Gala { 83c916d7c9SKumar Gala int i; 84c916d7c9SKumar Gala struct ccsr_fman *reg; 85c916d7c9SKumar Gala 86c916d7c9SKumar Gala reg = (void *)CONFIG_SYS_FSL_FM1_ADDR; 87c916d7c9SKumar Gala if (fm_init_common(0, reg)) 88c916d7c9SKumar Gala return 0; 89c916d7c9SKumar Gala 90c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 91c916d7c9SKumar Gala if ((fm_info[i].enabled) && (fm_info[i].index == 1)) 92c916d7c9SKumar Gala fm_eth_initialize(reg, &fm_info[i]); 93c916d7c9SKumar Gala } 94c916d7c9SKumar Gala 95c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FMAN == 2) 96c916d7c9SKumar Gala reg = (void *)CONFIG_SYS_FSL_FM2_ADDR; 97c916d7c9SKumar Gala if (fm_init_common(1, reg)) 98c916d7c9SKumar Gala return 0; 99c916d7c9SKumar Gala 100c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 101c916d7c9SKumar Gala if ((fm_info[i].enabled) && (fm_info[i].index == 2)) 102c916d7c9SKumar Gala fm_eth_initialize(reg, &fm_info[i]); 103c916d7c9SKumar Gala } 104c916d7c9SKumar Gala #endif 105c916d7c9SKumar Gala 106c916d7c9SKumar Gala return 1; 107c916d7c9SKumar Gala } 108c916d7c9SKumar Gala 109c916d7c9SKumar Gala /* simple linear search to map from port to array index */ 110c916d7c9SKumar Gala static int fm_port_to_index(enum fm_port port) 111c916d7c9SKumar Gala { 112c916d7c9SKumar Gala int i; 113c916d7c9SKumar Gala 114c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 115c916d7c9SKumar Gala if (fm_info[i].port == port) 116c916d7c9SKumar Gala return i; 117c916d7c9SKumar Gala } 118c916d7c9SKumar Gala 119c916d7c9SKumar Gala return -1; 120c916d7c9SKumar Gala } 121c916d7c9SKumar Gala 122c916d7c9SKumar Gala /* 123c916d7c9SKumar Gala * Determine if an interface is actually active based on HW config 124c916d7c9SKumar Gala * we expect fman_port_enet_if() to report PHY_INTERFACE_MODE_NONE if 125c916d7c9SKumar Gala * the interface is not active based on HW cfg of the SoC 126c916d7c9SKumar Gala */ 127c916d7c9SKumar Gala void fman_enet_init(void) 128c916d7c9SKumar Gala { 129c916d7c9SKumar Gala int i; 130c916d7c9SKumar Gala 131c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 132c916d7c9SKumar Gala phy_interface_t enet_if; 133c916d7c9SKumar Gala 134c916d7c9SKumar Gala enet_if = fman_port_enet_if(fm_info[i].port); 135c916d7c9SKumar Gala if (enet_if != PHY_INTERFACE_MODE_NONE) { 136c916d7c9SKumar Gala fm_info[i].enabled = 1; 137c916d7c9SKumar Gala fm_info[i].enet_if = enet_if; 138c916d7c9SKumar Gala } else { 139c916d7c9SKumar Gala fm_info[i].enabled = 0; 140c916d7c9SKumar Gala } 141c916d7c9SKumar Gala } 142c916d7c9SKumar Gala 143c916d7c9SKumar Gala return ; 144c916d7c9SKumar Gala } 145c916d7c9SKumar Gala 14669a85242SKumar Gala void fm_disable_port(enum fm_port port) 14769a85242SKumar Gala { 14869a85242SKumar Gala int i = fm_port_to_index(port); 14969a85242SKumar Gala 15069a85242SKumar Gala fm_info[i].enabled = 0; 15169a85242SKumar Gala fman_disable_port(port); 15269a85242SKumar Gala } 15369a85242SKumar Gala 154f51d3b71SValentin Longchamp void fm_enable_port(enum fm_port port) 155f51d3b71SValentin Longchamp { 156f51d3b71SValentin Longchamp int i = fm_port_to_index(port); 157f51d3b71SValentin Longchamp 158f51d3b71SValentin Longchamp fm_info[i].enabled = 1; 159f51d3b71SValentin Longchamp fman_enable_port(port); 160f51d3b71SValentin Longchamp } 161f51d3b71SValentin Longchamp 162c916d7c9SKumar Gala void fm_info_set_mdio(enum fm_port port, struct mii_dev *bus) 163c916d7c9SKumar Gala { 164c916d7c9SKumar Gala int i = fm_port_to_index(port); 165c916d7c9SKumar Gala 166c916d7c9SKumar Gala if (i == -1) 167c916d7c9SKumar Gala return; 168c916d7c9SKumar Gala 169c916d7c9SKumar Gala fm_info[i].bus = bus; 170c916d7c9SKumar Gala } 171c916d7c9SKumar Gala 172c916d7c9SKumar Gala void fm_info_set_phy_address(enum fm_port port, int address) 173c916d7c9SKumar Gala { 174c916d7c9SKumar Gala int i = fm_port_to_index(port); 175c916d7c9SKumar Gala 176c916d7c9SKumar Gala if (i == -1) 177c916d7c9SKumar Gala return; 178c916d7c9SKumar Gala 179c916d7c9SKumar Gala fm_info[i].phy_addr = address; 180c916d7c9SKumar Gala } 181c916d7c9SKumar Gala 182c916d7c9SKumar Gala /* 183ae2291fbSTimur Tabi * Returns the PHY address for a given Fman port 184ae2291fbSTimur Tabi * 185ae2291fbSTimur Tabi * The port must be set via a prior call to fm_info_set_phy_address(). 186ae2291fbSTimur Tabi * A negative error code is returned if the port is invalid. 187ae2291fbSTimur Tabi */ 188ae2291fbSTimur Tabi int fm_info_get_phy_address(enum fm_port port) 189ae2291fbSTimur Tabi { 190ae2291fbSTimur Tabi int i = fm_port_to_index(port); 191ae2291fbSTimur Tabi 192ae2291fbSTimur Tabi if (i == -1) 193ae2291fbSTimur Tabi return -1; 194ae2291fbSTimur Tabi 195ae2291fbSTimur Tabi return fm_info[i].phy_addr; 196ae2291fbSTimur Tabi } 197ae2291fbSTimur Tabi 198ae2291fbSTimur Tabi /* 199c916d7c9SKumar Gala * Returns the type of the data interface between the given MAC and its PHY. 200c916d7c9SKumar Gala * This is typically determined by the RCW. 201c916d7c9SKumar Gala */ 202c916d7c9SKumar Gala phy_interface_t fm_info_get_enet_if(enum fm_port port) 203c916d7c9SKumar Gala { 204c916d7c9SKumar Gala int i = fm_port_to_index(port); 205c916d7c9SKumar Gala 206c916d7c9SKumar Gala if (i == -1) 207c916d7c9SKumar Gala return PHY_INTERFACE_MODE_NONE; 208c916d7c9SKumar Gala 209c916d7c9SKumar Gala if (fm_info[i].enabled) 210c916d7c9SKumar Gala return fm_info[i].enet_if; 211c916d7c9SKumar Gala 212c916d7c9SKumar Gala return PHY_INTERFACE_MODE_NONE; 213c916d7c9SKumar Gala } 214c916d7c9SKumar Gala 215c916d7c9SKumar Gala static void 216c916d7c9SKumar Gala __def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, 217c916d7c9SKumar Gala enum fm_port port, int offset) 218c916d7c9SKumar Gala { 219c916d7c9SKumar Gala return ; 220c916d7c9SKumar Gala } 221c916d7c9SKumar Gala 222c916d7c9SKumar Gala void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, 223c916d7c9SKumar Gala enum fm_port port, int offset) 224c916d7c9SKumar Gala __attribute__((weak, alias("__def_board_ft_fman_fixup_port"))); 225c916d7c9SKumar Gala 226c916d7c9SKumar Gala static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) 227c916d7c9SKumar Gala { 2284376b4c0STimur Tabi int off; 2294376b4c0STimur Tabi uint32_t ph; 230c916d7c9SKumar Gala phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset; 231e81c0abaSKumar Gala u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS + 232e81c0abaSKumar Gala CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET; 233c916d7c9SKumar Gala 234c916d7c9SKumar Gala off = fdt_node_offset_by_compat_reg(blob, prop, paddr); 235c916d7c9SKumar Gala 236c916d7c9SKumar Gala if (info->enabled) { 237c916d7c9SKumar Gala fdt_fixup_phy_connection(blob, off, info->enet_if); 238c916d7c9SKumar Gala board_ft_fman_fixup_port(blob, prop, paddr, info->port, off); 239c916d7c9SKumar Gala return ; 240c916d7c9SKumar Gala } 241c916d7c9SKumar Gala 242ae8a5d10SShengzhou Liu #ifdef CONFIG_SYS_FMAN_V3 243ae8a5d10SShengzhou Liu /* 244ae8a5d10SShengzhou Liu * Physically FM1_DTSEC9 and FM1_10GEC1 use the same dual-role MAC, when 245ae8a5d10SShengzhou Liu * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the 246ae8a5d10SShengzhou Liu * dual-role MAC is not disabled, ditto for other dual-role MACs. 247ae8a5d10SShengzhou Liu */ 248ae8a5d10SShengzhou Liu if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) || 249ae8a5d10SShengzhou Liu ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) || 250*82a55c1eSShengzhou Liu ((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC3))) || 251*82a55c1eSShengzhou Liu ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC4))) || 252ae8a5d10SShengzhou Liu ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) || 253*82a55c1eSShengzhou Liu ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) || 254*82a55c1eSShengzhou Liu ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC1))) || 255*82a55c1eSShengzhou Liu ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC2))) 256ae8a5d10SShengzhou Liu #if (CONFIG_SYS_NUM_FMAN == 2) 257ae8a5d10SShengzhou Liu || 258ae8a5d10SShengzhou Liu ((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) || 259ae8a5d10SShengzhou Liu ((info->port == FM2_DTSEC10) && (PORT_IS_ENABLED(FM2_10GEC2))) || 260ae8a5d10SShengzhou Liu ((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) || 261ae8a5d10SShengzhou Liu ((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10))) 262ae8a5d10SShengzhou Liu #endif 263ae8a5d10SShengzhou Liu ) 264ae8a5d10SShengzhou Liu return; 265ae8a5d10SShengzhou Liu #endif 266c916d7c9SKumar Gala /* board code might have caused offset to change */ 267c916d7c9SKumar Gala off = fdt_node_offset_by_compat_reg(blob, prop, paddr); 268c916d7c9SKumar Gala 269e81c0abaSKumar Gala /* Don't disable FM1-DTSEC1 MAC as its used for MDIO */ 2704376b4c0STimur Tabi if (paddr != dtsec1_addr) 2714376b4c0STimur Tabi fdt_status_disabled(blob, off); /* disable the MAC node */ 272c916d7c9SKumar Gala 2734376b4c0STimur Tabi /* disable the fsl,dpa-ethernet node that points to the MAC */ 274c916d7c9SKumar Gala ph = fdt_get_phandle(blob, off); 275c916d7c9SKumar Gala do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph), 276c916d7c9SKumar Gala "status", "disabled", strlen("disabled") + 1, 1); 277c916d7c9SKumar Gala } 278c916d7c9SKumar Gala 279c916d7c9SKumar Gala void fdt_fixup_fman_ethernet(void *blob) 280c916d7c9SKumar Gala { 281c916d7c9SKumar Gala int i; 282c916d7c9SKumar Gala 283ae8a5d10SShengzhou Liu #ifdef CONFIG_SYS_FMAN_V3 284ae8a5d10SShengzhou Liu for (i = 0; i < ARRAY_SIZE(fm_info); i++) 285ae8a5d10SShengzhou Liu ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac"); 286ae8a5d10SShengzhou Liu #else 287c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 288c916d7c9SKumar Gala if (fm_info[i].type == FM_ETH_1G_E) 289c916d7c9SKumar Gala ft_fixup_port(blob, &fm_info[i], "fsl,fman-1g-mac"); 290c916d7c9SKumar Gala else 291c916d7c9SKumar Gala ft_fixup_port(blob, &fm_info[i], "fsl,fman-10g-mac"); 292c916d7c9SKumar Gala } 293ae8a5d10SShengzhou Liu #endif 294c916d7c9SKumar Gala } 295ffee1ddeSZhao Qiang 296ffee1ddeSZhao Qiang /*QSGMII Riser Card can work in SGMII mode, but the PHY address is different. 297ffee1ddeSZhao Qiang *This function scans which Riser Card being used(QSGMII or SGMII Riser Card), 298ffee1ddeSZhao Qiang *then set the correct PHY address 299ffee1ddeSZhao Qiang */ 300ffee1ddeSZhao Qiang void set_sgmii_phy(struct mii_dev *bus, enum fm_port base_port, 301ffee1ddeSZhao Qiang unsigned int port_num, int phy_base_addr) 302ffee1ddeSZhao Qiang { 303ffee1ddeSZhao Qiang unsigned int regnum = 0; 304ffee1ddeSZhao Qiang int qsgmii; 305ffee1ddeSZhao Qiang int i; 306ffee1ddeSZhao Qiang int phy_real_addr; 307ffee1ddeSZhao Qiang 308ffee1ddeSZhao Qiang qsgmii = is_qsgmii_riser_card(bus, phy_base_addr, port_num, regnum); 309ffee1ddeSZhao Qiang 310ffee1ddeSZhao Qiang if (!qsgmii) 311ffee1ddeSZhao Qiang return; 312ffee1ddeSZhao Qiang 313ffee1ddeSZhao Qiang for (i = base_port; i < base_port + port_num; i++) { 314ffee1ddeSZhao Qiang if (fm_info_get_enet_if(i) == PHY_INTERFACE_MODE_SGMII) { 315ffee1ddeSZhao Qiang phy_real_addr = phy_base_addr + i - base_port; 316ffee1ddeSZhao Qiang fm_info_set_phy_address(i, phy_real_addr); 317ffee1ddeSZhao Qiang } 318ffee1ddeSZhao Qiang } 319ffee1ddeSZhao Qiang } 320ffee1ddeSZhao Qiang 321ffee1ddeSZhao Qiang /*to check whether qsgmii riser card is used*/ 322ffee1ddeSZhao Qiang int is_qsgmii_riser_card(struct mii_dev *bus, int phy_base_addr, 323ffee1ddeSZhao Qiang unsigned int port_num, unsigned regnum) 324ffee1ddeSZhao Qiang { 325ffee1ddeSZhao Qiang int i; 326ffee1ddeSZhao Qiang int val; 327ffee1ddeSZhao Qiang 328ffee1ddeSZhao Qiang if (!bus) 329ffee1ddeSZhao Qiang return 0; 330ffee1ddeSZhao Qiang 331ffee1ddeSZhao Qiang for (i = phy_base_addr; i < phy_base_addr + port_num; i++) { 332ffee1ddeSZhao Qiang val = bus->read(bus, i, MDIO_DEVAD_NONE, regnum); 333ffee1ddeSZhao Qiang if (val != MIIM_TIMEOUT) 334ffee1ddeSZhao Qiang return 1; 335ffee1ddeSZhao Qiang } 336ffee1ddeSZhao Qiang 337ffee1ddeSZhao Qiang return 0; 338ffee1ddeSZhao Qiang } 339