diff options
author | Pantelis Antoniou <pantelis.antoniou@gmail.com> | 2005-10-28 16:25:58 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-28 16:25:58 -0400 |
commit | 48257c4f168e5d040394aeca4d37b59f68e0d36b (patch) | |
tree | 7e553a6018862338d80fb5b0e4070a371a8fb001 /drivers/net/fs_enet/mac-fec.c | |
parent | d8840ac907c7943bc7e196b11812adfa95cb28ef (diff) |
Add fs_enet ethernet network driver, for several embedded platforms.
Diffstat (limited to 'drivers/net/fs_enet/mac-fec.c')
-rw-r--r-- | drivers/net/fs_enet/mac-fec.c | 653 |
1 files changed, 653 insertions, 0 deletions
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c new file mode 100644 index 000000000000..5ef4e845a387 --- /dev/null +++ b/drivers/net/fs_enet/mac-fec.c | |||
@@ -0,0 +1,653 @@ | |||
1 | /* | ||
2 | * Freescale Ethernet controllers | ||
3 | * | ||
4 | * Copyright (c) 2005 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/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/skbuff.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/bitops.h> | ||
36 | #include <linux/fs.h> | ||
37 | |||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #ifdef CONFIG_8xx | ||
42 | #include <asm/8xx_immap.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mpc8xx.h> | ||
45 | #include <asm/commproc.h> | ||
46 | #endif | ||
47 | |||
48 | #include "fs_enet.h" | ||
49 | |||
50 | /*************************************************/ | ||
51 | |||
52 | #if defined(CONFIG_CPM1) | ||
53 | /* for a CPM1 __raw_xxx's are sufficient */ | ||
54 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
55 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
56 | #define __fs_in32(addr) __raw_readl(addr) | ||
57 | #define __fs_in16(addr) __raw_readw(addr) | ||
58 | #else | ||
59 | /* for others play it safe */ | ||
60 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
61 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
62 | #define __fs_in32(addr) in_be32(addr) | ||
63 | #define __fs_in16(addr) in_be16(addr) | ||
64 | #endif | ||
65 | |||
66 | /* write */ | ||
67 | #define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v)) | ||
68 | |||
69 | /* read */ | ||
70 | #define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg) | ||
71 | |||
72 | /* set bits */ | ||
73 | #define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) | ||
74 | |||
75 | /* clear bits */ | ||
76 | #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) | ||
77 | |||
78 | |||
79 | /* CRC polynomium used by the FEC for the multicast group filtering */ | ||
80 | #define FEC_CRC_POLY 0x04C11DB7 | ||
81 | |||
82 | #define FEC_MAX_MULTICAST_ADDRS 64 | ||
83 | |||
84 | /* Interrupt events/masks. | ||
85 | */ | ||
86 | #define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ | ||
87 | #define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ | ||
88 | #define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ | ||
89 | #define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ | ||
90 | #define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ | ||
91 | #define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ | ||
92 | #define FEC_ENET_RXF 0x02000000U /* Full frame received */ | ||
93 | #define FEC_ENET_RXB 0x01000000U /* A buffer was received */ | ||
94 | #define FEC_ENET_MII 0x00800000U /* MII interrupt */ | ||
95 | #define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ | ||
96 | |||
97 | #define FEC_ECNTRL_PINMUX 0x00000004 | ||
98 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
99 | #define FEC_ECNTRL_RESET 0x00000001 | ||
100 | |||
101 | #define FEC_RCNTRL_BC_REJ 0x00000010 | ||
102 | #define FEC_RCNTRL_PROM 0x00000008 | ||
103 | #define FEC_RCNTRL_MII_MODE 0x00000004 | ||
104 | #define FEC_RCNTRL_DRT 0x00000002 | ||
105 | #define FEC_RCNTRL_LOOP 0x00000001 | ||
106 | |||
107 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
108 | #define FEC_TCNTRL_HBC 0x00000002 | ||
109 | #define FEC_TCNTRL_GTS 0x00000001 | ||
110 | |||
111 | |||
112 | /* Make MII read/write commands for the FEC. | ||
113 | */ | ||
114 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
115 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
116 | #define mk_mii_end 0 | ||
117 | |||
118 | #define FEC_MII_LOOPS 10000 | ||
119 | |||
120 | /* | ||
121 | * Delay to wait for FEC reset command to complete (in us) | ||
122 | */ | ||
123 | #define FEC_RESET_DELAY 50 | ||
124 | |||
125 | static int whack_reset(fec_t * fecp) | ||
126 | { | ||
127 | int i; | ||
128 | |||
129 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); | ||
130 | for (i = 0; i < FEC_RESET_DELAY; i++) { | ||
131 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) | ||
132 | return 0; /* OK */ | ||
133 | udelay(1); | ||
134 | } | ||
135 | |||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | static int do_pd_setup(struct fs_enet_private *fep) | ||
140 | { | ||
141 | struct platform_device *pdev = to_platform_device(fep->dev); | ||
142 | struct resource *r; | ||
143 | |||
144 | /* Fill out IRQ field */ | ||
145 | fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); | ||
146 | |||
147 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | ||
148 | fep->fec.fecp =(void*)r->start; | ||
149 | |||
150 | if(fep->fec.fecp == NULL) | ||
151 | return -EINVAL; | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | } | ||
156 | |||
157 | #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) | ||
158 | #define FEC_RX_EVENT (FEC_ENET_RXF) | ||
159 | #define FEC_TX_EVENT (FEC_ENET_TXF) | ||
160 | #define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ | ||
161 | FEC_ENET_BABT | FEC_ENET_EBERR) | ||
162 | |||
163 | static int setup_data(struct net_device *dev) | ||
164 | { | ||
165 | struct fs_enet_private *fep = netdev_priv(dev); | ||
166 | |||
167 | if (do_pd_setup(fep) != 0) | ||
168 | return -EINVAL; | ||
169 | |||
170 | fep->fec.hthi = 0; | ||
171 | fep->fec.htlo = 0; | ||
172 | |||
173 | fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; | ||
174 | fep->ev_rx = FEC_RX_EVENT; | ||
175 | fep->ev_tx = FEC_TX_EVENT; | ||
176 | fep->ev_err = FEC_ERR_EVENT_MSK; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int allocate_bd(struct net_device *dev) | ||
182 | { | ||
183 | struct fs_enet_private *fep = netdev_priv(dev); | ||
184 | const struct fs_platform_info *fpi = fep->fpi; | ||
185 | |||
186 | fep->ring_base = dma_alloc_coherent(fep->dev, | ||
187 | (fpi->tx_ring + fpi->rx_ring) * | ||
188 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
189 | GFP_KERNEL); | ||
190 | if (fep->ring_base == NULL) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void free_bd(struct net_device *dev) | ||
197 | { | ||
198 | struct fs_enet_private *fep = netdev_priv(dev); | ||
199 | const struct fs_platform_info *fpi = fep->fpi; | ||
200 | |||
201 | if(fep->ring_base) | ||
202 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) | ||
203 | * sizeof(cbd_t), | ||
204 | fep->ring_base, | ||
205 | fep->ring_mem_addr); | ||
206 | } | ||
207 | |||
208 | static void cleanup_data(struct net_device *dev) | ||
209 | { | ||
210 | /* nothing */ | ||
211 | } | ||
212 | |||
213 | static void set_promiscuous_mode(struct net_device *dev) | ||
214 | { | ||
215 | struct fs_enet_private *fep = netdev_priv(dev); | ||
216 | fec_t *fecp = fep->fec.fecp; | ||
217 | |||
218 | FS(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
219 | } | ||
220 | |||
221 | static void set_multicast_start(struct net_device *dev) | ||
222 | { | ||
223 | struct fs_enet_private *fep = netdev_priv(dev); | ||
224 | |||
225 | fep->fec.hthi = 0; | ||
226 | fep->fec.htlo = 0; | ||
227 | } | ||
228 | |||
229 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
230 | { | ||
231 | struct fs_enet_private *fep = netdev_priv(dev); | ||
232 | int temp, hash_index, i, j; | ||
233 | u32 crc, csrVal; | ||
234 | u8 byte, msb; | ||
235 | |||
236 | crc = 0xffffffff; | ||
237 | for (i = 0; i < 6; i++) { | ||
238 | byte = mac[i]; | ||
239 | for (j = 0; j < 8; j++) { | ||
240 | msb = crc >> 31; | ||
241 | crc <<= 1; | ||
242 | if (msb ^ (byte & 0x1)) | ||
243 | crc ^= FEC_CRC_POLY; | ||
244 | byte >>= 1; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | temp = (crc & 0x3f) >> 1; | ||
249 | hash_index = ((temp & 0x01) << 4) | | ||
250 | ((temp & 0x02) << 2) | | ||
251 | ((temp & 0x04)) | | ||
252 | ((temp & 0x08) >> 2) | | ||
253 | ((temp & 0x10) >> 4); | ||
254 | csrVal = 1 << hash_index; | ||
255 | if (crc & 1) | ||
256 | fep->fec.hthi |= csrVal; | ||
257 | else | ||
258 | fep->fec.htlo |= csrVal; | ||
259 | } | ||
260 | |||
261 | static void set_multicast_finish(struct net_device *dev) | ||
262 | { | ||
263 | struct fs_enet_private *fep = netdev_priv(dev); | ||
264 | fec_t *fecp = fep->fec.fecp; | ||
265 | |||
266 | /* if all multi or too many multicasts; just enable all */ | ||
267 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
268 | dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { | ||
269 | fep->fec.hthi = 0xffffffffU; | ||
270 | fep->fec.htlo = 0xffffffffU; | ||
271 | } | ||
272 | |||
273 | FC(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
274 | FW(fecp, hash_table_high, fep->fec.hthi); | ||
275 | FW(fecp, hash_table_low, fep->fec.htlo); | ||
276 | } | ||
277 | |||
278 | static void set_multicast_list(struct net_device *dev) | ||
279 | { | ||
280 | struct dev_mc_list *pmc; | ||
281 | |||
282 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
283 | set_multicast_start(dev); | ||
284 | for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) | ||
285 | set_multicast_one(dev, pmc->dmi_addr); | ||
286 | set_multicast_finish(dev); | ||
287 | } else | ||
288 | set_promiscuous_mode(dev); | ||
289 | } | ||
290 | |||
291 | static void restart(struct net_device *dev) | ||
292 | { | ||
293 | #ifdef CONFIG_DUET | ||
294 | immap_t *immap = fs_enet_immap; | ||
295 | u32 cptr; | ||
296 | #endif | ||
297 | struct fs_enet_private *fep = netdev_priv(dev); | ||
298 | fec_t *fecp = fep->fec.fecp; | ||
299 | const struct fs_platform_info *fpi = fep->fpi; | ||
300 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
301 | int r; | ||
302 | u32 addrhi, addrlo; | ||
303 | |||
304 | r = whack_reset(fep->fec.fecp); | ||
305 | if (r != 0) | ||
306 | printk(KERN_ERR DRV_MODULE_NAME | ||
307 | ": %s FEC Reset FAILED!\n", dev->name); | ||
308 | |||
309 | /* | ||
310 | * Set station address. | ||
311 | */ | ||
312 | addrhi = ((u32) dev->dev_addr[0] << 24) | | ||
313 | ((u32) dev->dev_addr[1] << 16) | | ||
314 | ((u32) dev->dev_addr[2] << 8) | | ||
315 | (u32) dev->dev_addr[3]; | ||
316 | addrlo = ((u32) dev->dev_addr[4] << 24) | | ||
317 | ((u32) dev->dev_addr[5] << 16); | ||
318 | FW(fecp, addr_low, addrhi); | ||
319 | FW(fecp, addr_high, addrlo); | ||
320 | |||
321 | /* | ||
322 | * Reset all multicast. | ||
323 | */ | ||
324 | FW(fecp, hash_table_high, fep->fec.hthi); | ||
325 | FW(fecp, hash_table_low, fep->fec.htlo); | ||
326 | |||
327 | /* | ||
328 | * Set maximum receive buffer size. | ||
329 | */ | ||
330 | FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); | ||
331 | FW(fecp, r_hash, PKT_MAXBUF_SIZE); | ||
332 | |||
333 | /* get physical address */ | ||
334 | rx_bd_base_phys = fep->ring_mem_addr; | ||
335 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
336 | |||
337 | /* | ||
338 | * Set receive and transmit descriptor base. | ||
339 | */ | ||
340 | FW(fecp, r_des_start, rx_bd_base_phys); | ||
341 | FW(fecp, x_des_start, tx_bd_base_phys); | ||
342 | |||
343 | fs_init_bds(dev); | ||
344 | |||
345 | /* | ||
346 | * Enable big endian and don't care about SDMA FC. | ||
347 | */ | ||
348 | FW(fecp, fun_code, 0x78000000); | ||
349 | |||
350 | /* | ||
351 | * Set MII speed. | ||
352 | */ | ||
353 | FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); | ||
354 | |||
355 | /* | ||
356 | * Clear any outstanding interrupt. | ||
357 | */ | ||
358 | FW(fecp, ievent, 0xffc0); | ||
359 | FW(fecp, ivec, (fep->interrupt / 2) << 29); | ||
360 | |||
361 | |||
362 | /* | ||
363 | * adjust to speed (only for DUET & RMII) | ||
364 | */ | ||
365 | #ifdef CONFIG_DUET | ||
366 | if (fpi->use_rmii) { | ||
367 | cptr = in_be32(&immap->im_cpm.cp_cptr); | ||
368 | switch (fs_get_fec_index(fpi->fs_no)) { | ||
369 | case 0: | ||
370 | cptr |= 0x100; | ||
371 | if (fep->speed == 10) | ||
372 | cptr |= 0x0000010; | ||
373 | else if (fep->speed == 100) | ||
374 | cptr &= ~0x0000010; | ||
375 | break; | ||
376 | case 1: | ||
377 | cptr |= 0x80; | ||
378 | if (fep->speed == 10) | ||
379 | cptr |= 0x0000008; | ||
380 | else if (fep->speed == 100) | ||
381 | cptr &= ~0x0000008; | ||
382 | break; | ||
383 | default: | ||
384 | BUG(); /* should never happen */ | ||
385 | break; | ||
386 | } | ||
387 | out_be32(&immap->im_cpm.cp_cptr, cptr); | ||
388 | } | ||
389 | #endif | ||
390 | |||
391 | FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
392 | /* | ||
393 | * adjust to duplex mode | ||
394 | */ | ||
395 | if (fep->duplex) { | ||
396 | FC(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
397 | FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ | ||
398 | } else { | ||
399 | FS(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
400 | FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Enable interrupts we wish to service. | ||
405 | */ | ||
406 | FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | | ||
407 | FEC_ENET_RXF | FEC_ENET_RXB); | ||
408 | |||
409 | /* | ||
410 | * And last, enable the transmit and receive processing. | ||
411 | */ | ||
412 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
413 | FW(fecp, r_des_active, 0x01000000); | ||
414 | } | ||
415 | |||
416 | static void stop(struct net_device *dev) | ||
417 | { | ||
418 | struct fs_enet_private *fep = netdev_priv(dev); | ||
419 | fec_t *fecp = fep->fec.fecp; | ||
420 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
421 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
422 | int i; | ||
423 | |||
424 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) | ||
425 | return; /* already down */ | ||
426 | |||
427 | FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ | ||
428 | for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && | ||
429 | i < FEC_RESET_DELAY; i++) | ||
430 | udelay(1); | ||
431 | |||
432 | if (i == FEC_RESET_DELAY) | ||
433 | printk(KERN_WARNING DRV_MODULE_NAME | ||
434 | ": %s FEC timeout on graceful transmit stop\n", | ||
435 | dev->name); | ||
436 | /* | ||
437 | * Disable FEC. Let only MII interrupts. | ||
438 | */ | ||
439 | FW(fecp, imask, 0); | ||
440 | FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); | ||
441 | |||
442 | fs_cleanup_bds(dev); | ||
443 | |||
444 | /* shut down FEC1? that's where the mii bus is */ | ||
445 | if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { | ||
446 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
447 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
448 | FW(fecp, ievent, FEC_ENET_MII); | ||
449 | FW(fecp, mii_speed, bus->fec.mii_speed); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | static void pre_request_irq(struct net_device *dev, int irq) | ||
454 | { | ||
455 | immap_t *immap = fs_enet_immap; | ||
456 | u32 siel; | ||
457 | |||
458 | /* SIU interrupt */ | ||
459 | if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { | ||
460 | |||
461 | siel = in_be32(&immap->im_siu_conf.sc_siel); | ||
462 | if ((irq & 1) == 0) | ||
463 | siel |= (0x80000000 >> irq); | ||
464 | else | ||
465 | siel &= ~(0x80000000 >> (irq & ~1)); | ||
466 | out_be32(&immap->im_siu_conf.sc_siel, siel); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static void post_free_irq(struct net_device *dev, int irq) | ||
471 | { | ||
472 | /* nothing */ | ||
473 | } | ||
474 | |||
475 | static void napi_clear_rx_event(struct net_device *dev) | ||
476 | { | ||
477 | struct fs_enet_private *fep = netdev_priv(dev); | ||
478 | fec_t *fecp = fep->fec.fecp; | ||
479 | |||
480 | FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); | ||
481 | } | ||
482 | |||
483 | static void napi_enable_rx(struct net_device *dev) | ||
484 | { | ||
485 | struct fs_enet_private *fep = netdev_priv(dev); | ||
486 | fec_t *fecp = fep->fec.fecp; | ||
487 | |||
488 | FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
489 | } | ||
490 | |||
491 | static void napi_disable_rx(struct net_device *dev) | ||
492 | { | ||
493 | struct fs_enet_private *fep = netdev_priv(dev); | ||
494 | fec_t *fecp = fep->fec.fecp; | ||
495 | |||
496 | FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
497 | } | ||
498 | |||
499 | static void rx_bd_done(struct net_device *dev) | ||
500 | { | ||
501 | struct fs_enet_private *fep = netdev_priv(dev); | ||
502 | fec_t *fecp = fep->fec.fecp; | ||
503 | |||
504 | FW(fecp, r_des_active, 0x01000000); | ||
505 | } | ||
506 | |||
507 | static void tx_kickstart(struct net_device *dev) | ||
508 | { | ||
509 | struct fs_enet_private *fep = netdev_priv(dev); | ||
510 | fec_t *fecp = fep->fec.fecp; | ||
511 | |||
512 | FW(fecp, x_des_active, 0x01000000); | ||
513 | } | ||
514 | |||
515 | static u32 get_int_events(struct net_device *dev) | ||
516 | { | ||
517 | struct fs_enet_private *fep = netdev_priv(dev); | ||
518 | fec_t *fecp = fep->fec.fecp; | ||
519 | |||
520 | return FR(fecp, ievent) & FR(fecp, imask); | ||
521 | } | ||
522 | |||
523 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
524 | { | ||
525 | struct fs_enet_private *fep = netdev_priv(dev); | ||
526 | fec_t *fecp = fep->fec.fecp; | ||
527 | |||
528 | FW(fecp, ievent, int_events); | ||
529 | } | ||
530 | |||
531 | static void ev_error(struct net_device *dev, u32 int_events) | ||
532 | { | ||
533 | printk(KERN_WARNING DRV_MODULE_NAME | ||
534 | ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); | ||
535 | } | ||
536 | |||
537 | int get_regs(struct net_device *dev, void *p, int *sizep) | ||
538 | { | ||
539 | struct fs_enet_private *fep = netdev_priv(dev); | ||
540 | |||
541 | if (*sizep < sizeof(fec_t)) | ||
542 | return -EINVAL; | ||
543 | |||
544 | memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t)); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | int get_regs_len(struct net_device *dev) | ||
550 | { | ||
551 | return sizeof(fec_t); | ||
552 | } | ||
553 | |||
554 | void tx_restart(struct net_device *dev) | ||
555 | { | ||
556 | /* nothing */ | ||
557 | } | ||
558 | |||
559 | /*************************************************************************/ | ||
560 | |||
561 | const struct fs_ops fs_fec_ops = { | ||
562 | .setup_data = setup_data, | ||
563 | .cleanup_data = cleanup_data, | ||
564 | .set_multicast_list = set_multicast_list, | ||
565 | .restart = restart, | ||
566 | .stop = stop, | ||
567 | .pre_request_irq = pre_request_irq, | ||
568 | .post_free_irq = post_free_irq, | ||
569 | .napi_clear_rx_event = napi_clear_rx_event, | ||
570 | .napi_enable_rx = napi_enable_rx, | ||
571 | .napi_disable_rx = napi_disable_rx, | ||
572 | .rx_bd_done = rx_bd_done, | ||
573 | .tx_kickstart = tx_kickstart, | ||
574 | .get_int_events = get_int_events, | ||
575 | .clear_int_events = clear_int_events, | ||
576 | .ev_error = ev_error, | ||
577 | .get_regs = get_regs, | ||
578 | .get_regs_len = get_regs_len, | ||
579 | .tx_restart = tx_restart, | ||
580 | .allocate_bd = allocate_bd, | ||
581 | .free_bd = free_bd, | ||
582 | }; | ||
583 | |||
584 | /***********************************************************************/ | ||
585 | |||
586 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | ||
587 | { | ||
588 | fec_t *fecp = bus->fec.fecp; | ||
589 | int i, ret = -1; | ||
590 | |||
591 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
592 | BUG(); | ||
593 | |||
594 | /* Add PHY address to register command. */ | ||
595 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
596 | |||
597 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
598 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
599 | break; | ||
600 | |||
601 | if (i < FEC_MII_LOOPS) { | ||
602 | FW(fecp, ievent, FEC_ENET_MII); | ||
603 | ret = FR(fecp, mii_data) & 0xffff; | ||
604 | } | ||
605 | |||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) | ||
610 | { | ||
611 | fec_t *fecp = bus->fec.fecp; | ||
612 | int i; | ||
613 | |||
614 | /* this must never happen */ | ||
615 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
616 | BUG(); | ||
617 | |||
618 | /* Add PHY address to register command. */ | ||
619 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); | ||
620 | |||
621 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
622 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
623 | break; | ||
624 | |||
625 | if (i < FEC_MII_LOOPS) | ||
626 | FW(fecp, ievent, FEC_ENET_MII); | ||
627 | } | ||
628 | |||
629 | int fs_mii_fec_init(struct fs_enet_mii_bus *bus) | ||
630 | { | ||
631 | bd_t *bd = (bd_t *)__res; | ||
632 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
633 | fec_t *fecp; | ||
634 | |||
635 | if (bi->id != 0) | ||
636 | return -1; | ||
637 | |||
638 | bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; | ||
639 | bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) | ||
640 | & 0x3F) << 1; | ||
641 | |||
642 | fecp = bus->fec.fecp; | ||
643 | |||
644 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
645 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
646 | FW(fecp, ievent, FEC_ENET_MII); | ||
647 | FW(fecp, mii_speed, bus->fec.mii_speed); | ||
648 | |||
649 | bus->mii_read = mii_read; | ||
650 | bus->mii_write = mii_write; | ||
651 | |||
652 | return 0; | ||
653 | } | ||