Home | History | Annotate | Line # | Download | only in common
lance.c revision 1.3.22.1
      1 /*	$NetBSD: lance.c,v 1.3.22.1 2008/01/09 01:45:58 matt 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", __func__, 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