Home | History | Annotate | Line # | Download | only in common
      1 /*	$NetBSD: lance.c,v 1.8 2021/12/05 03:04:41 msaitoh 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
     51 struct {
     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 
     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);
     64 
     65 void lance_setup(void);
     66 bool lance_set_initblock(struct leinit *);
     67 bool lance_do_initialize(void);
     68 
     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);
     76 
     77 bool
     78 lance_init(void)
     79 {
     80 
     81 	lance_setup();
     82 
     83 	if (!lance_set_initblock(&lance_mem.leinit))
     84 		return false;
     85 
     86 	if (!lance_do_initialize())
     87 		return false;
     88 
     89 	*LANCE_RDP = LE_C0_STRT;
     90 
     91 	return true;
     92 }
     93 
     94 void
     95 lance_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 
    103 bool
    104 lance_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 
    150 bool
    151 lance_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 = uimin(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 = -uimax(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 
    218 bool
    219 lance_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 
    282 bool
    283 lance_do_initialize(void)
    284 {
    285 
    286 	/* Initialize 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 
    298 void
    299 lance_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  */
    359 bool
    360 lance_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 
    374 bool
    375 lance_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 (!lance_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 
    394 void
    395 lance_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 
    449 void
    450 lance_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 
    483 bool
    484 lance_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 
    546 bool
    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 
    564 bool
    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