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.30 238 lines 5.6 kB view raw
1/* 2 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. 3 * 4 * Copyright (c) 2003 Intracom S.A. 5 * by Pantelis Antoniou <panto@intracom.gr> 6 * 7 * 2005 (c) MontaVista Software, Inc. 8 * Vitaly Bordug <vbordug@ru.mvista.com> 9 * 10 * This file is licensed under the terms of the GNU General Public License 11 * version 2. This program is licensed "as is" without any warranty of any 12 * kind, whether express or implied. 13 */ 14 15#include <linux/module.h> 16#include <linux/types.h> 17#include <linux/kernel.h> 18#include <linux/string.h> 19#include <linux/ptrace.h> 20#include <linux/errno.h> 21#include <linux/ioport.h> 22#include <linux/slab.h> 23#include <linux/interrupt.h> 24#include <linux/init.h> 25#include <linux/delay.h> 26#include <linux/netdevice.h> 27#include <linux/etherdevice.h> 28#include <linux/skbuff.h> 29#include <linux/spinlock.h> 30#include <linux/mii.h> 31#include <linux/ethtool.h> 32#include <linux/bitops.h> 33#include <linux/platform_device.h> 34#include <linux/of_platform.h> 35 36#include <asm/pgtable.h> 37#include <asm/irq.h> 38#include <asm/uaccess.h> 39 40#include "fs_enet.h" 41#include "fec.h" 42 43/* Make MII read/write commands for the FEC. 44*/ 45#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) 46#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) 47#define mk_mii_end 0 48 49#define FEC_MII_LOOPS 10000 50 51static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) 52{ 53 struct fec_info* fec = bus->priv; 54 fec_t __iomem *fecp = fec->fecp; 55 int i, ret = -1; 56 57 if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) 58 BUG(); 59 60 /* Add PHY address to register command. */ 61 out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); 62 63 for (i = 0; i < FEC_MII_LOOPS; i++) 64 if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) 65 break; 66 67 if (i < FEC_MII_LOOPS) { 68 out_be32(&fecp->fec_ievent, FEC_ENET_MII); 69 ret = in_be32(&fecp->fec_mii_data) & 0xffff; 70 } 71 72 return ret; 73} 74 75static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) 76{ 77 struct fec_info* fec = bus->priv; 78 fec_t __iomem *fecp = fec->fecp; 79 int i; 80 81 /* this must never happen */ 82 if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) 83 BUG(); 84 85 /* Add PHY address to register command. */ 86 out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); 87 88 for (i = 0; i < FEC_MII_LOOPS; i++) 89 if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) 90 break; 91 92 if (i < FEC_MII_LOOPS) 93 out_be32(&fecp->fec_ievent, FEC_ENET_MII); 94 95 return 0; 96 97} 98 99static int fs_enet_fec_mii_reset(struct mii_bus *bus) 100{ 101 /* nothing here - for now */ 102 return 0; 103} 104 105static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) 106{ 107 const u32 *data; 108 int len, id, irq; 109 110 data = of_get_property(np, "reg", &len); 111 if (!data || len != 4) 112 return; 113 114 id = *data; 115 bus->phy_mask &= ~(1 << id); 116 117 irq = of_irq_to_resource(np, 0, NULL); 118 if (irq != NO_IRQ) 119 bus->irq[id] = irq; 120} 121 122static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, 123 const struct of_device_id *match) 124{ 125 struct device_node *np = NULL; 126 struct resource res; 127 struct mii_bus *new_bus; 128 struct fec_info *fec; 129 int ret = -ENOMEM, i; 130 131 new_bus = mdiobus_alloc(); 132 if (!new_bus) 133 goto out; 134 135 fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); 136 if (!fec) 137 goto out_mii; 138 139 new_bus->priv = fec; 140 new_bus->name = "FEC MII Bus"; 141 new_bus->read = &fs_enet_fec_mii_read; 142 new_bus->write = &fs_enet_fec_mii_write; 143 new_bus->reset = &fs_enet_fec_mii_reset; 144 145 ret = of_address_to_resource(ofdev->node, 0, &res); 146 if (ret) 147 goto out_res; 148 149 snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); 150 151 fec->fecp = ioremap(res.start, res.end - res.start + 1); 152 if (!fec->fecp) 153 goto out_fec; 154 155 fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1; 156 157 setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); 158 setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | 159 FEC_ECNTRL_ETHER_EN); 160 out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); 161 out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed); 162 163 new_bus->phy_mask = ~0; 164 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 165 if (!new_bus->irq) 166 goto out_unmap_regs; 167 168 for (i = 0; i < PHY_MAX_ADDR; i++) 169 new_bus->irq[i] = -1; 170 171 while ((np = of_get_next_child(ofdev->node, np))) 172 if (!strcmp(np->type, "ethernet-phy")) 173 add_phy(new_bus, np); 174 175 new_bus->parent = &ofdev->dev; 176 dev_set_drvdata(&ofdev->dev, new_bus); 177 178 ret = mdiobus_register(new_bus); 179 if (ret) 180 goto out_free_irqs; 181 182 return 0; 183 184out_free_irqs: 185 dev_set_drvdata(&ofdev->dev, NULL); 186 kfree(new_bus->irq); 187out_unmap_regs: 188 iounmap(fec->fecp); 189out_res: 190out_fec: 191 kfree(fec); 192out_mii: 193 mdiobus_free(new_bus); 194out: 195 return ret; 196} 197 198static int fs_enet_mdio_remove(struct of_device *ofdev) 199{ 200 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); 201 struct fec_info *fec = bus->priv; 202 203 mdiobus_unregister(bus); 204 dev_set_drvdata(&ofdev->dev, NULL); 205 kfree(bus->irq); 206 iounmap(fec->fecp); 207 kfree(fec); 208 mdiobus_free(bus); 209 210 return 0; 211} 212 213static struct of_device_id fs_enet_mdio_fec_match[] = { 214 { 215 .compatible = "fsl,pq1-fec-mdio", 216 }, 217 {}, 218}; 219 220static struct of_platform_driver fs_enet_fec_mdio_driver = { 221 .name = "fsl-fec-mdio", 222 .match_table = fs_enet_mdio_fec_match, 223 .probe = fs_enet_mdio_probe, 224 .remove = fs_enet_mdio_remove, 225}; 226 227static int fs_enet_mdio_fec_init(void) 228{ 229 return of_register_platform_driver(&fs_enet_fec_mdio_driver); 230} 231 232static void fs_enet_mdio_fec_exit(void) 233{ 234 of_unregister_platform_driver(&fs_enet_fec_mdio_driver); 235} 236 237module_init(fs_enet_mdio_fec_init); 238module_exit(fs_enet_mdio_fec_exit);