xref: /openbmc/linux/drivers/net/dsa/sja1105/sja1105_mdio.c (revision c708e135037087ffe90a9e0b1b01cd78a7f2aa4b)
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, &reg, 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, &reg, 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