15a8f0974SVladimir Oltean // SPDX-License-Identifier: GPL-2.0 23c9cfb52SVladimir 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 10ae271547SAndrew Lunn int sja1105_pcs_mdio_read_c45(struct mii_bus *bus, int phy, int mmd, 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 int rc; 173ad1d171SVladimir Oltean 18ae271547SAndrew Lunn addr = (mmd << 16) | reg; 193ad1d171SVladimir Oltean 203ad1d171SVladimir Oltean if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 213ad1d171SVladimir Oltean return 0xffff; 223ad1d171SVladimir Oltean 233ad1d171SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 243ad1d171SVladimir Oltean return NXP_SJA1105_XPCS_ID >> 16; 253ad1d171SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 263ad1d171SVladimir Oltean return NXP_SJA1105_XPCS_ID & GENMASK(15, 0); 273ad1d171SVladimir Oltean 283ad1d171SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 293ad1d171SVladimir Oltean if (rc < 0) 303ad1d171SVladimir Oltean return rc; 313ad1d171SVladimir Oltean 323ad1d171SVladimir Oltean return tmp & 0xffff; 333ad1d171SVladimir Oltean } 343ad1d171SVladimir Oltean 35ae271547SAndrew Lunn int sja1105_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd, 36ae271547SAndrew Lunn int reg, u16 val) 373ad1d171SVladimir Oltean { 383ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 393ad1d171SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 403ad1d171SVladimir Oltean u64 addr; 413ad1d171SVladimir Oltean u32 tmp; 423ad1d171SVladimir Oltean 43ae271547SAndrew Lunn addr = (mmd << 16) | reg; 443ad1d171SVladimir Oltean tmp = val; 453ad1d171SVladimir Oltean 463ad1d171SVladimir Oltean if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 473ad1d171SVladimir Oltean return -EINVAL; 483ad1d171SVladimir Oltean 493ad1d171SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 503ad1d171SVladimir Oltean } 513ad1d171SVladimir Oltean 52ae271547SAndrew Lunn int sja1110_pcs_mdio_read_c45(struct mii_bus *bus, int phy, int mmd, int reg) 5327871359SVladimir Oltean { 5427871359SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 5527871359SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 5627871359SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 5727871359SVladimir Oltean int offset, bank; 5827871359SVladimir Oltean u64 addr; 5927871359SVladimir Oltean u32 tmp; 6027871359SVladimir Oltean int rc; 6127871359SVladimir Oltean 6227871359SVladimir Oltean if (regs->pcs_base[phy] == SJA1105_RSV_ADDR) 6327871359SVladimir Oltean return -ENODEV; 6427871359SVladimir Oltean 65ae271547SAndrew Lunn addr = (mmd << 16) | reg; 6627871359SVladimir Oltean 6727871359SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 6827871359SVladimir Oltean return NXP_SJA1110_XPCS_ID >> 16; 6927871359SVladimir Oltean if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 7027871359SVladimir Oltean return NXP_SJA1110_XPCS_ID & GENMASK(15, 0); 7127871359SVladimir Oltean 7227871359SVladimir Oltean bank = addr >> 8; 7327871359SVladimir Oltean offset = addr & GENMASK(7, 0); 7427871359SVladimir Oltean 7527871359SVladimir Oltean /* This addressing scheme reserves register 0xff for the bank address 7627871359SVladimir Oltean * register, so that can never be addressed. 7727871359SVladimir Oltean */ 7827871359SVladimir Oltean if (WARN_ON(offset == 0xff)) 7927871359SVladimir Oltean return -ENODEV; 8027871359SVladimir Oltean 8127871359SVladimir Oltean tmp = bank; 8227871359SVladimir Oltean 8327871359SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, 8427871359SVladimir Oltean regs->pcs_base[phy] + SJA1110_PCS_BANK_REG, 8527871359SVladimir Oltean &tmp, NULL); 8627871359SVladimir Oltean if (rc < 0) 8727871359SVladimir Oltean return rc; 8827871359SVladimir Oltean 8927871359SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset, 9027871359SVladimir Oltean &tmp, NULL); 9127871359SVladimir Oltean if (rc < 0) 9227871359SVladimir Oltean return rc; 9327871359SVladimir Oltean 9427871359SVladimir Oltean return tmp & 0xffff; 9527871359SVladimir Oltean } 9627871359SVladimir Oltean 97ae271547SAndrew Lunn int sja1110_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int reg, int mmd, 98ae271547SAndrew Lunn u16 val) 9927871359SVladimir Oltean { 10027871359SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 10127871359SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 10227871359SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 10327871359SVladimir Oltean int offset, bank; 10427871359SVladimir Oltean u64 addr; 10527871359SVladimir Oltean u32 tmp; 10627871359SVladimir Oltean int rc; 10727871359SVladimir Oltean 10827871359SVladimir Oltean if (regs->pcs_base[phy] == SJA1105_RSV_ADDR) 10927871359SVladimir Oltean return -ENODEV; 11027871359SVladimir Oltean 111ae271547SAndrew Lunn addr = (mmd << 16) | reg; 11227871359SVladimir Oltean 11327871359SVladimir Oltean bank = addr >> 8; 11427871359SVladimir Oltean offset = addr & GENMASK(7, 0); 11527871359SVladimir Oltean 11627871359SVladimir Oltean /* This addressing scheme reserves register 0xff for the bank address 11727871359SVladimir Oltean * register, so that can never be addressed. 11827871359SVladimir Oltean */ 11927871359SVladimir Oltean if (WARN_ON(offset == 0xff)) 12027871359SVladimir Oltean return -ENODEV; 12127871359SVladimir Oltean 12227871359SVladimir Oltean tmp = bank; 12327871359SVladimir Oltean 12427871359SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_WRITE, 12527871359SVladimir Oltean regs->pcs_base[phy] + SJA1110_PCS_BANK_REG, 12627871359SVladimir Oltean &tmp, NULL); 12727871359SVladimir Oltean if (rc < 0) 12827871359SVladimir Oltean return rc; 12927871359SVladimir Oltean 13027871359SVladimir Oltean tmp = val; 13127871359SVladimir Oltean 13227871359SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset, 13327871359SVladimir Oltean &tmp, NULL); 13427871359SVladimir Oltean } 13527871359SVladimir Oltean 1365a8f0974SVladimir Oltean enum sja1105_mdio_opcode { 1375a8f0974SVladimir Oltean SJA1105_C45_ADDR = 0, 1385a8f0974SVladimir Oltean SJA1105_C22 = 1, 1395a8f0974SVladimir Oltean SJA1105_C45_DATA = 2, 1405a8f0974SVladimir Oltean SJA1105_C45_DATA_AUTOINC = 3, 1415a8f0974SVladimir Oltean }; 1425a8f0974SVladimir Oltean 1435a8f0974SVladimir Oltean static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv, 1445a8f0974SVladimir Oltean int phy, enum sja1105_mdio_opcode op, 1455a8f0974SVladimir Oltean int xad) 1465a8f0974SVladimir Oltean { 1475a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 1485a8f0974SVladimir Oltean 1495a8f0974SVladimir Oltean return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0); 1505a8f0974SVladimir Oltean } 1515a8f0974SVladimir Oltean 152*c708e135SAndrew Lunn static int sja1105_base_t1_mdio_read_c22(struct mii_bus *bus, int phy, int reg) 1535a8f0974SVladimir Oltean { 1545a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 1555a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 1565a8f0974SVladimir Oltean u64 addr; 1575a8f0974SVladimir Oltean u32 tmp; 1585a8f0974SVladimir Oltean int rc; 1595a8f0974SVladimir Oltean 1605a8f0974SVladimir Oltean addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 1615a8f0974SVladimir Oltean 1625a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 1635a8f0974SVladimir Oltean if (rc < 0) 1645a8f0974SVladimir Oltean return rc; 1655a8f0974SVladimir Oltean 1665a8f0974SVladimir Oltean return tmp & 0xffff; 1675a8f0974SVladimir Oltean } 1685a8f0974SVladimir Oltean 169*c708e135SAndrew Lunn static int sja1105_base_t1_mdio_read_c45(struct mii_bus *bus, int phy, 170*c708e135SAndrew Lunn int mmd, int reg) 171*c708e135SAndrew Lunn { 172*c708e135SAndrew Lunn struct sja1105_mdio_private *mdio_priv = bus->priv; 173*c708e135SAndrew Lunn struct sja1105_private *priv = mdio_priv->priv; 174*c708e135SAndrew Lunn u64 addr; 175*c708e135SAndrew Lunn u32 tmp; 176*c708e135SAndrew Lunn int rc; 177*c708e135SAndrew Lunn 178*c708e135SAndrew Lunn addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd); 179*c708e135SAndrew Lunn 180*c708e135SAndrew Lunn rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, ®, NULL); 181*c708e135SAndrew Lunn if (rc < 0) 182*c708e135SAndrew Lunn return rc; 183*c708e135SAndrew Lunn 184*c708e135SAndrew Lunn addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd); 185*c708e135SAndrew Lunn 186*c708e135SAndrew Lunn rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 187*c708e135SAndrew Lunn if (rc < 0) 188*c708e135SAndrew Lunn return rc; 189*c708e135SAndrew Lunn 190*c708e135SAndrew Lunn return tmp & 0xffff; 191*c708e135SAndrew Lunn } 192*c708e135SAndrew Lunn 193*c708e135SAndrew Lunn static int sja1105_base_t1_mdio_write_c22(struct mii_bus *bus, int phy, int reg, 1945a8f0974SVladimir Oltean u16 val) 1955a8f0974SVladimir Oltean { 1965a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 1975a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 1985a8f0974SVladimir Oltean u64 addr; 1995a8f0974SVladimir Oltean u32 tmp; 2005a8f0974SVladimir Oltean 201*c708e135SAndrew Lunn addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 2025a8f0974SVladimir Oltean 2035a8f0974SVladimir Oltean tmp = val & 0xffff; 2045a8f0974SVladimir Oltean 205*c708e135SAndrew Lunn return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 206*c708e135SAndrew Lunn } 207*c708e135SAndrew Lunn 208*c708e135SAndrew Lunn static int sja1105_base_t1_mdio_write_c45(struct mii_bus *bus, int phy, 209*c708e135SAndrew Lunn int mmd, int reg, u16 val) 210*c708e135SAndrew Lunn { 211*c708e135SAndrew Lunn struct sja1105_mdio_private *mdio_priv = bus->priv; 212*c708e135SAndrew Lunn struct sja1105_private *priv = mdio_priv->priv; 213*c708e135SAndrew Lunn u64 addr; 214*c708e135SAndrew Lunn u32 tmp; 215*c708e135SAndrew Lunn int rc; 216*c708e135SAndrew Lunn 217*c708e135SAndrew Lunn addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd); 218*c708e135SAndrew Lunn 219*c708e135SAndrew Lunn rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, ®, NULL); 2205a8f0974SVladimir Oltean if (rc < 0) 2215a8f0974SVladimir Oltean return rc; 2225a8f0974SVladimir Oltean 223*c708e135SAndrew Lunn addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd); 2245a8f0974SVladimir Oltean 2255a8f0974SVladimir Oltean tmp = val & 0xffff; 2265a8f0974SVladimir Oltean 2275a8f0974SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 2285a8f0974SVladimir Oltean } 2295a8f0974SVladimir Oltean 2305a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg) 2315a8f0974SVladimir Oltean { 2325a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 2335a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 2345a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 2355a8f0974SVladimir Oltean u32 tmp; 2365a8f0974SVladimir Oltean int rc; 2375a8f0974SVladimir Oltean 23824deec6bSVladimir Oltean if (reg & MII_ADDR_C45) 23924deec6bSVladimir Oltean return -EOPNOTSUPP; 24024deec6bSVladimir Oltean 2415a8f0974SVladimir Oltean rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg, 2425a8f0974SVladimir Oltean &tmp, NULL); 2435a8f0974SVladimir Oltean if (rc < 0) 2445a8f0974SVladimir Oltean return rc; 2455a8f0974SVladimir Oltean 2465a8f0974SVladimir Oltean return tmp & 0xffff; 2475a8f0974SVladimir Oltean } 2485a8f0974SVladimir Oltean 2495a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg, 2505a8f0974SVladimir Oltean u16 val) 2515a8f0974SVladimir Oltean { 2525a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv = bus->priv; 2535a8f0974SVladimir Oltean struct sja1105_private *priv = mdio_priv->priv; 2545a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 2555a8f0974SVladimir Oltean u32 tmp = val; 2565a8f0974SVladimir Oltean 25724deec6bSVladimir Oltean if (reg & MII_ADDR_C45) 25824deec6bSVladimir Oltean return -EOPNOTSUPP; 25924deec6bSVladimir Oltean 2605a8f0974SVladimir Oltean return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg, 2615a8f0974SVladimir Oltean &tmp, NULL); 2625a8f0974SVladimir Oltean } 2635a8f0974SVladimir Oltean 2645a8f0974SVladimir Oltean static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv, 2655a8f0974SVladimir Oltean struct device_node *mdio_node) 2665a8f0974SVladimir Oltean { 2675a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 2685a8f0974SVladimir Oltean struct device_node *np; 2695a8f0974SVladimir Oltean struct mii_bus *bus; 2705a8f0974SVladimir Oltean int rc = 0; 2715a8f0974SVladimir Oltean 272ed5d2937SVladimir Oltean np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio"); 2735a8f0974SVladimir Oltean if (!np) 2745a8f0974SVladimir Oltean return 0; 2755a8f0974SVladimir Oltean 2765a8f0974SVladimir Oltean if (!of_device_is_available(np)) 2775a8f0974SVladimir Oltean goto out_put_np; 2785a8f0974SVladimir Oltean 2795a8f0974SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 2805a8f0974SVladimir Oltean if (!bus) { 2815a8f0974SVladimir Oltean rc = -ENOMEM; 2825a8f0974SVladimir Oltean goto out_put_np; 2835a8f0974SVladimir Oltean } 2845a8f0974SVladimir Oltean 2855a8f0974SVladimir Oltean bus->name = "SJA1110 100base-TX MDIO bus"; 2865a8f0974SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx", 2875a8f0974SVladimir Oltean dev_name(priv->ds->dev)); 2885a8f0974SVladimir Oltean bus->read = sja1105_base_tx_mdio_read; 2895a8f0974SVladimir Oltean bus->write = sja1105_base_tx_mdio_write; 2905a8f0974SVladimir Oltean bus->parent = priv->ds->dev; 2915a8f0974SVladimir Oltean mdio_priv = bus->priv; 2925a8f0974SVladimir Oltean mdio_priv->priv = priv; 2935a8f0974SVladimir Oltean 2945a8f0974SVladimir Oltean rc = of_mdiobus_register(bus, np); 2955a8f0974SVladimir Oltean if (rc) { 2965a8f0974SVladimir Oltean mdiobus_free(bus); 2975a8f0974SVladimir Oltean goto out_put_np; 2985a8f0974SVladimir Oltean } 2995a8f0974SVladimir Oltean 3005a8f0974SVladimir Oltean priv->mdio_base_tx = bus; 3015a8f0974SVladimir Oltean 3025a8f0974SVladimir Oltean out_put_np: 3035a8f0974SVladimir Oltean of_node_put(np); 3045a8f0974SVladimir Oltean 305ab324d8dSColin Ian King return rc; 3065a8f0974SVladimir Oltean } 3075a8f0974SVladimir Oltean 3085a8f0974SVladimir Oltean static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv) 3095a8f0974SVladimir Oltean { 3105a8f0974SVladimir Oltean if (!priv->mdio_base_tx) 3115a8f0974SVladimir Oltean return; 3125a8f0974SVladimir Oltean 3135a8f0974SVladimir Oltean mdiobus_unregister(priv->mdio_base_tx); 3145a8f0974SVladimir Oltean mdiobus_free(priv->mdio_base_tx); 3155a8f0974SVladimir Oltean priv->mdio_base_tx = NULL; 3165a8f0974SVladimir Oltean } 3175a8f0974SVladimir Oltean 3185a8f0974SVladimir Oltean static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv, 3195a8f0974SVladimir Oltean struct device_node *mdio_node) 3205a8f0974SVladimir Oltean { 3215a8f0974SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 3225a8f0974SVladimir Oltean struct device_node *np; 3235a8f0974SVladimir Oltean struct mii_bus *bus; 3245a8f0974SVladimir Oltean int rc = 0; 3255a8f0974SVladimir Oltean 326ed5d2937SVladimir Oltean np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio"); 3275a8f0974SVladimir Oltean if (!np) 3285a8f0974SVladimir Oltean return 0; 3295a8f0974SVladimir Oltean 3305a8f0974SVladimir Oltean if (!of_device_is_available(np)) 3315a8f0974SVladimir Oltean goto out_put_np; 3325a8f0974SVladimir Oltean 3335a8f0974SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 3345a8f0974SVladimir Oltean if (!bus) { 3355a8f0974SVladimir Oltean rc = -ENOMEM; 3365a8f0974SVladimir Oltean goto out_put_np; 3375a8f0974SVladimir Oltean } 3385a8f0974SVladimir Oltean 3395a8f0974SVladimir Oltean bus->name = "SJA1110 100base-T1 MDIO bus"; 3405a8f0974SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1", 3415a8f0974SVladimir Oltean dev_name(priv->ds->dev)); 342*c708e135SAndrew Lunn bus->read = sja1105_base_t1_mdio_read_c22; 343*c708e135SAndrew Lunn bus->write = sja1105_base_t1_mdio_write_c22; 344*c708e135SAndrew Lunn bus->read_c45 = sja1105_base_t1_mdio_read_c45; 345*c708e135SAndrew Lunn bus->write_c45 = sja1105_base_t1_mdio_write_c45; 3465a8f0974SVladimir Oltean bus->parent = priv->ds->dev; 3475a8f0974SVladimir Oltean mdio_priv = bus->priv; 3485a8f0974SVladimir Oltean mdio_priv->priv = priv; 3495a8f0974SVladimir Oltean 3505a8f0974SVladimir Oltean rc = of_mdiobus_register(bus, np); 3515a8f0974SVladimir Oltean if (rc) { 3525a8f0974SVladimir Oltean mdiobus_free(bus); 3535a8f0974SVladimir Oltean goto out_put_np; 3545a8f0974SVladimir Oltean } 3555a8f0974SVladimir Oltean 3565a8f0974SVladimir Oltean priv->mdio_base_t1 = bus; 3575a8f0974SVladimir Oltean 3585a8f0974SVladimir Oltean out_put_np: 3595a8f0974SVladimir Oltean of_node_put(np); 3605a8f0974SVladimir Oltean 3615a8f0974SVladimir Oltean return rc; 3625a8f0974SVladimir Oltean } 3635a8f0974SVladimir Oltean 3645a8f0974SVladimir Oltean static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv) 3655a8f0974SVladimir Oltean { 3665a8f0974SVladimir Oltean if (!priv->mdio_base_t1) 3675a8f0974SVladimir Oltean return; 3685a8f0974SVladimir Oltean 3695a8f0974SVladimir Oltean mdiobus_unregister(priv->mdio_base_t1); 3705a8f0974SVladimir Oltean mdiobus_free(priv->mdio_base_t1); 3715a8f0974SVladimir Oltean priv->mdio_base_t1 = NULL; 3725a8f0974SVladimir Oltean } 3735a8f0974SVladimir Oltean 3743ad1d171SVladimir Oltean static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) 3753ad1d171SVladimir Oltean { 3763ad1d171SVladimir Oltean struct sja1105_mdio_private *mdio_priv; 3773ad1d171SVladimir Oltean struct dsa_switch *ds = priv->ds; 3783ad1d171SVladimir Oltean struct mii_bus *bus; 3793ad1d171SVladimir Oltean int rc = 0; 3803ad1d171SVladimir Oltean int port; 3813ad1d171SVladimir Oltean 382ae271547SAndrew Lunn if (!priv->info->pcs_mdio_read_c45 || !priv->info->pcs_mdio_write_c45) 3833ad1d171SVladimir Oltean return 0; 3843ad1d171SVladimir Oltean 3853ad1d171SVladimir Oltean bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 3863ad1d171SVladimir Oltean if (!bus) 3873ad1d171SVladimir Oltean return -ENOMEM; 3883ad1d171SVladimir Oltean 3893ad1d171SVladimir Oltean bus->name = "SJA1105 PCS MDIO bus"; 3903ad1d171SVladimir Oltean snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs", 3913ad1d171SVladimir Oltean dev_name(ds->dev)); 392ae271547SAndrew Lunn bus->read_c45 = priv->info->pcs_mdio_read_c45; 393ae271547SAndrew Lunn bus->write_c45 = priv->info->pcs_mdio_write_c45; 3943ad1d171SVladimir Oltean bus->parent = ds->dev; 3953ad1d171SVladimir Oltean /* There is no PHY on this MDIO bus => mask out all PHY addresses 3963ad1d171SVladimir Oltean * from auto probing. 3973ad1d171SVladimir Oltean */ 3983ad1d171SVladimir Oltean bus->phy_mask = ~0; 3993ad1d171SVladimir Oltean mdio_priv = bus->priv; 4003ad1d171SVladimir Oltean mdio_priv->priv = priv; 4013ad1d171SVladimir Oltean 4023ad1d171SVladimir Oltean rc = mdiobus_register(bus); 4033ad1d171SVladimir Oltean if (rc) { 4043ad1d171SVladimir Oltean mdiobus_free(bus); 4053ad1d171SVladimir Oltean return rc; 4063ad1d171SVladimir Oltean } 4073ad1d171SVladimir Oltean 4083ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 4093ad1d171SVladimir Oltean struct mdio_device *mdiodev; 4103ad1d171SVladimir Oltean struct dw_xpcs *xpcs; 4113ad1d171SVladimir Oltean 4123ad1d171SVladimir Oltean if (dsa_is_unused_port(ds, port)) 4133ad1d171SVladimir Oltean continue; 4143ad1d171SVladimir Oltean 41556b63466SVladimir Oltean if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII && 41656b63466SVladimir Oltean priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX) 4173ad1d171SVladimir Oltean continue; 4183ad1d171SVladimir Oltean 4193ad1d171SVladimir Oltean mdiodev = mdio_device_create(bus, port); 4203ad1d171SVladimir Oltean if (IS_ERR(mdiodev)) { 4213ad1d171SVladimir Oltean rc = PTR_ERR(mdiodev); 4223ad1d171SVladimir Oltean goto out_pcs_free; 4233ad1d171SVladimir Oltean } 4243ad1d171SVladimir Oltean 4253ad1d171SVladimir Oltean xpcs = xpcs_create(mdiodev, priv->phy_mode[port]); 4263ad1d171SVladimir Oltean if (IS_ERR(xpcs)) { 4273ad1d171SVladimir Oltean rc = PTR_ERR(xpcs); 4283ad1d171SVladimir Oltean goto out_pcs_free; 4293ad1d171SVladimir Oltean } 4303ad1d171SVladimir Oltean 4313ad1d171SVladimir Oltean priv->xpcs[port] = xpcs; 4323ad1d171SVladimir Oltean } 4333ad1d171SVladimir Oltean 4343ad1d171SVladimir Oltean priv->mdio_pcs = bus; 4353ad1d171SVladimir Oltean 4363ad1d171SVladimir Oltean return 0; 4373ad1d171SVladimir Oltean 4383ad1d171SVladimir Oltean out_pcs_free: 4393ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 4403ad1d171SVladimir Oltean if (!priv->xpcs[port]) 4413ad1d171SVladimir Oltean continue; 4423ad1d171SVladimir Oltean 4433ad1d171SVladimir Oltean mdio_device_free(priv->xpcs[port]->mdiodev); 4443ad1d171SVladimir Oltean xpcs_destroy(priv->xpcs[port]); 4453ad1d171SVladimir Oltean priv->xpcs[port] = NULL; 4463ad1d171SVladimir Oltean } 4473ad1d171SVladimir Oltean 4483ad1d171SVladimir Oltean mdiobus_unregister(bus); 4493ad1d171SVladimir Oltean mdiobus_free(bus); 4503ad1d171SVladimir Oltean 4513ad1d171SVladimir Oltean return rc; 4523ad1d171SVladimir Oltean } 4533ad1d171SVladimir Oltean 4543ad1d171SVladimir Oltean static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv) 4553ad1d171SVladimir Oltean { 4563ad1d171SVladimir Oltean struct dsa_switch *ds = priv->ds; 4573ad1d171SVladimir Oltean int port; 4583ad1d171SVladimir Oltean 4593ad1d171SVladimir Oltean if (!priv->mdio_pcs) 4603ad1d171SVladimir Oltean return; 4613ad1d171SVladimir Oltean 4623ad1d171SVladimir Oltean for (port = 0; port < ds->num_ports; port++) { 4633ad1d171SVladimir Oltean if (!priv->xpcs[port]) 4643ad1d171SVladimir Oltean continue; 4653ad1d171SVladimir Oltean 4663ad1d171SVladimir Oltean mdio_device_free(priv->xpcs[port]->mdiodev); 4673ad1d171SVladimir Oltean xpcs_destroy(priv->xpcs[port]); 4683ad1d171SVladimir Oltean priv->xpcs[port] = NULL; 4693ad1d171SVladimir Oltean } 4703ad1d171SVladimir Oltean 4713ad1d171SVladimir Oltean mdiobus_unregister(priv->mdio_pcs); 4723ad1d171SVladimir Oltean mdiobus_free(priv->mdio_pcs); 4733ad1d171SVladimir Oltean priv->mdio_pcs = NULL; 4743ad1d171SVladimir Oltean } 4753ad1d171SVladimir Oltean 4765a8f0974SVladimir Oltean int sja1105_mdiobus_register(struct dsa_switch *ds) 4775a8f0974SVladimir Oltean { 4785a8f0974SVladimir Oltean struct sja1105_private *priv = ds->priv; 4795a8f0974SVladimir Oltean const struct sja1105_regs *regs = priv->info->regs; 4805a8f0974SVladimir Oltean struct device_node *switch_node = ds->dev->of_node; 4815a8f0974SVladimir Oltean struct device_node *mdio_node; 4825a8f0974SVladimir Oltean int rc; 4835a8f0974SVladimir Oltean 4843ad1d171SVladimir Oltean rc = sja1105_mdiobus_pcs_register(priv); 4853ad1d171SVladimir Oltean if (rc) 4863ad1d171SVladimir Oltean return rc; 4873ad1d171SVladimir Oltean 4885a8f0974SVladimir Oltean mdio_node = of_get_child_by_name(switch_node, "mdios"); 4895a8f0974SVladimir Oltean if (!mdio_node) 4905a8f0974SVladimir Oltean return 0; 4915a8f0974SVladimir Oltean 4925a8f0974SVladimir Oltean if (!of_device_is_available(mdio_node)) 4935a8f0974SVladimir Oltean goto out_put_mdio_node; 4945a8f0974SVladimir Oltean 4955a8f0974SVladimir Oltean if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) { 4965a8f0974SVladimir Oltean rc = sja1105_mdiobus_base_tx_register(priv, mdio_node); 4975a8f0974SVladimir Oltean if (rc) 4985a8f0974SVladimir Oltean goto err_put_mdio_node; 4995a8f0974SVladimir Oltean } 5005a8f0974SVladimir Oltean 5015a8f0974SVladimir Oltean if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) { 5025a8f0974SVladimir Oltean rc = sja1105_mdiobus_base_t1_register(priv, mdio_node); 5035a8f0974SVladimir Oltean if (rc) 5045a8f0974SVladimir Oltean goto err_free_base_tx_mdiobus; 5055a8f0974SVladimir Oltean } 5065a8f0974SVladimir Oltean 5075a8f0974SVladimir Oltean out_put_mdio_node: 5085a8f0974SVladimir Oltean of_node_put(mdio_node); 5095a8f0974SVladimir Oltean 5105a8f0974SVladimir Oltean return 0; 5115a8f0974SVladimir Oltean 5125a8f0974SVladimir Oltean err_free_base_tx_mdiobus: 5135a8f0974SVladimir Oltean sja1105_mdiobus_base_tx_unregister(priv); 5145a8f0974SVladimir Oltean err_put_mdio_node: 5155a8f0974SVladimir Oltean of_node_put(mdio_node); 5163ad1d171SVladimir Oltean sja1105_mdiobus_pcs_unregister(priv); 5175a8f0974SVladimir Oltean 5185a8f0974SVladimir Oltean return rc; 5195a8f0974SVladimir Oltean } 5205a8f0974SVladimir Oltean 5215a8f0974SVladimir Oltean void sja1105_mdiobus_unregister(struct dsa_switch *ds) 5225a8f0974SVladimir Oltean { 5235a8f0974SVladimir Oltean struct sja1105_private *priv = ds->priv; 5245a8f0974SVladimir Oltean 5255a8f0974SVladimir Oltean sja1105_mdiobus_base_t1_unregister(priv); 5265a8f0974SVladimir Oltean sja1105_mdiobus_base_tx_unregister(priv); 5273ad1d171SVladimir Oltean sja1105_mdiobus_pcs_unregister(priv); 5285a8f0974SVladimir Oltean } 529