Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / ews4800mips / stand / common / lance.c
blob70fd608f9dd1e52460a9abef2051ef09412b7c62
1 /* $NetBSD: lance.c,v 1.4 2007/12/15 00:39:17 perry Exp $ */
3 /*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 /* LANCE driver for EWS4800/360 */
34 #include <lib/libsa/stand.h>
35 #include <lib/libkern/libkern.h>
37 #include <dev/ic/am7990reg.h>
38 #include <dev/ic/lancereg.h>
40 #include "local.h"
42 /* Register Address Pointer */
43 #define LANCE_RAP ((volatile uint16_t *)0xbe400006)
44 /* Register Data Port */
45 #define LANCE_RDP ((volatile uint16_t *)0xbe400000)
47 #define RX_DESC_NUM 8
48 #define TX_DESC_NUM 8
49 #define TX_BUFSIZE 0x1000
50 #define RX_BUFSIZE 0x1000
51 struct {
52 struct leinit leinit;
53 struct lermd lermd[RX_DESC_NUM];
54 struct letmd letmd[TX_DESC_NUM];
55 uint8_t eaddr[6];
56 uint8_t txdata[TX_BUFSIZE] __attribute__((__aligned__(0x1000)));
57 uint8_t rxdata[RX_BUFSIZE] __attribute__((__aligned__(0x1000)));
58 } lance_mem __attribute__((__aligned__(64)));
60 bool lance_init(void);
61 void lance_eaddr(uint8_t *);
62 bool lance_get(void *, size_t);
63 bool lance_put(void *, size_t);
65 void lance_setup(void);
66 bool lance_set_initblock(struct leinit *);
67 bool lacne_do_initialize(void);
69 bool lance_test(void);
70 bool lance_internal_loopback_test(bool);
71 void lance_internal_loopback_setup(bool);
72 void lance_internal_loopback_testdata(void);
73 bool lance_internal_loopback_data_check(bool);
74 bool __poll_interrupt(void);
75 bool __poll_lance_c0(uint16_t);
77 bool
78 lance_init(void)
81 lance_setup();
83 if (!lance_set_initblock(&lance_mem.leinit))
84 return false;
86 if (!lacne_do_initialize())
87 return false;
89 *LANCE_RDP = LE_C0_STRT;
91 return true;
94 void
95 lance_eaddr(uint8_t *p)
97 int i;
99 for (i = 0; i < 6; i++)
100 p[i] = lance_mem.eaddr[i];
103 bool
104 lance_get(void *data, size_t len)
106 static int current;
107 struct lermd *rmd;
108 int i, j, k, n;
109 int start, end;
110 uint8_t *q, *p = data, *p_end = p + len;
112 while ((*LANCE_RDP & (LE_C0_RINT | LE_C0_INTR)) == 0)
114 *LANCE_RDP = LE_C0_RINT;
116 start = end = -1;
117 n = 0;
118 for (i = 0; i < 8; i++) {
119 rmd = &lance_mem.lermd[(current + i) & 0x7];
120 if (rmd->rmd1_bits & LE_R1_STP)
121 start = i;
122 if (rmd->rmd1_bits & LE_R1_ENP) {
123 end = i;
124 n = rmd->rmd3; /* total amount of packet */
125 break;
128 #ifdef DEBUG
129 printf("%s: %d [%d,%d] %d\n", __func__, len, start, end, n);
130 #endif
131 if (start < 0 || end < 0)
132 return false;
134 for (i = start; i <= end; i++) {
135 rmd = &lance_mem.lermd[(current + i) & 0x7];
136 q = (uint8_t *)((rmd->rmd1_hadr << 16) | rmd->rmd0 |
137 0xa0000000);
138 j = i == end ? n : -rmd->rmd2;
139 for (k = 0; k < j; k++)
140 if (p < p_end)
141 *p++ = *q++;
142 n -= j;
143 rmd->rmd1_bits = LE_R1_OWN; /* return to LANCE */
145 current = (current + i) & 0x7;
147 return true;
150 bool
151 lance_put(void *data, size_t len)
153 static int current;
154 struct letmd *tmd;
155 uint16_t r;
156 uint8_t *p, *q = data;
157 int i, j, n, start;
159 start = current;
160 tmd = &lance_mem.letmd[current];
161 tmd->tmd1_bits = LE_T1_STP;
162 for (i = 0; i < 8; i++) {
163 current = (current + 1) & 0x7;
164 n = min(len, 512);
165 p = (uint8_t *)((tmd->tmd1_hadr << 16) | tmd->tmd0 |
166 0xa0000000);
167 for (j = 0; j < n; j++)
168 *p++ = *q++;
169 len -= n;
170 #if 1
171 tmd->tmd2 = -max(n, 64) | 0xf000;
172 #else
173 tmd->tmd2 = -n | 0xf000;
174 #endif
175 tmd->tmd3 = 0;
176 if (len == 0) {
177 tmd->tmd1_bits |= LE_T1_ENP;
178 break;
180 tmd = &lance_mem.letmd[current];
183 n = i + 1;
185 for (i = 0; i < n; i++) {
186 tmd = &lance_mem.letmd[start + i];
187 *LANCE_RDP = LE_C0_INEA;
188 tmd->tmd1_bits |= LE_T1_OWN;
189 j = 0;
190 do {
191 *LANCE_RAP;
192 r = *LANCE_RDP;
193 if (r & LE_C0_ERR) {
194 printf("Error. CSR0=%x\n", r);
195 return false;
197 if (j++ > 0xa0000) {
198 printf("Timeout CSR0=%x\n", r);
199 return false;
201 } while ((r & (LE_C0_TINT | LE_C0_INTR)) == 0);
203 *LANCE_RDP = LE_C0_TINT;
206 for (i = 0; i < n; i++) {
207 uint8_t *bits = &lance_mem.letmd[i].tmd1_bits;
208 if (*bits & LE_T1_OWN || *bits & LE_T1_ERR) {
209 printf("desc%d not transmitted. cause=%x\n", i, *bits);
210 return false;
212 *bits = 0;
215 return true;
218 bool
219 lance_set_initblock(struct leinit *leinit)
221 uint16_t test_data[] = { 0xffff, 0xaaaa, 0x5555, 0x0000 };
222 uint16_t t;
223 uint32_t addr = (uint32_t)leinit;
224 int i;
226 /* Control and status register */
227 for (i = 3; i >= 0; i--) {
228 *LANCE_RAP = i;
229 if ((*LANCE_RAP & 3) != i)
230 goto reg_rw_error;
232 *LANCE_RDP = LE_C0_STOP; /* disable all external activity */
233 if (*LANCE_RDP != LE_C0_STOP)
234 goto reg_rw_error;
236 /* Low address of init block */
237 for (i = 0; i < 4; i++) {
238 t = test_data[i] & 0xfffe;
239 *LANCE_RAP = LE_CSR1;
240 *LANCE_RDP = t;
241 if (*LANCE_RDP != t)
242 goto reg_rw_error;
244 *LANCE_RDP = addr & 0xfffe;
245 #if DEBUG
246 printf("initblock low addr=%x\n", *LANCE_RDP);
247 #endif
249 /* High address of init block */
250 for (i = 0; i < 4; i++) {
251 t = test_data[i] & 0x00ff;
252 *LANCE_RAP = LE_CSR2;
253 *LANCE_RDP = t;
254 if (*LANCE_RDP != t)
255 goto reg_rw_error;
257 *LANCE_RDP = (addr >> 16) & 0x00ff;
258 #ifdef DEBUG
259 printf("initblock high addr=%x\n", *LANCE_RDP);
260 #endif
262 /* Bus master and control */
263 *LANCE_RAP = LE_CSR3;
264 *LANCE_RDP = 7;
265 if (*LANCE_RDP != 7)
266 goto reg_rw_error;
268 *LANCE_RAP = LE_CSR3;
269 *LANCE_RDP = 0;
270 if (*LANCE_RDP != 0)
271 goto reg_rw_error;
273 *LANCE_RDP = LE_C3_BSWP | LE_C3_BCON;
275 return true;
277 reg_rw_error:
278 printf("LANCE register r/w error.\n");
279 return false;
282 bool
283 lacne_do_initialize(void)
286 /* Initialze LANCE */
287 *LANCE_RAP = LE_CSR0;
288 *LANCE_RDP = LE_C0_INEA | LE_C0_INIT;
290 /* Wait interrupt */
291 if (!__poll_interrupt())
292 return false;
293 *LANCE_RDP = *LANCE_RDP;
295 return true;
298 void
299 lance_setup(void)
301 struct leinit *init = &lance_mem.leinit;
302 struct lermd *lermd = lance_mem.lermd;
303 struct letmd *letmd = lance_mem.letmd;
304 uint32_t addr;
305 uint8_t *eaddr;
306 int i;
308 memset(&lance_mem, 0, sizeof lance_mem);
309 /* Ethernet address from NVSRAM */
310 eaddr = lance_mem.eaddr;
311 for (i = 0; i < 6; i++)
312 eaddr[i] = *(uint8_t *)(0xbe491008 + i * 4);
314 /* Init block */
315 init->init_mode = 0;
316 init->init_padr[0] = (eaddr[1] << 8) | eaddr[0];
317 init->init_padr[1] = (eaddr[3] << 8) | eaddr[2];
318 init->init_padr[2] = (eaddr[5] << 8) | eaddr[4];
319 /* Logical address filter */
320 for (i = 0; i < 4; i++)
321 init->init_ladrf[i] = 0x0000;
323 /* Location of Rx descriptor ring */
324 addr = (uint32_t)lermd;
325 init->init_rdra = addr & 0xffff;
326 init->init_rlen = ((ffs(RX_DESC_NUM) - 1) << 13) |
327 ((addr >> 16) & 0xff);
329 /* Location of Tx descriptor ring */
330 addr = (uint32_t)letmd;
331 init->init_tdra = addr & 0xffff;
332 init->init_tlen = ((ffs(RX_DESC_NUM) - 1) << 13) |
333 ((addr >> 16) & 0xff);
335 /* Rx descriptor */
336 addr = (uint32_t)lance_mem.rxdata;
337 for (i = 0; i < RX_DESC_NUM; i++, lermd++) {
338 lermd->rmd0 = (addr & 0xffff) + i * 512; /* data block size */
339 lermd->rmd1_hadr = (addr >> 16) & 0xff;
340 lermd->rmd1_bits = LE_R1_OWN;
341 lermd->rmd2 = -512;
342 lermd->rmd3 = 0;
345 /* Tx descriptor */
346 addr = (uint32_t)lance_mem.txdata;
347 for (i = 0; i < TX_DESC_NUM; i++, letmd++) {
348 letmd->tmd0 = (addr & 0xffff) + i * 512; /* data block size */
349 letmd->tmd1_hadr = (addr >> 16) & 0xff;
350 letmd->tmd1_bits = 0;
351 letmd->tmd2 = 0;
352 letmd->tmd3 = 0;
357 * Internal loopback test.
359 bool
360 lance_test(void)
363 /* Internal loop back test. (no CRC) */
364 if (!lance_internal_loopback_test(false))
365 return false;
367 /* Internal loop back test. (with CRC) */
368 if (!lance_internal_loopback_test(true))
369 return false;
371 return true;
374 bool
375 lance_internal_loopback_test(bool crc)
378 lance_internal_loopback_setup(crc);
380 if (!lance_set_initblock(&lance_mem.leinit))
381 return false;
383 if (!lacne_do_initialize())
384 return false;
386 /* Transmit Start */
387 *LANCE_RAP = LE_CSR0; /* Control and status register */
388 *LANCE_RDP = LE_C0_INEA | LE_C0_STRT;
390 /* Check trasmited data. */
391 return lance_internal_loopback_data_check(crc);
394 void
395 lance_internal_loopback_setup(bool crc)
397 struct leinit *init = &lance_mem.leinit;
398 struct lermd *lermd = lance_mem.lermd;
399 struct letmd *letmd = lance_mem.letmd;
400 uint32_t addr;
401 int i;
403 memset(&lance_mem, 0, sizeof lance_mem);
405 /* Init block */
406 init->init_mode = LE_C15_INTL | LE_C15_LOOP;
407 if (!crc)
408 init->init_mode |= LE_C15_DXMTFCS;
410 init->init_padr[0] = 0x0000;
411 init->init_padr[1] = 0x8400;
412 init->init_padr[2] = 0x0000;
413 for (i = 0; i < 4; i++)
414 init->init_ladrf[i] = 0x0000;
416 addr = (uint32_t)lermd;
417 init->init_rdra = addr & 0xffff;
418 init->init_rlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff);
419 addr = (uint32_t)letmd;
420 init->init_tdra = addr & 0xffff;
421 init->init_tlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff);
423 /* Rx descriptor */
424 addr = (uint32_t)lance_mem.rxdata;
425 for (i = 0; i < RX_DESC_NUM; i++, lermd++) {
426 lermd->rmd0 = (addr & 0xffff) + i * 64; /* data block size */
427 lermd->rmd1_hadr = (addr >> 16) & 0xff;
428 lermd->rmd1_bits = LE_R1_OWN;
429 lermd->rmd2 = -64;
430 lermd->rmd3 = 0;
433 /* Tx descriptor */
434 addr = (uint32_t)lance_mem.txdata;
435 for (i = 0; i < TX_DESC_NUM; i++, letmd++) {
436 letmd->tmd0 = (addr & 0xffff) + i * 64; /* data block size */
437 letmd->tmd1_hadr = (addr >> 16) & 0xff;
438 letmd->tmd1_bits = LE_T1_STP | LE_T1_ENP;
439 if (crc)
440 letmd->tmd2 = -28;
441 else
442 letmd->tmd2 = -32;
443 letmd->tmd3 = 0;
446 lance_internal_loopback_testdata();
449 void
450 lance_internal_loopback_testdata(void)
452 uint16_t test_data[] = {
453 0x55aa, 0xff00, 0x0102, 0x0304, 0x0506, 0x0708, 0x0910,
454 0x40db, 0xdfcf, /* CRC */
455 0x23dc, 0x23dc, 0x1918, 0x1716, 0x1514, 0x1312, 0x1110,
456 0x7081, 0x90cb, /* CRC */
457 0x6699, 0xaa55, 0x0515, 0x2535, 0x4555, 0x6575, 0x8595,
458 0x55f6, 0xa448, /* CRC */
459 0x4e4e, 0x5a5a, 0x6969, 0x7878, 0x0f0f, 0x1e1e, 0x2d2d,
460 0xa548, 0x7404, /* CRC */
462 uint16_t test_header[] = {
463 0x0000, 0x0084, 0x0000, /* dst */
464 0x0000, 0x0084, 0x0000, /* src */
465 0x000e
467 uint16_t *p = (uint16_t *)lance_mem.txdata;
468 int i, j, k;
470 for (i = 0; i < 2; i++) { /* 64byte * 8 */
471 uint16_t *r = test_data;
472 for (j = 0; j < 4; j++) { /* 64byte * 4 */
473 uint16_t *q = test_header;
474 for (k = 0; k < 7; k++) /* 14byte */
475 *p++ = *q++;
476 for (k = 0; k < 9; k++) /* 18byte */
477 *p++ = *r++;
478 p += 16; /* 32byte skip */
483 bool
484 lance_internal_loopback_data_check(bool crc_check)
486 uint32_t *p = (uint32_t *)lance_mem.txdata;
487 uint32_t *q = (uint32_t *)lance_mem.rxdata;
488 int i, j;
490 /* Read all data block */
491 for (i = 0; i < 8; i++) {
492 printf("block %d ", i);
493 lance_mem.letmd[i].tmd1_bits |= LE_T1_OWN;/* buffer is filled */
494 /* wait interrupt */
495 if (!__poll_interrupt())
496 goto timeout_error;
497 /* wait LANCE status */
498 if (!__poll_lance_c0(LE_C0_RINT | LE_C0_TINT | LE_C0_INTR |
499 LE_C0_INEA | LE_C0_RXON | LE_C0_TXON | LE_C0_STRT |
500 LE_C0_INIT))
501 goto timeout_error;
503 /* check Tx descriptor */
504 if (lance_mem.letmd[i].tmd1_bits & LE_T1_ERR) {
505 printf("tx desc error.\n");
506 goto tx_rx_error;
509 /* check Rx descriptor */
510 if (lance_mem.lermd[i].rmd1_bits & LE_R1_ERR) {
511 printf("rx desc error.\n");
512 goto tx_rx_error;
515 /* Compare transmitted data */
516 for (j = 0; j < 7; j++) /* first 28byte */
517 if (*p++ != *q++) {
518 printf("data error.\n");
519 goto tx_rx_error;
522 /* check CRC */
523 if (crc_check) {
524 printf("CRC=%x ", *p);
525 if (*p != *q) { /* CRC */
526 goto crc_error;
529 printf("ok.\n");
531 p += 9; /* 36byte skip */
532 q += 9;
534 return true;
535 timeout_error:
536 printf("LANCE timeout.\n");
537 return false;
538 tx_rx_error:
539 printf("LANCE Tx/Rx data error.\n");
540 return false;
541 crc_error:
542 printf("LANCE CRC error.\n");
543 return false;
546 bool
547 __poll_interrupt(void)
549 int j;
551 for (j = 0; j < 0x10000; j++) {
552 *LANCE_RAP;
553 if (*(volatile uint32_t *)0xbe40a008 & 1)
554 break;
556 if (j == 0x10000) {
557 printf ("interrupt timeout.\n");
558 return false;
561 return true;
564 bool
565 __poll_lance_c0(uint16_t r)
567 int j;
569 for (j = 0; j < 0x60000; j++)
570 if (*LANCE_RDP == r)
571 break;
572 if (j == 0x60000) {
573 printf("lance CSR0 %x != %x\n", *LANCE_RDP, r);
574 return false;
577 *LANCE_RDP = (LE_C0_RINT | LE_C0_TINT| LE_C0_INEA) & r;
579 return true;