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