lance.c revision 1.1.18.3 1 /* $NetBSD: lance.c,v 1.1.18.3 2007/02/26 09:06:31 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /* LANCE driver for EWS4800/360 */
40
41 #include <lib/libsa/stand.h>
42 #include <lib/libkern/libkern.h>
43
44 #include <dev/ic/am7990reg.h>
45 #include <dev/ic/lancereg.h>
46
47 #include "local.h"
48
49 /* Register Address Pointer */
50 #define LANCE_RAP ((volatile uint16_t *)0xbe400006)
51 /* Register Data Port */
52 #define LANCE_RDP ((volatile uint16_t *)0xbe400000)
53
54 #define RX_DESC_NUM 8
55 #define TX_DESC_NUM 8
56 #define TX_BUFSIZE 0x1000
57 #define RX_BUFSIZE 0x1000
58 struct {
59 struct leinit leinit;
60 struct lermd lermd[RX_DESC_NUM];
61 struct letmd letmd[TX_DESC_NUM];
62 uint8_t eaddr[6];
63 uint8_t txdata[TX_BUFSIZE] __attribute__((__aligned__(0x1000)));
64 uint8_t rxdata[RX_BUFSIZE] __attribute__((__aligned__(0x1000)));
65 } lance_mem __attribute__((__aligned__(64)));
66
67 bool lance_init(void);
68 void lance_eaddr(uint8_t *);
69 bool lance_get(void *, size_t);
70 bool lance_put(void *, size_t);
71
72 void lance_setup(void);
73 bool lance_set_initblock(struct leinit *);
74 bool lacne_do_initialize(void);
75
76 bool lance_test(void);
77 bool lance_internal_loopback_test(bool);
78 void lance_internal_loopback_setup(bool);
79 void lance_internal_loopback_testdata(void);
80 bool lance_internal_loopback_data_check(bool);
81 bool __poll_interrupt(void);
82 bool __poll_lance_c0(uint16_t);
83
84 bool
85 lance_init(void)
86 {
87
88 lance_setup();
89
90 if (!lance_set_initblock(&lance_mem.leinit))
91 return false;
92
93 if (!lacne_do_initialize())
94 return false;
95
96 *LANCE_RDP = LE_C0_STRT;
97
98 return true;
99 }
100
101 void
102 lance_eaddr(uint8_t *p)
103 {
104 int i;
105
106 for (i = 0; i < 6; i++)
107 p[i] = lance_mem.eaddr[i];
108 }
109
110 bool
111 lance_get(void *data, size_t len)
112 {
113 static int current;
114 struct lermd *rmd;
115 int i, j, k, n;
116 int start, end;
117 uint8_t *q, *p = data, *p_end = p + len;
118
119 while ((*LANCE_RDP & (LE_C0_RINT | LE_C0_INTR)) == 0)
120 ;
121 *LANCE_RDP = LE_C0_RINT;
122
123 start = end = -1;
124 n = 0;
125 for (i = 0; i < 8; i++) {
126 rmd = &lance_mem.lermd[(current + i) & 0x7];
127 if (rmd->rmd1_bits & LE_R1_STP)
128 start = i;
129 if (rmd->rmd1_bits & LE_R1_ENP) {
130 end = i;
131 n = rmd->rmd3; /* total amount of packet */
132 break;
133 }
134 }
135 #ifdef DEBUG
136 printf("%s: %d [%d,%d] %d\n", __FUNCTION__, len, start, end, n);
137 #endif
138 if (start < 0 || end < 0)
139 return false;
140
141 for (i = start; i <= end; i++) {
142 rmd = &lance_mem.lermd[(current + i) & 0x7];
143 q = (uint8_t *)((rmd->rmd1_hadr << 16) | rmd->rmd0 |
144 0xa0000000);
145 j = i == end ? n : -rmd->rmd2;
146 for (k = 0; k < j; k++)
147 if (p < p_end)
148 *p++ = *q++;
149 n -= j;
150 rmd->rmd1_bits = LE_R1_OWN; /* return to LANCE */
151 }
152 current = (current + i) & 0x7;
153
154 return true;
155 }
156
157 bool
158 lance_put(void *data, size_t len)
159 {
160 static int current;
161 struct letmd *tmd;
162 uint16_t r;
163 uint8_t *p, *q = data;
164 int i, j, n, start;
165
166 start = current;
167 tmd = &lance_mem.letmd[current];
168 tmd->tmd1_bits = LE_T1_STP;
169 for (i = 0; i < 8; i++) {
170 current = (current + 1) & 0x7;
171 n = min(len, 512);
172 p = (uint8_t *)((tmd->tmd1_hadr << 16) | tmd->tmd0 |
173 0xa0000000);
174 for (j = 0; j < n; j++)
175 *p++ = *q++;
176 len -= n;
177 #if 1
178 tmd->tmd2 = -max(n, 64) | 0xf000;
179 #else
180 tmd->tmd2 = -n | 0xf000;
181 #endif
182 tmd->tmd3 = 0;
183 if (len == 0) {
184 tmd->tmd1_bits |= LE_T1_ENP;
185 break;
186 }
187 tmd = &lance_mem.letmd[current];
188 }
189
190 n = i + 1;
191
192 for (i = 0; i < n; i++) {
193 tmd = &lance_mem.letmd[start + i];
194 *LANCE_RDP = LE_C0_INEA;
195 tmd->tmd1_bits |= LE_T1_OWN;
196 j = 0;
197 do {
198 *LANCE_RAP;
199 r = *LANCE_RDP;
200 if (r & LE_C0_ERR) {
201 printf("Error. CSR0=%x\n", r);
202 return false;
203 }
204 if (j++ > 0xa0000) {
205 printf("Timeout CSR0=%x\n", r);
206 return false;
207 }
208 } while ((r & (LE_C0_TINT | LE_C0_INTR)) == 0);
209
210 *LANCE_RDP = LE_C0_TINT;
211 }
212
213 for (i = 0; i < n; i++) {
214 uint8_t *bits = &lance_mem.letmd[i].tmd1_bits;
215 if (*bits & LE_T1_OWN || *bits & LE_T1_ERR) {
216 printf("desc%d not transmitted. cause=%x\n", i, *bits);
217 return false;
218 }
219 *bits = 0;
220 }
221
222 return true;
223 }
224
225 bool
226 lance_set_initblock(struct leinit *leinit)
227 {
228 uint16_t test_data[] = { 0xffff, 0xaaaa, 0x5555, 0x0000 };
229 uint16_t t;
230 uint32_t addr = (uint32_t)leinit;
231 int i;
232
233 /* Control and status register */
234 for (i = 3; i >= 0; i--) {
235 *LANCE_RAP = i;
236 if ((*LANCE_RAP & 3) != i)
237 goto reg_rw_error;
238 }
239 *LANCE_RDP = LE_C0_STOP; /* disable all external activity */
240 if (*LANCE_RDP != LE_C0_STOP)
241 goto reg_rw_error;
242
243 /* Low address of init block */
244 for (i = 0; i < 4; i++) {
245 t = test_data[i] & 0xfffe;
246 *LANCE_RAP = LE_CSR1;
247 *LANCE_RDP = t;
248 if (*LANCE_RDP != t)
249 goto reg_rw_error;
250 }
251 *LANCE_RDP = addr & 0xfffe;
252 #if DEBUG
253 printf("initblock low addr=%x\n", *LANCE_RDP);
254 #endif
255
256 /* High address of init block */
257 for (i = 0; i < 4; i++) {
258 t = test_data[i] & 0x00ff;
259 *LANCE_RAP = LE_CSR2;
260 *LANCE_RDP = t;
261 if (*LANCE_RDP != t)
262 goto reg_rw_error;
263 }
264 *LANCE_RDP = (addr >> 16) & 0x00ff;
265 #ifdef DEBUG
266 printf("initblock high addr=%x\n", *LANCE_RDP);
267 #endif
268
269 /* Bus master and control */
270 *LANCE_RAP = LE_CSR3;
271 *LANCE_RDP = 7;
272 if (*LANCE_RDP != 7)
273 goto reg_rw_error;
274
275 *LANCE_RAP = LE_CSR3;
276 *LANCE_RDP = 0;
277 if (*LANCE_RDP != 0)
278 goto reg_rw_error;
279
280 *LANCE_RDP = LE_C3_BSWP | LE_C3_BCON;
281
282 return true;
283
284 reg_rw_error:
285 printf("LANCE register r/w error.\n");
286 return false;
287 }
288
289 bool
290 lacne_do_initialize(void)
291 {
292
293 /* Initialze LANCE */
294 *LANCE_RAP = LE_CSR0;
295 *LANCE_RDP = LE_C0_INEA | LE_C0_INIT;
296
297 /* Wait interrupt */
298 if (!__poll_interrupt())
299 return false;
300 *LANCE_RDP = *LANCE_RDP;
301
302 return true;
303 }
304
305 void
306 lance_setup(void)
307 {
308 struct leinit *init = &lance_mem.leinit;
309 struct lermd *lermd = lance_mem.lermd;
310 struct letmd *letmd = lance_mem.letmd;
311 uint32_t addr;
312 uint8_t *eaddr;
313 int i;
314
315 memset(&lance_mem, 0, sizeof lance_mem);
316 /* Ethernet address from NVSRAM */
317 eaddr = lance_mem.eaddr;
318 for (i = 0; i < 6; i++)
319 eaddr[i] = *(uint8_t *)(0xbe491008 + i * 4);
320
321 /* Init block */
322 init->init_mode = 0;
323 init->init_padr[0] = (eaddr[1] << 8) | eaddr[0];
324 init->init_padr[1] = (eaddr[3] << 8) | eaddr[2];
325 init->init_padr[2] = (eaddr[5] << 8) | eaddr[4];
326 /* Logical address filter */
327 for (i = 0; i < 4; i++)
328 init->init_ladrf[i] = 0x0000;
329
330 /* Location of Rx descriptor ring */
331 addr = (uint32_t)lermd;
332 init->init_rdra = addr & 0xffff;
333 init->init_rlen = ((ffs(RX_DESC_NUM) - 1) << 13) |
334 ((addr >> 16) & 0xff);
335
336 /* Location of Tx descriptor ring */
337 addr = (uint32_t)letmd;
338 init->init_tdra = addr & 0xffff;
339 init->init_tlen = ((ffs(RX_DESC_NUM) - 1) << 13) |
340 ((addr >> 16) & 0xff);
341
342 /* Rx descriptor */
343 addr = (uint32_t)lance_mem.rxdata;
344 for (i = 0; i < RX_DESC_NUM; i++, lermd++) {
345 lermd->rmd0 = (addr & 0xffff) + i * 512; /* data block size */
346 lermd->rmd1_hadr = (addr >> 16) & 0xff;
347 lermd->rmd1_bits = LE_R1_OWN;
348 lermd->rmd2 = -512;
349 lermd->rmd3 = 0;
350 }
351
352 /* Tx descriptor */
353 addr = (uint32_t)lance_mem.txdata;
354 for (i = 0; i < TX_DESC_NUM; i++, letmd++) {
355 letmd->tmd0 = (addr & 0xffff) + i * 512; /* data block size */
356 letmd->tmd1_hadr = (addr >> 16) & 0xff;
357 letmd->tmd1_bits = 0;
358 letmd->tmd2 = 0;
359 letmd->tmd3 = 0;
360 }
361 }
362
363 /*
364 * Internal loopback test.
365 */
366 bool
367 lance_test(void)
368 {
369
370 /* Internal loop back test. (no CRC) */
371 if (!lance_internal_loopback_test(false))
372 return false;
373
374 /* Internal loop back test. (with CRC) */
375 if (!lance_internal_loopback_test(true))
376 return false;
377
378 return true;
379 }
380
381 bool
382 lance_internal_loopback_test(bool crc)
383 {
384
385 lance_internal_loopback_setup(crc);
386
387 if (!lance_set_initblock(&lance_mem.leinit))
388 return false;
389
390 if (!lacne_do_initialize())
391 return false;
392
393 /* Transmit Start */
394 *LANCE_RAP = LE_CSR0; /* Control and status register */
395 *LANCE_RDP = LE_C0_INEA | LE_C0_STRT;
396
397 /* Check trasmited data. */
398 return lance_internal_loopback_data_check(crc);
399 }
400
401 void
402 lance_internal_loopback_setup(bool crc)
403 {
404 struct leinit *init = &lance_mem.leinit;
405 struct lermd *lermd = lance_mem.lermd;
406 struct letmd *letmd = lance_mem.letmd;
407 uint32_t addr;
408 int i;
409
410 memset(&lance_mem, 0, sizeof lance_mem);
411
412 /* Init block */
413 init->init_mode = LE_C15_INTL | LE_C15_LOOP;
414 if (!crc)
415 init->init_mode |= LE_C15_DXMTFCS;
416
417 init->init_padr[0] = 0x0000;
418 init->init_padr[1] = 0x8400;
419 init->init_padr[2] = 0x0000;
420 for (i = 0; i < 4; i++)
421 init->init_ladrf[i] = 0x0000;
422
423 addr = (uint32_t)lermd;
424 init->init_rdra = addr & 0xffff;
425 init->init_rlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff);
426 addr = (uint32_t)letmd;
427 init->init_tdra = addr & 0xffff;
428 init->init_tlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff);
429
430 /* Rx descriptor */
431 addr = (uint32_t)lance_mem.rxdata;
432 for (i = 0; i < RX_DESC_NUM; i++, lermd++) {
433 lermd->rmd0 = (addr & 0xffff) + i * 64; /* data block size */
434 lermd->rmd1_hadr = (addr >> 16) & 0xff;
435 lermd->rmd1_bits = LE_R1_OWN;
436 lermd->rmd2 = -64;
437 lermd->rmd3 = 0;
438 }
439
440 /* Tx descriptor */
441 addr = (uint32_t)lance_mem.txdata;
442 for (i = 0; i < TX_DESC_NUM; i++, letmd++) {
443 letmd->tmd0 = (addr & 0xffff) + i * 64; /* data block size */
444 letmd->tmd1_hadr = (addr >> 16) & 0xff;
445 letmd->tmd1_bits = LE_T1_STP | LE_T1_ENP;
446 if (crc)
447 letmd->tmd2 = -28;
448 else
449 letmd->tmd2 = -32;
450 letmd->tmd3 = 0;
451 }
452
453 lance_internal_loopback_testdata();
454 }
455
456 void
457 lance_internal_loopback_testdata(void)
458 {
459 uint16_t test_data[] = {
460 0x55aa, 0xff00, 0x0102, 0x0304, 0x0506, 0x0708, 0x0910,
461 0x40db, 0xdfcf, /* CRC */
462 0x23dc, 0x23dc, 0x1918, 0x1716, 0x1514, 0x1312, 0x1110,
463 0x7081, 0x90cb, /* CRC */
464 0x6699, 0xaa55, 0x0515, 0x2535, 0x4555, 0x6575, 0x8595,
465 0x55f6, 0xa448, /* CRC */
466 0x4e4e, 0x5a5a, 0x6969, 0x7878, 0x0f0f, 0x1e1e, 0x2d2d,
467 0xa548, 0x7404, /* CRC */
468 };
469 uint16_t test_header[] = {
470 0x0000, 0x0084, 0x0000, /* dst */
471 0x0000, 0x0084, 0x0000, /* src */
472 0x000e
473 };
474 uint16_t *p = (uint16_t *)lance_mem.txdata;
475 int i, j, k;
476
477 for (i = 0; i < 2; i++) { /* 64byte * 8 */
478 uint16_t *r = test_data;
479 for (j = 0; j < 4; j++) { /* 64byte * 4 */
480 uint16_t *q = test_header;
481 for (k = 0; k < 7; k++) /* 14byte */
482 *p++ = *q++;
483 for (k = 0; k < 9; k++) /* 18byte */
484 *p++ = *r++;
485 p += 16; /* 32byte skip */
486 }
487 }
488 }
489
490 bool
491 lance_internal_loopback_data_check(bool crc_check)
492 {
493 uint32_t *p = (uint32_t *)lance_mem.txdata;
494 uint32_t *q = (uint32_t *)lance_mem.rxdata;
495 int i, j;
496
497 /* Read all data block */
498 for (i = 0; i < 8; i++) {
499 printf("block %d ", i);
500 lance_mem.letmd[i].tmd1_bits |= LE_T1_OWN;/* buffer is filled */
501 /* wait interrupt */
502 if (!__poll_interrupt())
503 goto timeout_error;
504 /* wait LANCE status */
505 if (!__poll_lance_c0(LE_C0_RINT | LE_C0_TINT | LE_C0_INTR |
506 LE_C0_INEA | LE_C0_RXON | LE_C0_TXON | LE_C0_STRT |
507 LE_C0_INIT))
508 goto timeout_error;
509
510 /* check Tx descriptor */
511 if (lance_mem.letmd[i].tmd1_bits & LE_T1_ERR) {
512 printf("tx desc error.\n");
513 goto tx_rx_error;
514 }
515
516 /* check Rx descriptor */
517 if (lance_mem.lermd[i].rmd1_bits & LE_R1_ERR) {
518 printf("rx desc error.\n");
519 goto tx_rx_error;
520 }
521
522 /* Compare transmitted data */
523 for (j = 0; j < 7; j++) /* first 28byte */
524 if (*p++ != *q++) {
525 printf("data error.\n");
526 goto tx_rx_error;
527 }
528
529 /* check CRC */
530 if (crc_check) {
531 printf("CRC=%x ", *p);
532 if (*p != *q) { /* CRC */
533 goto crc_error;
534 }
535 }
536 printf("ok.\n");
537
538 p += 9; /* 36byte skip */
539 q += 9;
540 }
541 return true;
542 timeout_error:
543 printf("LANCE timeout.\n");
544 return false;
545 tx_rx_error:
546 printf("LANCE Tx/Rx data error.\n");
547 return false;
548 crc_error:
549 printf("LANCE CRC error.\n");
550 return false;
551 }
552
553 bool
554 __poll_interrupt(void)
555 {
556 int j;
557
558 for (j = 0; j < 0x10000; j++) {
559 *LANCE_RAP;
560 if (*(volatile uint32_t *)0xbe40a008 & 1)
561 break;
562 }
563 if (j == 0x10000) {
564 printf ("interrupt timeout.\n");
565 return false;
566 }
567
568 return true;
569 }
570
571 bool
572 __poll_lance_c0(uint16_t r)
573 {
574 int j;
575
576 for (j = 0; j < 0x60000; j++)
577 if (*LANCE_RDP == r)
578 break;
579 if (j == 0x60000) {
580 printf("lance CSR0 %x != %x\n", *LANCE_RDP, r);
581 return false;
582 }
583
584 *LANCE_RDP = (LE_C0_RINT | LE_C0_TINT| LE_C0_INEA) & r;
585
586 return true;
587 }
588