19f35a734STimur Tabi /* 29f35a734STimur Tabi * QorIQ 10G MDIO Controller 39f35a734STimur Tabi * 49f35a734STimur Tabi * Copyright 2012 Freescale Semiconductor, Inc. 59f35a734STimur Tabi * 69f35a734STimur Tabi * Authors: Andy Fleming <afleming@freescale.com> 79f35a734STimur Tabi * Timur Tabi <timur@freescale.com> 89f35a734STimur Tabi * 99f35a734STimur Tabi * This file is licensed under the terms of the GNU General Public License 109f35a734STimur Tabi * version 2. This program is licensed "as is" without any warranty of any 119f35a734STimur Tabi * kind, whether express or implied. 129f35a734STimur Tabi */ 139f35a734STimur Tabi 149f35a734STimur Tabi #include <linux/kernel.h> 159f35a734STimur Tabi #include <linux/slab.h> 169f35a734STimur Tabi #include <linux/interrupt.h> 179f35a734STimur Tabi #include <linux/module.h> 189f35a734STimur Tabi #include <linux/phy.h> 199f35a734STimur Tabi #include <linux/mdio.h> 205af50730SRob Herring #include <linux/of_address.h> 219f35a734STimur Tabi #include <linux/of_platform.h> 229f35a734STimur Tabi #include <linux/of_mdio.h> 239f35a734STimur Tabi 249f35a734STimur Tabi /* Number of microseconds to wait for a register to respond */ 259f35a734STimur Tabi #define TIMEOUT 1000 269f35a734STimur Tabi 279f35a734STimur Tabi struct tgec_mdio_controller { 289f35a734STimur Tabi __be32 reserved[12]; 299f35a734STimur Tabi __be32 mdio_stat; /* MDIO configuration and status */ 309f35a734STimur Tabi __be32 mdio_ctl; /* MDIO control */ 319f35a734STimur Tabi __be32 mdio_data; /* MDIO data */ 329f35a734STimur Tabi __be32 mdio_addr; /* MDIO address */ 339f35a734STimur Tabi } __packed; 349f35a734STimur Tabi 359f35a734STimur Tabi #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) 369f35a734STimur Tabi #define MDIO_STAT_BSY (1 << 0) 379f35a734STimur Tabi #define MDIO_STAT_RD_ER (1 << 1) 389f35a734STimur Tabi #define MDIO_CTL_DEV_ADDR(x) (x & 0x1f) 399f35a734STimur Tabi #define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5) 409f35a734STimur Tabi #define MDIO_CTL_PRE_DIS (1 << 10) 419f35a734STimur Tabi #define MDIO_CTL_SCAN_EN (1 << 11) 429f35a734STimur Tabi #define MDIO_CTL_POST_INC (1 << 14) 439f35a734STimur Tabi #define MDIO_CTL_READ (1 << 15) 449f35a734STimur Tabi 459f35a734STimur Tabi #define MDIO_DATA(x) (x & 0xffff) 469f35a734STimur Tabi #define MDIO_DATA_BSY (1 << 31) 479f35a734STimur Tabi 489f35a734STimur Tabi /* 49c1543d37SMadalin Bucur * Wait until the MDIO bus is free 509f35a734STimur Tabi */ 519f35a734STimur Tabi static int xgmac_wait_until_free(struct device *dev, 529f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs) 539f35a734STimur Tabi { 549f35a734STimur Tabi uint32_t status; 559f35a734STimur Tabi 569f35a734STimur Tabi /* Wait till the bus is free */ 579f35a734STimur Tabi status = spin_event_timeout( 589f35a734STimur Tabi !((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); 599f35a734STimur Tabi if (!status) { 609f35a734STimur Tabi dev_err(dev, "timeout waiting for bus to be free\n"); 619f35a734STimur Tabi return -ETIMEDOUT; 629f35a734STimur Tabi } 639f35a734STimur Tabi 649f35a734STimur Tabi return 0; 659f35a734STimur Tabi } 669f35a734STimur Tabi 679f35a734STimur Tabi /* 689f35a734STimur Tabi * Wait till the MDIO read or write operation is complete 699f35a734STimur Tabi */ 709f35a734STimur Tabi static int xgmac_wait_until_done(struct device *dev, 719f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs) 729f35a734STimur Tabi { 739f35a734STimur Tabi uint32_t status; 749f35a734STimur Tabi 759f35a734STimur Tabi /* Wait till the MDIO write is complete */ 769f35a734STimur Tabi status = spin_event_timeout( 779f35a734STimur Tabi !((in_be32(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); 789f35a734STimur Tabi if (!status) { 799f35a734STimur Tabi dev_err(dev, "timeout waiting for operation to complete\n"); 809f35a734STimur Tabi return -ETIMEDOUT; 819f35a734STimur Tabi } 829f35a734STimur Tabi 839f35a734STimur Tabi return 0; 849f35a734STimur Tabi } 859f35a734STimur Tabi 869f35a734STimur Tabi /* 879f35a734STimur Tabi * Write value to the PHY for this device to the register at regnum,waiting 889f35a734STimur Tabi * until the write is done before it returns. All PHY configuration has to be 899f35a734STimur Tabi * done through the TSEC1 MIIM regs. 909f35a734STimur Tabi */ 919f35a734STimur Tabi static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) 929f35a734STimur Tabi { 939f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs = bus->priv; 949f35a734STimur Tabi uint16_t dev_addr = regnum >> 16; 959f35a734STimur Tabi int ret; 969f35a734STimur Tabi 979f35a734STimur Tabi /* Setup the MII Mgmt clock speed */ 989f35a734STimur Tabi out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); 999f35a734STimur Tabi 1009f35a734STimur Tabi ret = xgmac_wait_until_free(&bus->dev, regs); 1019f35a734STimur Tabi if (ret) 1029f35a734STimur Tabi return ret; 1039f35a734STimur Tabi 1049f35a734STimur Tabi /* Set the port and dev addr */ 1059f35a734STimur Tabi out_be32(®s->mdio_ctl, 1069f35a734STimur Tabi MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr)); 1079f35a734STimur Tabi 1089f35a734STimur Tabi /* Set the register address */ 1099f35a734STimur Tabi out_be32(®s->mdio_addr, regnum & 0xffff); 1109f35a734STimur Tabi 1119f35a734STimur Tabi ret = xgmac_wait_until_free(&bus->dev, regs); 1129f35a734STimur Tabi if (ret) 1139f35a734STimur Tabi return ret; 1149f35a734STimur Tabi 1159f35a734STimur Tabi /* Write the value to the register */ 1169f35a734STimur Tabi out_be32(®s->mdio_data, MDIO_DATA(value)); 1179f35a734STimur Tabi 1189f35a734STimur Tabi ret = xgmac_wait_until_done(&bus->dev, regs); 1199f35a734STimur Tabi if (ret) 1209f35a734STimur Tabi return ret; 1219f35a734STimur Tabi 1229f35a734STimur Tabi return 0; 1239f35a734STimur Tabi } 1249f35a734STimur Tabi 1259f35a734STimur Tabi /* 1269f35a734STimur Tabi * Reads from register regnum in the PHY for device dev, returning the value. 1279f35a734STimur Tabi * Clears miimcom first. All PHY configuration has to be done through the 1289f35a734STimur Tabi * TSEC1 MIIM regs. 1299f35a734STimur Tabi */ 1309f35a734STimur Tabi static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) 1319f35a734STimur Tabi { 1329f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs = bus->priv; 1339f35a734STimur Tabi uint16_t dev_addr = regnum >> 16; 1349f35a734STimur Tabi uint32_t mdio_ctl; 1359f35a734STimur Tabi uint16_t value; 1369f35a734STimur Tabi int ret; 1379f35a734STimur Tabi 1389f35a734STimur Tabi /* Setup the MII Mgmt clock speed */ 1399f35a734STimur Tabi out_be32(®s->mdio_stat, MDIO_STAT_CLKDIV(100)); 1409f35a734STimur Tabi 1419f35a734STimur Tabi ret = xgmac_wait_until_free(&bus->dev, regs); 1429f35a734STimur Tabi if (ret) 1439f35a734STimur Tabi return ret; 1449f35a734STimur Tabi 1459f35a734STimur Tabi /* Set the Port and Device Addrs */ 1469f35a734STimur Tabi mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 1479f35a734STimur Tabi out_be32(®s->mdio_ctl, mdio_ctl); 1489f35a734STimur Tabi 1499f35a734STimur Tabi /* Set the register address */ 1509f35a734STimur Tabi out_be32(®s->mdio_addr, regnum & 0xffff); 1519f35a734STimur Tabi 1529f35a734STimur Tabi ret = xgmac_wait_until_free(&bus->dev, regs); 1539f35a734STimur Tabi if (ret) 1549f35a734STimur Tabi return ret; 1559f35a734STimur Tabi 1569f35a734STimur Tabi /* Initiate the read */ 1579f35a734STimur Tabi out_be32(®s->mdio_ctl, mdio_ctl | MDIO_CTL_READ); 1589f35a734STimur Tabi 1599f35a734STimur Tabi ret = xgmac_wait_until_done(&bus->dev, regs); 1609f35a734STimur Tabi if (ret) 1619f35a734STimur Tabi return ret; 1629f35a734STimur Tabi 1639f35a734STimur Tabi /* Return all Fs if nothing was there */ 1649f35a734STimur Tabi if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { 16555fd3641SShruti Kanetkar dev_err(&bus->dev, 1669e6492ecSShruti Kanetkar "Error while reading PHY%d reg at %d.%hhu\n", 16755fd3641SShruti Kanetkar phy_id, dev_addr, regnum); 1689f35a734STimur Tabi return 0xffff; 1699f35a734STimur Tabi } 1709f35a734STimur Tabi 1719f35a734STimur Tabi value = in_be32(®s->mdio_data) & 0xffff; 1729f35a734STimur Tabi dev_dbg(&bus->dev, "read %04x\n", value); 1739f35a734STimur Tabi 1749f35a734STimur Tabi return value; 1759f35a734STimur Tabi } 1769f35a734STimur Tabi 17733897cc8SBill Pemberton static int xgmac_mdio_probe(struct platform_device *pdev) 1789f35a734STimur Tabi { 1799f35a734STimur Tabi struct device_node *np = pdev->dev.of_node; 1809f35a734STimur Tabi struct mii_bus *bus; 1819f35a734STimur Tabi struct resource res; 1829f35a734STimur Tabi int ret; 1839f35a734STimur Tabi 1849f35a734STimur Tabi ret = of_address_to_resource(np, 0, &res); 1859f35a734STimur Tabi if (ret) { 1869f35a734STimur Tabi dev_err(&pdev->dev, "could not obtain address\n"); 1879f35a734STimur Tabi return ret; 1889f35a734STimur Tabi } 1899f35a734STimur Tabi 190aa842478SShaohui Xie bus = mdiobus_alloc(); 1919f35a734STimur Tabi if (!bus) 1929f35a734STimur Tabi return -ENOMEM; 1939f35a734STimur Tabi 1949f35a734STimur Tabi bus->name = "Freescale XGMAC MDIO Bus"; 1959f35a734STimur Tabi bus->read = xgmac_mdio_read; 1969f35a734STimur Tabi bus->write = xgmac_mdio_write; 1979f35a734STimur Tabi bus->parent = &pdev->dev; 1989f35a734STimur Tabi snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start); 1999f35a734STimur Tabi 2009f35a734STimur Tabi /* Set the PHY base address */ 2019f35a734STimur Tabi bus->priv = of_iomap(np, 0); 2029f35a734STimur Tabi if (!bus->priv) { 2039f35a734STimur Tabi ret = -ENOMEM; 2049f35a734STimur Tabi goto err_ioremap; 2059f35a734STimur Tabi } 2069f35a734STimur Tabi 2079f35a734STimur Tabi ret = of_mdiobus_register(bus, np); 2089f35a734STimur Tabi if (ret) { 2099f35a734STimur Tabi dev_err(&pdev->dev, "cannot register MDIO bus\n"); 2109f35a734STimur Tabi goto err_registration; 2119f35a734STimur Tabi } 2129f35a734STimur Tabi 2138513fbd8SJingoo Han platform_set_drvdata(pdev, bus); 2149f35a734STimur Tabi 2159f35a734STimur Tabi return 0; 2169f35a734STimur Tabi 2179f35a734STimur Tabi err_registration: 2189f35a734STimur Tabi iounmap(bus->priv); 2199f35a734STimur Tabi 2209f35a734STimur Tabi err_ioremap: 2219f35a734STimur Tabi mdiobus_free(bus); 2229f35a734STimur Tabi 2239f35a734STimur Tabi return ret; 2249f35a734STimur Tabi } 2259f35a734STimur Tabi 22633897cc8SBill Pemberton static int xgmac_mdio_remove(struct platform_device *pdev) 2279f35a734STimur Tabi { 2288513fbd8SJingoo Han struct mii_bus *bus = platform_get_drvdata(pdev); 2299f35a734STimur Tabi 2309f35a734STimur Tabi mdiobus_unregister(bus); 2319f35a734STimur Tabi iounmap(bus->priv); 2329f35a734STimur Tabi mdiobus_free(bus); 2339f35a734STimur Tabi 2349f35a734STimur Tabi return 0; 2359f35a734STimur Tabi } 2369f35a734STimur Tabi 2379f35a734STimur Tabi static struct of_device_id xgmac_mdio_match[] = { 2389f35a734STimur Tabi { 2399f35a734STimur Tabi .compatible = "fsl,fman-xmdio", 2409f35a734STimur Tabi }, 2419f35a734STimur Tabi {}, 2429f35a734STimur Tabi }; 2439f35a734STimur Tabi MODULE_DEVICE_TABLE(of, xgmac_mdio_match); 2449f35a734STimur Tabi 2459f35a734STimur Tabi static struct platform_driver xgmac_mdio_driver = { 2469f35a734STimur Tabi .driver = { 2479f35a734STimur Tabi .name = "fsl-fman_xmdio", 2489f35a734STimur Tabi .of_match_table = xgmac_mdio_match, 2499f35a734STimur Tabi }, 2509f35a734STimur Tabi .probe = xgmac_mdio_probe, 2519f35a734STimur Tabi .remove = xgmac_mdio_remove, 2529f35a734STimur Tabi }; 2539f35a734STimur Tabi 2549f35a734STimur Tabi module_platform_driver(xgmac_mdio_driver); 2559f35a734STimur Tabi 2569f35a734STimur Tabi MODULE_DESCRIPTION("Freescale QorIQ 10G MDIO Controller"); 2579f35a734STimur Tabi MODULE_LICENSE("GPL v2"); 258