xref: /linux/drivers/net/dsa/sja1105/sja1105_mdio.c (revision c120209b)
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 
sja1105_pcs_mdio_read_c45(struct mii_bus * bus,int phy,int mmd,int reg)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 
sja1105_pcs_mdio_write_c45(struct mii_bus * bus,int phy,int mmd,int reg,u16 val)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 
sja1110_pcs_mdio_read_c45(struct mii_bus * bus,int phy,int mmd,int reg)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 
sja1110_pcs_mdio_write_c45(struct mii_bus * bus,int phy,int mmd,int reg,u16 val)97*c120209bSChristophe JAILLET int sja1110_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd, int reg,
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 
sja1105_base_t1_encode_addr(struct sja1105_private * priv,int phy,enum sja1105_mdio_opcode op,int xad)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 
sja1105_base_t1_mdio_read_c22(struct mii_bus * bus,int phy,int reg)152c708e135SAndrew 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 
sja1105_base_t1_mdio_read_c45(struct mii_bus * bus,int phy,int mmd,int reg)169c708e135SAndrew Lunn static int sja1105_base_t1_mdio_read_c45(struct mii_bus *bus, int phy,
170c708e135SAndrew Lunn 					 int mmd, int reg)
171c708e135SAndrew Lunn {
172c708e135SAndrew Lunn 	struct sja1105_mdio_private *mdio_priv = bus->priv;
173c708e135SAndrew Lunn 	struct sja1105_private *priv = mdio_priv->priv;
174c708e135SAndrew Lunn 	u64 addr;
175c708e135SAndrew Lunn 	u32 tmp;
176c708e135SAndrew Lunn 	int rc;
177c708e135SAndrew Lunn 
178c708e135SAndrew Lunn 	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd);
179c708e135SAndrew Lunn 
180c708e135SAndrew Lunn 	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &reg, NULL);
181c708e135SAndrew Lunn 	if (rc < 0)
182c708e135SAndrew Lunn 		return rc;
183c708e135SAndrew Lunn 
184c708e135SAndrew Lunn 	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd);
185c708e135SAndrew Lunn 
186c708e135SAndrew Lunn 	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
187c708e135SAndrew Lunn 	if (rc < 0)
188c708e135SAndrew Lunn 		return rc;
189c708e135SAndrew Lunn 
190c708e135SAndrew Lunn 	return tmp & 0xffff;
191c708e135SAndrew Lunn }
192c708e135SAndrew Lunn 
sja1105_base_t1_mdio_write_c22(struct mii_bus * bus,int phy,int reg,u16 val)193c708e135SAndrew 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 
201c708e135SAndrew Lunn 	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
2025a8f0974SVladimir Oltean 
2035a8f0974SVladimir Oltean 	tmp = val & 0xffff;
2045a8f0974SVladimir Oltean 
205c708e135SAndrew Lunn 	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
206c708e135SAndrew Lunn }
207c708e135SAndrew Lunn 
sja1105_base_t1_mdio_write_c45(struct mii_bus * bus,int phy,int mmd,int reg,u16 val)208c708e135SAndrew Lunn static int sja1105_base_t1_mdio_write_c45(struct mii_bus *bus, int phy,
209c708e135SAndrew Lunn 					  int mmd, int reg, u16 val)
210c708e135SAndrew Lunn {
211c708e135SAndrew Lunn 	struct sja1105_mdio_private *mdio_priv = bus->priv;
212c708e135SAndrew Lunn 	struct sja1105_private *priv = mdio_priv->priv;
213c708e135SAndrew Lunn 	u64 addr;
214c708e135SAndrew Lunn 	u32 tmp;
215c708e135SAndrew Lunn 	int rc;
216c708e135SAndrew Lunn 
217c708e135SAndrew Lunn 	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd);
218c708e135SAndrew Lunn 
219c708e135SAndrew Lunn 	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &reg, NULL);
2205a8f0974SVladimir Oltean 	if (rc < 0)
2215a8f0974SVladimir Oltean 		return rc;
2225a8f0974SVladimir Oltean 
223c708e135SAndrew 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 
sja1105_base_tx_mdio_read(struct mii_bus * bus,int phy,int reg)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 
2385a8f0974SVladimir Oltean 	rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
2395a8f0974SVladimir Oltean 			      &tmp, NULL);
2405a8f0974SVladimir Oltean 	if (rc < 0)
2415a8f0974SVladimir Oltean 		return rc;
2425a8f0974SVladimir Oltean 
2435a8f0974SVladimir Oltean 	return tmp & 0xffff;
2445a8f0974SVladimir Oltean }
2455a8f0974SVladimir Oltean 
sja1105_base_tx_mdio_write(struct mii_bus * bus,int phy,int reg,u16 val)2465a8f0974SVladimir Oltean static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
2475a8f0974SVladimir Oltean 				      u16 val)
2485a8f0974SVladimir Oltean {
2495a8f0974SVladimir Oltean 	struct sja1105_mdio_private *mdio_priv = bus->priv;
2505a8f0974SVladimir Oltean 	struct sja1105_private *priv = mdio_priv->priv;
2515a8f0974SVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
2525a8f0974SVladimir Oltean 	u32 tmp = val;
2535a8f0974SVladimir Oltean 
2545a8f0974SVladimir Oltean 	return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
2555a8f0974SVladimir Oltean 				&tmp, NULL);
2565a8f0974SVladimir Oltean }
2575a8f0974SVladimir Oltean 
sja1105_mdiobus_base_tx_register(struct sja1105_private * priv,struct device_node * mdio_node)2585a8f0974SVladimir Oltean static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,
2595a8f0974SVladimir Oltean 					    struct device_node *mdio_node)
2605a8f0974SVladimir Oltean {
2615a8f0974SVladimir Oltean 	struct sja1105_mdio_private *mdio_priv;
2625a8f0974SVladimir Oltean 	struct device_node *np;
2635a8f0974SVladimir Oltean 	struct mii_bus *bus;
2645a8f0974SVladimir Oltean 	int rc = 0;
2655a8f0974SVladimir Oltean 
266ed5d2937SVladimir Oltean 	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio");
2675a8f0974SVladimir Oltean 	if (!np)
2685a8f0974SVladimir Oltean 		return 0;
2695a8f0974SVladimir Oltean 
2705a8f0974SVladimir Oltean 	if (!of_device_is_available(np))
2715a8f0974SVladimir Oltean 		goto out_put_np;
2725a8f0974SVladimir Oltean 
2735a8f0974SVladimir Oltean 	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
2745a8f0974SVladimir Oltean 	if (!bus) {
2755a8f0974SVladimir Oltean 		rc = -ENOMEM;
2765a8f0974SVladimir Oltean 		goto out_put_np;
2775a8f0974SVladimir Oltean 	}
2785a8f0974SVladimir Oltean 
2795a8f0974SVladimir Oltean 	bus->name = "SJA1110 100base-TX MDIO bus";
2805a8f0974SVladimir Oltean 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",
2815a8f0974SVladimir Oltean 		 dev_name(priv->ds->dev));
2825a8f0974SVladimir Oltean 	bus->read = sja1105_base_tx_mdio_read;
2835a8f0974SVladimir Oltean 	bus->write = sja1105_base_tx_mdio_write;
2845a8f0974SVladimir Oltean 	bus->parent = priv->ds->dev;
2855a8f0974SVladimir Oltean 	mdio_priv = bus->priv;
2865a8f0974SVladimir Oltean 	mdio_priv->priv = priv;
2875a8f0974SVladimir Oltean 
2885a8f0974SVladimir Oltean 	rc = of_mdiobus_register(bus, np);
2895a8f0974SVladimir Oltean 	if (rc) {
2905a8f0974SVladimir Oltean 		mdiobus_free(bus);
2915a8f0974SVladimir Oltean 		goto out_put_np;
2925a8f0974SVladimir Oltean 	}
2935a8f0974SVladimir Oltean 
2945a8f0974SVladimir Oltean 	priv->mdio_base_tx = bus;
2955a8f0974SVladimir Oltean 
2965a8f0974SVladimir Oltean out_put_np:
2975a8f0974SVladimir Oltean 	of_node_put(np);
2985a8f0974SVladimir Oltean 
299ab324d8dSColin Ian King 	return rc;
3005a8f0974SVladimir Oltean }
3015a8f0974SVladimir Oltean 
sja1105_mdiobus_base_tx_unregister(struct sja1105_private * priv)3025a8f0974SVladimir Oltean static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)
3035a8f0974SVladimir Oltean {
3045a8f0974SVladimir Oltean 	if (!priv->mdio_base_tx)
3055a8f0974SVladimir Oltean 		return;
3065a8f0974SVladimir Oltean 
3075a8f0974SVladimir Oltean 	mdiobus_unregister(priv->mdio_base_tx);
3085a8f0974SVladimir Oltean 	mdiobus_free(priv->mdio_base_tx);
3095a8f0974SVladimir Oltean 	priv->mdio_base_tx = NULL;
3105a8f0974SVladimir Oltean }
3115a8f0974SVladimir Oltean 
sja1105_mdiobus_base_t1_register(struct sja1105_private * priv,struct device_node * mdio_node)3125a8f0974SVladimir Oltean static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,
3135a8f0974SVladimir Oltean 					    struct device_node *mdio_node)
3145a8f0974SVladimir Oltean {
3155a8f0974SVladimir Oltean 	struct sja1105_mdio_private *mdio_priv;
3165a8f0974SVladimir Oltean 	struct device_node *np;
3175a8f0974SVladimir Oltean 	struct mii_bus *bus;
3185a8f0974SVladimir Oltean 	int rc = 0;
3195a8f0974SVladimir Oltean 
320ed5d2937SVladimir Oltean 	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio");
3215a8f0974SVladimir Oltean 	if (!np)
3225a8f0974SVladimir Oltean 		return 0;
3235a8f0974SVladimir Oltean 
3245a8f0974SVladimir Oltean 	if (!of_device_is_available(np))
3255a8f0974SVladimir Oltean 		goto out_put_np;
3265a8f0974SVladimir Oltean 
3275a8f0974SVladimir Oltean 	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
3285a8f0974SVladimir Oltean 	if (!bus) {
3295a8f0974SVladimir Oltean 		rc = -ENOMEM;
3305a8f0974SVladimir Oltean 		goto out_put_np;
3315a8f0974SVladimir Oltean 	}
3325a8f0974SVladimir Oltean 
3335a8f0974SVladimir Oltean 	bus->name = "SJA1110 100base-T1 MDIO bus";
3345a8f0974SVladimir Oltean 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",
3355a8f0974SVladimir Oltean 		 dev_name(priv->ds->dev));
336c708e135SAndrew Lunn 	bus->read = sja1105_base_t1_mdio_read_c22;
337c708e135SAndrew Lunn 	bus->write = sja1105_base_t1_mdio_write_c22;
338c708e135SAndrew Lunn 	bus->read_c45 = sja1105_base_t1_mdio_read_c45;
339c708e135SAndrew Lunn 	bus->write_c45 = sja1105_base_t1_mdio_write_c45;
3405a8f0974SVladimir Oltean 	bus->parent = priv->ds->dev;
3415a8f0974SVladimir Oltean 	mdio_priv = bus->priv;
3425a8f0974SVladimir Oltean 	mdio_priv->priv = priv;
3435a8f0974SVladimir Oltean 
3445a8f0974SVladimir Oltean 	rc = of_mdiobus_register(bus, np);
3455a8f0974SVladimir Oltean 	if (rc) {
3465a8f0974SVladimir Oltean 		mdiobus_free(bus);
3475a8f0974SVladimir Oltean 		goto out_put_np;
3485a8f0974SVladimir Oltean 	}
3495a8f0974SVladimir Oltean 
3505a8f0974SVladimir Oltean 	priv->mdio_base_t1 = bus;
3515a8f0974SVladimir Oltean 
3525a8f0974SVladimir Oltean out_put_np:
3535a8f0974SVladimir Oltean 	of_node_put(np);
3545a8f0974SVladimir Oltean 
3555a8f0974SVladimir Oltean 	return rc;
3565a8f0974SVladimir Oltean }
3575a8f0974SVladimir Oltean 
sja1105_mdiobus_base_t1_unregister(struct sja1105_private * priv)3585a8f0974SVladimir Oltean static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)
3595a8f0974SVladimir Oltean {
3605a8f0974SVladimir Oltean 	if (!priv->mdio_base_t1)
3615a8f0974SVladimir Oltean 		return;
3625a8f0974SVladimir Oltean 
3635a8f0974SVladimir Oltean 	mdiobus_unregister(priv->mdio_base_t1);
3645a8f0974SVladimir Oltean 	mdiobus_free(priv->mdio_base_t1);
3655a8f0974SVladimir Oltean 	priv->mdio_base_t1 = NULL;
3665a8f0974SVladimir Oltean }
3675a8f0974SVladimir Oltean 
sja1105_mdiobus_pcs_register(struct sja1105_private * priv)3683ad1d171SVladimir Oltean static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
3693ad1d171SVladimir Oltean {
3703ad1d171SVladimir Oltean 	struct sja1105_mdio_private *mdio_priv;
3713ad1d171SVladimir Oltean 	struct dsa_switch *ds = priv->ds;
3723ad1d171SVladimir Oltean 	struct mii_bus *bus;
3733ad1d171SVladimir Oltean 	int rc = 0;
3743ad1d171SVladimir Oltean 	int port;
3753ad1d171SVladimir Oltean 
376ae271547SAndrew Lunn 	if (!priv->info->pcs_mdio_read_c45 || !priv->info->pcs_mdio_write_c45)
3773ad1d171SVladimir Oltean 		return 0;
3783ad1d171SVladimir Oltean 
3793ad1d171SVladimir Oltean 	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
3803ad1d171SVladimir Oltean 	if (!bus)
3813ad1d171SVladimir Oltean 		return -ENOMEM;
3823ad1d171SVladimir Oltean 
3833ad1d171SVladimir Oltean 	bus->name = "SJA1105 PCS MDIO bus";
3843ad1d171SVladimir Oltean 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs",
3853ad1d171SVladimir Oltean 		 dev_name(ds->dev));
386ae271547SAndrew Lunn 	bus->read_c45 = priv->info->pcs_mdio_read_c45;
387ae271547SAndrew Lunn 	bus->write_c45 = priv->info->pcs_mdio_write_c45;
3883ad1d171SVladimir Oltean 	bus->parent = ds->dev;
3893ad1d171SVladimir Oltean 	/* There is no PHY on this MDIO bus => mask out all PHY addresses
3903ad1d171SVladimir Oltean 	 * from auto probing.
3913ad1d171SVladimir Oltean 	 */
3923ad1d171SVladimir Oltean 	bus->phy_mask = ~0;
3933ad1d171SVladimir Oltean 	mdio_priv = bus->priv;
3943ad1d171SVladimir Oltean 	mdio_priv->priv = priv;
3953ad1d171SVladimir Oltean 
3963ad1d171SVladimir Oltean 	rc = mdiobus_register(bus);
3973ad1d171SVladimir Oltean 	if (rc) {
3983ad1d171SVladimir Oltean 		mdiobus_free(bus);
3993ad1d171SVladimir Oltean 		return rc;
4003ad1d171SVladimir Oltean 	}
4013ad1d171SVladimir Oltean 
4023ad1d171SVladimir Oltean 	for (port = 0; port < ds->num_ports; port++) {
4033ad1d171SVladimir Oltean 		struct dw_xpcs *xpcs;
4043ad1d171SVladimir Oltean 
4053ad1d171SVladimir Oltean 		if (dsa_is_unused_port(ds, port))
4063ad1d171SVladimir Oltean 			continue;
4073ad1d171SVladimir Oltean 
40856b63466SVladimir Oltean 		if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII &&
40956b63466SVladimir Oltean 		    priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX)
4103ad1d171SVladimir Oltean 			continue;
4113ad1d171SVladimir Oltean 
412bf9a17b0SRussell King (Oracle) 		xpcs = xpcs_create_mdiodev(bus, port, priv->phy_mode[port]);
4133ad1d171SVladimir Oltean 		if (IS_ERR(xpcs)) {
4143ad1d171SVladimir Oltean 			rc = PTR_ERR(xpcs);
4153ad1d171SVladimir Oltean 			goto out_pcs_free;
4163ad1d171SVladimir Oltean 		}
4173ad1d171SVladimir Oltean 
4183ad1d171SVladimir Oltean 		priv->xpcs[port] = xpcs;
4193ad1d171SVladimir Oltean 	}
4203ad1d171SVladimir Oltean 
4213ad1d171SVladimir Oltean 	priv->mdio_pcs = bus;
4223ad1d171SVladimir Oltean 
4233ad1d171SVladimir Oltean 	return 0;
4243ad1d171SVladimir Oltean 
4253ad1d171SVladimir Oltean out_pcs_free:
4263ad1d171SVladimir Oltean 	for (port = 0; port < ds->num_ports; port++) {
4273ad1d171SVladimir Oltean 		if (!priv->xpcs[port])
4283ad1d171SVladimir Oltean 			continue;
4293ad1d171SVladimir Oltean 
4303ad1d171SVladimir Oltean 		xpcs_destroy(priv->xpcs[port]);
4313ad1d171SVladimir Oltean 		priv->xpcs[port] = NULL;
4323ad1d171SVladimir Oltean 	}
4333ad1d171SVladimir Oltean 
4343ad1d171SVladimir Oltean 	mdiobus_unregister(bus);
4353ad1d171SVladimir Oltean 	mdiobus_free(bus);
4363ad1d171SVladimir Oltean 
4373ad1d171SVladimir Oltean 	return rc;
4383ad1d171SVladimir Oltean }
4393ad1d171SVladimir Oltean 
sja1105_mdiobus_pcs_unregister(struct sja1105_private * priv)4403ad1d171SVladimir Oltean static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv)
4413ad1d171SVladimir Oltean {
4423ad1d171SVladimir Oltean 	struct dsa_switch *ds = priv->ds;
4433ad1d171SVladimir Oltean 	int port;
4443ad1d171SVladimir Oltean 
4453ad1d171SVladimir Oltean 	if (!priv->mdio_pcs)
4463ad1d171SVladimir Oltean 		return;
4473ad1d171SVladimir Oltean 
4483ad1d171SVladimir Oltean 	for (port = 0; port < ds->num_ports; port++) {
4493ad1d171SVladimir Oltean 		if (!priv->xpcs[port])
4503ad1d171SVladimir Oltean 			continue;
4513ad1d171SVladimir Oltean 
4523ad1d171SVladimir Oltean 		xpcs_destroy(priv->xpcs[port]);
4533ad1d171SVladimir Oltean 		priv->xpcs[port] = NULL;
4543ad1d171SVladimir Oltean 	}
4553ad1d171SVladimir Oltean 
4563ad1d171SVladimir Oltean 	mdiobus_unregister(priv->mdio_pcs);
4573ad1d171SVladimir Oltean 	mdiobus_free(priv->mdio_pcs);
4583ad1d171SVladimir Oltean 	priv->mdio_pcs = NULL;
4593ad1d171SVladimir Oltean }
4603ad1d171SVladimir Oltean 
sja1105_mdiobus_register(struct dsa_switch * ds)4615a8f0974SVladimir Oltean int sja1105_mdiobus_register(struct dsa_switch *ds)
4625a8f0974SVladimir Oltean {
4635a8f0974SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
4645a8f0974SVladimir Oltean 	const struct sja1105_regs *regs = priv->info->regs;
4655a8f0974SVladimir Oltean 	struct device_node *switch_node = ds->dev->of_node;
4665a8f0974SVladimir Oltean 	struct device_node *mdio_node;
4675a8f0974SVladimir Oltean 	int rc;
4685a8f0974SVladimir Oltean 
4693ad1d171SVladimir Oltean 	rc = sja1105_mdiobus_pcs_register(priv);
4703ad1d171SVladimir Oltean 	if (rc)
4713ad1d171SVladimir Oltean 		return rc;
4723ad1d171SVladimir Oltean 
4735a8f0974SVladimir Oltean 	mdio_node = of_get_child_by_name(switch_node, "mdios");
4745a8f0974SVladimir Oltean 	if (!mdio_node)
4755a8f0974SVladimir Oltean 		return 0;
4765a8f0974SVladimir Oltean 
4775a8f0974SVladimir Oltean 	if (!of_device_is_available(mdio_node))
4785a8f0974SVladimir Oltean 		goto out_put_mdio_node;
4795a8f0974SVladimir Oltean 
4805a8f0974SVladimir Oltean 	if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {
4815a8f0974SVladimir Oltean 		rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);
4825a8f0974SVladimir Oltean 		if (rc)
4835a8f0974SVladimir Oltean 			goto err_put_mdio_node;
4845a8f0974SVladimir Oltean 	}
4855a8f0974SVladimir Oltean 
4865a8f0974SVladimir Oltean 	if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {
4875a8f0974SVladimir Oltean 		rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);
4885a8f0974SVladimir Oltean 		if (rc)
4895a8f0974SVladimir Oltean 			goto err_free_base_tx_mdiobus;
4905a8f0974SVladimir Oltean 	}
4915a8f0974SVladimir Oltean 
4925a8f0974SVladimir Oltean out_put_mdio_node:
4935a8f0974SVladimir Oltean 	of_node_put(mdio_node);
4945a8f0974SVladimir Oltean 
4955a8f0974SVladimir Oltean 	return 0;
4965a8f0974SVladimir Oltean 
4975a8f0974SVladimir Oltean err_free_base_tx_mdiobus:
4985a8f0974SVladimir Oltean 	sja1105_mdiobus_base_tx_unregister(priv);
4995a8f0974SVladimir Oltean err_put_mdio_node:
5005a8f0974SVladimir Oltean 	of_node_put(mdio_node);
5013ad1d171SVladimir Oltean 	sja1105_mdiobus_pcs_unregister(priv);
5025a8f0974SVladimir Oltean 
5035a8f0974SVladimir Oltean 	return rc;
5045a8f0974SVladimir Oltean }
5055a8f0974SVladimir Oltean 
sja1105_mdiobus_unregister(struct dsa_switch * ds)5065a8f0974SVladimir Oltean void sja1105_mdiobus_unregister(struct dsa_switch *ds)
5075a8f0974SVladimir Oltean {
5085a8f0974SVladimir Oltean 	struct sja1105_private *priv = ds->priv;
5095a8f0974SVladimir Oltean 
5105a8f0974SVladimir Oltean 	sja1105_mdiobus_base_t1_unregister(priv);
5115a8f0974SVladimir Oltean 	sja1105_mdiobus_base_tx_unregister(priv);
5123ad1d171SVladimir Oltean 	sja1105_mdiobus_pcs_unregister(priv);
5135a8f0974SVladimir Oltean }
514