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 187 static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np) 188 { 189 #if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) 190 struct gfar __iomem *enet_regs; 191 192 /* 193 * This is mildly evil, but so is our hardware for doing this. 194 * Also, we have to cast back to struct gfar because of 195 * definition weirdness done in gianfar.h. 196 */ 197 if(of_device_is_compatible(np, "fsl,gianfar-mdio") || 198 of_device_is_compatible(np, "fsl,gianfar-tbi") || 199 of_device_is_compatible(np, "gianfar")) { 200 enet_regs = (struct gfar __iomem *)regs; 201 return &enet_regs->tbipa; 202 } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") || 203 of_device_is_compatible(np, "fsl,etsec2-tbi")) { 204 return of_iomap(np, 1); 205 } 206 #endif 207 return NULL; 208 } 209 210 211 static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id) 212 { 213 #if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) 214 struct device_node *np = NULL; 215 int err = 0; 216 217 for_each_compatible_node(np, NULL, "ucc_geth") { 218 struct resource tempres; 219 220 err = of_address_to_resource(np, 0, &tempres); 221 if (err) 222 continue; 223 224 /* if our mdio regs fall within this UCC regs range */ 225 if ((start >= tempres.start) && (end <= tempres.end)) { 226 /* Find the id of the UCC */ 227 const u32 *id; 228 229 id = of_get_property(np, "cell-index", NULL); 230 if (!id) { 231 id = of_get_property(np, "device-id", NULL); 232 if (!id) 233 continue; 234 } 235 236 *ucc_id = *id; 237 238 return 0; 239 } 240 } 241 242 if (err) 243 return err; 244 else 245 return -EINVAL; 246 #else 247 return -ENODEV; 248 #endif 249 } 250 251 static int fsl_pq_mdio_probe(struct platform_device *ofdev) 252 { 253 struct device_node *np = ofdev->dev.of_node; 254 struct device_node *tbi; 255 struct fsl_pq_mdio_priv *priv; 256 struct fsl_pq_mdio __iomem *regs = NULL; 257 void __iomem *map; 258 u32 __iomem *tbipa; 259 struct mii_bus *new_bus; 260 int tbiaddr = -1; 261 const u32 *addrp; 262 u64 addr = 0, size = 0; 263 int err; 264 265 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 266 if (!priv) 267 return -ENOMEM; 268 269 new_bus = mdiobus_alloc(); 270 if (!new_bus) { 271 err = -ENOMEM; 272 goto err_free_priv; 273 } 274 275 new_bus->name = "Freescale PowerQUICC MII Bus", 276 new_bus->read = &fsl_pq_mdio_read, 277 new_bus->write = &fsl_pq_mdio_write, 278 new_bus->reset = &fsl_pq_mdio_reset, 279 new_bus->priv = priv; 280 fsl_pq_mdio_bus_name(new_bus->id, np); 281 282 addrp = of_get_address(np, 0, &size, NULL); 283 if (!addrp) { 284 err = -EINVAL; 285 goto err_free_bus; 286 } 287 288 /* Set the PHY base address */ 289 addr = of_translate_address(np, addrp); 290 if (addr == OF_BAD_ADDR) { 291 err = -EINVAL; 292 goto err_free_bus; 293 } 294 295 map = ioremap(addr, size); 296 if (!map) { 297 err = -ENOMEM; 298 goto err_free_bus; 299 } 300 priv->map = map; 301 302 if (of_device_is_compatible(np, "fsl,gianfar-mdio") || 303 of_device_is_compatible(np, "fsl,gianfar-tbi") || 304 of_device_is_compatible(np, "fsl,ucc-mdio") || 305 of_device_is_compatible(np, "ucc_geth_phy")) 306 map -= offsetof(struct fsl_pq_mdio, miimcfg); 307 regs = map; 308 priv->regs = regs; 309 310 new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); 311 312 if (NULL == new_bus->irq) { 313 err = -ENOMEM; 314 goto err_unmap_regs; 315 } 316 317 new_bus->parent = &ofdev->dev; 318 dev_set_drvdata(&ofdev->dev, new_bus); 319 320 if (of_device_is_compatible(np, "fsl,gianfar-mdio") || 321 of_device_is_compatible(np, "fsl,gianfar-tbi") || 322 of_device_is_compatible(np, "fsl,etsec2-mdio") || 323 of_device_is_compatible(np, "fsl,etsec2-tbi") || 324 of_device_is_compatible(np, "gianfar")) { 325 tbipa = get_gfar_tbipa(regs, np); 326 if (!tbipa) { 327 err = -EINVAL; 328 goto err_free_irqs; 329 } 330 } else if (of_device_is_compatible(np, "fsl,ucc-mdio") || 331 of_device_is_compatible(np, "ucc_geth_phy")) { 332 u32 id; 333 static u32 mii_mng_master; 334 335 tbipa = ®s->utbipar; 336 337 if ((err = get_ucc_id_for_range(addr, addr + size, &id))) 338 goto err_free_irqs; 339 340 if (!mii_mng_master) { 341 mii_mng_master = id; 342 ucc_set_qe_mux_mii_mng(id - 1); 343 } 344 } else { 345 err = -ENODEV; 346 goto err_free_irqs; 347 } 348 349 for_each_child_of_node(np, tbi) { 350 if (!strncmp(tbi->type, "tbi-phy", 8)) 351 break; 352 } 353 354 if (tbi) { 355 const u32 *prop = of_get_property(tbi, "reg", NULL); 356 357 if (prop) 358 tbiaddr = *prop; 359 360 if (tbiaddr == -1) { 361 err = -EBUSY; 362 goto err_free_irqs; 363 } else { 364 out_be32(tbipa, tbiaddr); 365 } 366 } 367 368 err = of_mdiobus_register(new_bus, np); 369 if (err) { 370 printk (KERN_ERR "%s: Cannot register as MDIO bus\n", 371 new_bus->name); 372 goto err_free_irqs; 373 } 374 375 return 0; 376 377 err_free_irqs: 378 kfree(new_bus->irq); 379 err_unmap_regs: 380 iounmap(priv->map); 381 err_free_bus: 382 kfree(new_bus); 383 err_free_priv: 384 kfree(priv); 385 return err; 386 } 387 388 389 static int fsl_pq_mdio_remove(struct platform_device *ofdev) 390 { 391 struct device *device = &ofdev->dev; 392 struct mii_bus *bus = dev_get_drvdata(device); 393 struct fsl_pq_mdio_priv *priv = bus->priv; 394 395 mdiobus_unregister(bus); 396 397 dev_set_drvdata(device, NULL); 398 399 iounmap(priv->map); 400 bus->priv = NULL; 401 mdiobus_free(bus); 402 kfree(priv); 403 404 return 0; 405 } 406 407 static struct of_device_id fsl_pq_mdio_match[] = { 408 { 409 .type = "mdio", 410 .compatible = "ucc_geth_phy", 411 }, 412 { 413 .type = "mdio", 414 .compatible = "gianfar", 415 }, 416 { 417 .compatible = "fsl,ucc-mdio", 418 }, 419 { 420 .compatible = "fsl,gianfar-tbi", 421 }, 422 { 423 .compatible = "fsl,gianfar-mdio", 424 }, 425 { 426 .compatible = "fsl,etsec2-tbi", 427 }, 428 { 429 .compatible = "fsl,etsec2-mdio", 430 }, 431 {}, 432 }; 433 MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match); 434 435 static struct platform_driver fsl_pq_mdio_driver = { 436 .driver = { 437 .name = "fsl-pq_mdio", 438 .owner = THIS_MODULE, 439 .of_match_table = fsl_pq_mdio_match, 440 }, 441 .probe = fsl_pq_mdio_probe, 442 .remove = fsl_pq_mdio_remove, 443 }; 444 445 module_platform_driver(fsl_pq_mdio_driver); 446 447 MODULE_LICENSE("GPL"); 448