1/*	$NetBSD: lance.c,v 1.4 2007/12/15 00:39:17 perry 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 *
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.
30 */
31
32/* LANCE driver for EWS4800/360 */
33
34#include <lib/libsa/stand.h>
35#include <lib/libkern/libkern.h>
36
37#include <dev/ic/am7990reg.h>
38#include <dev/ic/lancereg.h>
39
40#include "local.h"
41
42/* Register Address Pointer */
43#define	LANCE_RAP	((volatile uint16_t *)0xbe400006)
44/* Register Data Port */
45#define	LANCE_RDP	((volatile uint16_t *)0xbe400000)
46
47#define	RX_DESC_NUM	8
48#define	TX_DESC_NUM	8
49#define	TX_BUFSIZE	0x1000
50#define	RX_BUFSIZE	0x1000
51struct {
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)));
59
60bool lance_init(void);
61void lance_eaddr(uint8_t *);
62bool lance_get(void *, size_t);
63bool lance_put(void *, size_t);
64
65void lance_setup(void);
66bool lance_set_initblock(struct leinit *);
67bool lacne_do_initialize(void);
68
69bool lance_test(void);
70bool lance_internal_loopback_test(bool);
71void lance_internal_loopback_setup(bool);
72void lance_internal_loopback_testdata(void);
73bool lance_internal_loopback_data_check(bool);
74bool __poll_interrupt(void);
75bool __poll_lance_c0(uint16_t);
76
77bool
78lance_init(void)
79{
80
81	lance_setup();
82
83	if (!lance_set_initblock(&lance_mem.leinit))
84		return false;
85
86	if (!lacne_do_initialize())
87		return false;
88
89	*LANCE_RDP = LE_C0_STRT;
90
91	return true;
92}
93
94void
95lance_eaddr(uint8_t *p)
96{
97	int i;
98
99	for (i = 0; i < 6; i++)
100		p[i] = lance_mem.eaddr[i];
101}
102
103bool
104lance_get(void *data, size_t len)
105{
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;
111
112	while ((*LANCE_RDP & (LE_C0_RINT | LE_C0_INTR)) == 0)
113		;
114	*LANCE_RDP = LE_C0_RINT;
115
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;
126		}
127	}
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;
133
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 */
144	}
145	current = (current + i) & 0x7;
146
147	return true;
148}
149
150bool
151lance_put(void *data, size_t len)
152{
153	static int current;
154	struct letmd *tmd;
155	uint16_t r;
156	uint8_t *p, *q = data;
157	int i, j, n, start;
158
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;
179		}
180		tmd = &lance_mem.letmd[current];
181	}
182
183	n = i + 1;
184
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;
196			}
197			if (j++ > 0xa0000) {
198				printf("Timeout CSR0=%x\n", r);
199				return false;
200			}
201		} while ((r & (LE_C0_TINT | LE_C0_INTR)) == 0);
202
203		*LANCE_RDP = LE_C0_TINT;
204	}
205
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;
211		}
212		*bits = 0;
213	}
214
215	return true;
216}
217
218bool
219lance_set_initblock(struct leinit *leinit)
220{
221	uint16_t test_data[] = { 0xffff, 0xaaaa, 0x5555, 0x0000 };
222	uint16_t t;
223	uint32_t addr = (uint32_t)leinit;
224	int i;
225
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;
231	}
232	*LANCE_RDP = LE_C0_STOP;	/* disable all external activity */
233	if (*LANCE_RDP != LE_C0_STOP)
234		goto reg_rw_error;
235
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;
243	}
244	*LANCE_RDP = addr & 0xfffe;
245#if DEBUG
246	printf("initblock low addr=%x\n", *LANCE_RDP);
247#endif
248
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;
256	}
257	*LANCE_RDP = (addr >> 16) & 0x00ff;
258#ifdef DEBUG
259	printf("initblock high addr=%x\n", *LANCE_RDP);
260#endif
261
262	/* Bus master and control */
263	*LANCE_RAP = LE_CSR3;
264	*LANCE_RDP = 7;
265	if (*LANCE_RDP != 7)
266		goto reg_rw_error;
267
268	*LANCE_RAP = LE_CSR3;
269	*LANCE_RDP = 0;
270	if (*LANCE_RDP != 0)
271		goto reg_rw_error;
272
273	*LANCE_RDP = LE_C3_BSWP | LE_C3_BCON;
274
275	return true;
276
277 reg_rw_error:
278	printf("LANCE register r/w error.\n");
279	return false;
280}
281
282bool
283lacne_do_initialize(void)
284{
285
286	/* Initialze LANCE */
287	*LANCE_RAP = LE_CSR0;
288	*LANCE_RDP = LE_C0_INEA | LE_C0_INIT;
289
290	/* Wait interrupt */
291	if (!__poll_interrupt())
292		return false;
293	*LANCE_RDP = *LANCE_RDP;
294
295	return true;
296}
297
298void
299lance_setup(void)
300{
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;
307
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);
313
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;
322
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);
328
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);
334
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;
343	}
344
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;
353	}
354}
355
356/*
357 * Internal loopback test.
358 */
359bool
360lance_test(void)
361{
362
363	/* Internal loop back test. (no CRC) */
364	if (!lance_internal_loopback_test(false))
365		return false;
366
367	/* Internal loop back test. (with CRC) */
368	if (!lance_internal_loopback_test(true))
369		return false;
370
371	return true;
372}
373
374bool
375lance_internal_loopback_test(bool crc)
376{
377
378	lance_internal_loopback_setup(crc);
379
380	if (!lance_set_initblock(&lance_mem.leinit))
381		return false;
382
383	if (!lacne_do_initialize())
384		return false;
385
386	/* Transmit Start */
387	*LANCE_RAP = LE_CSR0;	/* Control and status register */
388	*LANCE_RDP = LE_C0_INEA | LE_C0_STRT;
389
390	/* Check trasmited data. */
391	return lance_internal_loopback_data_check(crc);
392}
393
394void
395lance_internal_loopback_setup(bool crc)
396{
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;
402
403	memset(&lance_mem, 0, sizeof lance_mem);
404
405	/* Init block */
406	init->init_mode = LE_C15_INTL | LE_C15_LOOP;
407	if (!crc)
408		init->init_mode |= LE_C15_DXMTFCS;
409
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;
415
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);
422
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;
431	}
432
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;
444	}
445
446	lance_internal_loopback_testdata();
447}
448
449void
450lance_internal_loopback_testdata(void)
451{
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 */
461	};
462	uint16_t test_header[] = {
463		0x0000, 0x0084, 0x0000,	/* dst */
464		0x0000, 0x0084, 0x0000,	/* src */
465		0x000e
466	};
467	uint16_t *p = (uint16_t *)lance_mem.txdata;
468	int i, j, k;
469
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 */
479		}
480	}
481}
482
483bool
484lance_internal_loopback_data_check(bool crc_check)
485{
486	uint32_t *p = (uint32_t *)lance_mem.txdata;
487	uint32_t *q = (uint32_t *)lance_mem.rxdata;
488	int i, j;
489
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;
502
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;
507		}
508
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;
513		}
514
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;
520			}
521
522		/* check CRC */
523		if (crc_check) {
524			printf("CRC=%x ", *p);
525			if (*p != *q) {	/* CRC */
526				goto crc_error;
527			}
528		}
529		printf("ok.\n");
530
531		p += 9;	/* 36byte skip */
532		q += 9;
533	}
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;
544}
545
546bool
547__poll_interrupt(void)
548{
549	int j;
550
551	for (j = 0; j < 0x10000; j++) {
552		*LANCE_RAP;
553		if (*(volatile uint32_t *)0xbe40a008 & 1)
554			break;
555	}
556	if (j == 0x10000) {
557		printf ("interrupt timeout.\n");
558		return false;
559	}
560
561	return true;
562}
563
564bool
565__poll_lance_c0(uint16_t r)
566{
567	int j;
568
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;
575	}
576
577	*LANCE_RDP = (LE_C0_RINT | LE_C0_TINT| LE_C0_INEA) & r;
578
579	return true;
580}
581