Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.29-rc8 379 lines 9.0 kB view raw
1/* 2 * drivers/net/gianfar_mii.c 3 * 4 * Gianfar Ethernet Driver -- MIIM bus implementation 5 * Provides Bus interface for MIIM regs 6 * 7 * Author: Andy Fleming 8 * Maintainer: Kumar Gala 9 * 10 * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. 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_platform.h> 39 40#include <asm/io.h> 41#include <asm/irq.h> 42#include <asm/uaccess.h> 43 44#include "gianfar.h" 45#include "gianfar_mii.h" 46 47/* 48 * Write value to the PHY at mii_id at register regnum, 49 * on the bus attached to the local interface, which may be different from the 50 * generic mdio bus (tied to a single interface), waiting until the write is 51 * done before returning. This is helpful in programming interfaces like 52 * the TBI which control interfaces like onchip SERDES and are always tied to 53 * the local mdio pins, which may not be the same as system mdio bus, used for 54 * controlling the external PHYs, for example. 55 */ 56int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, 57 int regnum, u16 value) 58{ 59 /* Set the PHY address and the register address we want to write */ 60 gfar_write(&regs->miimadd, (mii_id << 8) | regnum); 61 62 /* Write out the value we want */ 63 gfar_write(&regs->miimcon, value); 64 65 /* Wait for the transaction to finish */ 66 while (gfar_read(&regs->miimind) & MIIMIND_BUSY) 67 cpu_relax(); 68 69 return 0; 70} 71 72/* 73 * Read the bus for PHY at addr mii_id, register regnum, and 74 * return the value. Clears miimcom first. All PHY operation 75 * done on the bus attached to the local interface, 76 * which may be different from the generic mdio bus 77 * This is helpful in programming interfaces like 78 * the TBI which, inturn, control interfaces like onchip SERDES 79 * and are always tied to the local mdio pins, which may not be the 80 * same as system mdio bus, used for controlling the external PHYs, for eg. 81 */ 82int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum) 83{ 84 u16 value; 85 86 /* Set the PHY address and the register address we want to read */ 87 gfar_write(&regs->miimadd, (mii_id << 8) | regnum); 88 89 /* Clear miimcom, and then initiate a read */ 90 gfar_write(&regs->miimcom, 0); 91 gfar_write(&regs->miimcom, MII_READ_COMMAND); 92 93 /* Wait for the transaction to finish */ 94 while (gfar_read(&regs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) 95 cpu_relax(); 96 97 /* Grab the value of the register from miimstat */ 98 value = gfar_read(&regs->miimstat); 99 100 return value; 101} 102 103/* Write value to the PHY at mii_id at register regnum, 104 * on the bus, waiting until the write is done before returning. 105 * All PHY configuration is done through the TSEC1 MIIM regs */ 106int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) 107{ 108 struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; 109 110 /* Write to the local MII regs */ 111 return(gfar_local_mdio_write(regs, mii_id, regnum, value)); 112} 113 114/* Read the bus for PHY at addr mii_id, register regnum, and 115 * return the value. Clears miimcom first. All PHY 116 * configuration has to be done through the TSEC1 MIIM regs */ 117int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 118{ 119 struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; 120 121 /* Read the local MII regs */ 122 return(gfar_local_mdio_read(regs, mii_id, regnum)); 123} 124 125/* Reset the MIIM registers, and wait for the bus to free */ 126static int gfar_mdio_reset(struct mii_bus *bus) 127{ 128 struct gfar_mii __iomem *regs = (void __iomem *)bus->priv; 129 unsigned int timeout = PHY_INIT_TIMEOUT; 130 131 mutex_lock(&bus->mdio_lock); 132 133 /* Reset the management interface */ 134 gfar_write(&regs->miimcfg, MIIMCFG_RESET); 135 136 /* Setup the MII Mgmt clock speed */ 137 gfar_write(&regs->miimcfg, MIIMCFG_INIT_VALUE); 138 139 /* Wait until the bus is free */ 140 while ((gfar_read(&regs->miimind) & MIIMIND_BUSY) && 141 --timeout) 142 cpu_relax(); 143 144 mutex_unlock(&bus->mdio_lock); 145 146 if(timeout == 0) { 147 printk(KERN_ERR "%s: The MII Bus is stuck!\n", 148 bus->name); 149 return -EBUSY; 150 } 151 152 return 0; 153} 154 155/* Allocate an array which provides irq #s for each PHY on the given bus */ 156static int *create_irq_map(struct device_node *np) 157{ 158 int *irqs; 159 int i; 160 struct device_node *child = NULL; 161 162 irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); 163 164 if (!irqs) 165 return NULL; 166 167 for (i = 0; i < PHY_MAX_ADDR; i++) 168 irqs[i] = PHY_POLL; 169 170 while ((child = of_get_next_child(np, child)) != NULL) { 171 int irq = irq_of_parse_and_map(child, 0); 172 const u32 *id; 173 174 if (irq == NO_IRQ) 175 continue; 176 177 id = of_get_property(child, "reg", NULL); 178 179 if (!id) 180 continue; 181 182 if (*id < PHY_MAX_ADDR && *id >= 0) 183 irqs[*id] = irq; 184 else 185 printk(KERN_WARNING "%s: " 186 "%d is not a valid PHY address\n", 187 np->full_name, *id); 188 } 189 190 return irqs; 191} 192 193 194void gfar_mdio_bus_name(char *name, struct device_node *np) 195{ 196 const u32 *reg; 197 198 reg = of_get_property(np, "reg", NULL); 199 200 snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0); 201} 202 203/* Scan the bus in reverse, looking for an empty spot */ 204static int gfar_mdio_find_free(struct mii_bus *new_bus) 205{ 206 int i; 207 208 for (i = PHY_MAX_ADDR; i > 0; i--) { 209 u32 phy_id; 210 211 if (get_phy_id(new_bus, i, &phy_id)) 212 return -1; 213 214 if (phy_id == 0xffffffff) 215 break; 216 } 217 218 return i; 219} 220 221static int gfar_mdio_probe(struct of_device *ofdev, 222 const struct of_device_id *match) 223{ 224 struct gfar_mii __iomem *regs; 225 struct gfar __iomem *enet_regs; 226 struct mii_bus *new_bus; 227 int err = 0; 228 u64 addr, size; 229 struct device_node *np = ofdev->node; 230 struct device_node *tbi; 231 int tbiaddr = -1; 232 233 new_bus = mdiobus_alloc(); 234 if (NULL == new_bus) 235 return -ENOMEM; 236 237 device_init_wakeup(&ofdev->dev, 1); 238 239 new_bus->name = "Gianfar MII Bus", 240 new_bus->read = &gfar_mdio_read, 241 new_bus->write = &gfar_mdio_write, 242 new_bus->reset = &gfar_mdio_reset, 243 gfar_mdio_bus_name(new_bus->id, np); 244 245 /* Set the PHY base address */ 246 addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); 247 regs = ioremap(addr, size); 248 249 if (NULL == regs) { 250 err = -ENOMEM; 251 goto err_free_bus; 252 } 253 254 new_bus->priv = (void __force *)regs; 255 256 new_bus->irq = create_irq_map(np); 257 258 if (new_bus->irq == NULL) { 259 err = -ENOMEM; 260 goto err_unmap_regs; 261 } 262 263 new_bus->parent = &ofdev->dev; 264 dev_set_drvdata(&ofdev->dev, new_bus); 265 266 /* 267 * This is mildly evil, but so is our hardware for doing this. 268 * Also, we have to cast back to struct gfar_mii because of 269 * definition weirdness done in gianfar.h. 270 */ 271 enet_regs = (struct gfar __iomem *) 272 ((char *)regs - offsetof(struct gfar, gfar_mii_regs)); 273 274 for_each_child_of_node(np, tbi) { 275 if (!strncmp(tbi->type, "tbi-phy", 8)) 276 break; 277 } 278 279 if (tbi) { 280 const u32 *prop = of_get_property(tbi, "reg", NULL); 281 282 if (prop) 283 tbiaddr = *prop; 284 } 285 286 if (tbiaddr == -1) { 287 gfar_write(&enet_regs->tbipa, 0); 288 289 tbiaddr = gfar_mdio_find_free(new_bus); 290 } 291 292 /* 293 * We define TBIPA at 0 to be illegal, opting to fail for boards that 294 * have PHYs at 1-31, rather than change tbipa and rescan. 295 */ 296 if (tbiaddr == 0) { 297 err = -EBUSY; 298 299 goto err_free_irqs; 300 } 301 302 gfar_write(&enet_regs->tbipa, tbiaddr); 303 304 /* 305 * The TBIPHY-only buses will find PHYs at every address, 306 * so we mask them all but the TBI 307 */ 308 if (!of_device_is_compatible(np, "fsl,gianfar-mdio")) 309 new_bus->phy_mask = ~(1 << tbiaddr); 310 311 err = mdiobus_register(new_bus); 312 313 if (err != 0) { 314 printk (KERN_ERR "%s: Cannot register as MDIO bus\n", 315 new_bus->name); 316 goto err_free_irqs; 317 } 318 319 return 0; 320 321err_free_irqs: 322 kfree(new_bus->irq); 323err_unmap_regs: 324 iounmap(regs); 325err_free_bus: 326 mdiobus_free(new_bus); 327 328 return err; 329} 330 331 332static int gfar_mdio_remove(struct of_device *ofdev) 333{ 334 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); 335 336 mdiobus_unregister(bus); 337 338 dev_set_drvdata(&ofdev->dev, NULL); 339 340 iounmap((void __iomem *)bus->priv); 341 bus->priv = NULL; 342 kfree(bus->irq); 343 mdiobus_free(bus); 344 345 return 0; 346} 347 348static struct of_device_id gfar_mdio_match[] = 349{ 350 { 351 .compatible = "fsl,gianfar-mdio", 352 }, 353 { 354 .compatible = "fsl,gianfar-tbi", 355 }, 356 { 357 .type = "mdio", 358 .compatible = "gianfar", 359 }, 360 {}, 361}; 362 363static struct of_platform_driver gianfar_mdio_driver = { 364 .name = "fsl-gianfar_mdio", 365 .match_table = gfar_mdio_match, 366 367 .probe = gfar_mdio_probe, 368 .remove = gfar_mdio_remove, 369}; 370 371int __init gfar_mdio_init(void) 372{ 373 return of_register_platform_driver(&gianfar_mdio_driver); 374} 375 376void gfar_mdio_exit(void) 377{ 378 of_unregister_platform_driver(&gianfar_mdio_driver); 379}