1 /* $NetBSD: lance.c,v 1.4 2007/12/15 00:39:17 perry Exp $ */
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
42 /* Register Address Pointer */
43 #define LANCE_RAP ((volatile uint16_t *)0xbe400006)
44 /* Register Data Port */
45 #define LANCE_RDP ((volatile uint16_t *)0xbe400000)
49 #define TX_BUFSIZE 0x1000
50 #define RX_BUFSIZE 0x1000
53 struct lermd lermd
[RX_DESC_NUM
];
54 struct letmd letmd
[TX_DESC_NUM
];
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);
83 if (!lance_set_initblock(&lance_mem
.leinit
))
86 if (!lacne_do_initialize())
89 *LANCE_RDP
= LE_C0_STRT
;
95 lance_eaddr(uint8_t *p
)
99 for (i
= 0; i
< 6; i
++)
100 p
[i
] = lance_mem
.eaddr
[i
];
104 lance_get(void *data
, size_t len
)
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
;
118 for (i
= 0; i
< 8; i
++) {
119 rmd
= &lance_mem
.lermd
[(current
+ i
) & 0x7];
120 if (rmd
->rmd1_bits
& LE_R1_STP
)
122 if (rmd
->rmd1_bits
& LE_R1_ENP
) {
124 n
= rmd
->rmd3
; /* total amount of packet */
129 printf("%s: %d [%d,%d] %d\n", __func__
, len
, start
, end
, n
);
131 if (start
< 0 || end
< 0)
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
|
138 j
= i
== end
? n
: -rmd
->rmd2
;
139 for (k
= 0; k
< j
; k
++)
143 rmd
->rmd1_bits
= LE_R1_OWN
; /* return to LANCE */
145 current
= (current
+ i
) & 0x7;
151 lance_put(void *data
, size_t len
)
156 uint8_t *p
, *q
= data
;
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;
165 p
= (uint8_t *)((tmd
->tmd1_hadr
<< 16) | tmd
->tmd0
|
167 for (j
= 0; j
< n
; j
++)
171 tmd
->tmd2
= -max(n
, 64) | 0xf000;
173 tmd
->tmd2
= -n
| 0xf000;
177 tmd
->tmd1_bits
|= LE_T1_ENP
;
180 tmd
= &lance_mem
.letmd
[current
];
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
;
194 printf("Error. CSR0=%x\n", r
);
198 printf("Timeout CSR0=%x\n", r
);
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
);
219 lance_set_initblock(struct leinit
*leinit
)
221 uint16_t test_data
[] = { 0xffff, 0xaaaa, 0x5555, 0x0000 };
223 uint32_t addr
= (uint32_t)leinit
;
226 /* Control and status register */
227 for (i
= 3; i
>= 0; i
--) {
229 if ((*LANCE_RAP
& 3) != i
)
232 *LANCE_RDP
= LE_C0_STOP
; /* disable all external activity */
233 if (*LANCE_RDP
!= LE_C0_STOP
)
236 /* Low address of init block */
237 for (i
= 0; i
< 4; i
++) {
238 t
= test_data
[i
] & 0xfffe;
239 *LANCE_RAP
= LE_CSR1
;
244 *LANCE_RDP
= addr
& 0xfffe;
246 printf("initblock low addr=%x\n", *LANCE_RDP
);
249 /* High address of init block */
250 for (i
= 0; i
< 4; i
++) {
251 t
= test_data
[i
] & 0x00ff;
252 *LANCE_RAP
= LE_CSR2
;
257 *LANCE_RDP
= (addr
>> 16) & 0x00ff;
259 printf("initblock high addr=%x\n", *LANCE_RDP
);
262 /* Bus master and control */
263 *LANCE_RAP
= LE_CSR3
;
268 *LANCE_RAP
= LE_CSR3
;
273 *LANCE_RDP
= LE_C3_BSWP
| LE_C3_BCON
;
278 printf("LANCE register r/w error.\n");
283 lacne_do_initialize(void)
286 /* Initialze LANCE */
287 *LANCE_RAP
= LE_CSR0
;
288 *LANCE_RDP
= LE_C0_INEA
| LE_C0_INIT
;
291 if (!__poll_interrupt())
293 *LANCE_RDP
= *LANCE_RDP
;
301 struct leinit
*init
= &lance_mem
.leinit
;
302 struct lermd
*lermd
= lance_mem
.lermd
;
303 struct letmd
*letmd
= lance_mem
.letmd
;
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);
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);
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
;
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;
357 * Internal loopback test.
363 /* Internal loop back test. (no CRC) */
364 if (!lance_internal_loopback_test(false))
367 /* Internal loop back test. (with CRC) */
368 if (!lance_internal_loopback_test(true))
375 lance_internal_loopback_test(bool crc
)
378 lance_internal_loopback_setup(crc
);
380 if (!lance_set_initblock(&lance_mem
.leinit
))
383 if (!lacne_do_initialize())
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
);
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
;
403 memset(&lance_mem
, 0, sizeof lance_mem
);
406 init
->init_mode
= LE_C15_INTL
| LE_C15_LOOP
;
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);
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
;
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
;
446 lance_internal_loopback_testdata();
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 */
467 uint16_t *p
= (uint16_t *)lance_mem
.txdata
;
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 */
476 for (k
= 0; k
< 9; k
++) /* 18byte */
478 p
+= 16; /* 32byte skip */
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
;
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 */
495 if (!__poll_interrupt())
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
|
503 /* check Tx descriptor */
504 if (lance_mem
.letmd
[i
].tmd1_bits
& LE_T1_ERR
) {
505 printf("tx desc error.\n");
509 /* check Rx descriptor */
510 if (lance_mem
.lermd
[i
].rmd1_bits
& LE_R1_ERR
) {
511 printf("rx desc error.\n");
515 /* Compare transmitted data */
516 for (j
= 0; j
< 7; j
++) /* first 28byte */
518 printf("data error.\n");
524 printf("CRC=%x ", *p
);
525 if (*p
!= *q
) { /* CRC */
531 p
+= 9; /* 36byte skip */
536 printf("LANCE timeout.\n");
539 printf("LANCE Tx/Rx data error.\n");
542 printf("LANCE CRC error.\n");
547 __poll_interrupt(void)
551 for (j
= 0; j
< 0x10000; j
++) {
553 if (*(volatile uint32_t *)0xbe40a008 & 1)
557 printf ("interrupt timeout.\n");
565 __poll_lance_c0(uint16_t r
)
569 for (j
= 0; j
< 0x60000; j
++)
573 printf("lance CSR0 %x != %x\n", *LANCE_RDP
, r
);
577 *LANCE_RDP
= (LE_C0_RINT
| LE_C0_TINT
| LE_C0_INEA
) & r
;