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, ®, 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, ®, 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