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 351fcf77c8SAndy Fleming #define MDIO_STAT_ENC BIT(6) 369f35a734STimur Tabi #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) 379f35a734STimur Tabi #define MDIO_STAT_BSY (1 << 0) 389f35a734STimur Tabi #define MDIO_STAT_RD_ER (1 << 1) 399f35a734STimur Tabi #define MDIO_CTL_DEV_ADDR(x) (x & 0x1f) 409f35a734STimur Tabi #define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5) 419f35a734STimur Tabi #define MDIO_CTL_PRE_DIS (1 << 10) 429f35a734STimur Tabi #define MDIO_CTL_SCAN_EN (1 << 11) 439f35a734STimur Tabi #define MDIO_CTL_POST_INC (1 << 14) 449f35a734STimur Tabi #define MDIO_CTL_READ (1 << 15) 459f35a734STimur Tabi 469f35a734STimur Tabi #define MDIO_DATA(x) (x & 0xffff) 479f35a734STimur Tabi #define MDIO_DATA_BSY (1 << 31) 489f35a734STimur Tabi 499f35a734STimur Tabi /* 50c1543d37SMadalin Bucur * Wait until the MDIO bus is free 519f35a734STimur Tabi */ 529f35a734STimur Tabi static int xgmac_wait_until_free(struct device *dev, 539f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs) 549f35a734STimur Tabi { 559f35a734STimur Tabi uint32_t status; 569f35a734STimur Tabi 579f35a734STimur Tabi /* Wait till the bus is free */ 589f35a734STimur Tabi status = spin_event_timeout( 599f35a734STimur Tabi !((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0); 609f35a734STimur Tabi if (!status) { 619f35a734STimur Tabi dev_err(dev, "timeout waiting for bus to be free\n"); 629f35a734STimur Tabi return -ETIMEDOUT; 639f35a734STimur Tabi } 649f35a734STimur Tabi 659f35a734STimur Tabi return 0; 669f35a734STimur Tabi } 679f35a734STimur Tabi 689f35a734STimur Tabi /* 699f35a734STimur Tabi * Wait till the MDIO read or write operation is complete 709f35a734STimur Tabi */ 719f35a734STimur Tabi static int xgmac_wait_until_done(struct device *dev, 729f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs) 739f35a734STimur Tabi { 749f35a734STimur Tabi uint32_t status; 759f35a734STimur Tabi 769f35a734STimur Tabi /* Wait till the MDIO write is complete */ 779f35a734STimur Tabi status = spin_event_timeout( 789f35a734STimur Tabi !((in_be32(®s->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0); 799f35a734STimur Tabi if (!status) { 809f35a734STimur Tabi dev_err(dev, "timeout waiting for operation to complete\n"); 819f35a734STimur Tabi return -ETIMEDOUT; 829f35a734STimur Tabi } 839f35a734STimur Tabi 849f35a734STimur Tabi return 0; 859f35a734STimur Tabi } 869f35a734STimur Tabi 879f35a734STimur Tabi /* 889f35a734STimur Tabi * Write value to the PHY for this device to the register at regnum,waiting 899f35a734STimur Tabi * until the write is done before it returns. All PHY configuration has to be 909f35a734STimur Tabi * done through the TSEC1 MIIM regs. 919f35a734STimur Tabi */ 929f35a734STimur Tabi static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) 939f35a734STimur Tabi { 949f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs = bus->priv; 951fcf77c8SAndy Fleming uint16_t dev_addr; 961fcf77c8SAndy Fleming u32 mdio_ctl, mdio_stat; 979f35a734STimur Tabi int ret; 989f35a734STimur Tabi 991fcf77c8SAndy Fleming mdio_stat = in_be32(®s->mdio_stat); 1001fcf77c8SAndy Fleming if (regnum & MII_ADDR_C45) { 1011fcf77c8SAndy Fleming /* Clause 45 (ie 10G) */ 1021fcf77c8SAndy Fleming dev_addr = (regnum >> 16) & 0x1f; 1031fcf77c8SAndy Fleming mdio_stat |= MDIO_STAT_ENC; 1041fcf77c8SAndy Fleming } else { 1051fcf77c8SAndy Fleming /* Clause 22 (ie 1G) */ 1061fcf77c8SAndy Fleming dev_addr = regnum & 0x1f; 1071fcf77c8SAndy Fleming mdio_stat &= ~MDIO_STAT_ENC; 1081fcf77c8SAndy Fleming } 1091fcf77c8SAndy Fleming 1101fcf77c8SAndy Fleming out_be32(®s->mdio_stat, mdio_stat); 1111fcf77c8SAndy Fleming 1121fcf77c8SAndy Fleming ret = xgmac_wait_until_free(&bus->dev, regs); 1131fcf77c8SAndy Fleming if (ret) 1141fcf77c8SAndy Fleming return ret; 1151fcf77c8SAndy Fleming 1169f35a734STimur Tabi /* Set the port and dev addr */ 1171fcf77c8SAndy Fleming mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 1181fcf77c8SAndy Fleming out_be32(®s->mdio_ctl, mdio_ctl); 1199f35a734STimur Tabi 1209f35a734STimur Tabi /* Set the register address */ 1211fcf77c8SAndy Fleming if (regnum & MII_ADDR_C45) { 1229f35a734STimur Tabi out_be32(®s->mdio_addr, regnum & 0xffff); 1239f35a734STimur Tabi 1249f35a734STimur Tabi ret = xgmac_wait_until_free(&bus->dev, regs); 1259f35a734STimur Tabi if (ret) 1269f35a734STimur Tabi return ret; 1271fcf77c8SAndy Fleming } 1289f35a734STimur Tabi 1299f35a734STimur Tabi /* Write the value to the register */ 1309f35a734STimur Tabi out_be32(®s->mdio_data, MDIO_DATA(value)); 1319f35a734STimur Tabi 1329f35a734STimur Tabi ret = xgmac_wait_until_done(&bus->dev, regs); 1339f35a734STimur Tabi if (ret) 1349f35a734STimur Tabi return ret; 1359f35a734STimur Tabi 1369f35a734STimur Tabi return 0; 1379f35a734STimur Tabi } 1389f35a734STimur Tabi 1399f35a734STimur Tabi /* 1409f35a734STimur Tabi * Reads from register regnum in the PHY for device dev, returning the value. 1419f35a734STimur Tabi * Clears miimcom first. All PHY configuration has to be done through the 1429f35a734STimur Tabi * TSEC1 MIIM regs. 1439f35a734STimur Tabi */ 1449f35a734STimur Tabi static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) 1459f35a734STimur Tabi { 1469f35a734STimur Tabi struct tgec_mdio_controller __iomem *regs = bus->priv; 1471fcf77c8SAndy Fleming uint16_t dev_addr; 1481fcf77c8SAndy Fleming uint32_t mdio_stat; 1499f35a734STimur Tabi uint32_t mdio_ctl; 1509f35a734STimur Tabi uint16_t value; 1519f35a734STimur Tabi int ret; 1529f35a734STimur Tabi 1531fcf77c8SAndy Fleming mdio_stat = in_be32(®s->mdio_stat); 1541fcf77c8SAndy Fleming if (regnum & MII_ADDR_C45) { 1551fcf77c8SAndy Fleming dev_addr = (regnum >> 16) & 0x1f; 1561fcf77c8SAndy Fleming mdio_stat |= MDIO_STAT_ENC; 1571fcf77c8SAndy Fleming } else { 1581fcf77c8SAndy Fleming dev_addr = regnum & 0x1f; 159e54bfe9dSShaohui Xie mdio_stat &= ~MDIO_STAT_ENC; 1601fcf77c8SAndy Fleming } 1611fcf77c8SAndy Fleming 1621fcf77c8SAndy Fleming out_be32(®s->mdio_stat, mdio_stat); 1631fcf77c8SAndy Fleming 1641fcf77c8SAndy Fleming ret = xgmac_wait_until_free(&bus->dev, regs); 1651fcf77c8SAndy Fleming if (ret) 1661fcf77c8SAndy Fleming return ret; 1671fcf77c8SAndy Fleming 1689f35a734STimur Tabi /* Set the Port and Device Addrs */ 1699f35a734STimur Tabi mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 1709f35a734STimur Tabi out_be32(®s->mdio_ctl, mdio_ctl); 1719f35a734STimur Tabi 1729f35a734STimur Tabi /* Set the register address */ 1731fcf77c8SAndy Fleming if (regnum & MII_ADDR_C45) { 1749f35a734STimur Tabi out_be32(®s->mdio_addr, regnum & 0xffff); 1759f35a734STimur Tabi 1769f35a734STimur Tabi ret = xgmac_wait_until_free(&bus->dev, regs); 1779f35a734STimur Tabi if (ret) 1789f35a734STimur Tabi return ret; 1791fcf77c8SAndy Fleming } 1809f35a734STimur Tabi 1819f35a734STimur Tabi /* Initiate the read */ 1829f35a734STimur Tabi out_be32(®s->mdio_ctl, mdio_ctl | MDIO_CTL_READ); 1839f35a734STimur Tabi 1849f35a734STimur Tabi ret = xgmac_wait_until_done(&bus->dev, regs); 1859f35a734STimur Tabi if (ret) 1869f35a734STimur Tabi return ret; 1879f35a734STimur Tabi 1889f35a734STimur Tabi /* Return all Fs if nothing was there */ 1899f35a734STimur Tabi if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER) { 19055fd3641SShruti Kanetkar dev_err(&bus->dev, 1919e6492ecSShruti Kanetkar "Error while reading PHY%d reg at %d.%hhu\n", 19255fd3641SShruti Kanetkar phy_id, dev_addr, regnum); 1939f35a734STimur Tabi return 0xffff; 1949f35a734STimur Tabi } 1959f35a734STimur Tabi 1969f35a734STimur Tabi value = in_be32(®s->mdio_data) & 0xffff; 1979f35a734STimur Tabi dev_dbg(&bus->dev, "read %04x\n", value); 1989f35a734STimur Tabi 1999f35a734STimur Tabi return value; 2009f35a734STimur Tabi } 2019f35a734STimur Tabi 20233897cc8SBill Pemberton static int xgmac_mdio_probe(struct platform_device *pdev) 2039f35a734STimur Tabi { 2049f35a734STimur Tabi struct device_node *np = pdev->dev.of_node; 2059f35a734STimur Tabi struct mii_bus *bus; 2069f35a734STimur Tabi struct resource res; 2079f35a734STimur Tabi int ret; 2089f35a734STimur Tabi 2099f35a734STimur Tabi ret = of_address_to_resource(np, 0, &res); 2109f35a734STimur Tabi if (ret) { 2119f35a734STimur Tabi dev_err(&pdev->dev, "could not obtain address\n"); 2129f35a734STimur Tabi return ret; 2139f35a734STimur Tabi } 2149f35a734STimur Tabi 215aa842478SShaohui Xie bus = mdiobus_alloc(); 2169f35a734STimur Tabi if (!bus) 2179f35a734STimur Tabi return -ENOMEM; 2189f35a734STimur Tabi 2199f35a734STimur Tabi bus->name = "Freescale XGMAC MDIO Bus"; 2209f35a734STimur Tabi bus->read = xgmac_mdio_read; 2219f35a734STimur Tabi bus->write = xgmac_mdio_write; 2229f35a734STimur Tabi bus->parent = &pdev->dev; 2239f35a734STimur Tabi snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start); 2249f35a734STimur Tabi 2259f35a734STimur Tabi /* Set the PHY base address */ 2269f35a734STimur Tabi bus->priv = of_iomap(np, 0); 2279f35a734STimur Tabi if (!bus->priv) { 2289f35a734STimur Tabi ret = -ENOMEM; 2299f35a734STimur Tabi goto err_ioremap; 2309f35a734STimur Tabi } 2319f35a734STimur Tabi 2329f35a734STimur Tabi ret = of_mdiobus_register(bus, np); 2339f35a734STimur Tabi if (ret) { 2349f35a734STimur Tabi dev_err(&pdev->dev, "cannot register MDIO bus\n"); 2359f35a734STimur Tabi goto err_registration; 2369f35a734STimur Tabi } 2379f35a734STimur Tabi 2388513fbd8SJingoo Han platform_set_drvdata(pdev, bus); 2399f35a734STimur Tabi 2409f35a734STimur Tabi return 0; 2419f35a734STimur Tabi 2429f35a734STimur Tabi err_registration: 2439f35a734STimur Tabi iounmap(bus->priv); 2449f35a734STimur Tabi 2459f35a734STimur Tabi err_ioremap: 2469f35a734STimur Tabi mdiobus_free(bus); 2479f35a734STimur Tabi 2489f35a734STimur Tabi return ret; 2499f35a734STimur Tabi } 2509f35a734STimur Tabi 25133897cc8SBill Pemberton static int xgmac_mdio_remove(struct platform_device *pdev) 2529f35a734STimur Tabi { 2538513fbd8SJingoo Han struct mii_bus *bus = platform_get_drvdata(pdev); 2549f35a734STimur Tabi 2559f35a734STimur Tabi mdiobus_unregister(bus); 2569f35a734STimur Tabi iounmap(bus->priv); 2579f35a734STimur Tabi mdiobus_free(bus); 2589f35a734STimur Tabi 2599f35a734STimur Tabi return 0; 2609f35a734STimur Tabi } 2619f35a734STimur Tabi 2629f35a734STimur Tabi static struct of_device_id xgmac_mdio_match[] = { 2639f35a734STimur Tabi { 2649f35a734STimur Tabi .compatible = "fsl,fman-xmdio", 2659f35a734STimur Tabi }, 2661fcf77c8SAndy Fleming { 2671fcf77c8SAndy Fleming .compatible = "fsl,fman-memac-mdio", 2681fcf77c8SAndy Fleming }, 2699f35a734STimur Tabi {}, 2709f35a734STimur Tabi }; 2719f35a734STimur Tabi MODULE_DEVICE_TABLE(of, xgmac_mdio_match); 2729f35a734STimur Tabi 2739f35a734STimur Tabi static struct platform_driver xgmac_mdio_driver = { 2749f35a734STimur Tabi .driver = { 2759f35a734STimur Tabi .name = "fsl-fman_xmdio", 2769f35a734STimur Tabi .of_match_table = xgmac_mdio_match, 2779f35a734STimur Tabi }, 2789f35a734STimur Tabi .probe = xgmac_mdio_probe, 2799f35a734STimur Tabi .remove = xgmac_mdio_remove, 2809f35a734STimur Tabi }; 2819f35a734STimur Tabi 2829f35a734STimur Tabi module_platform_driver(xgmac_mdio_driver); 2839f35a734STimur Tabi 2849f35a734STimur Tabi MODULE_DESCRIPTION("Freescale QorIQ 10G MDIO Controller"); 2859f35a734STimur Tabi MODULE_LICENSE("GPL v2"); 286