1 /* 2 * QorIQ 10G MDIO Controller 3 * 4 * Copyright 2012 Freescale Semiconductor, Inc. 5 * 6 * Authors: Andy Fleming <afleming@freescale.com> 7 * Timur Tabi <timur@freescale.com> 8 * 9 * This file is licensed under the terms of the GNU General Public License 10 * version 2. This program is licensed "as is" without any warranty of any 11 * kind, whether express or implied. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/slab.h> 16 #include <linux/interrupt.h> 17 #include <linux/module.h> 18 #include <linux/phy.h> 19 #include <linux/mdio.h> 20 #include <linux/of_address.h> 21 #include <linux/of_platform.h> 22 #include <linux/of_mdio.h> 23 24 /* Number of microseconds to wait for a register to respond */ 25 #define TIMEOUT 1000 26 27 struct tgec_mdio_controller { 28 __be32 reserved[12]; 29 __be32 mdio_stat; /* MDIO configuration and status */ 30 __be32 mdio_ctl; /* MDIO control */ 31 __be32 mdio_data; /* MDIO data */ 32 __be32 mdio_addr; /* MDIO address */ 33 } __packed; 34 35 #define MDIO_STAT_ENC BIT(6) 36 #define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8) 37 #define MDIO_STAT_BSY BIT(0) 38 #define MDIO_STAT_RD_ER BIT(1) 39 #define MDIO_CTL_DEV_ADDR(x) (x & 0x1f) 40 #define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5) 41 #define MDIO_CTL_PRE_DIS BIT(10) 42 #define MDIO_CTL_SCAN_EN BIT(11) 43 #define MDIO_CTL_POST_INC BIT(14) 44 #define MDIO_CTL_READ BIT(15) 45 46 #define MDIO_DATA(x) (x & 0xffff) 47 #define MDIO_DATA_BSY BIT(31) 48 49 struct mdio_fsl_priv { 50 struct tgec_mdio_controller __iomem *mdio_base; 51 bool is_little_endian; 52 }; 53 54 static u32 xgmac_read32(void __iomem *regs, 55 bool is_little_endian) 56 { 57 if (is_little_endian) 58 return ioread32(regs); 59 else 60 return ioread32be(regs); 61 } 62 63 static void xgmac_write32(u32 value, 64 void __iomem *regs, 65 bool is_little_endian) 66 { 67 if (is_little_endian) 68 iowrite32(value, regs); 69 else 70 iowrite32be(value, regs); 71 } 72 73 /* 74 * Wait until the MDIO bus is free 75 */ 76 static int xgmac_wait_until_free(struct device *dev, 77 struct tgec_mdio_controller __iomem *regs, 78 bool is_little_endian) 79 { 80 unsigned int timeout; 81 82 /* Wait till the bus is free */ 83 timeout = TIMEOUT; 84 while ((xgmac_read32(®s->mdio_stat, is_little_endian) & 85 MDIO_STAT_BSY) && timeout) { 86 cpu_relax(); 87 timeout--; 88 } 89 90 if (!timeout) { 91 dev_err(dev, "timeout waiting for bus to be free\n"); 92 return -ETIMEDOUT; 93 } 94 95 return 0; 96 } 97 98 /* 99 * Wait till the MDIO read or write operation is complete 100 */ 101 static int xgmac_wait_until_done(struct device *dev, 102 struct tgec_mdio_controller __iomem *regs, 103 bool is_little_endian) 104 { 105 unsigned int timeout; 106 107 /* Wait till the MDIO write is complete */ 108 timeout = TIMEOUT; 109 while ((xgmac_read32(®s->mdio_stat, is_little_endian) & 110 MDIO_STAT_BSY) && timeout) { 111 cpu_relax(); 112 timeout--; 113 } 114 115 if (!timeout) { 116 dev_err(dev, "timeout waiting for operation to complete\n"); 117 return -ETIMEDOUT; 118 } 119 120 return 0; 121 } 122 123 /* 124 * Write value to the PHY for this device to the register at regnum,waiting 125 * until the write is done before it returns. All PHY configuration has to be 126 * done through the TSEC1 MIIM regs. 127 */ 128 static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) 129 { 130 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv; 131 struct tgec_mdio_controller __iomem *regs = priv->mdio_base; 132 uint16_t dev_addr; 133 u32 mdio_ctl, mdio_stat; 134 int ret; 135 bool endian = priv->is_little_endian; 136 137 mdio_stat = xgmac_read32(®s->mdio_stat, endian); 138 if (regnum & MII_ADDR_C45) { 139 /* Clause 45 (ie 10G) */ 140 dev_addr = (regnum >> 16) & 0x1f; 141 mdio_stat |= MDIO_STAT_ENC; 142 } else { 143 /* Clause 22 (ie 1G) */ 144 dev_addr = regnum & 0x1f; 145 mdio_stat &= ~MDIO_STAT_ENC; 146 } 147 148 xgmac_write32(mdio_stat, ®s->mdio_stat, endian); 149 150 ret = xgmac_wait_until_free(&bus->dev, regs, endian); 151 if (ret) 152 return ret; 153 154 /* Set the port and dev addr */ 155 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 156 xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian); 157 158 /* Set the register address */ 159 if (regnum & MII_ADDR_C45) { 160 xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian); 161 162 ret = xgmac_wait_until_free(&bus->dev, regs, endian); 163 if (ret) 164 return ret; 165 } 166 167 /* Write the value to the register */ 168 xgmac_write32(MDIO_DATA(value), ®s->mdio_data, endian); 169 170 ret = xgmac_wait_until_done(&bus->dev, regs, endian); 171 if (ret) 172 return ret; 173 174 return 0; 175 } 176 177 /* 178 * Reads from register regnum in the PHY for device dev, returning the value. 179 * Clears miimcom first. All PHY configuration has to be done through the 180 * TSEC1 MIIM regs. 181 */ 182 static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) 183 { 184 struct mdio_fsl_priv *priv = (struct mdio_fsl_priv *)bus->priv; 185 struct tgec_mdio_controller __iomem *regs = priv->mdio_base; 186 uint16_t dev_addr; 187 uint32_t mdio_stat; 188 uint32_t mdio_ctl; 189 uint16_t value; 190 int ret; 191 bool endian = priv->is_little_endian; 192 193 mdio_stat = xgmac_read32(®s->mdio_stat, endian); 194 if (regnum & MII_ADDR_C45) { 195 dev_addr = (regnum >> 16) & 0x1f; 196 mdio_stat |= MDIO_STAT_ENC; 197 } else { 198 dev_addr = regnum & 0x1f; 199 mdio_stat &= ~MDIO_STAT_ENC; 200 } 201 202 xgmac_write32(mdio_stat, ®s->mdio_stat, endian); 203 204 ret = xgmac_wait_until_free(&bus->dev, regs, endian); 205 if (ret) 206 return ret; 207 208 /* Set the Port and Device Addrs */ 209 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 210 xgmac_write32(mdio_ctl, ®s->mdio_ctl, endian); 211 212 /* Set the register address */ 213 if (regnum & MII_ADDR_C45) { 214 xgmac_write32(regnum & 0xffff, ®s->mdio_addr, endian); 215 216 ret = xgmac_wait_until_free(&bus->dev, regs, endian); 217 if (ret) 218 return ret; 219 } 220 221 /* Initiate the read */ 222 xgmac_write32(mdio_ctl | MDIO_CTL_READ, ®s->mdio_ctl, endian); 223 224 ret = xgmac_wait_until_done(&bus->dev, regs, endian); 225 if (ret) 226 return ret; 227 228 /* Return all Fs if nothing was there */ 229 if (xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) { 230 dev_err(&bus->dev, 231 "Error while reading PHY%d reg at %d.%hhu\n", 232 phy_id, dev_addr, regnum); 233 return 0xffff; 234 } 235 236 value = xgmac_read32(®s->mdio_data, endian) & 0xffff; 237 dev_dbg(&bus->dev, "read %04x\n", value); 238 239 return value; 240 } 241 242 static int xgmac_mdio_probe(struct platform_device *pdev) 243 { 244 struct device_node *np = pdev->dev.of_node; 245 struct mii_bus *bus; 246 struct resource res; 247 struct mdio_fsl_priv *priv; 248 int ret; 249 250 ret = of_address_to_resource(np, 0, &res); 251 if (ret) { 252 dev_err(&pdev->dev, "could not obtain address\n"); 253 return ret; 254 } 255 256 bus = mdiobus_alloc_size(sizeof(struct mdio_fsl_priv)); 257 if (!bus) 258 return -ENOMEM; 259 260 bus->name = "Freescale XGMAC MDIO Bus"; 261 bus->read = xgmac_mdio_read; 262 bus->write = xgmac_mdio_write; 263 bus->parent = &pdev->dev; 264 snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start); 265 266 /* Set the PHY base address */ 267 priv = bus->priv; 268 priv->mdio_base = of_iomap(np, 0); 269 if (!priv->mdio_base) { 270 ret = -ENOMEM; 271 goto err_ioremap; 272 } 273 274 if (of_get_property(pdev->dev.of_node, 275 "little-endian", NULL)) 276 priv->is_little_endian = true; 277 else 278 priv->is_little_endian = false; 279 280 ret = of_mdiobus_register(bus, np); 281 if (ret) { 282 dev_err(&pdev->dev, "cannot register MDIO bus\n"); 283 goto err_registration; 284 } 285 286 platform_set_drvdata(pdev, bus); 287 288 return 0; 289 290 err_registration: 291 iounmap(priv->mdio_base); 292 293 err_ioremap: 294 mdiobus_free(bus); 295 296 return ret; 297 } 298 299 static int xgmac_mdio_remove(struct platform_device *pdev) 300 { 301 struct mii_bus *bus = platform_get_drvdata(pdev); 302 303 mdiobus_unregister(bus); 304 iounmap(bus->priv); 305 mdiobus_free(bus); 306 307 return 0; 308 } 309 310 static const struct of_device_id xgmac_mdio_match[] = { 311 { 312 .compatible = "fsl,fman-xmdio", 313 }, 314 { 315 .compatible = "fsl,fman-memac-mdio", 316 }, 317 {}, 318 }; 319 MODULE_DEVICE_TABLE(of, xgmac_mdio_match); 320 321 static struct platform_driver xgmac_mdio_driver = { 322 .driver = { 323 .name = "fsl-fman_xmdio", 324 .of_match_table = xgmac_mdio_match, 325 }, 326 .probe = xgmac_mdio_probe, 327 .remove = xgmac_mdio_remove, 328 }; 329 330 module_platform_driver(xgmac_mdio_driver); 331 332 MODULE_DESCRIPTION("Freescale QorIQ 10G MDIO Controller"); 333 MODULE_LICENSE("GPL v2"); 334