aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/8390
diff options
context:
space:
mode:
authorGreg Ungerer <gerg@uclinux.org>2012-07-04 09:50:00 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-12 10:54:45 -0400
commit064bff1c9f70ba495f83668a3ee2f10ea3f1c99c (patch)
treefd1adeb8316e3cdebd7c58fa7aca42d802df416a /drivers/net/ethernet/8390
parent2c624880fb34e5ad2a5832b9c5b3a49d1e579a3d (diff)
net: add support for NS8390 based eth controllers on some ColdFire CPU boards
A number of older ColdFire CPU based boards use NS8390 based network controllers. Most use the Davicom 9008F or the UMC 9008F. This driver provides the support code to get these devices working on these platforms. Generally the NS8390 based eth device is direct connected via the general purpose bus of the ColdFire CPU. So its addressing and interrupt setup is fixed on each of the different platforms (classic platform setup). This driver is based on the other drivers/net/ethernet/8390 drivers, and includes the lib8390.c code. It uses the existing definitions of the board NS8390 device addresses, interrupts and access types from the arch/m68k/include/asm/mcf8390.h, but moves the IO access functions into the driver code and out of that header. Signed-off-by: Greg Ungerer <gerg@uclinux.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/8390')
-rw-r--r--drivers/net/ethernet/8390/Kconfig14
-rw-r--r--drivers/net/ethernet/8390/Makefile1
-rw-r--r--drivers/net/ethernet/8390/mcf8390.c480
3 files changed, 495 insertions, 0 deletions
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 2e538676924d..e1219e037c04 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -162,6 +162,20 @@ config MAC8390
162 and read the Ethernet-HOWTO, available from 162 and read the Ethernet-HOWTO, available from
163 <http://www.tldp.org/docs.html#howto>. 163 <http://www.tldp.org/docs.html#howto>.
164 164
165config MCF8390
166 tristate "ColdFire NS8390 based Ethernet support"
167 depends on COLDFIRE
168 select CRC32
169 ---help---
170 This driver is for Ethernet devices using an NS8390-compatible
171 chipset on many common ColdFire CPU based boards. Many of the older
172 Freescale dev boards use this, and some other common boards like
173 some SnapGear routers do as well.
174
175 If you have one of these boards and want to use the network interface
176 on them then choose Y. To compile this driver as a module, choose M
177 here, the module will be called mcf8390.
178
165config NE2000 179config NE2000
166 tristate "NE2000/NE1000 support" 180 tristate "NE2000/NE1000 support"
167 depends on (ISA || (Q40 && m) || M32R || MACH_TX49XX) 181 depends on (ISA || (Q40 && m) || M32R || MACH_TX49XX)
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index d13790b7fd27..f43038babf86 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
14obj-$(CONFIG_HPLAN) += hp.o 8390p.o 14obj-$(CONFIG_HPLAN) += hp.o 8390p.o
15obj-$(CONFIG_HYDRA) += hydra.o 8390.o 15obj-$(CONFIG_HYDRA) += hydra.o 8390.o
16obj-$(CONFIG_LNE390) += lne390.o 8390.o 16obj-$(CONFIG_LNE390) += lne390.o 8390.o
17obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o
17obj-$(CONFIG_NE2000) += ne.o 8390p.o 18obj-$(CONFIG_NE2000) += ne.o 8390p.o
18obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o 19obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
19obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o 20obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c
new file mode 100644
index 000000000000..230efd6fa5d5
--- /dev/null
+++ b/drivers/net/ethernet/8390/mcf8390.c
@@ -0,0 +1,480 @@
1/*
2 * Support for ColdFire CPU based boards using a NS8390 Ethernet device.
3 *
4 * Derived from the many other 8390 drivers.
5 *
6 * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of the Linux
10 * distribution for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/init.h>
17#include <linux/platform_device.h>
18#include <linux/netdevice.h>
19#include <linux/etherdevice.h>
20#include <linux/jiffies.h>
21#include <linux/io.h>
22#include <asm/mcf8390.h>
23
24static const char version[] =
25 "mcf8390.c: (15-06-2012) Greg Ungerer <gerg@uclinux.org>";
26
27#define NE_CMD 0x00
28#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset */
29#define NE_RESET 0x1f /* Issue a read to reset ,a write to clear */
30#define NE_EN0_ISR 0x07
31#define NE_EN0_DCFG 0x0e
32#define NE_EN0_RSARLO 0x08
33#define NE_EN0_RSARHI 0x09
34#define NE_EN0_RCNTLO 0x0a
35#define NE_EN0_RXCR 0x0c
36#define NE_EN0_TXCR 0x0d
37#define NE_EN0_RCNTHI 0x0b
38#define NE_EN0_IMR 0x0f
39
40#define NESM_START_PG 0x40 /* First page of TX buffer */
41#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
42
43#ifdef NE2000_ODDOFFSET
44/*
45 * A lot of the ColdFire boards use a separate address region for odd offset
46 * register addresses. The following functions convert and map as required.
47 * Note that the data port accesses are treated a little differently, and
48 * always accessed via the insX/outsX functions.
49 */
50static inline u32 NE_PTR(u32 addr)
51{
52 if (addr & 1)
53 return addr - 1 + NE2000_ODDOFFSET;
54 return addr;
55}
56
57static inline u32 NE_DATA_PTR(u32 addr)
58{
59 return addr;
60}
61
62void ei_outb(u32 val, u32 addr)
63{
64 NE2000_BYTE *rp;
65
66 rp = (NE2000_BYTE *) NE_PTR(addr);
67 *rp = RSWAP(val);
68}
69
70#define ei_inb ei_inb
71u8 ei_inb(u32 addr)
72{
73 NE2000_BYTE *rp, val;
74
75 rp = (NE2000_BYTE *) NE_PTR(addr);
76 val = *rp;
77 return (u8) (RSWAP(val) & 0xff);
78}
79
80void ei_insb(u32 addr, void *vbuf, int len)
81{
82 NE2000_BYTE *rp, val;
83 u8 *buf;
84
85 buf = (u8 *) vbuf;
86 rp = (NE2000_BYTE *) NE_DATA_PTR(addr);
87 for (; (len > 0); len--) {
88 val = *rp;
89 *buf++ = RSWAP(val);
90 }
91}
92
93void ei_insw(u32 addr, void *vbuf, int len)
94{
95 volatile u16 *rp;
96 u16 w, *buf;
97
98 buf = (u16 *) vbuf;
99 rp = (volatile u16 *) NE_DATA_PTR(addr);
100 for (; (len > 0); len--) {
101 w = *rp;
102 *buf++ = BSWAP(w);
103 }
104}
105
106void ei_outsb(u32 addr, const void *vbuf, int len)
107{
108 NE2000_BYTE *rp, val;
109 u8 *buf;
110
111 buf = (u8 *) vbuf;
112 rp = (NE2000_BYTE *) NE_DATA_PTR(addr);
113 for (; (len > 0); len--) {
114 val = *buf++;
115 *rp = RSWAP(val);
116 }
117}
118
119void ei_outsw(u32 addr, const void *vbuf, int len)
120{
121 volatile u16 *rp;
122 u16 w, *buf;
123
124 buf = (u16 *) vbuf;
125 rp = (volatile u16 *) NE_DATA_PTR(addr);
126 for (; (len > 0); len--) {
127 w = *buf++;
128 *rp = BSWAP(w);
129 }
130}
131
132#else /* !NE2000_ODDOFFSET */
133
134#define ei_inb inb
135#define ei_outb outb
136#define ei_insb insb
137#define ei_insw insw
138#define ei_outsb outsb
139#define ei_outsw outsw
140
141#endif /* !NE2000_ODDOFFSET */
142
143#define ei_inb_p ei_inb
144#define ei_outb_p ei_outb
145
146#include "lib8390.c"
147
148/*
149 * Hard reset the card. This used to pause for the same period that a
150 * 8390 reset command required, but that shouldn't be necessary.
151 */
152static void mcf8390_reset_8390(struct net_device *dev)
153{
154 unsigned long reset_start_time = jiffies;
155 u32 addr = dev->base_addr;
156
157 if (ei_debug > 1)
158 netdev_dbg(dev, "resetting the 8390 t=%ld...\n", jiffies);
159
160 ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET);
161
162 ei_status.txing = 0;
163 ei_status.dmaing = 0;
164
165 /* This check _should_not_ be necessary, omit eventually. */
166 while ((ei_inb(addr + NE_EN0_ISR) & ENISR_RESET) == 0) {
167 if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) {
168 netdev_warn(dev, "%s: did not complete\n", __func__);
169 break;
170 }
171 }
172
173 ei_outb(ENISR_RESET, addr + NE_EN0_ISR);
174}
175
176/*
177 * This *shouldn't* happen.
178 * If it does, it's the last thing you'll see
179 */
180static void mcf8390_dmaing_err(const char *func, struct net_device *dev,
181 struct ei_device *ei_local)
182{
183 netdev_err(dev, "%s: DMAing conflict [DMAstat:%d][irqlock:%d]\n",
184 func, ei_local->dmaing, ei_local->irqlock);
185}
186
187/*
188 * Grab the 8390 specific header. Similar to the block_input routine, but
189 * we don't need to be concerned with ring wrap as the header will be at
190 * the start of a page, so we optimize accordingly.
191 */
192static void mcf8390_get_8390_hdr(struct net_device *dev,
193 struct e8390_pkt_hdr *hdr, int ring_page)
194{
195 struct ei_device *ei_local = netdev_priv(dev);
196 u32 addr = dev->base_addr;
197
198 if (ei_local->dmaing) {
199 mcf8390_dmaing_err(__func__, dev, ei_local);
200 return;
201 }
202
203 ei_local->dmaing |= 0x01;
204 ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, addr + NE_CMD);
205 ei_outb(ENISR_RDC, addr + NE_EN0_ISR);
206 ei_outb(sizeof(struct e8390_pkt_hdr), addr + NE_EN0_RCNTLO);
207 ei_outb(0, addr + NE_EN0_RCNTHI);
208 ei_outb(0, addr + NE_EN0_RSARLO); /* On page boundary */
209 ei_outb(ring_page, addr + NE_EN0_RSARHI);
210 ei_outb(E8390_RREAD + E8390_START, addr + NE_CMD);
211
212 ei_insw(addr + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr) >> 1);
213
214 outb(ENISR_RDC, addr + NE_EN0_ISR); /* Ack intr */
215 ei_local->dmaing &= ~0x01;
216
217 hdr->count = cpu_to_le16(hdr->count);
218}
219
220/*
221 * Block input and output, similar to the Crynwr packet driver.
222 * If you are porting to a new ethercard, look at the packet driver source
223 * for hints. The NEx000 doesn't share the on-board packet memory --
224 * you have to put the packet out through the "remote DMA" dataport
225 * using z_writeb.
226 */
227static void mcf8390_block_input(struct net_device *dev, int count,
228 struct sk_buff *skb, int ring_offset)
229{
230 struct ei_device *ei_local = netdev_priv(dev);
231 u32 addr = dev->base_addr;
232 char *buf = skb->data;
233
234 if (ei_local->dmaing) {
235 mcf8390_dmaing_err(__func__, dev, ei_local);
236 return;
237 }
238
239 ei_local->dmaing |= 0x01;
240 ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, addr + NE_CMD);
241 ei_outb(ENISR_RDC, addr + NE_EN0_ISR);
242 ei_outb(count & 0xff, addr + NE_EN0_RCNTLO);
243 ei_outb(count >> 8, addr + NE_EN0_RCNTHI);
244 ei_outb(ring_offset & 0xff, addr + NE_EN0_RSARLO);
245 ei_outb(ring_offset >> 8, addr + NE_EN0_RSARHI);
246 ei_outb(E8390_RREAD + E8390_START, addr + NE_CMD);
247
248 ei_insw(addr + NE_DATAPORT, buf, count >> 1);
249 if (count & 1)
250 buf[count - 1] = ei_inb(addr + NE_DATAPORT);
251
252 ei_outb(ENISR_RDC, addr + NE_EN0_ISR); /* Ack intr */
253 ei_local->dmaing &= ~0x01;
254}
255
256static void mcf8390_block_output(struct net_device *dev, int count,
257 const unsigned char *buf,
258 const int start_page)
259{
260 struct ei_device *ei_local = netdev_priv(dev);
261 u32 addr = dev->base_addr;
262 unsigned long dma_start;
263
264 /* Make sure we transfer all bytes if 16bit IO writes */
265 if (count & 0x1)
266 count++;
267
268 if (ei_local->dmaing) {
269 mcf8390_dmaing_err(__func__, dev, ei_local);
270 return;
271 }
272
273 ei_local->dmaing |= 0x01;
274 /* We should already be in page 0, but to be safe... */
275 ei_outb(E8390_PAGE0 + E8390_START + E8390_NODMA, addr + NE_CMD);
276
277 ei_outb(ENISR_RDC, addr + NE_EN0_ISR);
278
279 /* Now the normal output. */
280 ei_outb(count & 0xff, addr + NE_EN0_RCNTLO);
281 ei_outb(count >> 8, addr + NE_EN0_RCNTHI);
282 ei_outb(0x00, addr + NE_EN0_RSARLO);
283 ei_outb(start_page, addr + NE_EN0_RSARHI);
284 ei_outb(E8390_RWRITE + E8390_START, addr + NE_CMD);
285
286 ei_outsw(addr + NE_DATAPORT, buf, count >> 1);
287
288 dma_start = jiffies;
289 while ((ei_inb(addr + NE_EN0_ISR) & ENISR_RDC) == 0) {
290 if (time_after(jiffies, dma_start + 2 * HZ / 100)) { /* 20ms */
291 netdev_err(dev, "timeout waiting for Tx RDC\n");
292 mcf8390_reset_8390(dev);
293 __NS8390_init(dev, 1);
294 break;
295 }
296 }
297
298 ei_outb(ENISR_RDC, addr + NE_EN0_ISR); /* Ack intr */
299 ei_local->dmaing &= ~0x01;
300}
301
302static const struct net_device_ops mcf8390_netdev_ops = {
303 .ndo_open = __ei_open,
304 .ndo_stop = __ei_close,
305 .ndo_start_xmit = __ei_start_xmit,
306 .ndo_tx_timeout = __ei_tx_timeout,
307 .ndo_get_stats = __ei_get_stats,
308 .ndo_set_rx_mode = __ei_set_multicast_list,
309 .ndo_validate_addr = eth_validate_addr,
310 .ndo_set_mac_address = eth_mac_addr,
311 .ndo_change_mtu = eth_change_mtu,
312#ifdef CONFIG_NET_POLL_CONTROLLER
313 .ndo_poll_controller = __ei_poll,
314#endif
315};
316
317static int mcf8390_init(struct net_device *dev)
318{
319 static u32 offsets[] = {
320 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
321 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
322 };
323 struct ei_device *ei_local = netdev_priv(dev);
324 unsigned char SA_prom[32];
325 u32 addr = dev->base_addr;
326 int start_page, stop_page;
327 int i, ret;
328
329 mcf8390_reset_8390(dev);
330
331 /*
332 * Read the 16 bytes of station address PROM.
333 * We must first initialize registers,
334 * similar to NS8390_init(eifdev, 0).
335 * We can't reliably read the SAPROM address without this.
336 * (I learned the hard way!).
337 */
338 {
339 static const struct {
340 u32 value;
341 u32 offset;
342 } program_seq[] = {
343 {E8390_NODMA + E8390_PAGE0 + E8390_STOP, NE_CMD},
344 /* Select page 0 */
345 {0x48, NE_EN0_DCFG}, /* 0x48: Set byte-wide access */
346 {0x00, NE_EN0_RCNTLO}, /* Clear the count regs */
347 {0x00, NE_EN0_RCNTHI},
348 {0x00, NE_EN0_IMR}, /* Mask completion irq */
349 {0xFF, NE_EN0_ISR},
350 {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */
351 {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode */
352 {32, NE_EN0_RCNTLO},
353 {0x00, NE_EN0_RCNTHI},
354 {0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000 */
355 {0x00, NE_EN0_RSARHI},
356 {E8390_RREAD + E8390_START, NE_CMD},
357 };
358 for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
359 ei_outb(program_seq[i].value,
360 addr + program_seq[i].offset);
361 }
362 }
363
364 for (i = 0; i < 16; i++) {
365 SA_prom[i] = ei_inb(addr + NE_DATAPORT);
366 ei_inb(addr + NE_DATAPORT);
367 }
368
369 /* We must set the 8390 for word mode. */
370 ei_outb(0x49, addr + NE_EN0_DCFG);
371 start_page = NESM_START_PG;
372 stop_page = NESM_STOP_PG;
373
374 /* Install the Interrupt handler */
375 ret = request_irq(dev->irq, __ei_interrupt, 0, dev->name, dev);
376 if (ret)
377 return ret;
378
379 for (i = 0; i < ETH_ALEN; i++)
380 dev->dev_addr[i] = SA_prom[i];
381
382 netdev_dbg(dev, "Found ethernet address: %pM\n", dev->dev_addr);
383
384 ei_local->name = "mcf8390";
385 ei_local->tx_start_page = start_page;
386 ei_local->stop_page = stop_page;
387 ei_local->word16 = 1;
388 ei_local->rx_start_page = start_page + TX_PAGES;
389 ei_local->reset_8390 = mcf8390_reset_8390;
390 ei_local->block_input = mcf8390_block_input;
391 ei_local->block_output = mcf8390_block_output;
392 ei_local->get_8390_hdr = mcf8390_get_8390_hdr;
393 ei_local->reg_offset = offsets;
394
395 dev->netdev_ops = &mcf8390_netdev_ops;
396 __NS8390_init(dev, 0);
397 ret = register_netdev(dev);
398 if (ret) {
399 free_irq(dev->irq, dev);
400 return ret;
401 }
402
403 netdev_info(dev, "addr=0x%08x irq=%d, Ethernet Address %pM\n",
404 addr, dev->irq, dev->dev_addr);
405 return 0;
406}
407
408static int mcf8390_probe(struct platform_device *pdev)
409{
410 struct net_device *dev;
411 struct ei_device *ei_local;
412 struct resource *mem, *irq;
413 resource_size_t msize;
414 int ret;
415
416 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
417 if (irq == NULL) {
418 dev_err(&pdev->dev, "no IRQ specified?\n");
419 return -ENXIO;
420 }
421
422 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
423 if (mem == NULL) {
424 dev_err(&pdev->dev, "no memory address specified?\n");
425 return -ENXIO;
426 }
427 msize = resource_size(mem);
428 if (!request_mem_region(mem->start, msize, pdev->name))
429 return -EBUSY;
430
431 dev = ____alloc_ei_netdev(0);
432 if (dev == NULL) {
433 release_mem_region(mem->start, msize);
434 return -ENOMEM;
435 }
436
437 SET_NETDEV_DEV(dev, &pdev->dev);
438 platform_set_drvdata(pdev, dev);
439 ei_local = netdev_priv(dev);
440
441 dev->irq = irq->start;
442 dev->base_addr = mem->start;
443
444 ret = mcf8390_init(dev);
445 if (ret) {
446 release_mem_region(mem->start, msize);
447 free_netdev(dev);
448 return ret;
449 }
450 return 0;
451}
452
453static int mcf8390_remove(struct platform_device *pdev)
454{
455 struct net_device *dev = platform_get_drvdata(pdev);
456 struct resource *mem;
457
458 unregister_netdev(dev);
459 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
460 if (mem)
461 release_mem_region(mem->start, resource_size(mem));
462 free_netdev(dev);
463 return 0;
464}
465
466static struct platform_driver mcf8390_drv = {
467 .driver = {
468 .name = "mcf8390",
469 .owner = THIS_MODULE,
470 },
471 .probe = mcf8390_probe,
472 .remove = mcf8390_remove,
473};
474
475module_platform_driver(mcf8390_drv);
476
477MODULE_DESCRIPTION("MCF8390 ColdFire NS8390 driver");
478MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
479MODULE_LICENSE("GPL");
480MODULE_ALIAS("platform:mcf8390");