472 lines · c
1/*2 * QorIQ 10G MDIO Controller3 *4 * Copyright 2012 Freescale Semiconductor, Inc.5 * Copyright 2021 NXP6 *7 * Authors: Andy Fleming <afleming@freescale.com>8 * Timur Tabi <timur@freescale.com>9 *10 * This file is licensed under the terms of the GNU General Public License11 * version 2. This program is licensed "as is" without any warranty of any12 * kind, whether express or implied.13 */14 15#include <linux/acpi.h>16#include <linux/acpi_mdio.h>17#include <linux/clk.h>18#include <linux/interrupt.h>19#include <linux/kernel.h>20#include <linux/mdio.h>21#include <linux/module.h>22#include <linux/of.h>23#include <linux/of_mdio.h>24#include <linux/phy.h>25#include <linux/platform_device.h>26#include <linux/slab.h>27 28/* Number of microseconds to wait for a register to respond */29#define TIMEOUT 100030 31struct tgec_mdio_controller {32 __be32 reserved[12];33 __be32 mdio_stat; /* MDIO configuration and status */34 __be32 mdio_ctl; /* MDIO control */35 __be32 mdio_data; /* MDIO data */36 __be32 mdio_addr; /* MDIO address */37} __packed;38 39#define MDIO_STAT_ENC BIT(6)40#define MDIO_STAT_CLKDIV(x) (((x) & 0x1ff) << 7)41#define MDIO_STAT_BSY BIT(0)42#define MDIO_STAT_RD_ER BIT(1)43#define MDIO_STAT_PRE_DIS BIT(5)44#define MDIO_CTL_DEV_ADDR(x) (x & 0x1f)45#define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5)46#define MDIO_CTL_PRE_DIS BIT(10)47#define MDIO_CTL_SCAN_EN BIT(11)48#define MDIO_CTL_POST_INC BIT(14)49#define MDIO_CTL_READ BIT(15)50 51#define MDIO_DATA(x) (x & 0xffff)52 53struct mdio_fsl_priv {54 struct tgec_mdio_controller __iomem *mdio_base;55 struct clk *enet_clk;56 u32 mdc_freq;57 bool is_little_endian;58 bool has_a009885;59 bool has_a011043;60};61 62static u32 xgmac_read32(void __iomem *regs,63 bool is_little_endian)64{65 if (is_little_endian)66 return ioread32(regs);67 else68 return ioread32be(regs);69}70 71static void xgmac_write32(u32 value,72 void __iomem *regs,73 bool is_little_endian)74{75 if (is_little_endian)76 iowrite32(value, regs);77 else78 iowrite32be(value, regs);79}80 81/*82 * Wait until the MDIO bus is free83 */84static int xgmac_wait_until_free(struct device *dev,85 struct tgec_mdio_controller __iomem *regs,86 bool is_little_endian)87{88 unsigned int timeout;89 90 /* Wait till the bus is free */91 timeout = TIMEOUT;92 while ((xgmac_read32(®s->mdio_stat, is_little_endian) &93 MDIO_STAT_BSY) && timeout) {94 cpu_relax();95 timeout--;96 }97 98 if (!timeout) {99 dev_err(dev, "timeout waiting for bus to be free\n");100 return -ETIMEDOUT;101 }102 103 return 0;104}105 106/*107 * Wait till the MDIO read or write operation is complete108 */109static int xgmac_wait_until_done(struct device *dev,110 struct tgec_mdio_controller __iomem *regs,111 bool is_little_endian)112{113 unsigned int timeout;114 115 /* Wait till the MDIO write is complete */116 timeout = TIMEOUT;117 while ((xgmac_read32(®s->mdio_stat, is_little_endian) &118 MDIO_STAT_BSY) && timeout) {119 cpu_relax();120 timeout--;121 }122 123 if (!timeout) {124 dev_err(dev, "timeout waiting for operation to complete\n");125 return -ETIMEDOUT;126 }127 128 return 0;129}130 131static int xgmac_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,132 u16 value)133{134 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;135 struct tgec_mdio_controller __iomem *regs = priv->mdio_base;136 bool endian = priv->is_little_endian;137 u16 dev_addr = regnum & 0x1f;138 u32 mdio_ctl, mdio_stat;139 int ret;140 141 mdio_stat = xgmac_read32(®s->mdio_stat, endian);142 mdio_stat &= ~MDIO_STAT_ENC;143 xgmac_write32(mdio_stat, ®s->mdio_stat, endian);144 145 ret = xgmac_wait_until_free(&bus->dev, regs, endian);146 if (ret)147 return ret;148 149 /* Set the port and dev addr */150 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);151 xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);152 153 /* Write the value to the register */154 xgmac_write32(MDIO_DATA(value), ®s->mdio_data, endian);155 156 ret = xgmac_wait_until_done(&bus->dev, regs, endian);157 if (ret)158 return ret;159 160 return 0;161}162 163static int xgmac_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,164 int regnum, u16 value)165{166 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;167 struct tgec_mdio_controller __iomem *regs = priv->mdio_base;168 bool endian = priv->is_little_endian;169 u32 mdio_ctl, mdio_stat;170 int ret;171 172 mdio_stat = xgmac_read32(®s->mdio_stat, endian);173 mdio_stat |= MDIO_STAT_ENC;174 175 xgmac_write32(mdio_stat, ®s->mdio_stat, endian);176 177 ret = xgmac_wait_until_free(&bus->dev, regs, endian);178 if (ret)179 return ret;180 181 /* Set the port and dev addr */182 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);183 xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);184 185 /* Set the register address */186 xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian);187 188 ret = xgmac_wait_until_free(&bus->dev, regs, endian);189 if (ret)190 return ret;191 192 /* Write the value to the register */193 xgmac_write32(MDIO_DATA(value), ®s->mdio_data, endian);194 195 ret = xgmac_wait_until_done(&bus->dev, regs, endian);196 if (ret)197 return ret;198 199 return 0;200}201 202/* Reads from register regnum in the PHY for device dev, returning the value.203 * Clears miimcom first. All PHY configuration has to be done through the204 * TSEC1 MIIM regs.205 */206static int xgmac_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)207{208 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;209 struct tgec_mdio_controller __iomem *regs = priv->mdio_base;210 bool endian = priv->is_little_endian;211 u16 dev_addr = regnum & 0x1f;212 unsigned long flags;213 uint32_t mdio_stat;214 uint32_t mdio_ctl;215 int ret;216 217 mdio_stat = xgmac_read32(®s->mdio_stat, endian);218 mdio_stat &= ~MDIO_STAT_ENC;219 xgmac_write32(mdio_stat, ®s->mdio_stat, endian);220 221 ret = xgmac_wait_until_free(&bus->dev, regs, endian);222 if (ret)223 return ret;224 225 /* Set the Port and Device Addrs */226 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);227 xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);228 229 if (priv->has_a009885)230 /* Once the operation completes, i.e. MDIO_STAT_BSY clears, we231 * must read back the data register within 16 MDC cycles.232 */233 local_irq_save(flags);234 235 /* Initiate the read */236 xgmac_write32(mdio_ctl | MDIO_CTL_READ, ®s->mdio_ctl, endian);237 238 ret = xgmac_wait_until_done(&bus->dev, regs, endian);239 if (ret)240 goto irq_restore;241 242 /* Return all Fs if nothing was there */243 if ((xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) &&244 !priv->has_a011043) {245 dev_dbg(&bus->dev,246 "Error while reading PHY%d reg at %d.%d\n",247 phy_id, dev_addr, regnum);248 ret = 0xffff;249 } else {250 ret = xgmac_read32(®s->mdio_data, endian) & 0xffff;251 dev_dbg(&bus->dev, "read %04x\n", ret);252 }253 254irq_restore:255 if (priv->has_a009885)256 local_irq_restore(flags);257 258 return ret;259}260 261/* Reads from register regnum in the PHY for device dev, returning the value.262 * Clears miimcom first. All PHY configuration has to be done through the263 * TSEC1 MIIM regs.264 */265static int xgmac_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,266 int regnum)267{268 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;269 struct tgec_mdio_controller __iomem *regs = priv->mdio_base;270 bool endian = priv->is_little_endian;271 u32 mdio_stat, mdio_ctl;272 unsigned long flags;273 int ret;274 275 mdio_stat = xgmac_read32(®s->mdio_stat, endian);276 mdio_stat |= MDIO_STAT_ENC;277 278 xgmac_write32(mdio_stat, ®s->mdio_stat, endian);279 280 ret = xgmac_wait_until_free(&bus->dev, regs, endian);281 if (ret)282 return ret;283 284 /* Set the Port and Device Addrs */285 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);286 xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian);287 288 /* Set the register address */289 xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian);290 291 ret = xgmac_wait_until_free(&bus->dev, regs, endian);292 if (ret)293 return ret;294 295 if (priv->has_a009885)296 /* Once the operation completes, i.e. MDIO_STAT_BSY clears, we297 * must read back the data register within 16 MDC cycles.298 */299 local_irq_save(flags);300 301 /* Initiate the read */302 xgmac_write32(mdio_ctl | MDIO_CTL_READ, ®s->mdio_ctl, endian);303 304 ret = xgmac_wait_until_done(&bus->dev, regs, endian);305 if (ret)306 goto irq_restore;307 308 /* Return all Fs if nothing was there */309 if ((xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) &&310 !priv->has_a011043) {311 dev_dbg(&bus->dev,312 "Error while reading PHY%d reg at %d.%d\n",313 phy_id, dev_addr, regnum);314 ret = 0xffff;315 } else {316 ret = xgmac_read32(®s->mdio_data, endian) & 0xffff;317 dev_dbg(&bus->dev, "read %04x\n", ret);318 }319 320irq_restore:321 if (priv->has_a009885)322 local_irq_restore(flags);323 324 return ret;325}326 327static int xgmac_mdio_set_mdc_freq(struct mii_bus *bus)328{329 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;330 struct tgec_mdio_controller __iomem *regs = priv->mdio_base;331 struct device *dev = bus->parent;332 u32 mdio_stat, div;333 334 if (device_property_read_u32(dev, "clock-frequency", &priv->mdc_freq))335 return 0;336 337 priv->enet_clk = devm_clk_get(dev, NULL);338 if (IS_ERR(priv->enet_clk)) {339 dev_err(dev, "Input clock unknown, not changing MDC frequency");340 return PTR_ERR(priv->enet_clk);341 }342 343 div = ((clk_get_rate(priv->enet_clk) / priv->mdc_freq) - 1) / 2;344 if (div < 5 || div > 0x1ff) {345 dev_err(dev, "Requested MDC frequency is out of range, ignoring");346 return -EINVAL;347 }348 349 mdio_stat = xgmac_read32(®s->mdio_stat, priv->is_little_endian);350 mdio_stat &= ~MDIO_STAT_CLKDIV(0x1ff);351 mdio_stat |= MDIO_STAT_CLKDIV(div);352 xgmac_write32(mdio_stat, ®s->mdio_stat, priv->is_little_endian);353 return 0;354}355 356static void xgmac_mdio_set_suppress_preamble(struct mii_bus *bus)357{358 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv;359 struct tgec_mdio_controller __iomem *regs = priv->mdio_base;360 struct device *dev = bus->parent;361 u32 mdio_stat;362 363 if (!device_property_read_bool(dev, "suppress-preamble"))364 return;365 366 mdio_stat = xgmac_read32(®s->mdio_stat, priv->is_little_endian);367 mdio_stat |= MDIO_STAT_PRE_DIS;368 xgmac_write32(mdio_stat, ®s->mdio_stat, priv->is_little_endian);369}370 371static int xgmac_mdio_probe(struct platform_device *pdev)372{373 struct fwnode_handle *fwnode;374 struct mdio_fsl_priv *priv;375 struct resource *res;376 struct mii_bus *bus;377 int ret;378 379 /* In DPAA-1, MDIO is one of the many FMan sub-devices. The FMan380 * defines a register space that spans a large area, covering all the381 * subdevice areas. Therefore, MDIO cannot claim exclusive access to382 * this register area.383 */384 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);385 if (!res) {386 dev_err(&pdev->dev, "could not obtain address\n");387 return -EINVAL;388 }389 390 bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(struct mdio_fsl_priv));391 if (!bus)392 return -ENOMEM;393 394 bus->name = "Freescale XGMAC MDIO Bus";395 bus->read = xgmac_mdio_read_c22;396 bus->write = xgmac_mdio_write_c22;397 bus->read_c45 = xgmac_mdio_read_c45;398 bus->write_c45 = xgmac_mdio_write_c45;399 bus->parent = &pdev->dev;400 snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res->start);401 402 priv = bus->priv;403 priv->mdio_base = devm_ioremap(&pdev->dev, res->start,404 resource_size(res));405 if (!priv->mdio_base)406 return -ENOMEM;407 408 /* For both ACPI and DT cases, endianness of MDIO controller409 * needs to be specified using "little-endian" property.410 */411 priv->is_little_endian = device_property_read_bool(&pdev->dev,412 "little-endian");413 414 priv->has_a009885 = device_property_read_bool(&pdev->dev,415 "fsl,erratum-a009885");416 priv->has_a011043 = device_property_read_bool(&pdev->dev,417 "fsl,erratum-a011043");418 419 xgmac_mdio_set_suppress_preamble(bus);420 421 ret = xgmac_mdio_set_mdc_freq(bus);422 if (ret)423 return ret;424 425 fwnode = dev_fwnode(&pdev->dev);426 if (is_of_node(fwnode))427 ret = of_mdiobus_register(bus, to_of_node(fwnode));428 else if (is_acpi_node(fwnode))429 ret = acpi_mdiobus_register(bus, fwnode);430 else431 ret = -EINVAL;432 if (ret) {433 dev_err(&pdev->dev, "cannot register MDIO bus\n");434 return ret;435 }436 437 platform_set_drvdata(pdev, bus);438 439 return 0;440}441 442static const struct of_device_id xgmac_mdio_match[] = {443 {444 .compatible = "fsl,fman-xmdio",445 },446 {447 .compatible = "fsl,fman-memac-mdio",448 },449 {},450};451MODULE_DEVICE_TABLE(of, xgmac_mdio_match);452 453static const struct acpi_device_id xgmac_acpi_match[] = {454 { "NXP0006" },455 { }456};457MODULE_DEVICE_TABLE(acpi, xgmac_acpi_match);458 459static struct platform_driver xgmac_mdio_driver = {460 .driver = {461 .name = "fsl-fman_xmdio",462 .of_match_table = xgmac_mdio_match,463 .acpi_match_table = xgmac_acpi_match,464 },465 .probe = xgmac_mdio_probe,466};467 468module_platform_driver(xgmac_mdio_driver);469 470MODULE_DESCRIPTION("Freescale QorIQ 10G MDIO Controller");471MODULE_LICENSE("GPL v2");472