1c916d7c9SKumar Gala /* 2c916d7c9SKumar Gala * Copyright 2011 Freescale Semiconductor, Inc. 3c916d7c9SKumar Gala * 4*1a459660SWolfgang 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 67c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FM2_10GEC >= 1) 68c916d7c9SKumar Gala FM_TGEC_INFO_INITIALIZER(2, 1), 69c916d7c9SKumar Gala #endif 70944b6ccfSShaohui Xie #if (CONFIG_SYS_NUM_FM2_10GEC >= 2) 71944b6ccfSShaohui Xie FM_TGEC_INFO_INITIALIZER(2, 2), 72944b6ccfSShaohui Xie #endif 73c916d7c9SKumar Gala }; 74c916d7c9SKumar Gala 75c916d7c9SKumar Gala int fm_standard_init(bd_t *bis) 76c916d7c9SKumar Gala { 77c916d7c9SKumar Gala int i; 78c916d7c9SKumar Gala struct ccsr_fman *reg; 79c916d7c9SKumar Gala 80c916d7c9SKumar Gala reg = (void *)CONFIG_SYS_FSL_FM1_ADDR; 81c916d7c9SKumar Gala if (fm_init_common(0, reg)) 82c916d7c9SKumar Gala return 0; 83c916d7c9SKumar Gala 84c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 85c916d7c9SKumar Gala if ((fm_info[i].enabled) && (fm_info[i].index == 1)) 86c916d7c9SKumar Gala fm_eth_initialize(reg, &fm_info[i]); 87c916d7c9SKumar Gala } 88c916d7c9SKumar Gala 89c916d7c9SKumar Gala #if (CONFIG_SYS_NUM_FMAN == 2) 90c916d7c9SKumar Gala reg = (void *)CONFIG_SYS_FSL_FM2_ADDR; 91c916d7c9SKumar Gala if (fm_init_common(1, reg)) 92c916d7c9SKumar Gala return 0; 93c916d7c9SKumar Gala 94c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 95c916d7c9SKumar Gala if ((fm_info[i].enabled) && (fm_info[i].index == 2)) 96c916d7c9SKumar Gala fm_eth_initialize(reg, &fm_info[i]); 97c916d7c9SKumar Gala } 98c916d7c9SKumar Gala #endif 99c916d7c9SKumar Gala 100c916d7c9SKumar Gala return 1; 101c916d7c9SKumar Gala } 102c916d7c9SKumar Gala 103c916d7c9SKumar Gala /* simple linear search to map from port to array index */ 104c916d7c9SKumar Gala static int fm_port_to_index(enum fm_port port) 105c916d7c9SKumar Gala { 106c916d7c9SKumar Gala int i; 107c916d7c9SKumar Gala 108c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 109c916d7c9SKumar Gala if (fm_info[i].port == port) 110c916d7c9SKumar Gala return i; 111c916d7c9SKumar Gala } 112c916d7c9SKumar Gala 113c916d7c9SKumar Gala return -1; 114c916d7c9SKumar Gala } 115c916d7c9SKumar Gala 116c916d7c9SKumar Gala /* 117c916d7c9SKumar Gala * Determine if an interface is actually active based on HW config 118c916d7c9SKumar Gala * we expect fman_port_enet_if() to report PHY_INTERFACE_MODE_NONE if 119c916d7c9SKumar Gala * the interface is not active based on HW cfg of the SoC 120c916d7c9SKumar Gala */ 121c916d7c9SKumar Gala void fman_enet_init(void) 122c916d7c9SKumar Gala { 123c916d7c9SKumar Gala int i; 124c916d7c9SKumar Gala 125c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 126c916d7c9SKumar Gala phy_interface_t enet_if; 127c916d7c9SKumar Gala 128c916d7c9SKumar Gala enet_if = fman_port_enet_if(fm_info[i].port); 129c916d7c9SKumar Gala if (enet_if != PHY_INTERFACE_MODE_NONE) { 130c916d7c9SKumar Gala fm_info[i].enabled = 1; 131c916d7c9SKumar Gala fm_info[i].enet_if = enet_if; 132c916d7c9SKumar Gala } else { 133c916d7c9SKumar Gala fm_info[i].enabled = 0; 134c916d7c9SKumar Gala } 135c916d7c9SKumar Gala } 136c916d7c9SKumar Gala 137c916d7c9SKumar Gala return ; 138c916d7c9SKumar Gala } 139c916d7c9SKumar Gala 14069a85242SKumar Gala void fm_disable_port(enum fm_port port) 14169a85242SKumar Gala { 14269a85242SKumar Gala int i = fm_port_to_index(port); 14369a85242SKumar Gala 14469a85242SKumar Gala fm_info[i].enabled = 0; 14569a85242SKumar Gala fman_disable_port(port); 14669a85242SKumar Gala } 14769a85242SKumar Gala 148c916d7c9SKumar Gala void fm_info_set_mdio(enum fm_port port, struct mii_dev *bus) 149c916d7c9SKumar Gala { 150c916d7c9SKumar Gala int i = fm_port_to_index(port); 151c916d7c9SKumar Gala 152c916d7c9SKumar Gala if (i == -1) 153c916d7c9SKumar Gala return; 154c916d7c9SKumar Gala 155c916d7c9SKumar Gala fm_info[i].bus = bus; 156c916d7c9SKumar Gala } 157c916d7c9SKumar Gala 158c916d7c9SKumar Gala void fm_info_set_phy_address(enum fm_port port, int address) 159c916d7c9SKumar Gala { 160c916d7c9SKumar Gala int i = fm_port_to_index(port); 161c916d7c9SKumar Gala 162c916d7c9SKumar Gala if (i == -1) 163c916d7c9SKumar Gala return; 164c916d7c9SKumar Gala 165c916d7c9SKumar Gala fm_info[i].phy_addr = address; 166c916d7c9SKumar Gala } 167c916d7c9SKumar Gala 168c916d7c9SKumar Gala /* 169ae2291fbSTimur Tabi * Returns the PHY address for a given Fman port 170ae2291fbSTimur Tabi * 171ae2291fbSTimur Tabi * The port must be set via a prior call to fm_info_set_phy_address(). 172ae2291fbSTimur Tabi * A negative error code is returned if the port is invalid. 173ae2291fbSTimur Tabi */ 174ae2291fbSTimur Tabi int fm_info_get_phy_address(enum fm_port port) 175ae2291fbSTimur Tabi { 176ae2291fbSTimur Tabi int i = fm_port_to_index(port); 177ae2291fbSTimur Tabi 178ae2291fbSTimur Tabi if (i == -1) 179ae2291fbSTimur Tabi return -1; 180ae2291fbSTimur Tabi 181ae2291fbSTimur Tabi return fm_info[i].phy_addr; 182ae2291fbSTimur Tabi } 183ae2291fbSTimur Tabi 184ae2291fbSTimur Tabi /* 185c916d7c9SKumar Gala * Returns the type of the data interface between the given MAC and its PHY. 186c916d7c9SKumar Gala * This is typically determined by the RCW. 187c916d7c9SKumar Gala */ 188c916d7c9SKumar Gala phy_interface_t fm_info_get_enet_if(enum fm_port port) 189c916d7c9SKumar Gala { 190c916d7c9SKumar Gala int i = fm_port_to_index(port); 191c916d7c9SKumar Gala 192c916d7c9SKumar Gala if (i == -1) 193c916d7c9SKumar Gala return PHY_INTERFACE_MODE_NONE; 194c916d7c9SKumar Gala 195c916d7c9SKumar Gala if (fm_info[i].enabled) 196c916d7c9SKumar Gala return fm_info[i].enet_if; 197c916d7c9SKumar Gala 198c916d7c9SKumar Gala return PHY_INTERFACE_MODE_NONE; 199c916d7c9SKumar Gala } 200c916d7c9SKumar Gala 201c916d7c9SKumar Gala static void 202c916d7c9SKumar Gala __def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, 203c916d7c9SKumar Gala enum fm_port port, int offset) 204c916d7c9SKumar Gala { 205c916d7c9SKumar Gala return ; 206c916d7c9SKumar Gala } 207c916d7c9SKumar Gala 208c916d7c9SKumar Gala void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa, 209c916d7c9SKumar Gala enum fm_port port, int offset) 210c916d7c9SKumar Gala __attribute__((weak, alias("__def_board_ft_fman_fixup_port"))); 211c916d7c9SKumar Gala 212c916d7c9SKumar Gala static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) 213c916d7c9SKumar Gala { 2144376b4c0STimur Tabi int off; 2154376b4c0STimur Tabi uint32_t ph; 216c916d7c9SKumar Gala phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset; 217e81c0abaSKumar Gala u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS + 218e81c0abaSKumar Gala CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET; 219c916d7c9SKumar Gala 220c916d7c9SKumar Gala off = fdt_node_offset_by_compat_reg(blob, prop, paddr); 221c916d7c9SKumar Gala 222c916d7c9SKumar Gala if (info->enabled) { 223c916d7c9SKumar Gala fdt_fixup_phy_connection(blob, off, info->enet_if); 224c916d7c9SKumar Gala board_ft_fman_fixup_port(blob, prop, paddr, info->port, off); 225c916d7c9SKumar Gala return ; 226c916d7c9SKumar Gala } 227c916d7c9SKumar Gala 228ae8a5d10SShengzhou Liu #ifdef CONFIG_SYS_FMAN_V3 229ae8a5d10SShengzhou Liu /* 230ae8a5d10SShengzhou Liu * Physically FM1_DTSEC9 and FM1_10GEC1 use the same dual-role MAC, when 231ae8a5d10SShengzhou Liu * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the 232ae8a5d10SShengzhou Liu * dual-role MAC is not disabled, ditto for other dual-role MACs. 233ae8a5d10SShengzhou Liu */ 234ae8a5d10SShengzhou Liu if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) || 235ae8a5d10SShengzhou Liu ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) || 236ae8a5d10SShengzhou Liu ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) || 237ae8a5d10SShengzhou Liu ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) 238ae8a5d10SShengzhou Liu #if (CONFIG_SYS_NUM_FMAN == 2) 239ae8a5d10SShengzhou Liu || 240ae8a5d10SShengzhou Liu ((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) || 241ae8a5d10SShengzhou Liu ((info->port == FM2_DTSEC10) && (PORT_IS_ENABLED(FM2_10GEC2))) || 242ae8a5d10SShengzhou Liu ((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) || 243ae8a5d10SShengzhou Liu ((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10))) 244ae8a5d10SShengzhou Liu #endif 245ae8a5d10SShengzhou Liu ) 246ae8a5d10SShengzhou Liu return; 247ae8a5d10SShengzhou Liu #endif 248c916d7c9SKumar Gala /* board code might have caused offset to change */ 249c916d7c9SKumar Gala off = fdt_node_offset_by_compat_reg(blob, prop, paddr); 250c916d7c9SKumar Gala 251e81c0abaSKumar Gala /* Don't disable FM1-DTSEC1 MAC as its used for MDIO */ 2524376b4c0STimur Tabi if (paddr != dtsec1_addr) 2534376b4c0STimur Tabi fdt_status_disabled(blob, off); /* disable the MAC node */ 254c916d7c9SKumar Gala 2554376b4c0STimur Tabi /* disable the fsl,dpa-ethernet node that points to the MAC */ 256c916d7c9SKumar Gala ph = fdt_get_phandle(blob, off); 257c916d7c9SKumar Gala do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph), 258c916d7c9SKumar Gala "status", "disabled", strlen("disabled") + 1, 1); 259c916d7c9SKumar Gala } 260c916d7c9SKumar Gala 261c916d7c9SKumar Gala void fdt_fixup_fman_ethernet(void *blob) 262c916d7c9SKumar Gala { 263c916d7c9SKumar Gala int i; 264c916d7c9SKumar Gala 265ae8a5d10SShengzhou Liu #ifdef CONFIG_SYS_FMAN_V3 266ae8a5d10SShengzhou Liu for (i = 0; i < ARRAY_SIZE(fm_info); i++) 267ae8a5d10SShengzhou Liu ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac"); 268ae8a5d10SShengzhou Liu #else 269c916d7c9SKumar Gala for (i = 0; i < ARRAY_SIZE(fm_info); i++) { 270c916d7c9SKumar Gala if (fm_info[i].type == FM_ETH_1G_E) 271c916d7c9SKumar Gala ft_fixup_port(blob, &fm_info[i], "fsl,fman-1g-mac"); 272c916d7c9SKumar Gala else 273c916d7c9SKumar Gala ft_fixup_port(blob, &fm_info[i], "fsl,fman-10g-mac"); 274c916d7c9SKumar Gala } 275ae8a5d10SShengzhou Liu #endif 276c916d7c9SKumar Gala } 277