diff options
-rw-r--r-- | drivers/net/gianfar_mii.c | 379 |
1 files changed, 0 insertions, 379 deletions
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c deleted file mode 100644 index 64e4679b3279..000000000000 --- a/drivers/net/gianfar_mii.c +++ /dev/null | |||
@@ -1,379 +0,0 @@ | |||
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 | */ | ||
56 | int 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(®s->miimadd, (mii_id << 8) | regnum); | ||
61 | |||
62 | /* Write out the value we want */ | ||
63 | gfar_write(®s->miimcon, value); | ||
64 | |||
65 | /* Wait for the transaction to finish */ | ||
66 | while (gfar_read(®s->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 | */ | ||
82 | int 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(®s->miimadd, (mii_id << 8) | regnum); | ||
88 | |||
89 | /* Clear miimcom, and then initiate a read */ | ||
90 | gfar_write(®s->miimcom, 0); | ||
91 | gfar_write(®s->miimcom, MII_READ_COMMAND); | ||
92 | |||
93 | /* Wait for the transaction to finish */ | ||
94 | while (gfar_read(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) | ||
95 | cpu_relax(); | ||
96 | |||
97 | /* Grab the value of the register from miimstat */ | ||
98 | value = gfar_read(®s->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 */ | ||
106 | int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | ||
107 | { | ||
108 | struct gfar_mii __iomem *regs = (void __force __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 */ | ||
117 | int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | ||
118 | { | ||
119 | struct gfar_mii __iomem *regs = (void __force __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 */ | ||
126 | static int gfar_mdio_reset(struct mii_bus *bus) | ||
127 | { | ||
128 | struct gfar_mii __iomem *regs = (void __force __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(®s->miimcfg, MIIMCFG_RESET); | ||
135 | |||
136 | /* Setup the MII Mgmt clock speed */ | ||
137 | gfar_write(®s->miimcfg, MIIMCFG_INIT_VALUE); | ||
138 | |||
139 | /* Wait until the bus is free */ | ||
140 | while ((gfar_read(®s->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 */ | ||
156 | static 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 | |||
194 | void 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 */ | ||
204 | static 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 | |||
221 | static 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 __force __iomem *) | ||
272 | ((char __force *)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 | |||
321 | err_free_irqs: | ||
322 | kfree(new_bus->irq); | ||
323 | err_unmap_regs: | ||
324 | iounmap(regs); | ||
325 | err_free_bus: | ||
326 | mdiobus_free(new_bus); | ||
327 | |||
328 | return err; | ||
329 | } | ||
330 | |||
331 | |||
332 | static 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 __force __iomem *)bus->priv); | ||
341 | bus->priv = NULL; | ||
342 | kfree(bus->irq); | ||
343 | mdiobus_free(bus); | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static 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 | |||
363 | static 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 | |||
371 | int __init gfar_mdio_init(void) | ||
372 | { | ||
373 | return of_register_platform_driver(&gianfar_mdio_driver); | ||
374 | } | ||
375 | |||
376 | void gfar_mdio_exit(void) | ||
377 | { | ||
378 | of_unregister_platform_driver(&gianfar_mdio_driver); | ||
379 | } | ||