xref: /openbmc/linux/drivers/net/dsa/sja1105/sja1105_mdio.c (revision ed5d2937a6a8f12e7f815748f991990e79ac4cd1)
15a8f0974SVladimir Oltean // SPDX-License-Identifier: GPL-2.0
25a8f0974SVladimir Oltean /* Copyright 2021, NXP Semiconductors
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 
287*ed5d2937SVladimir 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 
341*ed5d2937SVladimir 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