15a8f0974SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 2*3c9cfb52SVladimir Oltean /* Copyright 2021 NXP 35a8f0974SVladimir Oltean */ 43ad1d171SVladimir Oltean #include <linux/pcs/pcs-xpcs.h> 55a8f0974SVladimir Oltean #include <linux/of_mdio.h> 65a8f0974SVladimir Oltean #include "sja1105.h" 75a8f0974SVladimir Oltean 827871359SVladimir Oltean #define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc) 927871359SVladimir Oltean 103ad1d171SVladimir Oltean int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg) 113ad1d171SVladimir Oltean { 123ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 133ad1d171SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 143ad1d171SVladimir Oltean u64 addr; 153ad1d171SVladimir Oltean u32 tmp; 163ad1d171SVladimir Oltean u16 mmd; 173ad1d171SVladimir Oltean int rc; 183ad1d171SVladimir Oltean 193ad1d171SVladimir Oltean if (!(reg & MII_ADDR_C45)) 203ad1d171SVladimir Oltean return -EINVAL; 213ad1d171SVladimir Oltean 223ad1d171SVladimir Oltean mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 233ad1d171SVladimir Oltean addr = (mmd << 16) | (reg & GENMASK(15, 0)); 243ad1d171SVladimir Oltean 253ad1d171SVladimir Oltean if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 263ad1d171SVladimir Oltean return 0xffff; 273ad1d171SVladimir Oltean 283ad1d171SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 293ad1d171SVladimir Oltean return NXP_SJA1105_XPCS_ID >> 16; 303ad1d171SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 313ad1d171SVladimir Oltean return NXP_SJA1105_XPCS_ID & GENMASK(15, 0); 323ad1d171SVladimir Oltean 333ad1d171SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 343ad1d171SVladimir Oltean if (rc < 0) 353ad1d171SVladimir Oltean return rc; 363ad1d171SVladimir Oltean 373ad1d171SVladimir Oltean return tmp & 0xffff; 383ad1d171SVladimir Oltean } 393ad1d171SVladimir Oltean 403ad1d171SVladimir Oltean int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 413ad1d171SVladimir Oltean { 423ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 433ad1d171SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 443ad1d171SVladimir Oltean u64 addr; 453ad1d171SVladimir Oltean u32 tmp; 463ad1d171SVladimir Oltean u16 mmd; 473ad1d171SVladimir Oltean 483ad1d171SVladimir Oltean if (!(reg & MII_ADDR_C45)) 493ad1d171SVladimir Oltean return -EINVAL; 503ad1d171SVladimir Oltean 513ad1d171SVladimir Oltean mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 523ad1d171SVladimir Oltean addr = (mmd << 16) | (reg & GENMASK(15, 0)); 533ad1d171SVladimir Oltean tmp = val; 543ad1d171SVladimir Oltean 553ad1d171SVladimir Oltean if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 563ad1d171SVladimir Oltean return -EINVAL; 573ad1d171SVladimir Oltean 583ad1d171SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 593ad1d171SVladimir Oltean } 603ad1d171SVladimir Oltean 6127871359SVladimir Oltean int sja1110_pcs_mdio_read(struct mii_bus *bus, int phy, int reg) 6227871359SVladimir Oltean { 6327871359SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 6427871359SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 6527871359SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 6627871359SVladimir Oltean int offset, bank; 6727871359SVladimir Oltean u64 addr; 6827871359SVladimir Oltean u32 tmp; 6927871359SVladimir Oltean u16 mmd; 7027871359SVladimir Oltean int rc; 7127871359SVladimir Oltean 7227871359SVladimir Oltean if (!(reg & MII_ADDR_C45)) 7327871359SVladimir Oltean return -EINVAL; 7427871359SVladimir Oltean 7527871359SVladimir Oltean if (regs->pcs_base[phy] == SJA1105_RSV_ADDR) 7627871359SVladimir Oltean return -ENODEV; 7727871359SVladimir Oltean 7827871359SVladimir Oltean mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 7927871359SVladimir Oltean addr = (mmd << 16) | (reg & GENMASK(15, 0)); 8027871359SVladimir Oltean 8127871359SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 8227871359SVladimir Oltean return NXP_SJA1110_XPCS_ID >> 16; 8327871359SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 8427871359SVladimir Oltean return NXP_SJA1110_XPCS_ID & GENMASK(15, 0); 8527871359SVladimir Oltean 8627871359SVladimir Oltean bank = addr >> 8; 8727871359SVladimir Oltean offset = addr & GENMASK(7, 0); 8827871359SVladimir Oltean 8927871359SVladimir Oltean /* This addressing scheme reserves register 0xff for the bank address 9027871359SVladimir Oltean * register, so that can never be addressed. 9127871359SVladimir Oltean */ 9227871359SVladimir Oltean if (WARN_ON(offset == 0xff)) 9327871359SVladimir Oltean return -ENODEV; 9427871359SVladimir Oltean 9527871359SVladimir Oltean tmp = bank; 9627871359SVladimir Oltean 9727871359SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, 9827871359SVladimir Oltean regs->pcs_base[phy] + SJA1110_PCS_BANK_REG, 9927871359SVladimir Oltean &tmp, NULL); 10027871359SVladimir Oltean if (rc < 0) 10127871359SVladimir Oltean return rc; 10227871359SVladimir Oltean 10327871359SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset, 10427871359SVladimir Oltean &tmp, NULL); 10527871359SVladimir Oltean if (rc < 0) 10627871359SVladimir Oltean return rc; 10727871359SVladimir Oltean 10827871359SVladimir Oltean return tmp & 0xffff; 10927871359SVladimir Oltean } 11027871359SVladimir Oltean 11127871359SVladimir Oltean int sja1110_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) 11227871359SVladimir Oltean { 11327871359SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 11427871359SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 11527871359SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 11627871359SVladimir Oltean int offset, bank; 11727871359SVladimir Oltean u64 addr; 11827871359SVladimir Oltean u32 tmp; 11927871359SVladimir Oltean u16 mmd; 12027871359SVladimir Oltean int rc; 12127871359SVladimir Oltean 12227871359SVladimir Oltean if (!(reg & MII_ADDR_C45)) 12327871359SVladimir Oltean return -EINVAL; 12427871359SVladimir Oltean 12527871359SVladimir Oltean if (regs->pcs_base[phy] == SJA1105_RSV_ADDR) 12627871359SVladimir Oltean return -ENODEV; 12727871359SVladimir Oltean 12827871359SVladimir Oltean mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 12927871359SVladimir Oltean addr = (mmd << 16) | (reg & GENMASK(15, 0)); 13027871359SVladimir Oltean 13127871359SVladimir Oltean bank = addr >> 8; 13227871359SVladimir Oltean offset = addr & GENMASK(7, 0); 13327871359SVladimir Oltean 13427871359SVladimir Oltean /* This addressing scheme reserves register 0xff for the bank address 13527871359SVladimir Oltean * register, so that can never be addressed. 13627871359SVladimir Oltean */ 13727871359SVladimir Oltean if (WARN_ON(offset == 0xff)) 13827871359SVladimir Oltean return -ENODEV; 13927871359SVladimir Oltean 14027871359SVladimir Oltean tmp = bank; 14127871359SVladimir Oltean 14227871359SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, 14327871359SVladimir Oltean regs->pcs_base[phy] + SJA1110_PCS_BANK_REG, 14427871359SVladimir Oltean &tmp, NULL); 14527871359SVladimir Oltean if (rc < 0) 14627871359SVladimir Oltean return rc; 14727871359SVladimir Oltean 14827871359SVladimir Oltean tmp = val; 14927871359SVladimir Oltean 15027871359SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset, 15127871359SVladimir Oltean &tmp, NULL); 15227871359SVladimir Oltean } 15327871359SVladimir Oltean 1545a8f0974SVladimir Oltean enum sja1105_mdio_opcode { 1555a8f0974SVladimir Oltean SJA1105_C45_ADDR = 0, 1565a8f0974SVladimir Oltean SJA1105_C22 = 1, 1575a8f0974SVladimir Oltean SJA1105_C45_DATA = 2, 1585a8f0974SVladimir Oltean SJA1105_C45_DATA_AUTOINC = 3, 1595a8f0974SVladimir Oltean }; 1605a8f0974SVladimir Oltean 1615a8f0974SVladimir Oltean static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv, 1625a8f0974SVladimir Oltean int phy, enum sja1105_mdio_opcode op, 1635a8f0974SVladimir Oltean int xad) 1645a8f0974SVladimir Oltean { 1655a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 1665a8f0974SVladimir Oltean 1675a8f0974SVladimir Oltean return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0); 1685a8f0974SVladimir Oltean } 1695a8f0974SVladimir Oltean 1705a8f0974SVladimir Oltean static int sja1105_base_t1_mdio_read(struct mii_bus *bus, int phy, int reg) 1715a8f0974SVladimir Oltean { 1725a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 1735a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 1745a8f0974SVladimir Oltean u64 addr; 1755a8f0974SVladimir Oltean u32 tmp; 1765a8f0974SVladimir Oltean int rc; 1775a8f0974SVladimir Oltean 1785a8f0974SVladimir Oltean if (reg & MII_ADDR_C45) { 1795a8f0974SVladimir Oltean u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 1805a8f0974SVladimir Oltean 1815a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, 1825a8f0974SVladimir Oltean mmd); 1835a8f0974SVladimir Oltean 1845a8f0974SVladimir Oltean tmp = reg & MII_REGADDR_C45_MASK; 1855a8f0974SVladimir Oltean 1865a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 1875a8f0974SVladimir Oltean if (rc < 0) 1885a8f0974SVladimir Oltean return rc; 1895a8f0974SVladimir Oltean 1905a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, 1915a8f0974SVladimir Oltean mmd); 1925a8f0974SVladimir Oltean 1935a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 1945a8f0974SVladimir Oltean if (rc < 0) 1955a8f0974SVladimir Oltean return rc; 1965a8f0974SVladimir Oltean 1975a8f0974SVladimir Oltean return tmp & 0xffff; 1985a8f0974SVladimir Oltean } 1995a8f0974SVladimir Oltean 2005a8f0974SVladimir Oltean /* Clause 22 read */ 2015a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 2025a8f0974SVladimir Oltean 2035a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 2045a8f0974SVladimir Oltean if (rc < 0) 2055a8f0974SVladimir Oltean return rc; 2065a8f0974SVladimir Oltean 2075a8f0974SVladimir Oltean return tmp & 0xffff; 2085a8f0974SVladimir Oltean } 2095a8f0974SVladimir Oltean 2105a8f0974SVladimir Oltean static int sja1105_base_t1_mdio_write(struct mii_bus *bus, int phy, int reg, 2115a8f0974SVladimir Oltean u16 val) 2125a8f0974SVladimir Oltean { 2135a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 2145a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 2155a8f0974SVladimir Oltean u64 addr; 2165a8f0974SVladimir Oltean u32 tmp; 2175a8f0974SVladimir Oltean int rc; 2185a8f0974SVladimir Oltean 2195a8f0974SVladimir Oltean if (reg & MII_ADDR_C45) { 2205a8f0974SVladimir Oltean u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f; 2215a8f0974SVladimir Oltean 2225a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, 2235a8f0974SVladimir Oltean mmd); 2245a8f0974SVladimir Oltean 2255a8f0974SVladimir Oltean tmp = reg & MII_REGADDR_C45_MASK; 2265a8f0974SVladimir Oltean 2275a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 2285a8f0974SVladimir Oltean if (rc < 0) 2295a8f0974SVladimir Oltean return rc; 2305a8f0974SVladimir Oltean 2315a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, 2325a8f0974SVladimir Oltean mmd); 2335a8f0974SVladimir Oltean 2345a8f0974SVladimir Oltean tmp = val & 0xffff; 2355a8f0974SVladimir Oltean 2365a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 2375a8f0974SVladimir Oltean if (rc < 0) 2385a8f0974SVladimir Oltean return rc; 2395a8f0974SVladimir Oltean 2405a8f0974SVladimir Oltean return 0; 2415a8f0974SVladimir Oltean } 2425a8f0974SVladimir Oltean 2435a8f0974SVladimir Oltean /* Clause 22 write */ 2445a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 2455a8f0974SVladimir Oltean 2465a8f0974SVladimir Oltean tmp = val & 0xffff; 2475a8f0974SVladimir Oltean 2485a8f0974SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 2495a8f0974SVladimir Oltean } 2505a8f0974SVladimir Oltean 2515a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg) 2525a8f0974SVladimir Oltean { 2535a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 2545a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 2555a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 2565a8f0974SVladimir Oltean u32 tmp; 2575a8f0974SVladimir Oltean int rc; 2585a8f0974SVladimir Oltean 2595a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg, 2605a8f0974SVladimir Oltean &tmp, NULL); 2615a8f0974SVladimir Oltean if (rc < 0) 2625a8f0974SVladimir Oltean return rc; 2635a8f0974SVladimir Oltean 2645a8f0974SVladimir Oltean return tmp & 0xffff; 2655a8f0974SVladimir Oltean } 2665a8f0974SVladimir Oltean 2675a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg, 2685a8f0974SVladimir Oltean u16 val) 2695a8f0974SVladimir Oltean { 2705a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 2715a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 2725a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 2735a8f0974SVladimir Oltean u32 tmp = val; 2745a8f0974SVladimir Oltean 2755a8f0974SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg, 2765a8f0974SVladimir Oltean &tmp, NULL); 2775a8f0974SVladimir Oltean } 2785a8f0974SVladimir Oltean 2795a8f0974SVladimir Oltean static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv, 2805a8f0974SVladimir Oltean struct device_node *mdio_node) 2815a8f0974SVladimir Oltean { 2825a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 2835a8f0974SVladimir Oltean struct device_node *np; 2845a8f0974SVladimir Oltean struct mii_bus *bus; 2855a8f0974SVladimir Oltean int rc = 0; 2865a8f0974SVladimir Oltean 287ed5d2937SVladimir Oltean np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio"); 2885a8f0974SVladimir Oltean if (!np) 2895a8f0974SVladimir Oltean return 0; 2905a8f0974SVladimir Oltean 2915a8f0974SVladimir Oltean if (!of_device_is_available(np)) 2925a8f0974SVladimir Oltean goto out_put_np; 2935a8f0974SVladimir Oltean 2945a8f0974SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 2955a8f0974SVladimir Oltean if (!bus) { 2965a8f0974SVladimir Oltean rc = -ENOMEM; 2975a8f0974SVladimir Oltean goto out_put_np; 2985a8f0974SVladimir Oltean } 2995a8f0974SVladimir Oltean 3005a8f0974SVladimir Oltean bus->name = "SJA1110 100base-TX MDIO bus"; 3015a8f0974SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx", 3025a8f0974SVladimir Oltean dev_name(priv->ds->dev)); 3035a8f0974SVladimir Oltean bus->read = sja1105_base_tx_mdio_read; 3045a8f0974SVladimir Oltean bus->write = sja1105_base_tx_mdio_write; 3055a8f0974SVladimir Oltean bus->parent = priv->ds->dev; 3065a8f0974SVladimir Oltean mdio_priv = bus->priv; 3075a8f0974SVladimir Oltean mdio_priv->priv = priv; 3085a8f0974SVladimir Oltean 3095a8f0974SVladimir Oltean rc = of_mdiobus_register(bus, np); 3105a8f0974SVladimir Oltean if (rc) { 3115a8f0974SVladimir Oltean mdiobus_free(bus); 3125a8f0974SVladimir Oltean goto out_put_np; 3135a8f0974SVladimir Oltean } 3145a8f0974SVladimir Oltean 3155a8f0974SVladimir Oltean priv->mdio_base_tx = bus; 3165a8f0974SVladimir Oltean 3175a8f0974SVladimir Oltean out_put_np: 3185a8f0974SVladimir Oltean of_node_put(np); 3195a8f0974SVladimir Oltean 320ab324d8dSColin Ian King return rc; 3215a8f0974SVladimir Oltean } 3225a8f0974SVladimir Oltean 3235a8f0974SVladimir Oltean static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv) 3245a8f0974SVladimir Oltean { 3255a8f0974SVladimir Oltean if (!priv->mdio_base_tx) 3265a8f0974SVladimir Oltean return; 3275a8f0974SVladimir Oltean 3285a8f0974SVladimir Oltean mdiobus_unregister(priv->mdio_base_tx); 3295a8f0974SVladimir Oltean mdiobus_free(priv->mdio_base_tx); 3305a8f0974SVladimir Oltean priv->mdio_base_tx = NULL; 3315a8f0974SVladimir Oltean } 3325a8f0974SVladimir Oltean 3335a8f0974SVladimir Oltean static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv, 3345a8f0974SVladimir Oltean struct device_node *mdio_node) 3355a8f0974SVladimir Oltean { 3365a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 3375a8f0974SVladimir Oltean struct device_node *np; 3385a8f0974SVladimir Oltean struct mii_bus *bus; 3395a8f0974SVladimir Oltean int rc = 0; 3405a8f0974SVladimir Oltean 341ed5d2937SVladimir Oltean np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio"); 3425a8f0974SVladimir Oltean if (!np) 3435a8f0974SVladimir Oltean return 0; 3445a8f0974SVladimir Oltean 3455a8f0974SVladimir Oltean if (!of_device_is_available(np)) 3465a8f0974SVladimir Oltean goto out_put_np; 3475a8f0974SVladimir Oltean 3485a8f0974SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 3495a8f0974SVladimir Oltean if (!bus) { 3505a8f0974SVladimir Oltean rc = -ENOMEM; 3515a8f0974SVladimir Oltean goto out_put_np; 3525a8f0974SVladimir Oltean } 3535a8f0974SVladimir Oltean 3545a8f0974SVladimir Oltean bus->name = "SJA1110 100base-T1 MDIO bus"; 3555a8f0974SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1", 3565a8f0974SVladimir Oltean dev_name(priv->ds->dev)); 3575a8f0974SVladimir Oltean bus->read = sja1105_base_t1_mdio_read; 3585a8f0974SVladimir Oltean bus->write = sja1105_base_t1_mdio_write; 3595a8f0974SVladimir Oltean bus->parent = priv->ds->dev; 3605a8f0974SVladimir Oltean mdio_priv = bus->priv; 3615a8f0974SVladimir Oltean mdio_priv->priv = priv; 3625a8f0974SVladimir Oltean 3635a8f0974SVladimir Oltean rc = of_mdiobus_register(bus, np); 3645a8f0974SVladimir Oltean if (rc) { 3655a8f0974SVladimir Oltean mdiobus_free(bus); 3665a8f0974SVladimir Oltean goto out_put_np; 3675a8f0974SVladimir Oltean } 3685a8f0974SVladimir Oltean 3695a8f0974SVladimir Oltean priv->mdio_base_t1 = bus; 3705a8f0974SVladimir Oltean 3715a8f0974SVladimir Oltean out_put_np: 3725a8f0974SVladimir Oltean of_node_put(np); 3735a8f0974SVladimir Oltean 3745a8f0974SVladimir Oltean return rc; 3755a8f0974SVladimir Oltean } 3765a8f0974SVladimir Oltean 3775a8f0974SVladimir Oltean static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv) 3785a8f0974SVladimir Oltean { 3795a8f0974SVladimir Oltean if (!priv->mdio_base_t1) 3805a8f0974SVladimir Oltean return; 3815a8f0974SVladimir Oltean 3825a8f0974SVladimir Oltean mdiobus_unregister(priv->mdio_base_t1); 3835a8f0974SVladimir Oltean mdiobus_free(priv->mdio_base_t1); 3845a8f0974SVladimir Oltean priv->mdio_base_t1 = NULL; 3855a8f0974SVladimir Oltean } 3865a8f0974SVladimir Oltean 3873ad1d171SVladimir Oltean static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) 3883ad1d171SVladimir Oltean { 3893ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 3903ad1d171SVladimir Oltean struct dsa_switch *ds = priv->ds; 3913ad1d171SVladimir Oltean struct mii_bus *bus; 3923ad1d171SVladimir Oltean int rc = 0; 3933ad1d171SVladimir Oltean int port; 3943ad1d171SVladimir Oltean 3953ad1d171SVladimir Oltean if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write) 3963ad1d171SVladimir Oltean return 0; 3973ad1d171SVladimir Oltean 3983ad1d171SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 3993ad1d171SVladimir Oltean if (!bus) 4003ad1d171SVladimir Oltean return -ENOMEM; 4013ad1d171SVladimir Oltean 4023ad1d171SVladimir Oltean bus->name = "SJA1105 PCS MDIO bus"; 4033ad1d171SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs", 4043ad1d171SVladimir Oltean dev_name(ds->dev)); 4053ad1d171SVladimir Oltean bus->read = priv->info->pcs_mdio_read; 4063ad1d171SVladimir Oltean bus->write = priv->info->pcs_mdio_write; 4073ad1d171SVladimir Oltean bus->parent = ds->dev; 4083ad1d171SVladimir Oltean /* There is no PHY on this MDIO bus => mask out all PHY addresses 4093ad1d171SVladimir Oltean * from auto probing. 4103ad1d171SVladimir Oltean */ 4113ad1d171SVladimir Oltean bus->phy_mask = ~0; 4123ad1d171SVladimir Oltean mdio_priv = bus->priv; 4133ad1d171SVladimir Oltean mdio_priv->priv = priv; 4143ad1d171SVladimir Oltean 4153ad1d171SVladimir Oltean rc = mdiobus_register(bus); 4163ad1d171SVladimir Oltean if (rc) { 4173ad1d171SVladimir Oltean mdiobus_free(bus); 4183ad1d171SVladimir Oltean return rc; 4193ad1d171SVladimir Oltean } 4203ad1d171SVladimir Oltean 4213ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 4223ad1d171SVladimir Oltean struct mdio_device *mdiodev; 4233ad1d171SVladimir Oltean struct dw_xpcs *xpcs; 4243ad1d171SVladimir Oltean 4253ad1d171SVladimir Oltean if (dsa_is_unused_port(ds, port)) 4263ad1d171SVladimir Oltean continue; 4273ad1d171SVladimir Oltean 42856b63466SVladimir Oltean if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII && 42956b63466SVladimir Oltean priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX) 4303ad1d171SVladimir Oltean continue; 4313ad1d171SVladimir Oltean 4323ad1d171SVladimir Oltean mdiodev = mdio_device_create(bus, port); 4333ad1d171SVladimir Oltean if (IS_ERR(mdiodev)) { 4343ad1d171SVladimir Oltean rc = PTR_ERR(mdiodev); 4353ad1d171SVladimir Oltean goto out_pcs_free; 4363ad1d171SVladimir Oltean } 4373ad1d171SVladimir Oltean 4383ad1d171SVladimir Oltean xpcs = xpcs_create(mdiodev, priv->phy_mode[port]); 4393ad1d171SVladimir Oltean if (IS_ERR(xpcs)) { 4403ad1d171SVladimir Oltean rc = PTR_ERR(xpcs); 4413ad1d171SVladimir Oltean goto out_pcs_free; 4423ad1d171SVladimir Oltean } 4433ad1d171SVladimir Oltean 4443ad1d171SVladimir Oltean priv->xpcs[port] = xpcs; 4453ad1d171SVladimir Oltean } 4463ad1d171SVladimir Oltean 4473ad1d171SVladimir Oltean priv->mdio_pcs = bus; 4483ad1d171SVladimir Oltean 4493ad1d171SVladimir Oltean return 0; 4503ad1d171SVladimir Oltean 4513ad1d171SVladimir Oltean out_pcs_free: 4523ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 4533ad1d171SVladimir Oltean if (!priv->xpcs[port]) 4543ad1d171SVladimir Oltean continue; 4553ad1d171SVladimir Oltean 4563ad1d171SVladimir Oltean mdio_device_free(priv->xpcs[port]->mdiodev); 4573ad1d171SVladimir Oltean xpcs_destroy(priv->xpcs[port]); 4583ad1d171SVladimir Oltean priv->xpcs[port] = NULL; 4593ad1d171SVladimir Oltean } 4603ad1d171SVladimir Oltean 4613ad1d171SVladimir Oltean mdiobus_unregister(bus); 4623ad1d171SVladimir Oltean mdiobus_free(bus); 4633ad1d171SVladimir Oltean 4643ad1d171SVladimir Oltean return rc; 4653ad1d171SVladimir Oltean } 4663ad1d171SVladimir Oltean 4673ad1d171SVladimir Oltean static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv) 4683ad1d171SVladimir Oltean { 4693ad1d171SVladimir Oltean struct dsa_switch *ds = priv->ds; 4703ad1d171SVladimir Oltean int port; 4713ad1d171SVladimir Oltean 4723ad1d171SVladimir Oltean if (!priv->mdio_pcs) 4733ad1d171SVladimir Oltean return; 4743ad1d171SVladimir Oltean 4753ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 4763ad1d171SVladimir Oltean if (!priv->xpcs[port]) 4773ad1d171SVladimir Oltean continue; 4783ad1d171SVladimir Oltean 4793ad1d171SVladimir Oltean mdio_device_free(priv->xpcs[port]->mdiodev); 4803ad1d171SVladimir Oltean xpcs_destroy(priv->xpcs[port]); 4813ad1d171SVladimir Oltean priv->xpcs[port] = NULL; 4823ad1d171SVladimir Oltean } 4833ad1d171SVladimir Oltean 4843ad1d171SVladimir Oltean mdiobus_unregister(priv->mdio_pcs); 4853ad1d171SVladimir Oltean mdiobus_free(priv->mdio_pcs); 4863ad1d171SVladimir Oltean priv->mdio_pcs = NULL; 4873ad1d171SVladimir Oltean } 4883ad1d171SVladimir Oltean 4895a8f0974SVladimir Oltean int sja1105_mdiobus_register(struct dsa_switch *ds) 4905a8f0974SVladimir Oltean { 4915a8f0974SVladimir Oltean struct sja1105_private *priv = ds->priv; 4925a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 4935a8f0974SVladimir Oltean struct device_node *switch_node = ds->dev->of_node; 4945a8f0974SVladimir Oltean struct device_node *mdio_node; 4955a8f0974SVladimir Oltean int rc; 4965a8f0974SVladimir Oltean 4973ad1d171SVladimir Oltean rc = sja1105_mdiobus_pcs_register(priv); 4983ad1d171SVladimir Oltean if (rc) 4993ad1d171SVladimir Oltean return rc; 5003ad1d171SVladimir Oltean 5015a8f0974SVladimir Oltean mdio_node = of_get_child_by_name(switch_node, "mdios"); 5025a8f0974SVladimir Oltean if (!mdio_node) 5035a8f0974SVladimir Oltean return 0; 5045a8f0974SVladimir Oltean 5055a8f0974SVladimir Oltean if (!of_device_is_available(mdio_node)) 5065a8f0974SVladimir Oltean goto out_put_mdio_node; 5075a8f0974SVladimir Oltean 5085a8f0974SVladimir Oltean if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) { 5095a8f0974SVladimir Oltean rc = sja1105_mdiobus_base_tx_register(priv, mdio_node); 5105a8f0974SVladimir Oltean if (rc) 5115a8f0974SVladimir Oltean goto err_put_mdio_node; 5125a8f0974SVladimir Oltean } 5135a8f0974SVladimir Oltean 5145a8f0974SVladimir Oltean if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) { 5155a8f0974SVladimir Oltean rc = sja1105_mdiobus_base_t1_register(priv, mdio_node); 5165a8f0974SVladimir Oltean if (rc) 5175a8f0974SVladimir Oltean goto err_free_base_tx_mdiobus; 5185a8f0974SVladimir Oltean } 5195a8f0974SVladimir Oltean 5205a8f0974SVladimir Oltean out_put_mdio_node: 5215a8f0974SVladimir Oltean of_node_put(mdio_node); 5225a8f0974SVladimir Oltean 5235a8f0974SVladimir Oltean return 0; 5245a8f0974SVladimir Oltean 5255a8f0974SVladimir Oltean err_free_base_tx_mdiobus: 5265a8f0974SVladimir Oltean sja1105_mdiobus_base_tx_unregister(priv); 5275a8f0974SVladimir Oltean err_put_mdio_node: 5285a8f0974SVladimir Oltean of_node_put(mdio_node); 5293ad1d171SVladimir Oltean sja1105_mdiobus_pcs_unregister(priv); 5305a8f0974SVladimir Oltean 5315a8f0974SVladimir Oltean return rc; 5325a8f0974SVladimir Oltean } 5335a8f0974SVladimir Oltean 5345a8f0974SVladimir Oltean void sja1105_mdiobus_unregister(struct dsa_switch *ds) 5355a8f0974SVladimir Oltean { 5365a8f0974SVladimir Oltean struct sja1105_private *priv = ds->priv; 5375a8f0974SVladimir Oltean 5385a8f0974SVladimir Oltean sja1105_mdiobus_base_t1_unregister(priv); 5395a8f0974SVladimir Oltean sja1105_mdiobus_base_tx_unregister(priv); 5403ad1d171SVladimir Oltean sja1105_mdiobus_pcs_unregister(priv); 5415a8f0974SVladimir Oltean } 542