162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright 2021 NXP 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci#include <linux/pcs/pcs-xpcs.h> 562306a36Sopenharmony_ci#include <linux/of_mdio.h> 662306a36Sopenharmony_ci#include "sja1105.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc) 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciint sja1105_pcs_mdio_read_c45(struct mii_bus *bus, int phy, int mmd, int reg) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 1362306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 1462306a36Sopenharmony_ci u64 addr; 1562306a36Sopenharmony_ci u32 tmp; 1662306a36Sopenharmony_ci int rc; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci addr = (mmd << 16) | reg; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 2162306a36Sopenharmony_ci return 0xffff; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 2462306a36Sopenharmony_ci return NXP_SJA1105_XPCS_ID >> 16; 2562306a36Sopenharmony_ci if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 2662306a36Sopenharmony_ci return NXP_SJA1105_XPCS_ID & GENMASK(15, 0); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 2962306a36Sopenharmony_ci if (rc < 0) 3062306a36Sopenharmony_ci return rc; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci return tmp & 0xffff; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint sja1105_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd, 3662306a36Sopenharmony_ci int reg, u16 val) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 3962306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 4062306a36Sopenharmony_ci u64 addr; 4162306a36Sopenharmony_ci u32 tmp; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci addr = (mmd << 16) | reg; 4462306a36Sopenharmony_ci tmp = val; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2) 4762306a36Sopenharmony_ci return -EINVAL; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciint sja1110_pcs_mdio_read_c45(struct mii_bus *bus, int phy, int mmd, int reg) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 5562306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 5662306a36Sopenharmony_ci const struct sja1105_regs *regs = priv->info->regs; 5762306a36Sopenharmony_ci int offset, bank; 5862306a36Sopenharmony_ci u64 addr; 5962306a36Sopenharmony_ci u32 tmp; 6062306a36Sopenharmony_ci int rc; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (regs->pcs_base[phy] == SJA1105_RSV_ADDR) 6362306a36Sopenharmony_ci return -ENODEV; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci addr = (mmd << 16) | reg; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1) 6862306a36Sopenharmony_ci return NXP_SJA1110_XPCS_ID >> 16; 6962306a36Sopenharmony_ci if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2) 7062306a36Sopenharmony_ci return NXP_SJA1110_XPCS_ID & GENMASK(15, 0); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci bank = addr >> 8; 7362306a36Sopenharmony_ci offset = addr & GENMASK(7, 0); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* This addressing scheme reserves register 0xff for the bank address 7662306a36Sopenharmony_ci * register, so that can never be addressed. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci if (WARN_ON(offset == 0xff)) 7962306a36Sopenharmony_ci return -ENODEV; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci tmp = bank; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_WRITE, 8462306a36Sopenharmony_ci regs->pcs_base[phy] + SJA1110_PCS_BANK_REG, 8562306a36Sopenharmony_ci &tmp, NULL); 8662306a36Sopenharmony_ci if (rc < 0) 8762306a36Sopenharmony_ci return rc; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset, 9062306a36Sopenharmony_ci &tmp, NULL); 9162306a36Sopenharmony_ci if (rc < 0) 9262306a36Sopenharmony_ci return rc; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return tmp & 0xffff; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciint sja1110_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int reg, int mmd, 9862306a36Sopenharmony_ci u16 val) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 10162306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 10262306a36Sopenharmony_ci const struct sja1105_regs *regs = priv->info->regs; 10362306a36Sopenharmony_ci int offset, bank; 10462306a36Sopenharmony_ci u64 addr; 10562306a36Sopenharmony_ci u32 tmp; 10662306a36Sopenharmony_ci int rc; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (regs->pcs_base[phy] == SJA1105_RSV_ADDR) 10962306a36Sopenharmony_ci return -ENODEV; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci addr = (mmd << 16) | reg; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci bank = addr >> 8; 11462306a36Sopenharmony_ci offset = addr & GENMASK(7, 0); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* This addressing scheme reserves register 0xff for the bank address 11762306a36Sopenharmony_ci * register, so that can never be addressed. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci if (WARN_ON(offset == 0xff)) 12062306a36Sopenharmony_ci return -ENODEV; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci tmp = bank; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_WRITE, 12562306a36Sopenharmony_ci regs->pcs_base[phy] + SJA1110_PCS_BANK_REG, 12662306a36Sopenharmony_ci &tmp, NULL); 12762306a36Sopenharmony_ci if (rc < 0) 12862306a36Sopenharmony_ci return rc; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci tmp = val; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset, 13362306a36Sopenharmony_ci &tmp, NULL); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cienum sja1105_mdio_opcode { 13762306a36Sopenharmony_ci SJA1105_C45_ADDR = 0, 13862306a36Sopenharmony_ci SJA1105_C22 = 1, 13962306a36Sopenharmony_ci SJA1105_C45_DATA = 2, 14062306a36Sopenharmony_ci SJA1105_C45_DATA_AUTOINC = 3, 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv, 14462306a36Sopenharmony_ci int phy, enum sja1105_mdio_opcode op, 14562306a36Sopenharmony_ci int xad) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci const struct sja1105_regs *regs = priv->info->regs; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int sja1105_base_t1_mdio_read_c22(struct mii_bus *bus, int phy, int reg) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 15562306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 15662306a36Sopenharmony_ci u64 addr; 15762306a36Sopenharmony_ci u32 tmp; 15862306a36Sopenharmony_ci int rc; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 16362306a36Sopenharmony_ci if (rc < 0) 16462306a36Sopenharmony_ci return rc; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return tmp & 0xffff; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int sja1105_base_t1_mdio_read_c45(struct mii_bus *bus, int phy, 17062306a36Sopenharmony_ci int mmd, int reg) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 17362306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 17462306a36Sopenharmony_ci u64 addr; 17562306a36Sopenharmony_ci u32 tmp; 17662306a36Sopenharmony_ci int rc; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, ®, NULL); 18162306a36Sopenharmony_ci if (rc < 0) 18262306a36Sopenharmony_ci return rc; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL); 18762306a36Sopenharmony_ci if (rc < 0) 18862306a36Sopenharmony_ci return rc; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return tmp & 0xffff; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int sja1105_base_t1_mdio_write_c22(struct mii_bus *bus, int phy, int reg, 19462306a36Sopenharmony_ci u16 val) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 19762306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 19862306a36Sopenharmony_ci u64 addr; 19962306a36Sopenharmony_ci u32 tmp; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci tmp = val & 0xffff; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic int sja1105_base_t1_mdio_write_c45(struct mii_bus *bus, int phy, 20962306a36Sopenharmony_ci int mmd, int reg, u16 val) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 21262306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 21362306a36Sopenharmony_ci u64 addr; 21462306a36Sopenharmony_ci u32 tmp; 21562306a36Sopenharmony_ci int rc; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, ®, NULL); 22062306a36Sopenharmony_ci if (rc < 0) 22162306a36Sopenharmony_ci return rc; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci tmp = val & 0xffff; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 23362306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 23462306a36Sopenharmony_ci const struct sja1105_regs *regs = priv->info->regs; 23562306a36Sopenharmony_ci u32 tmp; 23662306a36Sopenharmony_ci int rc; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg, 23962306a36Sopenharmony_ci &tmp, NULL); 24062306a36Sopenharmony_ci if (rc < 0) 24162306a36Sopenharmony_ci return rc; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return tmp & 0xffff; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg, 24762306a36Sopenharmony_ci u16 val) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv = bus->priv; 25062306a36Sopenharmony_ci struct sja1105_private *priv = mdio_priv->priv; 25162306a36Sopenharmony_ci const struct sja1105_regs *regs = priv->info->regs; 25262306a36Sopenharmony_ci u32 tmp = val; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg, 25562306a36Sopenharmony_ci &tmp, NULL); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv, 25962306a36Sopenharmony_ci struct device_node *mdio_node) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv; 26262306a36Sopenharmony_ci struct device_node *np; 26362306a36Sopenharmony_ci struct mii_bus *bus; 26462306a36Sopenharmony_ci int rc = 0; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio"); 26762306a36Sopenharmony_ci if (!np) 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!of_device_is_available(np)) 27162306a36Sopenharmony_ci goto out_put_np; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 27462306a36Sopenharmony_ci if (!bus) { 27562306a36Sopenharmony_ci rc = -ENOMEM; 27662306a36Sopenharmony_ci goto out_put_np; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci bus->name = "SJA1110 100base-TX MDIO bus"; 28062306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx", 28162306a36Sopenharmony_ci dev_name(priv->ds->dev)); 28262306a36Sopenharmony_ci bus->read = sja1105_base_tx_mdio_read; 28362306a36Sopenharmony_ci bus->write = sja1105_base_tx_mdio_write; 28462306a36Sopenharmony_ci bus->parent = priv->ds->dev; 28562306a36Sopenharmony_ci mdio_priv = bus->priv; 28662306a36Sopenharmony_ci mdio_priv->priv = priv; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci rc = of_mdiobus_register(bus, np); 28962306a36Sopenharmony_ci if (rc) { 29062306a36Sopenharmony_ci mdiobus_free(bus); 29162306a36Sopenharmony_ci goto out_put_np; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci priv->mdio_base_tx = bus; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciout_put_np: 29762306a36Sopenharmony_ci of_node_put(np); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return rc; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci if (!priv->mdio_base_tx) 30562306a36Sopenharmony_ci return; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci mdiobus_unregister(priv->mdio_base_tx); 30862306a36Sopenharmony_ci mdiobus_free(priv->mdio_base_tx); 30962306a36Sopenharmony_ci priv->mdio_base_tx = NULL; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv, 31362306a36Sopenharmony_ci struct device_node *mdio_node) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv; 31662306a36Sopenharmony_ci struct device_node *np; 31762306a36Sopenharmony_ci struct mii_bus *bus; 31862306a36Sopenharmony_ci int rc = 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio"); 32162306a36Sopenharmony_ci if (!np) 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!of_device_is_available(np)) 32562306a36Sopenharmony_ci goto out_put_np; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 32862306a36Sopenharmony_ci if (!bus) { 32962306a36Sopenharmony_ci rc = -ENOMEM; 33062306a36Sopenharmony_ci goto out_put_np; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci bus->name = "SJA1110 100base-T1 MDIO bus"; 33462306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1", 33562306a36Sopenharmony_ci dev_name(priv->ds->dev)); 33662306a36Sopenharmony_ci bus->read = sja1105_base_t1_mdio_read_c22; 33762306a36Sopenharmony_ci bus->write = sja1105_base_t1_mdio_write_c22; 33862306a36Sopenharmony_ci bus->read_c45 = sja1105_base_t1_mdio_read_c45; 33962306a36Sopenharmony_ci bus->write_c45 = sja1105_base_t1_mdio_write_c45; 34062306a36Sopenharmony_ci bus->parent = priv->ds->dev; 34162306a36Sopenharmony_ci mdio_priv = bus->priv; 34262306a36Sopenharmony_ci mdio_priv->priv = priv; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci rc = of_mdiobus_register(bus, np); 34562306a36Sopenharmony_ci if (rc) { 34662306a36Sopenharmony_ci mdiobus_free(bus); 34762306a36Sopenharmony_ci goto out_put_np; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci priv->mdio_base_t1 = bus; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciout_put_np: 35362306a36Sopenharmony_ci of_node_put(np); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return rc; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci if (!priv->mdio_base_t1) 36162306a36Sopenharmony_ci return; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci mdiobus_unregister(priv->mdio_base_t1); 36462306a36Sopenharmony_ci mdiobus_free(priv->mdio_base_t1); 36562306a36Sopenharmony_ci priv->mdio_base_t1 = NULL; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct sja1105_mdio_private *mdio_priv; 37162306a36Sopenharmony_ci struct dsa_switch *ds = priv->ds; 37262306a36Sopenharmony_ci struct mii_bus *bus; 37362306a36Sopenharmony_ci int rc = 0; 37462306a36Sopenharmony_ci int port; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!priv->info->pcs_mdio_read_c45 || !priv->info->pcs_mdio_write_c45) 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci bus = mdiobus_alloc_size(sizeof(*mdio_priv)); 38062306a36Sopenharmony_ci if (!bus) 38162306a36Sopenharmony_ci return -ENOMEM; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci bus->name = "SJA1105 PCS MDIO bus"; 38462306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs", 38562306a36Sopenharmony_ci dev_name(ds->dev)); 38662306a36Sopenharmony_ci bus->read_c45 = priv->info->pcs_mdio_read_c45; 38762306a36Sopenharmony_ci bus->write_c45 = priv->info->pcs_mdio_write_c45; 38862306a36Sopenharmony_ci bus->parent = ds->dev; 38962306a36Sopenharmony_ci /* There is no PHY on this MDIO bus => mask out all PHY addresses 39062306a36Sopenharmony_ci * from auto probing. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci bus->phy_mask = ~0; 39362306a36Sopenharmony_ci mdio_priv = bus->priv; 39462306a36Sopenharmony_ci mdio_priv->priv = priv; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci rc = mdiobus_register(bus); 39762306a36Sopenharmony_ci if (rc) { 39862306a36Sopenharmony_ci mdiobus_free(bus); 39962306a36Sopenharmony_ci return rc; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci for (port = 0; port < ds->num_ports; port++) { 40362306a36Sopenharmony_ci struct dw_xpcs *xpcs; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (dsa_is_unused_port(ds, port)) 40662306a36Sopenharmony_ci continue; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII && 40962306a36Sopenharmony_ci priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX) 41062306a36Sopenharmony_ci continue; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci xpcs = xpcs_create_mdiodev(bus, port, priv->phy_mode[port]); 41362306a36Sopenharmony_ci if (IS_ERR(xpcs)) { 41462306a36Sopenharmony_ci rc = PTR_ERR(xpcs); 41562306a36Sopenharmony_ci goto out_pcs_free; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci priv->xpcs[port] = xpcs; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci priv->mdio_pcs = bus; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciout_pcs_free: 42662306a36Sopenharmony_ci for (port = 0; port < ds->num_ports; port++) { 42762306a36Sopenharmony_ci if (!priv->xpcs[port]) 42862306a36Sopenharmony_ci continue; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci xpcs_destroy(priv->xpcs[port]); 43162306a36Sopenharmony_ci priv->xpcs[port] = NULL; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci mdiobus_unregister(bus); 43562306a36Sopenharmony_ci mdiobus_free(bus); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return rc; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct dsa_switch *ds = priv->ds; 44362306a36Sopenharmony_ci int port; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (!priv->mdio_pcs) 44662306a36Sopenharmony_ci return; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (port = 0; port < ds->num_ports; port++) { 44962306a36Sopenharmony_ci if (!priv->xpcs[port]) 45062306a36Sopenharmony_ci continue; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci xpcs_destroy(priv->xpcs[port]); 45362306a36Sopenharmony_ci priv->xpcs[port] = NULL; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci mdiobus_unregister(priv->mdio_pcs); 45762306a36Sopenharmony_ci mdiobus_free(priv->mdio_pcs); 45862306a36Sopenharmony_ci priv->mdio_pcs = NULL; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ciint sja1105_mdiobus_register(struct dsa_switch *ds) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct sja1105_private *priv = ds->priv; 46462306a36Sopenharmony_ci const struct sja1105_regs *regs = priv->info->regs; 46562306a36Sopenharmony_ci struct device_node *switch_node = ds->dev->of_node; 46662306a36Sopenharmony_ci struct device_node *mdio_node; 46762306a36Sopenharmony_ci int rc; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci rc = sja1105_mdiobus_pcs_register(priv); 47062306a36Sopenharmony_ci if (rc) 47162306a36Sopenharmony_ci return rc; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci mdio_node = of_get_child_by_name(switch_node, "mdios"); 47462306a36Sopenharmony_ci if (!mdio_node) 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (!of_device_is_available(mdio_node)) 47862306a36Sopenharmony_ci goto out_put_mdio_node; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) { 48162306a36Sopenharmony_ci rc = sja1105_mdiobus_base_tx_register(priv, mdio_node); 48262306a36Sopenharmony_ci if (rc) 48362306a36Sopenharmony_ci goto err_put_mdio_node; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) { 48762306a36Sopenharmony_ci rc = sja1105_mdiobus_base_t1_register(priv, mdio_node); 48862306a36Sopenharmony_ci if (rc) 48962306a36Sopenharmony_ci goto err_free_base_tx_mdiobus; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciout_put_mdio_node: 49362306a36Sopenharmony_ci of_node_put(mdio_node); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return 0; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cierr_free_base_tx_mdiobus: 49862306a36Sopenharmony_ci sja1105_mdiobus_base_tx_unregister(priv); 49962306a36Sopenharmony_cierr_put_mdio_node: 50062306a36Sopenharmony_ci of_node_put(mdio_node); 50162306a36Sopenharmony_ci sja1105_mdiobus_pcs_unregister(priv); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return rc; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_civoid sja1105_mdiobus_unregister(struct dsa_switch *ds) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct sja1105_private *priv = ds->priv; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci sja1105_mdiobus_base_t1_unregister(priv); 51162306a36Sopenharmony_ci sja1105_mdiobus_base_tx_unregister(priv); 51262306a36Sopenharmony_ci sja1105_mdiobus_pcs_unregister(priv); 51362306a36Sopenharmony_ci} 514