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 /* Number of microseconds to wait for an MII register to respond */ 51 #define MII_TIMEOUT 1000 52 53 struct fsl_pq_mdio_priv { 54 void __iomem *map; 55 struct fsl_pq_mdio __iomem *regs; 56 }; 57 58 /* 59 * Write value to the PHY at mii_id at register regnum, 60 * on the bus attached to the local interface, which may be different from the 61 * generic mdio bus (tied to a single interface), waiting until the write is 62 * done before returning. This is helpful in programming interfaces like 63 * the TBI which control interfaces like onchip SERDES and are always tied to 64 * the local mdio pins, which may not be the same as system mdio bus, used for 65 * controlling the external PHYs, for example. 66 */ 67 int fsl_pq_local_mdio_write(struct fsl_pq_mdio __iomem *regs, int mii_id, 68 int regnum, u16 value) 69 { 70 u32 status; 71 72 /* Set the PHY address and the register address we want to write */ 73 out_be32(®s->miimadd, (mii_id << 8) | regnum); 74 75 /* Write out the value we want */ 76 out_be32(®s->miimcon, value); 77 78 /* Wait for the transaction to finish */ 79 status = spin_event_timeout(!(in_be32(®s->miimind) & MIIMIND_BUSY), 80 MII_TIMEOUT, 0); 81 82 return status ? 0 : -ETIMEDOUT; 83 } 84 85 /* 86 * Read the bus for PHY at addr mii_id, register regnum, and 87 * return the value. Clears miimcom first. All PHY operation 88 * done on the bus attached to the local interface, 89 * which may be different from the generic mdio bus 90 * This is helpful in programming interfaces like 91 * the TBI which, in turn, control interfaces like onchip SERDES 92 * and are always tied to the local mdio pins, which may not be the 93 * same as system mdio bus, used for controlling the external PHYs, for eg. 94 */ 95 int fsl_pq_local_mdio_read(struct fsl_pq_mdio __iomem *regs, 96 int mii_id, int regnum) 97 { 98 u16 value; 99 u32 status; 100 101 /* Set the PHY address and the register address we want to read */ 102 out_be32(®s->miimadd, (mii_id << 8) | regnum); 103 104 /* Clear miimcom, and then initiate a read */ 105 out_be32(®s->miimcom, 0); 106 out_be32(®s->miimcom, MII_READ_COMMAND); 107 108 /* Wait for the transaction to finish, normally less than 100us */ 109 status = spin_event_timeout(!(in_be32(®s->miimind) & 110 (MIIMIND_NOTVALID | MIIMIND_BUSY)), 111 MII_TIMEOUT, 0); 112 if (!status) 113 return -ETIMEDOUT; 114 115 /* Grab the value of the register from miimstat */ 116 value = in_be32(®s->miimstat); 117 118 return value; 119 } 120 121 static struct fsl_pq_mdio __iomem *fsl_pq_mdio_get_regs(struct mii_bus *bus) 122 { 123 struct fsl_pq_mdio_priv *priv = bus->priv; 124 125 return priv->regs; 126 } 127 128 /* 129 * Write value to the PHY at mii_id at register regnum, 130 * on the bus, waiting until the write is done before returning. 131 */ 132 int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) 133 { 134 struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); 135 136 /* Write to the local MII regs */ 137 return fsl_pq_local_mdio_write(regs, mii_id, regnum, value); 138 } 139 140 /* 141 * Read the bus for PHY at addr mii_id, register regnum, and 142 * return the value. Clears miimcom first. 143 */ 144 int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 145 { 146 struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); 147 148 /* Read the local MII regs */ 149 return fsl_pq_local_mdio_read(regs, mii_id, regnum); 150 } 151 152 /* Reset the MIIM registers, and wait for the bus to free */ 153 static int fsl_pq_mdio_reset(struct mii_bus *bus) 154 { 155 struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus); 156 u32 status; 157 158 mutex_lock(&bus->mdio_lock); 159 160 /* Reset the management interface */ 161 out_be32(®s->miimcfg, MIIMCFG_RESET); 162 163 /* Setup the MII Mgmt clock speed */ 164 out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); 165 166 /* Wait until the bus is free */ 167 status = spin_event_timeout(!(in_be32(®s->miimind) & MIIMIND_BUSY), 168 MII_TIMEOUT, 0); 169 170 mutex_unlock(&bus->mdio_lock); 171 172 if (!status) { 173 printk(KERN_ERR "%s: The MII Bus is stuck!\n", 174 bus->name); 175 return -EBUSY; 176 } 177 178 return 0; 179 } 180 181 void fsl_pq_mdio_bus_name(char *name, struct device_node *np) 182 { 183 const u32 *addr; 184 u64 taddr = OF_BAD_ADDR; 185 186 addr = of_get_address(np, 0, NULL, NULL); 187 if (addr) 188 taddr = of_translate_address(np, addr); 189 190 snprintf(name, MII_BUS_ID_SIZE, "%s@%llx", np->name, 191 (unsigned long long)taddr); 192 } 193 EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name); 194 195 196 static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np) 197 { 198 #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) 199 struct gfar __iomem *enet_regs; 200 201 /* 202 * This is mildly evil, but so is our hardware for doing this. 203 * Also, we have to cast back to struct gfar because of 204 * definition weirdness done in gianfar.h. 205 */ 206 if(of_device_is_compatible(np, "fsl,gianfar-mdio") || 207 of_device_is_compatible(np, "fsl,gianfar-tbi") || 208 of_device_is_compatible(np, "gianfar")) { 209 enet_regs = (struct gfar __iomem *)regs; 210 return &enet_regs->tbipa; 211 } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") || 212 of_device_is_compatible(np, "fsl,etsec2-tbi")) { 213 return of_iomap(np, 1); 214 } 215 #endif 216 return NULL; 217 } 218 219 220 static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id) 221 { 222 #if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) 223 struct device_node *np = NULL; 224 int err = 0; 225 226 for_each_compatible_node(np, NULL, "ucc_geth") { 227 struct resource tempres; 228 229 err = of_address_to_resource(np, 0, &tempres); 230 if (err) 231 continue; 232 233 /* if our mdio regs fall within this UCC regs range */ 234 if ((start >= tempres.start) && (end <= tempres.end)) { 235 /* Find the id of the UCC */ 236 const u32 *id; 237 238 id = of_get_property(np, "cell-index", NULL); 239 if (!id) { 240 id = of_get_property(np, "device-id", NULL); 241 if (!id) 242 continue; 243 } 244 245 *ucc_id = *id; 246 247 return 0; 248 } 249 } 250 251 if (err) 252 return err; 253 else 254 return -EINVAL; 255 #else 256 return -ENODEV; 257 #endif 258 } 259 260 static int fsl_pq_mdio_probe(struct platform_device *ofdev) 261 { 262 struct device_node *np = ofdev->dev.of_node; 263 struct device_node *tbi; 264 struct fsl_pq_mdio_priv *priv; 265 struct fsl_pq_mdio __iomem *regs = NULL; 266 void __iomem *map; 267 u32 __iomem *tbipa; 268 struct mii_bus *new_bus; 269 int tbiaddr = -1; 270 const u32 *addrp; 271 u64 addr = 0, size = 0; 272 int err; 273 274 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 275 if (!priv) 276 return -ENOMEM; 277 278 new_bus = mdiobus_alloc(); 279 if (!new_bus) { 280 err = -ENOMEM; 281 goto err_free_priv; 282 } 283 284 new_bus->name = "Freescale PowerQUICC MII Bus", 285 new_bus->read = &fsl_pq_mdio_read, 286 new_bus->write = &fsl_pq_mdio_write, 287 new_bus->reset = &fsl_pq_mdio_reset, 288 new_bus->priv = priv; 289 fsl_pq_mdio_bus_name(new_bus->id, np); 290 291 addrp = of_get_address(np, 0, &size, NULL); 292 if (!addrp) { 293 err = -EINVAL; 294 goto err_free_bus; 295 } 296 297 /* Set the PHY base address */ 298 addr = of_translate_address(np, addrp); 299 if (addr == OF_BAD_ADDR) { 300 err = -EINVAL; 301 goto err_free_bus; 302 } 303 304 map = ioremap(addr, size); 305 if (!map) { 306 err = -ENOMEM; 307 goto err_free_bus; 308 } 309 priv->map = map; 310 311 if (of_device_is_compatible(np, "fsl,gianfar-mdio") || 312 of_device_is_compatible(np, "fsl,gianfar-tbi") || 313 of_device_is_compatible(np, "fsl,ucc-mdio") || 314 of_device_is_compatible(np, "ucc_geth_phy")) 315 map -= offsetof(struct fsl_pq_mdio, miimcfg); 316 regs = map; 317 priv->regs = regs; 318 319 new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); 320 321 if (NULL == new_bus->irq) { 322 err = -ENOMEM; 323 goto err_unmap_regs; 324 } 325 326 new_bus->parent = &ofdev->dev; 327 dev_set_drvdata(&ofdev->dev, new_bus); 328 329 if (of_device_is_compatible(np, "fsl,gianfar-mdio") || 330 of_device_is_compatible(np, "fsl,gianfar-tbi") || 331 of_device_is_compatible(np, "fsl,etsec2-mdio") || 332 of_device_is_compatible(np, "fsl,etsec2-tbi") || 333 of_device_is_compatible(np, "gianfar")) { 334 tbipa = get_gfar_tbipa(regs, np); 335 if (!tbipa) { 336 err = -EINVAL; 337 goto err_free_irqs; 338 } 339 } else if (of_device_is_compatible(np, "fsl,ucc-mdio") || 340 of_device_is_compatible(np, "ucc_geth_phy")) { 341 u32 id; 342 static u32 mii_mng_master; 343 344 tbipa = ®s->utbipar; 345 346 if ((err = get_ucc_id_for_range(addr, addr + size, &id))) 347 goto err_free_irqs; 348 349 if (!mii_mng_master) { 350 mii_mng_master = id; 351 ucc_set_qe_mux_mii_mng(id - 1); 352 } 353 } else { 354 err = -ENODEV; 355 goto err_free_irqs; 356 } 357 358 for_each_child_of_node(np, tbi) { 359 if (!strncmp(tbi->type, "tbi-phy", 8)) 360 break; 361 } 362 363 if (tbi) { 364 const u32 *prop = of_get_property(tbi, "reg", NULL); 365 366 if (prop) 367 tbiaddr = *prop; 368 369 if (tbiaddr == -1) { 370 err = -EBUSY; 371 goto err_free_irqs; 372 } else { 373 out_be32(tbipa, tbiaddr); 374 } 375 } 376 377 err = of_mdiobus_register(new_bus, np); 378 if (err) { 379 printk (KERN_ERR "%s: Cannot register as MDIO bus\n", 380 new_bus->name); 381 goto err_free_irqs; 382 } 383 384 return 0; 385 386 err_free_irqs: 387 kfree(new_bus->irq); 388 err_unmap_regs: 389 iounmap(priv->map); 390 err_free_bus: 391 kfree(new_bus); 392 err_free_priv: 393 kfree(priv); 394 return err; 395 } 396 397 398 static int fsl_pq_mdio_remove(struct platform_device *ofdev) 399 { 400 struct device *device = &ofdev->dev; 401 struct mii_bus *bus = dev_get_drvdata(device); 402 struct fsl_pq_mdio_priv *priv = bus->priv; 403 404 mdiobus_unregister(bus); 405 406 dev_set_drvdata(device, NULL); 407 408 iounmap(priv->map); 409 bus->priv = NULL; 410 mdiobus_free(bus); 411 kfree(priv); 412 413 return 0; 414 } 415 416 static struct of_device_id fsl_pq_mdio_match[] = { 417 { 418 .type = "mdio", 419 .compatible = "ucc_geth_phy", 420 }, 421 { 422 .type = "mdio", 423 .compatible = "gianfar", 424 }, 425 { 426 .compatible = "fsl,ucc-mdio", 427 }, 428 { 429 .compatible = "fsl,gianfar-tbi", 430 }, 431 { 432 .compatible = "fsl,gianfar-mdio", 433 }, 434 { 435 .compatible = "fsl,etsec2-tbi", 436 }, 437 { 438 .compatible = "fsl,etsec2-mdio", 439 }, 440 {}, 441 }; 442 MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match); 443 444 static struct platform_driver fsl_pq_mdio_driver = { 445 .driver = { 446 .name = "fsl-pq_mdio", 447 .owner = THIS_MODULE, 448 .of_match_table = fsl_pq_mdio_match, 449 }, 450 .probe = fsl_pq_mdio_probe, 451 .remove = fsl_pq_mdio_remove, 452 }; 453 454 module_platform_driver(fsl_pq_mdio_driver); 455 456 MODULE_LICENSE("GPL"); 457