15a8f0974SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 25a8f0974SVladimir Oltean /* Copyright 2021, NXP Semiconductors 35a8f0974SVladimir Oltean */ 4*3ad1d171SVladimir Oltean #include <linux/pcs/pcs-xpcs.h> 55a8f0974SVladimir Oltean #include <linux/of_mdio.h> 65a8f0974SVladimir Oltean #include "sja1105.h" 75a8f0974SVladimir Oltean 8*3ad1d171SVladimir Oltean int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg) 9*3ad1d171SVladimir Oltean { 10*3ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 11*3ad1d171SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 12*3ad1d171SVladimir Oltean u64 addr; 13*3ad1d171SVladimir Oltean u32 tmp; 14*3ad1d171SVladimir Oltean u16 mmd; 15*3ad1d171SVladimir Oltean int rc; 16*3ad1d171SVladimir Oltean 17*3ad1d171SVladimir Oltean if (!(reg & MII_ADDR_C45)) 18*3ad1d171SVladimir Oltean return -EINVAL; 19*3ad1d171SVladimir Oltean 20*3ad1d171SVladimir Oltean mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 21*3ad1d171SVladimir Oltean addr = (mmd << 16) | (reg & GENMASK(15, 0)); 22*3ad1d171SVladimir Oltean 23*3ad1d171SVladimir Oltean if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 24*3ad1d171SVladimir Oltean return 0xffff; 25*3ad1d171SVladimir Oltean 26*3ad1d171SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 27*3ad1d171SVladimir Oltean return NXP_SJA1105_XPCS_ID >> 16; 28*3ad1d171SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 29*3ad1d171SVladimir Oltean return NXP_SJA1105_XPCS_ID & GENMASK(15, 0); 30*3ad1d171SVladimir Oltean 31*3ad1d171SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 32*3ad1d171SVladimir Oltean if (rc < 0) 33*3ad1d171SVladimir Oltean return rc; 34*3ad1d171SVladimir Oltean 35*3ad1d171SVladimir Oltean return tmp & 0xffff; 36*3ad1d171SVladimir Oltean } 37*3ad1d171SVladimir Oltean 38*3ad1d171SVladimir Oltean int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 39*3ad1d171SVladimir Oltean { 40*3ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 41*3ad1d171SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 42*3ad1d171SVladimir Oltean u64 addr; 43*3ad1d171SVladimir Oltean u32 tmp; 44*3ad1d171SVladimir Oltean u16 mmd; 45*3ad1d171SVladimir Oltean 46*3ad1d171SVladimir Oltean if (!(reg & MII_ADDR_C45)) 47*3ad1d171SVladimir Oltean return -EINVAL; 48*3ad1d171SVladimir Oltean 49*3ad1d171SVladimir Oltean mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 50*3ad1d171SVladimir Oltean addr = (mmd << 16) | (reg & GENMASK(15, 0)); 51*3ad1d171SVladimir Oltean tmp = val; 52*3ad1d171SVladimir Oltean 53*3ad1d171SVladimir Oltean if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 54*3ad1d171SVladimir Oltean return -EINVAL; 55*3ad1d171SVladimir Oltean 56*3ad1d171SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 57*3ad1d171SVladimir Oltean } 58*3ad1d171SVladimir Oltean 595a8f0974SVladimir Oltean enum sja1105_mdio_opcode { 605a8f0974SVladimir Oltean SJA1105_C45_ADDR = 0, 615a8f0974SVladimir Oltean SJA1105_C22 = 1, 625a8f0974SVladimir Oltean SJA1105_C45_DATA = 2, 635a8f0974SVladimir Oltean SJA1105_C45_DATA_AUTOINC = 3, 645a8f0974SVladimir Oltean }; 655a8f0974SVladimir Oltean 665a8f0974SVladimir Oltean static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv, 675a8f0974SVladimir Oltean int phy, enum sja1105_mdio_opcode op, 685a8f0974SVladimir Oltean int xad) 695a8f0974SVladimir Oltean { 705a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 715a8f0974SVladimir Oltean 725a8f0974SVladimir Oltean return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0); 735a8f0974SVladimir Oltean } 745a8f0974SVladimir Oltean 755a8f0974SVladimir Oltean static int sja1105_base_t1_mdio_read(struct mii_bus *bus, int phy, int reg) 765a8f0974SVladimir Oltean { 775a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 785a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 795a8f0974SVladimir Oltean u64 addr; 805a8f0974SVladimir Oltean u32 tmp; 815a8f0974SVladimir Oltean int rc; 825a8f0974SVladimir Oltean 835a8f0974SVladimir Oltean if (reg & MII_ADDR_C45) { 845a8f0974SVladimir Oltean u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 855a8f0974SVladimir Oltean 865a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, 875a8f0974SVladimir Oltean mmd); 885a8f0974SVladimir Oltean 895a8f0974SVladimir Oltean tmp = reg & MII_REGADDR_C45_MASK; 905a8f0974SVladimir Oltean 915a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 925a8f0974SVladimir Oltean if (rc < 0) 935a8f0974SVladimir Oltean return rc; 945a8f0974SVladimir Oltean 955a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, 965a8f0974SVladimir Oltean mmd); 975a8f0974SVladimir Oltean 985a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 995a8f0974SVladimir Oltean if (rc < 0) 1005a8f0974SVladimir Oltean return rc; 1015a8f0974SVladimir Oltean 1025a8f0974SVladimir Oltean return tmp & 0xffff; 1035a8f0974SVladimir Oltean } 1045a8f0974SVladimir Oltean 1055a8f0974SVladimir Oltean /* Clause 22 read */ 1065a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 1075a8f0974SVladimir Oltean 1085a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 1095a8f0974SVladimir Oltean if (rc < 0) 1105a8f0974SVladimir Oltean return rc; 1115a8f0974SVladimir Oltean 1125a8f0974SVladimir Oltean return tmp & 0xffff; 1135a8f0974SVladimir Oltean } 1145a8f0974SVladimir Oltean 1155a8f0974SVladimir Oltean static int sja1105_base_t1_mdio_write(struct mii_bus *bus, int phy, int reg, 1165a8f0974SVladimir Oltean u16 val) 1175a8f0974SVladimir Oltean { 1185a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 1195a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 1205a8f0974SVladimir Oltean u64 addr; 1215a8f0974SVladimir Oltean u32 tmp; 1225a8f0974SVladimir Oltean int rc; 1235a8f0974SVladimir Oltean 1245a8f0974SVladimir Oltean if (reg & MII_ADDR_C45) { 1255a8f0974SVladimir Oltean u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 1265a8f0974SVladimir Oltean 1275a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, 1285a8f0974SVladimir Oltean mmd); 1295a8f0974SVladimir Oltean 1305a8f0974SVladimir Oltean tmp = reg & MII_REGADDR_C45_MASK; 1315a8f0974SVladimir Oltean 1325a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 1335a8f0974SVladimir Oltean if (rc < 0) 1345a8f0974SVladimir Oltean return rc; 1355a8f0974SVladimir Oltean 1365a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, 1375a8f0974SVladimir Oltean mmd); 1385a8f0974SVladimir Oltean 1395a8f0974SVladimir Oltean tmp = val & 0xffff; 1405a8f0974SVladimir Oltean 1415a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 1425a8f0974SVladimir Oltean if (rc < 0) 1435a8f0974SVladimir Oltean return rc; 1445a8f0974SVladimir Oltean 1455a8f0974SVladimir Oltean return 0; 1465a8f0974SVladimir Oltean } 1475a8f0974SVladimir Oltean 1485a8f0974SVladimir Oltean /* Clause 22 write */ 1495a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 1505a8f0974SVladimir Oltean 1515a8f0974SVladimir Oltean tmp = val & 0xffff; 1525a8f0974SVladimir Oltean 1535a8f0974SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 1545a8f0974SVladimir Oltean } 1555a8f0974SVladimir Oltean 1565a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg) 1575a8f0974SVladimir Oltean { 1585a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 1595a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 1605a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 1615a8f0974SVladimir Oltean u32 tmp; 1625a8f0974SVladimir Oltean int rc; 1635a8f0974SVladimir Oltean 1645a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg, 1655a8f0974SVladimir Oltean &tmp, NULL); 1665a8f0974SVladimir Oltean if (rc < 0) 1675a8f0974SVladimir Oltean return rc; 1685a8f0974SVladimir Oltean 1695a8f0974SVladimir Oltean return tmp & 0xffff; 1705a8f0974SVladimir Oltean } 1715a8f0974SVladimir Oltean 1725a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg, 1735a8f0974SVladimir Oltean u16 val) 1745a8f0974SVladimir Oltean { 1755a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 1765a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 1775a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 1785a8f0974SVladimir Oltean u32 tmp = val; 1795a8f0974SVladimir Oltean 1805a8f0974SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg, 1815a8f0974SVladimir Oltean &tmp, NULL); 1825a8f0974SVladimir Oltean } 1835a8f0974SVladimir Oltean 1845a8f0974SVladimir Oltean static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv, 1855a8f0974SVladimir Oltean struct device_node *mdio_node) 1865a8f0974SVladimir Oltean { 1875a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 1885a8f0974SVladimir Oltean struct device_node *np; 1895a8f0974SVladimir Oltean struct mii_bus *bus; 1905a8f0974SVladimir Oltean int rc = 0; 1915a8f0974SVladimir Oltean 1925a8f0974SVladimir Oltean np = of_find_compatible_node(mdio_node, NULL, 1935a8f0974SVladimir Oltean "nxp,sja1110-base-tx-mdio"); 1945a8f0974SVladimir Oltean if (!np) 1955a8f0974SVladimir Oltean return 0; 1965a8f0974SVladimir Oltean 1975a8f0974SVladimir Oltean if (!of_device_is_available(np)) 1985a8f0974SVladimir Oltean goto out_put_np; 1995a8f0974SVladimir Oltean 2005a8f0974SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 2015a8f0974SVladimir Oltean if (!bus) { 2025a8f0974SVladimir Oltean rc = -ENOMEM; 2035a8f0974SVladimir Oltean goto out_put_np; 2045a8f0974SVladimir Oltean } 2055a8f0974SVladimir Oltean 2065a8f0974SVladimir Oltean bus->name = "SJA1110 100base-TX MDIO bus"; 2075a8f0974SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx", 2085a8f0974SVladimir Oltean dev_name(priv->ds->dev)); 2095a8f0974SVladimir Oltean bus->read = sja1105_base_tx_mdio_read; 2105a8f0974SVladimir Oltean bus->write = sja1105_base_tx_mdio_write; 2115a8f0974SVladimir Oltean bus->parent = priv->ds->dev; 2125a8f0974SVladimir Oltean mdio_priv = bus->priv; 2135a8f0974SVladimir Oltean mdio_priv->priv = priv; 2145a8f0974SVladimir Oltean 2155a8f0974SVladimir Oltean rc = of_mdiobus_register(bus, np); 2165a8f0974SVladimir Oltean if (rc) { 2175a8f0974SVladimir Oltean mdiobus_free(bus); 2185a8f0974SVladimir Oltean goto out_put_np; 2195a8f0974SVladimir Oltean } 2205a8f0974SVladimir Oltean 2215a8f0974SVladimir Oltean priv->mdio_base_tx = bus; 2225a8f0974SVladimir Oltean 2235a8f0974SVladimir Oltean out_put_np: 2245a8f0974SVladimir Oltean of_node_put(np); 2255a8f0974SVladimir Oltean 226ab324d8dSColin Ian King return rc; 2275a8f0974SVladimir Oltean } 2285a8f0974SVladimir Oltean 2295a8f0974SVladimir Oltean static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv) 2305a8f0974SVladimir Oltean { 2315a8f0974SVladimir Oltean if (!priv->mdio_base_tx) 2325a8f0974SVladimir Oltean return; 2335a8f0974SVladimir Oltean 2345a8f0974SVladimir Oltean mdiobus_unregister(priv->mdio_base_tx); 2355a8f0974SVladimir Oltean mdiobus_free(priv->mdio_base_tx); 2365a8f0974SVladimir Oltean priv->mdio_base_tx = NULL; 2375a8f0974SVladimir Oltean } 2385a8f0974SVladimir Oltean 2395a8f0974SVladimir Oltean static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv, 2405a8f0974SVladimir Oltean struct device_node *mdio_node) 2415a8f0974SVladimir Oltean { 2425a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 2435a8f0974SVladimir Oltean struct device_node *np; 2445a8f0974SVladimir Oltean struct mii_bus *bus; 2455a8f0974SVladimir Oltean int rc = 0; 2465a8f0974SVladimir Oltean 2475a8f0974SVladimir Oltean np = of_find_compatible_node(mdio_node, NULL, 2485a8f0974SVladimir Oltean "nxp,sja1110-base-t1-mdio"); 2495a8f0974SVladimir Oltean if (!np) 2505a8f0974SVladimir Oltean return 0; 2515a8f0974SVladimir Oltean 2525a8f0974SVladimir Oltean if (!of_device_is_available(np)) 2535a8f0974SVladimir Oltean goto out_put_np; 2545a8f0974SVladimir Oltean 2555a8f0974SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 2565a8f0974SVladimir Oltean if (!bus) { 2575a8f0974SVladimir Oltean rc = -ENOMEM; 2585a8f0974SVladimir Oltean goto out_put_np; 2595a8f0974SVladimir Oltean } 2605a8f0974SVladimir Oltean 2615a8f0974SVladimir Oltean bus->name = "SJA1110 100base-T1 MDIO bus"; 2625a8f0974SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1", 2635a8f0974SVladimir Oltean dev_name(priv->ds->dev)); 2645a8f0974SVladimir Oltean bus->read = sja1105_base_t1_mdio_read; 2655a8f0974SVladimir Oltean bus->write = sja1105_base_t1_mdio_write; 2665a8f0974SVladimir Oltean bus->parent = priv->ds->dev; 2675a8f0974SVladimir Oltean mdio_priv = bus->priv; 2685a8f0974SVladimir Oltean mdio_priv->priv = priv; 2695a8f0974SVladimir Oltean 2705a8f0974SVladimir Oltean rc = of_mdiobus_register(bus, np); 2715a8f0974SVladimir Oltean if (rc) { 2725a8f0974SVladimir Oltean mdiobus_free(bus); 2735a8f0974SVladimir Oltean goto out_put_np; 2745a8f0974SVladimir Oltean } 2755a8f0974SVladimir Oltean 2765a8f0974SVladimir Oltean priv->mdio_base_t1 = bus; 2775a8f0974SVladimir Oltean 2785a8f0974SVladimir Oltean out_put_np: 2795a8f0974SVladimir Oltean of_node_put(np); 2805a8f0974SVladimir Oltean 2815a8f0974SVladimir Oltean return rc; 2825a8f0974SVladimir Oltean } 2835a8f0974SVladimir Oltean 2845a8f0974SVladimir Oltean static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv) 2855a8f0974SVladimir Oltean { 2865a8f0974SVladimir Oltean if (!priv->mdio_base_t1) 2875a8f0974SVladimir Oltean return; 2885a8f0974SVladimir Oltean 2895a8f0974SVladimir Oltean mdiobus_unregister(priv->mdio_base_t1); 2905a8f0974SVladimir Oltean mdiobus_free(priv->mdio_base_t1); 2915a8f0974SVladimir Oltean priv->mdio_base_t1 = NULL; 2925a8f0974SVladimir Oltean } 2935a8f0974SVladimir Oltean 294*3ad1d171SVladimir Oltean static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) 295*3ad1d171SVladimir Oltean { 296*3ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 297*3ad1d171SVladimir Oltean struct dsa_switch *ds = priv->ds; 298*3ad1d171SVladimir Oltean struct mii_bus *bus; 299*3ad1d171SVladimir Oltean int rc = 0; 300*3ad1d171SVladimir Oltean int port; 301*3ad1d171SVladimir Oltean 302*3ad1d171SVladimir Oltean if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write) 303*3ad1d171SVladimir Oltean return 0; 304*3ad1d171SVladimir Oltean 305*3ad1d171SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 306*3ad1d171SVladimir Oltean if (!bus) 307*3ad1d171SVladimir Oltean return -ENOMEM; 308*3ad1d171SVladimir Oltean 309*3ad1d171SVladimir Oltean bus->name = "SJA1105 PCS MDIO bus"; 310*3ad1d171SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs", 311*3ad1d171SVladimir Oltean dev_name(ds->dev)); 312*3ad1d171SVladimir Oltean bus->read = priv->info->pcs_mdio_read; 313*3ad1d171SVladimir Oltean bus->write = priv->info->pcs_mdio_write; 314*3ad1d171SVladimir Oltean bus->parent = ds->dev; 315*3ad1d171SVladimir Oltean /* There is no PHY on this MDIO bus => mask out all PHY addresses 316*3ad1d171SVladimir Oltean * from auto probing. 317*3ad1d171SVladimir Oltean */ 318*3ad1d171SVladimir Oltean bus->phy_mask = ~0; 319*3ad1d171SVladimir Oltean mdio_priv = bus->priv; 320*3ad1d171SVladimir Oltean mdio_priv->priv = priv; 321*3ad1d171SVladimir Oltean 322*3ad1d171SVladimir Oltean rc = mdiobus_register(bus); 323*3ad1d171SVladimir Oltean if (rc) { 324*3ad1d171SVladimir Oltean mdiobus_free(bus); 325*3ad1d171SVladimir Oltean return rc; 326*3ad1d171SVladimir Oltean } 327*3ad1d171SVladimir Oltean 328*3ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 329*3ad1d171SVladimir Oltean struct mdio_device *mdiodev; 330*3ad1d171SVladimir Oltean struct dw_xpcs *xpcs; 331*3ad1d171SVladimir Oltean 332*3ad1d171SVladimir Oltean if (dsa_is_unused_port(ds, port)) 333*3ad1d171SVladimir Oltean continue; 334*3ad1d171SVladimir Oltean 335*3ad1d171SVladimir Oltean if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII) 336*3ad1d171SVladimir Oltean continue; 337*3ad1d171SVladimir Oltean 338*3ad1d171SVladimir Oltean mdiodev = mdio_device_create(bus, port); 339*3ad1d171SVladimir Oltean if (IS_ERR(mdiodev)) { 340*3ad1d171SVladimir Oltean rc = PTR_ERR(mdiodev); 341*3ad1d171SVladimir Oltean goto out_pcs_free; 342*3ad1d171SVladimir Oltean } 343*3ad1d171SVladimir Oltean 344*3ad1d171SVladimir Oltean xpcs = xpcs_create(mdiodev, priv->phy_mode[port]); 345*3ad1d171SVladimir Oltean if (IS_ERR(xpcs)) { 346*3ad1d171SVladimir Oltean rc = PTR_ERR(xpcs); 347*3ad1d171SVladimir Oltean goto out_pcs_free; 348*3ad1d171SVladimir Oltean } 349*3ad1d171SVladimir Oltean 350*3ad1d171SVladimir Oltean priv->xpcs[port] = xpcs; 351*3ad1d171SVladimir Oltean } 352*3ad1d171SVladimir Oltean 353*3ad1d171SVladimir Oltean priv->mdio_pcs = bus; 354*3ad1d171SVladimir Oltean 355*3ad1d171SVladimir Oltean return 0; 356*3ad1d171SVladimir Oltean 357*3ad1d171SVladimir Oltean out_pcs_free: 358*3ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 359*3ad1d171SVladimir Oltean if (!priv->xpcs[port]) 360*3ad1d171SVladimir Oltean continue; 361*3ad1d171SVladimir Oltean 362*3ad1d171SVladimir Oltean mdio_device_free(priv->xpcs[port]->mdiodev); 363*3ad1d171SVladimir Oltean xpcs_destroy(priv->xpcs[port]); 364*3ad1d171SVladimir Oltean priv->xpcs[port] = NULL; 365*3ad1d171SVladimir Oltean } 366*3ad1d171SVladimir Oltean 367*3ad1d171SVladimir Oltean mdiobus_unregister(bus); 368*3ad1d171SVladimir Oltean mdiobus_free(bus); 369*3ad1d171SVladimir Oltean 370*3ad1d171SVladimir Oltean return rc; 371*3ad1d171SVladimir Oltean } 372*3ad1d171SVladimir Oltean 373*3ad1d171SVladimir Oltean static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv) 374*3ad1d171SVladimir Oltean { 375*3ad1d171SVladimir Oltean struct dsa_switch *ds = priv->ds; 376*3ad1d171SVladimir Oltean int port; 377*3ad1d171SVladimir Oltean 378*3ad1d171SVladimir Oltean if (!priv->mdio_pcs) 379*3ad1d171SVladimir Oltean return; 380*3ad1d171SVladimir Oltean 381*3ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 382*3ad1d171SVladimir Oltean if (!priv->xpcs[port]) 383*3ad1d171SVladimir Oltean continue; 384*3ad1d171SVladimir Oltean 385*3ad1d171SVladimir Oltean mdio_device_free(priv->xpcs[port]->mdiodev); 386*3ad1d171SVladimir Oltean xpcs_destroy(priv->xpcs[port]); 387*3ad1d171SVladimir Oltean priv->xpcs[port] = NULL; 388*3ad1d171SVladimir Oltean } 389*3ad1d171SVladimir Oltean 390*3ad1d171SVladimir Oltean mdiobus_unregister(priv->mdio_pcs); 391*3ad1d171SVladimir Oltean mdiobus_free(priv->mdio_pcs); 392*3ad1d171SVladimir Oltean priv->mdio_pcs = NULL; 393*3ad1d171SVladimir Oltean } 394*3ad1d171SVladimir Oltean 3955a8f0974SVladimir Oltean int sja1105_mdiobus_register(struct dsa_switch *ds) 3965a8f0974SVladimir Oltean { 3975a8f0974SVladimir Oltean struct sja1105_private *priv = ds->priv; 3985a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 3995a8f0974SVladimir Oltean struct device_node *switch_node = ds->dev->of_node; 4005a8f0974SVladimir Oltean struct device_node *mdio_node; 4015a8f0974SVladimir Oltean int rc; 4025a8f0974SVladimir Oltean 403*3ad1d171SVladimir Oltean rc = sja1105_mdiobus_pcs_register(priv); 404*3ad1d171SVladimir Oltean if (rc) 405*3ad1d171SVladimir Oltean return rc; 406*3ad1d171SVladimir Oltean 4075a8f0974SVladimir Oltean mdio_node = of_get_child_by_name(switch_node, "mdios"); 4085a8f0974SVladimir Oltean if (!mdio_node) 4095a8f0974SVladimir Oltean return 0; 4105a8f0974SVladimir Oltean 4115a8f0974SVladimir Oltean if (!of_device_is_available(mdio_node)) 4125a8f0974SVladimir Oltean goto out_put_mdio_node; 4135a8f0974SVladimir Oltean 4145a8f0974SVladimir Oltean if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) { 4155a8f0974SVladimir Oltean rc = sja1105_mdiobus_base_tx_register(priv, mdio_node); 4165a8f0974SVladimir Oltean if (rc) 4175a8f0974SVladimir Oltean goto err_put_mdio_node; 4185a8f0974SVladimir Oltean } 4195a8f0974SVladimir Oltean 4205a8f0974SVladimir Oltean if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) { 4215a8f0974SVladimir Oltean rc = sja1105_mdiobus_base_t1_register(priv, mdio_node); 4225a8f0974SVladimir Oltean if (rc) 4235a8f0974SVladimir Oltean goto err_free_base_tx_mdiobus; 4245a8f0974SVladimir Oltean } 4255a8f0974SVladimir Oltean 4265a8f0974SVladimir Oltean out_put_mdio_node: 4275a8f0974SVladimir Oltean of_node_put(mdio_node); 4285a8f0974SVladimir Oltean 4295a8f0974SVladimir Oltean return 0; 4305a8f0974SVladimir Oltean 4315a8f0974SVladimir Oltean err_free_base_tx_mdiobus: 4325a8f0974SVladimir Oltean sja1105_mdiobus_base_tx_unregister(priv); 4335a8f0974SVladimir Oltean err_put_mdio_node: 4345a8f0974SVladimir Oltean of_node_put(mdio_node); 435*3ad1d171SVladimir Oltean sja1105_mdiobus_pcs_unregister(priv); 4365a8f0974SVladimir Oltean 4375a8f0974SVladimir Oltean return rc; 4385a8f0974SVladimir Oltean } 4395a8f0974SVladimir Oltean 4405a8f0974SVladimir Oltean void sja1105_mdiobus_unregister(struct dsa_switch *ds) 4415a8f0974SVladimir Oltean { 4425a8f0974SVladimir Oltean struct sja1105_private *priv = ds->priv; 4435a8f0974SVladimir Oltean 4445a8f0974SVladimir Oltean sja1105_mdiobus_base_t1_unregister(priv); 4455a8f0974SVladimir Oltean sja1105_mdiobus_base_tx_unregister(priv); 446*3ad1d171SVladimir Oltean sja1105_mdiobus_pcs_unregister(priv); 4475a8f0974SVladimir Oltean } 448