16706b115SCodrin Ciubotariu /* 26706b115SCodrin Ciubotariu * Copyright 2014 Freescale Semiconductor, Inc. 36706b115SCodrin Ciubotariu * 46706b115SCodrin Ciubotariu * SPDX-License-Identifier: GPL-2.0+ 56706b115SCodrin Ciubotariu * 66706b115SCodrin Ciubotariu * Driver for the Vitesse VSC9953 L2 Switch 76706b115SCodrin Ciubotariu */ 86706b115SCodrin Ciubotariu 96706b115SCodrin Ciubotariu #include <asm/io.h> 106706b115SCodrin Ciubotariu #include <asm/fsl_serdes.h> 116706b115SCodrin Ciubotariu #include <fm_eth.h> 12*cd348efaSShaohui Xie #include <fsl_memac.h> 136706b115SCodrin Ciubotariu #include <vsc9953.h> 146706b115SCodrin Ciubotariu 156706b115SCodrin Ciubotariu static struct vsc9953_info vsc9953_l2sw = { 166706b115SCodrin Ciubotariu .port[0] = VSC9953_PORT_INFO_INITIALIZER(0), 176706b115SCodrin Ciubotariu .port[1] = VSC9953_PORT_INFO_INITIALIZER(1), 186706b115SCodrin Ciubotariu .port[2] = VSC9953_PORT_INFO_INITIALIZER(2), 196706b115SCodrin Ciubotariu .port[3] = VSC9953_PORT_INFO_INITIALIZER(3), 206706b115SCodrin Ciubotariu .port[4] = VSC9953_PORT_INFO_INITIALIZER(4), 216706b115SCodrin Ciubotariu .port[5] = VSC9953_PORT_INFO_INITIALIZER(5), 226706b115SCodrin Ciubotariu .port[6] = VSC9953_PORT_INFO_INITIALIZER(6), 236706b115SCodrin Ciubotariu .port[7] = VSC9953_PORT_INFO_INITIALIZER(7), 246706b115SCodrin Ciubotariu .port[8] = VSC9953_PORT_INFO_INITIALIZER(8), 256706b115SCodrin Ciubotariu .port[9] = VSC9953_PORT_INFO_INITIALIZER(9), 266706b115SCodrin Ciubotariu }; 276706b115SCodrin Ciubotariu 286706b115SCodrin Ciubotariu void vsc9953_port_info_set_mdio(int port, struct mii_dev *bus) 296706b115SCodrin Ciubotariu { 306706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 316706b115SCodrin Ciubotariu return; 326706b115SCodrin Ciubotariu 336706b115SCodrin Ciubotariu vsc9953_l2sw.port[port].bus = bus; 346706b115SCodrin Ciubotariu } 356706b115SCodrin Ciubotariu 366706b115SCodrin Ciubotariu void vsc9953_port_info_set_phy_address(int port, int address) 376706b115SCodrin Ciubotariu { 386706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 396706b115SCodrin Ciubotariu return; 406706b115SCodrin Ciubotariu 416706b115SCodrin Ciubotariu vsc9953_l2sw.port[port].phyaddr = address; 426706b115SCodrin Ciubotariu } 436706b115SCodrin Ciubotariu 446706b115SCodrin Ciubotariu void vsc9953_port_info_set_phy_int(int port, phy_interface_t phy_int) 456706b115SCodrin Ciubotariu { 466706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 476706b115SCodrin Ciubotariu return; 486706b115SCodrin Ciubotariu 496706b115SCodrin Ciubotariu vsc9953_l2sw.port[port].enet_if = phy_int; 506706b115SCodrin Ciubotariu } 516706b115SCodrin Ciubotariu 526706b115SCodrin Ciubotariu void vsc9953_port_enable(int port) 536706b115SCodrin Ciubotariu { 546706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 556706b115SCodrin Ciubotariu return; 566706b115SCodrin Ciubotariu 576706b115SCodrin Ciubotariu vsc9953_l2sw.port[port].enabled = 1; 586706b115SCodrin Ciubotariu } 596706b115SCodrin Ciubotariu 606706b115SCodrin Ciubotariu void vsc9953_port_disable(int port) 616706b115SCodrin Ciubotariu { 626706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 636706b115SCodrin Ciubotariu return; 646706b115SCodrin Ciubotariu 656706b115SCodrin Ciubotariu vsc9953_l2sw.port[port].enabled = 0; 666706b115SCodrin Ciubotariu } 676706b115SCodrin Ciubotariu 686706b115SCodrin Ciubotariu static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr, 696706b115SCodrin Ciubotariu int regnum, int value) 706706b115SCodrin Ciubotariu { 716706b115SCodrin Ciubotariu int timeout = 50000; 726706b115SCodrin Ciubotariu 736706b115SCodrin Ciubotariu out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) | 746706b115SCodrin Ciubotariu ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) | 756706b115SCodrin Ciubotariu (0x1 << 1)); 766706b115SCodrin Ciubotariu asm("sync"); 776706b115SCodrin Ciubotariu 786706b115SCodrin Ciubotariu while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout) 796706b115SCodrin Ciubotariu udelay(1); 806706b115SCodrin Ciubotariu 816706b115SCodrin Ciubotariu if (timeout == 0) 826706b115SCodrin Ciubotariu debug("Timeout waiting for MDIO write\n"); 836706b115SCodrin Ciubotariu } 846706b115SCodrin Ciubotariu 856706b115SCodrin Ciubotariu static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr, 866706b115SCodrin Ciubotariu int regnum) 876706b115SCodrin Ciubotariu { 886706b115SCodrin Ciubotariu int value = 0xFFFF; 896706b115SCodrin Ciubotariu int timeout = 50000; 906706b115SCodrin Ciubotariu 916706b115SCodrin Ciubotariu while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout) 926706b115SCodrin Ciubotariu udelay(1); 936706b115SCodrin Ciubotariu if (timeout == 0) { 946706b115SCodrin Ciubotariu debug("Timeout waiting for MDIO operation to finish\n"); 956706b115SCodrin Ciubotariu return value; 966706b115SCodrin Ciubotariu } 976706b115SCodrin Ciubotariu 986706b115SCodrin Ciubotariu /* Put the address of the phy, and the register 996706b115SCodrin Ciubotariu * number into MIICMD 1006706b115SCodrin Ciubotariu */ 1016706b115SCodrin Ciubotariu out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) | 1026706b115SCodrin Ciubotariu ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) | 1036706b115SCodrin Ciubotariu (0x2 << 1)); 1046706b115SCodrin Ciubotariu 1056706b115SCodrin Ciubotariu timeout = 50000; 1066706b115SCodrin Ciubotariu /* Wait for the the indication that the read is done */ 1076706b115SCodrin Ciubotariu while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout) 1086706b115SCodrin Ciubotariu udelay(1); 1096706b115SCodrin Ciubotariu if (timeout == 0) 1106706b115SCodrin Ciubotariu debug("Timeout waiting for MDIO read\n"); 1116706b115SCodrin Ciubotariu 1126706b115SCodrin Ciubotariu /* Grab the value read from the PHY */ 1136706b115SCodrin Ciubotariu value = in_le32(&phyregs->miimdata); 1146706b115SCodrin Ciubotariu 1156706b115SCodrin Ciubotariu if ((value & 0x00030000) == 0) 1166706b115SCodrin Ciubotariu return value & 0x0000ffff; 1176706b115SCodrin Ciubotariu 1186706b115SCodrin Ciubotariu return value; 1196706b115SCodrin Ciubotariu } 1206706b115SCodrin Ciubotariu 1216706b115SCodrin Ciubotariu static int init_phy(struct eth_device *dev) 1226706b115SCodrin Ciubotariu { 1236706b115SCodrin Ciubotariu struct vsc9953_port_info *l2sw_port = dev->priv; 1246706b115SCodrin Ciubotariu struct phy_device *phydev = NULL; 1256706b115SCodrin Ciubotariu 1266706b115SCodrin Ciubotariu #ifdef CONFIG_PHYLIB 1276706b115SCodrin Ciubotariu if (!l2sw_port->bus) 1286706b115SCodrin Ciubotariu return 0; 1296706b115SCodrin Ciubotariu phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev, 1306706b115SCodrin Ciubotariu l2sw_port->enet_if); 1316706b115SCodrin Ciubotariu if (!phydev) { 1326706b115SCodrin Ciubotariu printf("Failed to connect\n"); 1336706b115SCodrin Ciubotariu return -1; 1346706b115SCodrin Ciubotariu } 1356706b115SCodrin Ciubotariu 1366706b115SCodrin Ciubotariu phydev->supported &= SUPPORTED_10baseT_Half | 1376706b115SCodrin Ciubotariu SUPPORTED_10baseT_Full | 1386706b115SCodrin Ciubotariu SUPPORTED_100baseT_Half | 1396706b115SCodrin Ciubotariu SUPPORTED_100baseT_Full | 1406706b115SCodrin Ciubotariu SUPPORTED_1000baseT_Full; 1416706b115SCodrin Ciubotariu phydev->advertising = phydev->supported; 1426706b115SCodrin Ciubotariu 1436706b115SCodrin Ciubotariu l2sw_port->phydev = phydev; 1446706b115SCodrin Ciubotariu 1456706b115SCodrin Ciubotariu phy_config(phydev); 1466706b115SCodrin Ciubotariu #endif 1476706b115SCodrin Ciubotariu 1486706b115SCodrin Ciubotariu return 0; 1496706b115SCodrin Ciubotariu } 1506706b115SCodrin Ciubotariu 1516706b115SCodrin Ciubotariu static int vsc9953_port_init(int port) 1526706b115SCodrin Ciubotariu { 1536706b115SCodrin Ciubotariu struct eth_device *dev; 1546706b115SCodrin Ciubotariu 1556706b115SCodrin Ciubotariu /* Internal ports never have a PHY */ 1566706b115SCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(port)) 1576706b115SCodrin Ciubotariu return 0; 1586706b115SCodrin Ciubotariu 1596706b115SCodrin Ciubotariu /* alloc eth device */ 1606706b115SCodrin Ciubotariu dev = (struct eth_device *)calloc(1, sizeof(struct eth_device)); 1616706b115SCodrin Ciubotariu if (!dev) 1626706b115SCodrin Ciubotariu return 1; 1636706b115SCodrin Ciubotariu 1646706b115SCodrin Ciubotariu sprintf(dev->name, "SW@PORT%d", port); 1656706b115SCodrin Ciubotariu dev->priv = &vsc9953_l2sw.port[port]; 1666706b115SCodrin Ciubotariu dev->init = NULL; 1676706b115SCodrin Ciubotariu dev->halt = NULL; 1686706b115SCodrin Ciubotariu dev->send = NULL; 1696706b115SCodrin Ciubotariu dev->recv = NULL; 1706706b115SCodrin Ciubotariu 1716706b115SCodrin Ciubotariu if (init_phy(dev)) { 1726706b115SCodrin Ciubotariu free(dev); 1736706b115SCodrin Ciubotariu return 1; 1746706b115SCodrin Ciubotariu } 1756706b115SCodrin Ciubotariu 1766706b115SCodrin Ciubotariu return 0; 1776706b115SCodrin Ciubotariu } 1786706b115SCodrin Ciubotariu 1796706b115SCodrin Ciubotariu void vsc9953_init(bd_t *bis) 1806706b115SCodrin Ciubotariu { 1816706b115SCodrin Ciubotariu u32 i, hdx_cfg = 0, phy_addr = 0; 1826706b115SCodrin Ciubotariu int timeout; 1836706b115SCodrin Ciubotariu struct vsc9953_system_reg *l2sys_reg; 1846706b115SCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 1856706b115SCodrin Ciubotariu struct vsc9953_dev_gmii *l2dev_gmii_reg; 1866706b115SCodrin Ciubotariu struct vsc9953_analyzer *l2ana_reg; 1876706b115SCodrin Ciubotariu struct vsc9953_devcpu_gcb *l2dev_gcb; 1886706b115SCodrin Ciubotariu 1896706b115SCodrin Ciubotariu l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET + 1906706b115SCodrin Ciubotariu VSC9953_DEV_GMII_OFFSET); 1916706b115SCodrin Ciubotariu 1926706b115SCodrin Ciubotariu l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + 1936706b115SCodrin Ciubotariu VSC9953_ANA_OFFSET); 1946706b115SCodrin Ciubotariu 1956706b115SCodrin Ciubotariu l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + 1966706b115SCodrin Ciubotariu VSC9953_SYS_OFFSET); 1976706b115SCodrin Ciubotariu 1986706b115SCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 1996706b115SCodrin Ciubotariu VSC9953_QSYS_OFFSET); 2006706b115SCodrin Ciubotariu 2016706b115SCodrin Ciubotariu l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET + 2026706b115SCodrin Ciubotariu VSC9953_DEVCPU_GCB); 2036706b115SCodrin Ciubotariu 2046706b115SCodrin Ciubotariu out_le32(&l2dev_gcb->chip_regs.soft_rst, 2056706b115SCodrin Ciubotariu CONFIG_VSC9953_SOFT_SWC_RST_ENA); 2066706b115SCodrin Ciubotariu timeout = 50000; 2076706b115SCodrin Ciubotariu while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) & 2086706b115SCodrin Ciubotariu CONFIG_VSC9953_SOFT_SWC_RST_ENA) && --timeout) 2096706b115SCodrin Ciubotariu udelay(1); /* busy wait for vsc9953 soft reset */ 2106706b115SCodrin Ciubotariu if (timeout == 0) 2116706b115SCodrin Ciubotariu debug("Timeout waiting for VSC9953 to reset\n"); 2126706b115SCodrin Ciubotariu 2136706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.reset_cfg, CONFIG_VSC9953_MEM_ENABLE | 2146706b115SCodrin Ciubotariu CONFIG_VSC9953_MEM_INIT); 2156706b115SCodrin Ciubotariu 2166706b115SCodrin Ciubotariu timeout = 50000; 2176706b115SCodrin Ciubotariu while ((in_le32(&l2sys_reg->sys.reset_cfg) & 2186706b115SCodrin Ciubotariu CONFIG_VSC9953_MEM_INIT) && --timeout) 2196706b115SCodrin Ciubotariu udelay(1); /* busy wait for vsc9953 memory init */ 2206706b115SCodrin Ciubotariu if (timeout == 0) 2216706b115SCodrin Ciubotariu debug("Timeout waiting for VSC9953 memory to initialize\n"); 2226706b115SCodrin Ciubotariu 2236706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg) 2246706b115SCodrin Ciubotariu | CONFIG_VSC9953_CORE_ENABLE)); 2256706b115SCodrin Ciubotariu 2266706b115SCodrin Ciubotariu /* VSC9953 Setting to be done once only */ 2276706b115SCodrin Ciubotariu out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00); 2286706b115SCodrin Ciubotariu 2296706b115SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) { 2306706b115SCodrin Ciubotariu if (vsc9953_port_init(i)) 2316706b115SCodrin Ciubotariu printf("Failed to initialize l2switch port %d\n", i); 2326706b115SCodrin Ciubotariu 2336706b115SCodrin Ciubotariu /* Enable VSC9953 GMII Ports Port ID 0 - 7 */ 2346706b115SCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(i)) { 2356706b115SCodrin Ciubotariu out_le32(&l2ana_reg->pfc[i].pfc_cfg, 2366706b115SCodrin Ciubotariu CONFIG_VSC9953_PFC_FC_QSGMII); 2376706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], 2386706b115SCodrin Ciubotariu CONFIG_VSC9953_MAC_FC_CFG_QSGMII); 2396706b115SCodrin Ciubotariu } else { 2406706b115SCodrin Ciubotariu out_le32(&l2ana_reg->pfc[i].pfc_cfg, 2416706b115SCodrin Ciubotariu CONFIG_VSC9953_PFC_FC); 2426706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], 2436706b115SCodrin Ciubotariu CONFIG_VSC9953_MAC_FC_CFG); 2446706b115SCodrin Ciubotariu } 2456706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->port_mode.clock_cfg, 2466706b115SCodrin Ciubotariu CONFIG_VSC9953_CLOCK_CFG); 2476706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg, 2486706b115SCodrin Ciubotariu CONFIG_VSC9953_MAC_ENA_CFG); 2496706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg, 2506706b115SCodrin Ciubotariu CONFIG_VSC9953_MAC_MODE_CFG); 2516706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg, 2526706b115SCodrin Ciubotariu CONFIG_VSC9953_MAC_IFG_CFG); 2536706b115SCodrin Ciubotariu /* mac_hdx_cfg varies with port id*/ 2546706b115SCodrin Ciubotariu hdx_cfg = (CONFIG_VSC9953_MAC_HDX_CFG | (i << 16)); 2556706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg); 2566706b115SCodrin Ciubotariu out_le32(&l2sys_reg->sys.front_port_mode[i], 2576706b115SCodrin Ciubotariu CONFIG_VSC9953_FRONT_PORT_MODE); 2586706b115SCodrin Ciubotariu out_le32(&l2qsys_reg->sys.switch_port_mode[i], 2596706b115SCodrin Ciubotariu CONFIG_VSC9953_PORT_ENA); 2606706b115SCodrin Ciubotariu out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg, 2616706b115SCodrin Ciubotariu CONFIG_VSC9953_MAC_MAX_LEN); 2626706b115SCodrin Ciubotariu out_le32(&l2sys_reg->pause_cfg.pause_cfg[i], 2636706b115SCodrin Ciubotariu CONFIG_VSC9953_PAUSE_CFG); 2646706b115SCodrin Ciubotariu /* WAIT FOR 2 us*/ 2656706b115SCodrin Ciubotariu udelay(2); 2666706b115SCodrin Ciubotariu 2676706b115SCodrin Ciubotariu l2dev_gmii_reg = (struct vsc9953_dev_gmii *)( 2686706b115SCodrin Ciubotariu (char *)l2dev_gmii_reg 2696706b115SCodrin Ciubotariu + T1040_SWITCH_GMII_DEV_OFFSET); 2706706b115SCodrin Ciubotariu 2716706b115SCodrin Ciubotariu /* Initialize Lynx PHY Wrappers */ 2726706b115SCodrin Ciubotariu phy_addr = 0; 2736706b115SCodrin Ciubotariu if (vsc9953_l2sw.port[i].enet_if == 2746706b115SCodrin Ciubotariu PHY_INTERFACE_MODE_QSGMII) 2756706b115SCodrin Ciubotariu phy_addr = (i + 0x4) & 0x1F; 2766706b115SCodrin Ciubotariu else if (vsc9953_l2sw.port[i].enet_if == 2776706b115SCodrin Ciubotariu PHY_INTERFACE_MODE_SGMII) 2786706b115SCodrin Ciubotariu phy_addr = (i + 1) & 0x1F; 2796706b115SCodrin Ciubotariu 2806706b115SCodrin Ciubotariu if (phy_addr) { 2816706b115SCodrin Ciubotariu /* SGMII IF mode + AN enable */ 2826706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 2836706b115SCodrin Ciubotariu 0x14, PHY_SGMII_IF_MODE_AN | 2846706b115SCodrin Ciubotariu PHY_SGMII_IF_MODE_SGMII); 2856706b115SCodrin Ciubotariu /* Dev ability according to SGMII specification */ 2866706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 2876706b115SCodrin Ciubotariu 0x4, PHY_SGMII_DEV_ABILITY_SGMII); 2886706b115SCodrin Ciubotariu /* Adjust link timer for SGMII 2896706b115SCodrin Ciubotariu * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 2906706b115SCodrin Ciubotariu */ 2916706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 2926706b115SCodrin Ciubotariu 0x13, 0x0003); 2936706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 2946706b115SCodrin Ciubotariu 0x12, 0x0d40); 2956706b115SCodrin Ciubotariu /* Restart AN */ 2966706b115SCodrin Ciubotariu vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, 2976706b115SCodrin Ciubotariu 0x0, PHY_SGMII_CR_DEF_VAL | 2986706b115SCodrin Ciubotariu PHY_SGMII_CR_RESET_AN); 2996706b115SCodrin Ciubotariu 3006706b115SCodrin Ciubotariu timeout = 50000; 3016706b115SCodrin Ciubotariu while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0], 3026706b115SCodrin Ciubotariu phy_addr, 0x01) & 0x0020) && --timeout) 3036706b115SCodrin Ciubotariu udelay(1); /* wait for AN to complete */ 3046706b115SCodrin Ciubotariu if (timeout == 0) 3056706b115SCodrin Ciubotariu debug("Timeout waiting for AN to complete\n"); 3066706b115SCodrin Ciubotariu } 3076706b115SCodrin Ciubotariu } 3086706b115SCodrin Ciubotariu 3096706b115SCodrin Ciubotariu printf("VSC9953 L2 switch initialized\n"); 3106706b115SCodrin Ciubotariu return; 3116706b115SCodrin Ciubotariu } 3126706b115SCodrin Ciubotariu 3136706b115SCodrin Ciubotariu #ifdef CONFIG_VSC9953_CMD 3146706b115SCodrin Ciubotariu /* Enable/disable status of a VSC9953 port */ 3156706b115SCodrin Ciubotariu static void vsc9953_port_status_set(int port_nr, u8 enabled) 3166706b115SCodrin Ciubotariu { 3176706b115SCodrin Ciubotariu u32 val; 3186706b115SCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 3196706b115SCodrin Ciubotariu 3206706b115SCodrin Ciubotariu /* Administrative down */ 3216706b115SCodrin Ciubotariu if (vsc9953_l2sw.port[port_nr].enabled == 0) 3226706b115SCodrin Ciubotariu return; 3236706b115SCodrin Ciubotariu 3246706b115SCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 3256706b115SCodrin Ciubotariu VSC9953_QSYS_OFFSET); 3266706b115SCodrin Ciubotariu 3276706b115SCodrin Ciubotariu val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_nr]); 3286706b115SCodrin Ciubotariu if (enabled == 1) 3296706b115SCodrin Ciubotariu val |= (1 << 13); 3306706b115SCodrin Ciubotariu else 3316706b115SCodrin Ciubotariu val &= ~(1 << 13); 3326706b115SCodrin Ciubotariu 3336706b115SCodrin Ciubotariu out_le32(&l2qsys_reg->sys.switch_port_mode[port_nr], val); 3346706b115SCodrin Ciubotariu } 3356706b115SCodrin Ciubotariu 3366706b115SCodrin Ciubotariu /* Set all VSC9953 ports' status */ 3376706b115SCodrin Ciubotariu static void vsc9953_port_all_status_set(u8 enabled) 3386706b115SCodrin Ciubotariu { 3396706b115SCodrin Ciubotariu int i; 3406706b115SCodrin Ciubotariu 3416706b115SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 3426706b115SCodrin Ciubotariu vsc9953_port_status_set(i, enabled); 3436706b115SCodrin Ciubotariu } 3446706b115SCodrin Ciubotariu 3456706b115SCodrin Ciubotariu /* Start autonegotiation for a VSC9953 PHY */ 3466706b115SCodrin Ciubotariu static void vsc9953_phy_autoneg(int port_nr) 3476706b115SCodrin Ciubotariu { 3486706b115SCodrin Ciubotariu if (!vsc9953_l2sw.port[port_nr].phydev) 3496706b115SCodrin Ciubotariu return; 3506706b115SCodrin Ciubotariu 3516706b115SCodrin Ciubotariu if (vsc9953_l2sw.port[port_nr].phydev->drv->startup( 3526706b115SCodrin Ciubotariu vsc9953_l2sw.port[port_nr].phydev)) 3536706b115SCodrin Ciubotariu printf("Failed to start PHY for port %d\n", port_nr); 3546706b115SCodrin Ciubotariu } 3556706b115SCodrin Ciubotariu 3566706b115SCodrin Ciubotariu /* Start autonegotiation for all VSC9953 PHYs */ 3576706b115SCodrin Ciubotariu static void vsc9953_phy_all_autoneg(void) 3586706b115SCodrin Ciubotariu { 3596706b115SCodrin Ciubotariu int i; 3606706b115SCodrin Ciubotariu 3616706b115SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 3626706b115SCodrin Ciubotariu vsc9953_phy_autoneg(i); 3636706b115SCodrin Ciubotariu } 3646706b115SCodrin Ciubotariu 3656706b115SCodrin Ciubotariu /* Print a VSC9953 port's configuration */ 3666706b115SCodrin Ciubotariu static void vsc9953_port_config_show(int port) 3676706b115SCodrin Ciubotariu { 3686706b115SCodrin Ciubotariu int speed; 3696706b115SCodrin Ciubotariu int duplex; 3706706b115SCodrin Ciubotariu int link; 3716706b115SCodrin Ciubotariu u8 enabled; 3726706b115SCodrin Ciubotariu u32 val; 3736706b115SCodrin Ciubotariu struct vsc9953_qsys_reg *l2qsys_reg; 3746706b115SCodrin Ciubotariu 3756706b115SCodrin Ciubotariu l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + 3766706b115SCodrin Ciubotariu VSC9953_QSYS_OFFSET); 3776706b115SCodrin Ciubotariu 3786706b115SCodrin Ciubotariu val = in_le32(&l2qsys_reg->sys.switch_port_mode[port]); 3796706b115SCodrin Ciubotariu enabled = vsc9953_l2sw.port[port].enabled & 3806706b115SCodrin Ciubotariu ((val & 0x00002000) >> 13); 3816706b115SCodrin Ciubotariu 3826706b115SCodrin Ciubotariu /* internal ports (8 and 9) are fixed */ 3836706b115SCodrin Ciubotariu if (VSC9953_INTERNAL_PORT_CHECK(port)) { 3846706b115SCodrin Ciubotariu link = 1; 3856706b115SCodrin Ciubotariu speed = SPEED_2500; 3866706b115SCodrin Ciubotariu duplex = DUPLEX_FULL; 3876706b115SCodrin Ciubotariu } else { 3886706b115SCodrin Ciubotariu if (vsc9953_l2sw.port[port].phydev) { 3896706b115SCodrin Ciubotariu link = vsc9953_l2sw.port[port].phydev->link; 3906706b115SCodrin Ciubotariu speed = vsc9953_l2sw.port[port].phydev->speed; 3916706b115SCodrin Ciubotariu duplex = vsc9953_l2sw.port[port].phydev->duplex; 3926706b115SCodrin Ciubotariu } else { 3936706b115SCodrin Ciubotariu link = -1; 3946706b115SCodrin Ciubotariu speed = -1; 3956706b115SCodrin Ciubotariu duplex = -1; 3966706b115SCodrin Ciubotariu } 3976706b115SCodrin Ciubotariu } 3986706b115SCodrin Ciubotariu 3996706b115SCodrin Ciubotariu printf("%8d ", port); 4006706b115SCodrin Ciubotariu printf("%8s ", enabled == 1 ? "enabled" : "disabled"); 4016706b115SCodrin Ciubotariu printf("%8s ", link == 1 ? "up" : "down"); 4026706b115SCodrin Ciubotariu 4036706b115SCodrin Ciubotariu switch (speed) { 4046706b115SCodrin Ciubotariu case SPEED_10: 4056706b115SCodrin Ciubotariu printf("%8d ", 10); 4066706b115SCodrin Ciubotariu break; 4076706b115SCodrin Ciubotariu case SPEED_100: 4086706b115SCodrin Ciubotariu printf("%8d ", 100); 4096706b115SCodrin Ciubotariu break; 4106706b115SCodrin Ciubotariu case SPEED_1000: 4116706b115SCodrin Ciubotariu printf("%8d ", 1000); 4126706b115SCodrin Ciubotariu break; 4136706b115SCodrin Ciubotariu case SPEED_2500: 4146706b115SCodrin Ciubotariu printf("%8d ", 2500); 4156706b115SCodrin Ciubotariu break; 4166706b115SCodrin Ciubotariu case SPEED_10000: 4176706b115SCodrin Ciubotariu printf("%8d ", 10000); 4186706b115SCodrin Ciubotariu break; 4196706b115SCodrin Ciubotariu default: 4206706b115SCodrin Ciubotariu printf("%8s ", "-"); 4216706b115SCodrin Ciubotariu } 4226706b115SCodrin Ciubotariu 4236706b115SCodrin Ciubotariu printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half"); 4246706b115SCodrin Ciubotariu } 4256706b115SCodrin Ciubotariu 4266706b115SCodrin Ciubotariu /* Print VSC9953 ports' configuration */ 4276706b115SCodrin Ciubotariu static void vsc9953_port_all_config_show(void) 4286706b115SCodrin Ciubotariu { 4296706b115SCodrin Ciubotariu int i; 4306706b115SCodrin Ciubotariu 4316706b115SCodrin Ciubotariu for (i = 0; i < VSC9953_MAX_PORTS; i++) 4326706b115SCodrin Ciubotariu vsc9953_port_config_show(i); 4336706b115SCodrin Ciubotariu } 4346706b115SCodrin Ciubotariu 4356706b115SCodrin Ciubotariu /* function to interpret commands starting with "ethsw " */ 4366706b115SCodrin Ciubotariu static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 4376706b115SCodrin Ciubotariu { 4386706b115SCodrin Ciubotariu u8 enable; 4396706b115SCodrin Ciubotariu u32 port; 4406706b115SCodrin Ciubotariu 4416706b115SCodrin Ciubotariu if (argc < 4) 4426706b115SCodrin Ciubotariu return -1; 4436706b115SCodrin Ciubotariu 4446706b115SCodrin Ciubotariu if (strcmp(argv[1], "port")) 4456706b115SCodrin Ciubotariu return -1; 4466706b115SCodrin Ciubotariu 4476706b115SCodrin Ciubotariu if (!strcmp(argv[3], "show")) { 4486706b115SCodrin Ciubotariu if (!strcmp(argv[2], "all")) { 4496706b115SCodrin Ciubotariu vsc9953_phy_all_autoneg(); 4506706b115SCodrin Ciubotariu printf("%8s %8s %8s %8s %8s\n", 4516706b115SCodrin Ciubotariu "Port", "Status", "Link", "Speed", 4526706b115SCodrin Ciubotariu "Duplex"); 4536706b115SCodrin Ciubotariu vsc9953_port_all_config_show(); 4546706b115SCodrin Ciubotariu return 0; 4556706b115SCodrin Ciubotariu } else { 4566706b115SCodrin Ciubotariu port = simple_strtoul(argv[2], NULL, 10); 4576706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 4586706b115SCodrin Ciubotariu return -1; 4596706b115SCodrin Ciubotariu vsc9953_phy_autoneg(port); 4606706b115SCodrin Ciubotariu printf("%8s %8s %8s %8s %8s\n", 4616706b115SCodrin Ciubotariu "Port", "Status", "Link", "Speed", 4626706b115SCodrin Ciubotariu "Duplex"); 4636706b115SCodrin Ciubotariu vsc9953_port_config_show(port); 4646706b115SCodrin Ciubotariu return 0; 4656706b115SCodrin Ciubotariu } 4666706b115SCodrin Ciubotariu } else if (!strcmp(argv[3], "enable")) { 4676706b115SCodrin Ciubotariu enable = 1; 4686706b115SCodrin Ciubotariu } else if (!strcmp(argv[3], "disable")) { 4696706b115SCodrin Ciubotariu enable = 0; 4706706b115SCodrin Ciubotariu } else { 4716706b115SCodrin Ciubotariu return -1; 4726706b115SCodrin Ciubotariu } 4736706b115SCodrin Ciubotariu 4746706b115SCodrin Ciubotariu if (!strcmp(argv[2], "all")) { 4756706b115SCodrin Ciubotariu vsc9953_port_all_status_set(enable); 4766706b115SCodrin Ciubotariu return 0; 4776706b115SCodrin Ciubotariu } else { 4786706b115SCodrin Ciubotariu port = simple_strtoul(argv[2], NULL, 10); 4796706b115SCodrin Ciubotariu if (!VSC9953_PORT_CHECK(port)) 4806706b115SCodrin Ciubotariu return -1; 4816706b115SCodrin Ciubotariu vsc9953_port_status_set(port, enable); 4826706b115SCodrin Ciubotariu return 0; 4836706b115SCodrin Ciubotariu } 4846706b115SCodrin Ciubotariu 4856706b115SCodrin Ciubotariu return -1; 4866706b115SCodrin Ciubotariu } 4876706b115SCodrin Ciubotariu 4886706b115SCodrin Ciubotariu U_BOOT_CMD(ethsw, 5, 0, do_ethsw, 4896706b115SCodrin Ciubotariu "vsc9953 l2 switch commands", 4906706b115SCodrin Ciubotariu "port <port_nr> enable|disable\n" 4916706b115SCodrin Ciubotariu " - enable/disable an l2 switch port\n" 4926706b115SCodrin Ciubotariu " port_nr=0..9; use \"all\" for all ports\n" 4936706b115SCodrin Ciubotariu "ethsw port <port_nr> show\n" 4946706b115SCodrin Ciubotariu " - show an l2 switch port's configuration\n" 4956706b115SCodrin Ciubotariu " port_nr=0..9; use \"all\" for all ports\n" 4966706b115SCodrin Ciubotariu ); 4976706b115SCodrin Ciubotariu #endif /* CONFIG_VSC9953_CMD */ 498