xref: /netbsd-src/sys/arch/ews4800mips/stand/common/lance.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: lance.c,v 1.1 2005/12/29 15:20:09 tsutsui 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 boolean_t lance_init(void);
68 void lance_eaddr(uint8_t *);
69 boolean_t lance_get(void *, size_t);
70 boolean_t lance_put(void *, size_t);
71 
72 void lance_setup(void);
73 boolean_t lance_set_initblock(struct leinit *);
74 boolean_t lacne_do_initialize(void);
75 
76 boolean_t lance_test(void);
77 boolean_t lance_internal_loopback_test(boolean_t);
78 void lance_internal_loopback_setup(boolean_t);
79 void lance_internal_loopback_testdata(void);
80 boolean_t lance_internal_loopback_data_check(boolean_t);
81 boolean_t __poll_interrupt(void);
82 boolean_t __poll_lance_c0(uint16_t);
83 
84 boolean_t
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 boolean_t
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 boolean_t
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 boolean_t
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 boolean_t
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 boolean_t
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 boolean_t
382 lance_internal_loopback_test(boolean_t 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(boolean_t 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 boolean_t
491 lance_internal_loopback_data_check(boolean_t 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 boolean_t
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 boolean_t
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