brintos

brintos / linux-shallow public Read only

0
0
Text · 11.5 KiB · 52ddb4e Raw
514 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright 2021 NXP3 */4#include <linux/pcs/pcs-xpcs.h>5#include <linux/of_mdio.h>6#include "sja1105.h"7 8#define SJA1110_PCS_BANK_REG		SJA1110_SPI_ADDR(0x3fc)9 10int sja1105_pcs_mdio_read_c45(struct mii_bus *bus, int phy, int mmd, int reg)11{12	struct sja1105_mdio_private *mdio_priv = bus->priv;13	struct sja1105_private *priv = mdio_priv->priv;14	u64 addr;15	u32 tmp;16	int rc;17 18	addr = (mmd << 16) | reg;19 20	if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)21		return 0xffff;22 23	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)24		return NXP_SJA1105_XPCS_ID >> 16;25	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)26		return NXP_SJA1105_XPCS_ID & GENMASK(15, 0);27 28	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);29	if (rc < 0)30		return rc;31 32	return tmp & 0xffff;33}34 35int sja1105_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd,36			       int reg, u16 val)37{38	struct sja1105_mdio_private *mdio_priv = bus->priv;39	struct sja1105_private *priv = mdio_priv->priv;40	u64 addr;41	u32 tmp;42 43	addr = (mmd << 16) | reg;44	tmp = val;45 46	if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)47		return -EINVAL;48 49	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);50}51 52int sja1110_pcs_mdio_read_c45(struct mii_bus *bus, int phy, int mmd, int reg)53{54	struct sja1105_mdio_private *mdio_priv = bus->priv;55	struct sja1105_private *priv = mdio_priv->priv;56	const struct sja1105_regs *regs = priv->info->regs;57	int offset, bank;58	u64 addr;59	u32 tmp;60	int rc;61 62	if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)63		return -ENODEV;64 65	addr = (mmd << 16) | reg;66 67	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)68		return NXP_SJA1110_XPCS_ID >> 16;69	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)70		return NXP_SJA1110_XPCS_ID & GENMASK(15, 0);71 72	bank = addr >> 8;73	offset = addr & GENMASK(7, 0);74 75	/* This addressing scheme reserves register 0xff for the bank address76	 * register, so that can never be addressed.77	 */78	if (WARN_ON(offset == 0xff))79		return -ENODEV;80 81	tmp = bank;82 83	rc = sja1105_xfer_u32(priv, SPI_WRITE,84			      regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,85			      &tmp, NULL);86	if (rc < 0)87		return rc;88 89	rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset,90			      &tmp, NULL);91	if (rc < 0)92		return rc;93 94	return tmp & 0xffff;95}96 97int sja1110_pcs_mdio_write_c45(struct mii_bus *bus, int phy, int mmd, int reg,98			       u16 val)99{100	struct sja1105_mdio_private *mdio_priv = bus->priv;101	struct sja1105_private *priv = mdio_priv->priv;102	const struct sja1105_regs *regs = priv->info->regs;103	int offset, bank;104	u64 addr;105	u32 tmp;106	int rc;107 108	if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)109		return -ENODEV;110 111	addr = (mmd << 16) | reg;112 113	bank = addr >> 8;114	offset = addr & GENMASK(7, 0);115 116	/* This addressing scheme reserves register 0xff for the bank address117	 * register, so that can never be addressed.118	 */119	if (WARN_ON(offset == 0xff))120		return -ENODEV;121 122	tmp = bank;123 124	rc = sja1105_xfer_u32(priv, SPI_WRITE,125			      regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,126			      &tmp, NULL);127	if (rc < 0)128		return rc;129 130	tmp = val;131 132	return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset,133				&tmp, NULL);134}135 136enum sja1105_mdio_opcode {137	SJA1105_C45_ADDR = 0,138	SJA1105_C22 = 1,139	SJA1105_C45_DATA = 2,140	SJA1105_C45_DATA_AUTOINC = 3,141};142 143static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv,144				       int phy, enum sja1105_mdio_opcode op,145				       int xad)146{147	const struct sja1105_regs *regs = priv->info->regs;148 149	return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0);150}151 152static int sja1105_base_t1_mdio_read_c22(struct mii_bus *bus, int phy, int reg)153{154	struct sja1105_mdio_private *mdio_priv = bus->priv;155	struct sja1105_private *priv = mdio_priv->priv;156	u64 addr;157	u32 tmp;158	int rc;159 160	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);161 162	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);163	if (rc < 0)164		return rc;165 166	return tmp & 0xffff;167}168 169static int sja1105_base_t1_mdio_read_c45(struct mii_bus *bus, int phy,170					 int mmd, int reg)171{172	struct sja1105_mdio_private *mdio_priv = bus->priv;173	struct sja1105_private *priv = mdio_priv->priv;174	u64 addr;175	u32 tmp;176	int rc;177 178	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd);179 180	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &reg, NULL);181	if (rc < 0)182		return rc;183 184	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd);185 186	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);187	if (rc < 0)188		return rc;189 190	return tmp & 0xffff;191}192 193static int sja1105_base_t1_mdio_write_c22(struct mii_bus *bus, int phy, int reg,194					  u16 val)195{196	struct sja1105_mdio_private *mdio_priv = bus->priv;197	struct sja1105_private *priv = mdio_priv->priv;198	u64 addr;199	u32 tmp;200 201	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);202 203	tmp = val & 0xffff;204 205	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);206}207 208static int sja1105_base_t1_mdio_write_c45(struct mii_bus *bus, int phy,209					  int mmd, int reg, u16 val)210{211	struct sja1105_mdio_private *mdio_priv = bus->priv;212	struct sja1105_private *priv = mdio_priv->priv;213	u64 addr;214	u32 tmp;215	int rc;216 217	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR, mmd);218 219	rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &reg, NULL);220	if (rc < 0)221		return rc;222 223	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA, mmd);224 225	tmp = val & 0xffff;226 227	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);228}229 230static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)231{232	struct sja1105_mdio_private *mdio_priv = bus->priv;233	struct sja1105_private *priv = mdio_priv->priv;234	const struct sja1105_regs *regs = priv->info->regs;235	u32 tmp;236	int rc;237 238	rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,239			      &tmp, NULL);240	if (rc < 0)241		return rc;242 243	return tmp & 0xffff;244}245 246static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,247				      u16 val)248{249	struct sja1105_mdio_private *mdio_priv = bus->priv;250	struct sja1105_private *priv = mdio_priv->priv;251	const struct sja1105_regs *regs = priv->info->regs;252	u32 tmp = val;253 254	return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,255				&tmp, NULL);256}257 258static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,259					    struct device_node *mdio_node)260{261	struct sja1105_mdio_private *mdio_priv;262	struct device_node *np;263	struct mii_bus *bus;264	int rc = 0;265 266	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio");267	if (!np)268		return 0;269 270	if (!of_device_is_available(np))271		goto out_put_np;272 273	bus = mdiobus_alloc_size(sizeof(*mdio_priv));274	if (!bus) {275		rc = -ENOMEM;276		goto out_put_np;277	}278 279	bus->name = "SJA1110 100base-TX MDIO bus";280	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",281		 dev_name(priv->ds->dev));282	bus->read = sja1105_base_tx_mdio_read;283	bus->write = sja1105_base_tx_mdio_write;284	bus->parent = priv->ds->dev;285	mdio_priv = bus->priv;286	mdio_priv->priv = priv;287 288	rc = of_mdiobus_register(bus, np);289	if (rc) {290		mdiobus_free(bus);291		goto out_put_np;292	}293 294	priv->mdio_base_tx = bus;295 296out_put_np:297	of_node_put(np);298 299	return rc;300}301 302static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)303{304	if (!priv->mdio_base_tx)305		return;306 307	mdiobus_unregister(priv->mdio_base_tx);308	mdiobus_free(priv->mdio_base_tx);309	priv->mdio_base_tx = NULL;310}311 312static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,313					    struct device_node *mdio_node)314{315	struct sja1105_mdio_private *mdio_priv;316	struct device_node *np;317	struct mii_bus *bus;318	int rc = 0;319 320	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio");321	if (!np)322		return 0;323 324	if (!of_device_is_available(np))325		goto out_put_np;326 327	bus = mdiobus_alloc_size(sizeof(*mdio_priv));328	if (!bus) {329		rc = -ENOMEM;330		goto out_put_np;331	}332 333	bus->name = "SJA1110 100base-T1 MDIO bus";334	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",335		 dev_name(priv->ds->dev));336	bus->read = sja1105_base_t1_mdio_read_c22;337	bus->write = sja1105_base_t1_mdio_write_c22;338	bus->read_c45 = sja1105_base_t1_mdio_read_c45;339	bus->write_c45 = sja1105_base_t1_mdio_write_c45;340	bus->parent = priv->ds->dev;341	mdio_priv = bus->priv;342	mdio_priv->priv = priv;343 344	rc = of_mdiobus_register(bus, np);345	if (rc) {346		mdiobus_free(bus);347		goto out_put_np;348	}349 350	priv->mdio_base_t1 = bus;351 352out_put_np:353	of_node_put(np);354 355	return rc;356}357 358static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)359{360	if (!priv->mdio_base_t1)361		return;362 363	mdiobus_unregister(priv->mdio_base_t1);364	mdiobus_free(priv->mdio_base_t1);365	priv->mdio_base_t1 = NULL;366}367 368static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)369{370	struct sja1105_mdio_private *mdio_priv;371	struct dsa_switch *ds = priv->ds;372	struct mii_bus *bus;373	int rc = 0;374	int port;375 376	if (!priv->info->pcs_mdio_read_c45 || !priv->info->pcs_mdio_write_c45)377		return 0;378 379	bus = mdiobus_alloc_size(sizeof(*mdio_priv));380	if (!bus)381		return -ENOMEM;382 383	bus->name = "SJA1105 PCS MDIO bus";384	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs",385		 dev_name(ds->dev));386	bus->read_c45 = priv->info->pcs_mdio_read_c45;387	bus->write_c45 = priv->info->pcs_mdio_write_c45;388	bus->parent = ds->dev;389	/* There is no PHY on this MDIO bus => mask out all PHY addresses390	 * from auto probing.391	 */392	bus->phy_mask = ~0;393	mdio_priv = bus->priv;394	mdio_priv->priv = priv;395 396	rc = mdiobus_register(bus);397	if (rc) {398		mdiobus_free(bus);399		return rc;400	}401 402	for (port = 0; port < ds->num_ports; port++) {403		struct dw_xpcs *xpcs;404 405		if (dsa_is_unused_port(ds, port))406			continue;407 408		if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII &&409		    priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX)410			continue;411 412		xpcs = xpcs_create_mdiodev(bus, port, priv->phy_mode[port]);413		if (IS_ERR(xpcs)) {414			rc = PTR_ERR(xpcs);415			goto out_pcs_free;416		}417 418		priv->xpcs[port] = xpcs;419	}420 421	priv->mdio_pcs = bus;422 423	return 0;424 425out_pcs_free:426	for (port = 0; port < ds->num_ports; port++) {427		if (!priv->xpcs[port])428			continue;429 430		xpcs_destroy(priv->xpcs[port]);431		priv->xpcs[port] = NULL;432	}433 434	mdiobus_unregister(bus);435	mdiobus_free(bus);436 437	return rc;438}439 440static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv)441{442	struct dsa_switch *ds = priv->ds;443	int port;444 445	if (!priv->mdio_pcs)446		return;447 448	for (port = 0; port < ds->num_ports; port++) {449		if (!priv->xpcs[port])450			continue;451 452		xpcs_destroy(priv->xpcs[port]);453		priv->xpcs[port] = NULL;454	}455 456	mdiobus_unregister(priv->mdio_pcs);457	mdiobus_free(priv->mdio_pcs);458	priv->mdio_pcs = NULL;459}460 461int sja1105_mdiobus_register(struct dsa_switch *ds)462{463	struct sja1105_private *priv = ds->priv;464	const struct sja1105_regs *regs = priv->info->regs;465	struct device_node *switch_node = ds->dev->of_node;466	struct device_node *mdio_node;467	int rc;468 469	rc = sja1105_mdiobus_pcs_register(priv);470	if (rc)471		return rc;472 473	mdio_node = of_get_child_by_name(switch_node, "mdios");474	if (!mdio_node)475		return 0;476 477	if (!of_device_is_available(mdio_node))478		goto out_put_mdio_node;479 480	if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {481		rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);482		if (rc)483			goto err_put_mdio_node;484	}485 486	if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {487		rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);488		if (rc)489			goto err_free_base_tx_mdiobus;490	}491 492out_put_mdio_node:493	of_node_put(mdio_node);494 495	return 0;496 497err_free_base_tx_mdiobus:498	sja1105_mdiobus_base_tx_unregister(priv);499err_put_mdio_node:500	of_node_put(mdio_node);501	sja1105_mdiobus_pcs_unregister(priv);502 503	return rc;504}505 506void sja1105_mdiobus_unregister(struct dsa_switch *ds)507{508	struct sja1105_private *priv = ds->priv;509 510	sja1105_mdiobus_base_t1_unregister(priv);511	sja1105_mdiobus_base_tx_unregister(priv);512	sja1105_mdiobus_pcs_unregister(priv);513}514