1 /* 2 * Freescale PowerQUICC Ethernet Driver -- MIIM bus implementation 3 * Provides Bus interface for MIIM regs 4 * 5 * Author: Andy Fleming <afleming@freescale.com> 6 * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> 7 * 8 * Copyright 2002-2004, 2008-2009 Freescale Semiconductor, Inc. 9 * 10 * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips) 11 * 12 * This program is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by the 14 * Free Software Foundation; either version 2 of the License, or (at your 15 * option) any later version. 16 * 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/string.h> 21 #include <linux/errno.h> 22 #include <linux/unistd.h> 23 #include <linux/slab.h> 24 #include <linux/interrupt.h> 25 #include <linux/init.h> 26 #include <linux/delay.h> 27 #include <linux/netdevice.h> 28 #include <linux/etherdevice.h> 29 #include <linux/skbuff.h> 30 #include <linux/spinlock.h> 31 #include <linux/mm.h> 32 #include <linux/module.h> 33 #include <linux/platform_device.h> 34 #include <linux/crc32.h> 35 #include <linux/mii.h> 36 #include <linux/phy.h> 37 #include <linux/of.h> 38 #include <linux/of_address.h> 39 #include <linux/of_mdio.h> 40 #include <linux/of_platform.h> 41 42 #include <asm/io.h> 43 #include <asm/irq.h> 44 #include <asm/uaccess.h> 45 #include <asm/ucc.h> 46 47 #include "gianfar.h" 48 #include "fsl_pq_mdio.h" 49 50 struct fsl_pq_mdio_priv { 51 void __iomem *map; 52 struct fsl_pq_mdio __iomem *regs; 53 }; 54 55 /* 56 * Write value to the PHY at mii_id at register regnum, 57 * on the bus attached to the local interface, which may be different from the 58 * generic mdio bus (tied to a single interface), waiting until the write is 59 * done before returning. This is helpful in programming interfaces like 60 * the TBI which control interfaces like onchip SERDES and are always tied to 61 * the local mdio pins, which may not be the same as system mdio bus, used for 62 * controlling the external PHYs, for example. 63 */ 64 int fsl_pq_local_mdio_write(struct fsl_pq_mdio __iomem *regs, int mii_id, 65 int regnum, u16 value) 66 { 67 /* Set the PHY address and the register address we want to write */ 68 out_be32(®s->miimadd, (mii_id << 8) | regnum); 69 70 /* Write out the value we want */ 71 out_be32(®s->miimcon, value); 72 73 /* Wait for the transaction to finish */ 74 while (in_be32(®s->miimind) & MIIMIND_BUSY) 75 cpu_relax(); 76 77 return 0; 78 } 79 80 /* 81 * Read the bus for PHY at addr mii_id, register regnum, and 82 * return the value. Clears miimcom first. All PHY operation 83 * done on the bus attached to the local interface, 84 * which may be different from the generic mdio bus 85 * This is helpful in programming interfaces like 86 * the TBI which, in turn, control interfaces like onchip SERDES 87 * and are always tied to the local mdio pins, which may not be the 88 * same as system mdio bus, used for controlling the external PHYs, for eg. 89 */ 90 int fsl_pq_local_mdio_read(struct fsl_pq_mdio __iomem *regs, 91 int mii_id, int regnum) 92 { 93 u16 value; 94 95 /* Set the PHY address and the register address we want to read */ 96 out_be32(®s->miimadd, (mii_id << 8) | regnum); 97 98 /* Clear miimcom, and then initiate a read */ 99 out_be32(®s->miimcom, 0); 100 out_be32(®s->miimcom, MII_READ_COMMAND); 101 102 /* Wait for the transaction to finish */ 103 while (in_be32(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) 104 cpu_relax(); 105 106 /* Grab the value of the register from miimstat */ 107 value = in_be32(®s->miimstat); 108 109 return value; 110 } 111 112 static struct fsl_pq_mdio __iomem *fsl_pq_mdio_get_regs(struct mii_bus *bus) 113 { 114 struct fsl_pq_mdio_priv *priv = bus->priv; 115 116 return priv->regs; 117 } 118 119 /* 120 * Write value to the PHY at mii_id at register regnum, 121 * on the bus, waiting until the write is done before returning. 122 */ 123 int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) 124 { 125 struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); 126 127 /* Write to the local MII regs */ 128 return fsl_pq_local_mdio_write(regs, mii_id, regnum, value); 129 } 130 131 /* 132 * Read the bus for PHY at addr mii_id, register regnum, and 133 * return the value. Clears miimcom first. 134 */ 135 int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 136 { 137 struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); 138 139 /* Read the local MII regs */ 140 return fsl_pq_local_mdio_read(regs, mii_id, regnum); 141 } 142 143 /* Reset the MIIM registers, and wait for the bus to free */ 144 static int fsl_pq_mdio_reset(struct mii_bus *bus) 145 { 146 struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); 147 int timeout = PHY_INIT_TIMEOUT; 148 149 mutex_lock(&bus->mdio_lock); 150 151 /* Reset the management interface */ 152 out_be32(®s->miimcfg, MIIMCFG_RESET); 153 154 /* Setup the MII Mgmt clock speed */ 155 out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); 156 157 /* Wait until the bus is free */ 158 while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) 159 cpu_relax(); 160 161 mutex_unlock(&bus->mdio_lock); 162 163 if (timeout < 0) { 164 printk(KERN_ERR "%s: The MII Bus is stuck!\n", 165 bus->name); 166 return -EBUSY; 167 } 168 169 return 0; 170 } 171 172 void fsl_pq_mdio_bus_name(char *name, struct device_node *np) 173 { 174 const u32 *addr; 175 u64 taddr = OF_BAD_ADDR; 176 177 addr = of_get_address(np, 0, NULL, NULL); 178 if (addr) 179 taddr = of_translate_address(np, addr); 180 181 snprintf(name, MII_BUS_ID_SIZE, "%s@%llx", np->name, 182 (unsigned long long)taddr); 183 } 184 EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name); 185 186 /* Scan the bus in reverse, looking for an empty spot */ 187 static int fsl_pq_mdio_find_free(struct mii_bus *new_bus) 188 { 189 int i; 190 191 for (i = PHY_MAX_ADDR; i > 0; i--) { 192 u32 phy_id; 193 194 if (get_phy_id(new_bus, i, &phy_id)) 195 return -1; 196 197 if (phy_id == 0xffffffff) 198 break; 199 } 200 201 return i; 202 } 203 204 205 #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) 206 static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np) 207 { 208 struct gfar __iomem *enet_regs; 209 210 /* 211 * This is mildly evil, but so is our hardware for doing this. 212 * Also, we have to cast back to struct gfar because of 213 * definition weirdness done in gianfar.h. 214 */ 215 if(of_device_is_compatible(np, "fsl,gianfar-mdio") || 216 of_device_is_compatible(np, "fsl,gianfar-tbi") || 217 of_device_is_compatible(np, "gianfar")) { 218 enet_regs = (struct gfar __iomem *)regs; 219 return &enet_regs->tbipa; 220 } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") || 221 of_device_is_compatible(np, "fsl,etsec2-tbi")) { 222 return of_iomap(np, 1); 223 } else 224 return NULL; 225 } 226 #endif 227 228 229 #if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) 230 static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id) 231 { 232 struct device_node *np = NULL; 233 int err = 0; 234 235 for_each_compatible_node(np, NULL, "ucc_geth") { 236 struct resource tempres; 237 238 err = of_address_to_resource(np, 0, &tempres); 239 if (err) 240 continue; 241 242 /* if our mdio regs fall within this UCC regs range */ 243 if ((start >= tempres.start) && (end <= tempres.end)) { 244 /* Find the id of the UCC */ 245 const u32 *id; 246 247 id = of_get_property(np, "cell-index", NULL); 248 if (!id) { 249 id = of_get_property(np, "device-id", NULL); 250 if (!id) 251 continue; 252 } 253 254 *ucc_id = *id; 255 256 return 0; 257 } 258 } 259 260 if (err) 261 return err; 262 else 263 return -EINVAL; 264 } 265 #endif 266 267 268 static int fsl_pq_mdio_probe(struct platform_device *ofdev) 269 { 270 struct device_node *np = ofdev->dev.of_node; 271 struct device_node *tbi; 272 struct fsl_pq_mdio_priv *priv; 273 struct fsl_pq_mdio __iomem *regs = NULL; 274 void __iomem *map; 275 u32 __iomem *tbipa; 276 struct mii_bus *new_bus; 277 int tbiaddr = -1; 278 const u32 *addrp; 279 u64 addr = 0, size = 0; 280 int err; 281 282 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 283 if (!priv) 284 return -ENOMEM; 285 286 new_bus = mdiobus_alloc(); 287 if (!new_bus) { 288 err = -ENOMEM; 289 goto err_free_priv; 290 } 291 292 new_bus->name = "Freescale PowerQUICC MII Bus", 293 new_bus->read = &fsl_pq_mdio_read, 294 new_bus->write = &fsl_pq_mdio_write, 295 new_bus->reset = &fsl_pq_mdio_reset, 296 new_bus->priv = priv; 297 fsl_pq_mdio_bus_name(new_bus->id, np); 298 299 addrp = of_get_address(np, 0, &size, NULL); 300 if (!addrp) { 301 err = -EINVAL; 302 goto err_free_bus; 303 } 304 305 /* Set the PHY base address */ 306 addr = of_translate_address(np, addrp); 307 if (addr == OF_BAD_ADDR) { 308 err = -EINVAL; 309 goto err_free_bus; 310 } 311 312 map = ioremap(addr, size); 313 if (!map) { 314 err = -ENOMEM; 315 goto err_free_bus; 316 } 317 priv->map = map; 318 319 if (of_device_is_compatible(np, "fsl,gianfar-mdio") || 320 of_device_is_compatible(np, "fsl,gianfar-tbi") || 321 of_device_is_compatible(np, "fsl,ucc-mdio") || 322 of_device_is_compatible(np, "ucc_geth_phy")) 323 map -= offsetof(struct fsl_pq_mdio, miimcfg); 324 regs = map; 325 priv->regs = regs; 326 327 new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); 328 329 if (NULL == new_bus->irq) { 330 err = -ENOMEM; 331 goto err_unmap_regs; 332 } 333 334 new_bus->parent = &ofdev->dev; 335 dev_set_drvdata(&ofdev->dev, new_bus); 336 337 if (of_device_is_compatible(np, "fsl,gianfar-mdio") || 338 of_device_is_compatible(np, "fsl,gianfar-tbi") || 339 of_device_is_compatible(np, "fsl,etsec2-mdio") || 340 of_device_is_compatible(np, "fsl,etsec2-tbi") || 341 of_device_is_compatible(np, "gianfar")) { 342 #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) 343 tbipa = get_gfar_tbipa(regs, np); 344 if (!tbipa) { 345 err = -EINVAL; 346 goto err_free_irqs; 347 } 348 #else 349 err = -ENODEV; 350 goto err_free_irqs; 351 #endif 352 } else if (of_device_is_compatible(np, "fsl,ucc-mdio") || 353 of_device_is_compatible(np, "ucc_geth_phy")) { 354 #if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) 355 u32 id; 356 static u32 mii_mng_master; 357 358 tbipa = ®s->utbipar; 359 360 if ((err = get_ucc_id_for_range(addr, addr + size, &id))) 361 goto err_free_irqs; 362 363 if (!mii_mng_master) { 364 mii_mng_master = id; 365 ucc_set_qe_mux_mii_mng(id - 1); 366 } 367 #else 368 err = -ENODEV; 369 goto err_free_irqs; 370 #endif 371 } else { 372 err = -ENODEV; 373 goto err_free_irqs; 374 } 375 376 for_each_child_of_node(np, tbi) { 377 if (!strncmp(tbi->type, "tbi-phy", 8)) 378 break; 379 } 380 381 if (tbi) { 382 const u32 *prop = of_get_property(tbi, "reg", NULL); 383 384 if (prop) 385 tbiaddr = *prop; 386 } 387 388 if (tbiaddr == -1) { 389 out_be32(tbipa, 0); 390 391 tbiaddr = fsl_pq_mdio_find_free(new_bus); 392 } 393 394 /* 395 * We define TBIPA at 0 to be illegal, opting to fail for boards that 396 * have PHYs at 1-31, rather than change tbipa and rescan. 397 */ 398 if (tbiaddr == 0) { 399 err = -EBUSY; 400 401 goto err_free_irqs; 402 } 403 404 out_be32(tbipa, tbiaddr); 405 406 err = of_mdiobus_register(new_bus, np); 407 if (err) { 408 printk (KERN_ERR "%s: Cannot register as MDIO bus\n", 409 new_bus->name); 410 goto err_free_irqs; 411 } 412 413 return 0; 414 415 err_free_irqs: 416 kfree(new_bus->irq); 417 err_unmap_regs: 418 iounmap(priv->map); 419 err_free_bus: 420 kfree(new_bus); 421 err_free_priv: 422 kfree(priv); 423 return err; 424 } 425 426 427 static int fsl_pq_mdio_remove(struct platform_device *ofdev) 428 { 429 struct device *device = &ofdev->dev; 430 struct mii_bus *bus = dev_get_drvdata(device); 431 struct fsl_pq_mdio_priv *priv = bus->priv; 432 433 mdiobus_unregister(bus); 434 435 dev_set_drvdata(device, NULL); 436 437 iounmap(priv->map); 438 bus->priv = NULL; 439 mdiobus_free(bus); 440 kfree(priv); 441 442 return 0; 443 } 444 445 static struct of_device_id fsl_pq_mdio_match[] = { 446 { 447 .type = "mdio", 448 .compatible = "ucc_geth_phy", 449 }, 450 { 451 .type = "mdio", 452 .compatible = "gianfar", 453 }, 454 { 455 .compatible = "fsl,ucc-mdio", 456 }, 457 { 458 .compatible = "fsl,gianfar-tbi", 459 }, 460 { 461 .compatible = "fsl,gianfar-mdio", 462 }, 463 { 464 .compatible = "fsl,etsec2-tbi", 465 }, 466 { 467 .compatible = "fsl,etsec2-mdio", 468 }, 469 {}, 470 }; 471 MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match); 472 473 static struct platform_driver fsl_pq_mdio_driver = { 474 .driver = { 475 .name = "fsl-pq_mdio", 476 .owner = THIS_MODULE, 477 .of_match_table = fsl_pq_mdio_match, 478 }, 479 .probe = fsl_pq_mdio_probe, 480 .remove = fsl_pq_mdio_remove, 481 }; 482 483 int __init fsl_pq_mdio_init(void) 484 { 485 return platform_driver_register(&fsl_pq_mdio_driver); 486 } 487 module_init(fsl_pq_mdio_init); 488 489 void fsl_pq_mdio_exit(void) 490 { 491 platform_driver_unregister(&fsl_pq_mdio_driver); 492 } 493 module_exit(fsl_pq_mdio_exit); 494 MODULE_LICENSE("GPL"); 495