Home | History | Annotate | Line # | Download | only in common
lance.c revision 1.5.44.1
      1  1.5.44.1      tls /*	$NetBSD: lance.c,v 1.5.44.1 2013/02/25 00:28:40 tls Exp $	*/
      2       1.1  tsutsui 
      3       1.1  tsutsui /*-
      4       1.1  tsutsui  * Copyright (c) 2004 The NetBSD Foundation, Inc.
      5       1.1  tsutsui  * All rights reserved.
      6       1.1  tsutsui  *
      7       1.1  tsutsui  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1  tsutsui  * by UCHIYAMA Yasushi.
      9       1.1  tsutsui  *
     10       1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
     11       1.1  tsutsui  * modification, are permitted provided that the following conditions
     12       1.1  tsutsui  * are met:
     13       1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
     14       1.1  tsutsui  *    notice, this list of conditions and the following disclaimer.
     15       1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
     18       1.1  tsutsui  *
     19       1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1  tsutsui  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1  tsutsui  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1  tsutsui  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1  tsutsui  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1  tsutsui  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1  tsutsui  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1  tsutsui  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1  tsutsui  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1  tsutsui  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1  tsutsui  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1  tsutsui  */
     31       1.1  tsutsui 
     32       1.1  tsutsui /* LANCE driver for EWS4800/360 */
     33       1.1  tsutsui 
     34       1.1  tsutsui #include <lib/libsa/stand.h>
     35       1.1  tsutsui #include <lib/libkern/libkern.h>
     36       1.1  tsutsui 
     37       1.1  tsutsui #include <dev/ic/am7990reg.h>
     38       1.1  tsutsui #include <dev/ic/lancereg.h>
     39       1.1  tsutsui 
     40       1.1  tsutsui #include "local.h"
     41       1.1  tsutsui 
     42       1.1  tsutsui /* Register Address Pointer */
     43       1.1  tsutsui #define	LANCE_RAP	((volatile uint16_t *)0xbe400006)
     44       1.1  tsutsui /* Register Data Port */
     45       1.1  tsutsui #define	LANCE_RDP	((volatile uint16_t *)0xbe400000)
     46       1.1  tsutsui 
     47       1.1  tsutsui #define	RX_DESC_NUM	8
     48       1.1  tsutsui #define	TX_DESC_NUM	8
     49       1.1  tsutsui #define	TX_BUFSIZE	0x1000
     50       1.1  tsutsui #define	RX_BUFSIZE	0x1000
     51       1.1  tsutsui struct {
     52       1.1  tsutsui 	struct leinit leinit;
     53       1.1  tsutsui 	struct lermd lermd[RX_DESC_NUM];
     54       1.1  tsutsui 	struct letmd letmd[TX_DESC_NUM];
     55       1.1  tsutsui 	uint8_t eaddr[6];
     56       1.1  tsutsui 	uint8_t txdata[TX_BUFSIZE] __attribute__((__aligned__(0x1000)));
     57       1.1  tsutsui 	uint8_t rxdata[RX_BUFSIZE] __attribute__((__aligned__(0x1000)));
     58       1.1  tsutsui } lance_mem __attribute__((__aligned__(64)));
     59       1.1  tsutsui 
     60       1.2  thorpej bool lance_init(void);
     61       1.1  tsutsui void lance_eaddr(uint8_t *);
     62       1.2  thorpej bool lance_get(void *, size_t);
     63       1.2  thorpej bool lance_put(void *, size_t);
     64       1.1  tsutsui 
     65       1.1  tsutsui void lance_setup(void);
     66       1.2  thorpej bool lance_set_initblock(struct leinit *);
     67  1.5.44.1      tls bool lance_do_initialize(void);
     68       1.1  tsutsui 
     69       1.2  thorpej bool lance_test(void);
     70       1.2  thorpej bool lance_internal_loopback_test(bool);
     71       1.2  thorpej void lance_internal_loopback_setup(bool);
     72       1.1  tsutsui void lance_internal_loopback_testdata(void);
     73       1.2  thorpej bool lance_internal_loopback_data_check(bool);
     74       1.2  thorpej bool __poll_interrupt(void);
     75       1.2  thorpej bool __poll_lance_c0(uint16_t);
     76       1.1  tsutsui 
     77       1.2  thorpej bool
     78       1.1  tsutsui lance_init(void)
     79       1.1  tsutsui {
     80       1.1  tsutsui 
     81       1.1  tsutsui 	lance_setup();
     82       1.1  tsutsui 
     83       1.1  tsutsui 	if (!lance_set_initblock(&lance_mem.leinit))
     84       1.3  thorpej 		return false;
     85       1.1  tsutsui 
     86  1.5.44.1      tls 	if (!lance_do_initialize())
     87       1.3  thorpej 		return false;
     88       1.1  tsutsui 
     89       1.1  tsutsui 	*LANCE_RDP = LE_C0_STRT;
     90       1.1  tsutsui 
     91       1.3  thorpej 	return true;
     92       1.1  tsutsui }
     93       1.1  tsutsui 
     94       1.1  tsutsui void
     95       1.1  tsutsui lance_eaddr(uint8_t *p)
     96       1.1  tsutsui {
     97       1.1  tsutsui 	int i;
     98       1.1  tsutsui 
     99       1.1  tsutsui 	for (i = 0; i < 6; i++)
    100       1.1  tsutsui 		p[i] = lance_mem.eaddr[i];
    101       1.1  tsutsui }
    102       1.1  tsutsui 
    103       1.2  thorpej bool
    104       1.1  tsutsui lance_get(void *data, size_t len)
    105       1.1  tsutsui {
    106       1.1  tsutsui 	static int current;
    107       1.1  tsutsui 	struct lermd *rmd;
    108       1.1  tsutsui 	int i, j, k, n;
    109       1.1  tsutsui 	int start, end;
    110       1.1  tsutsui 	uint8_t *q, *p = data, *p_end = p + len;
    111       1.1  tsutsui 
    112       1.1  tsutsui 	while ((*LANCE_RDP & (LE_C0_RINT | LE_C0_INTR)) == 0)
    113       1.1  tsutsui 		;
    114       1.1  tsutsui 	*LANCE_RDP = LE_C0_RINT;
    115       1.1  tsutsui 
    116       1.1  tsutsui 	start = end = -1;
    117       1.1  tsutsui 	n = 0;
    118       1.1  tsutsui 	for (i = 0; i < 8; i++) {
    119       1.1  tsutsui 		rmd = &lance_mem.lermd[(current + i) & 0x7];
    120       1.1  tsutsui 		if (rmd->rmd1_bits & LE_R1_STP)
    121       1.1  tsutsui 			start = i;
    122       1.1  tsutsui 		if (rmd->rmd1_bits & LE_R1_ENP) {
    123       1.1  tsutsui 			end = i;
    124       1.1  tsutsui 			n = rmd->rmd3;		/* total amount of packet */
    125       1.1  tsutsui 			break;
    126       1.1  tsutsui 		}
    127       1.1  tsutsui 	}
    128       1.1  tsutsui #ifdef DEBUG
    129       1.4    perry 	printf("%s: %d [%d,%d] %d\n", __func__, len, start, end, n);
    130       1.1  tsutsui #endif
    131       1.1  tsutsui 	if (start < 0 || end < 0)
    132       1.3  thorpej 		return false;
    133       1.1  tsutsui 
    134       1.1  tsutsui 	for (i = start; i <= end; i++) {
    135       1.1  tsutsui 		rmd = &lance_mem.lermd[(current + i) & 0x7];
    136       1.1  tsutsui 		q = (uint8_t *)((rmd->rmd1_hadr << 16) | rmd->rmd0 |
    137       1.1  tsutsui 		    0xa0000000);
    138       1.1  tsutsui 		j = i == end ? n : -rmd->rmd2;
    139       1.1  tsutsui 		for (k = 0; k < j; k++)
    140       1.1  tsutsui 			if (p < p_end)
    141       1.1  tsutsui 				*p++ = *q++;
    142       1.1  tsutsui 		n -= j;
    143       1.1  tsutsui 		rmd->rmd1_bits = LE_R1_OWN;	/* return to LANCE */
    144       1.1  tsutsui 	}
    145       1.1  tsutsui 	current = (current + i) & 0x7;
    146       1.1  tsutsui 
    147       1.3  thorpej 	return true;
    148       1.1  tsutsui }
    149       1.1  tsutsui 
    150       1.2  thorpej bool
    151       1.1  tsutsui lance_put(void *data, size_t len)
    152       1.1  tsutsui {
    153       1.1  tsutsui 	static int current;
    154       1.1  tsutsui 	struct letmd *tmd;
    155       1.1  tsutsui 	uint16_t r;
    156       1.1  tsutsui 	uint8_t *p, *q = data;
    157       1.1  tsutsui 	int i, j, n, start;
    158       1.1  tsutsui 
    159       1.1  tsutsui 	start = current;
    160       1.1  tsutsui 	tmd = &lance_mem.letmd[current];
    161       1.1  tsutsui 	tmd->tmd1_bits = LE_T1_STP;
    162       1.1  tsutsui 	for (i = 0; i < 8; i++) {
    163       1.1  tsutsui 		current = (current + 1) & 0x7;
    164       1.1  tsutsui 		n = min(len, 512);
    165       1.1  tsutsui 		p = (uint8_t *)((tmd->tmd1_hadr << 16) | tmd->tmd0 |
    166       1.1  tsutsui 		    0xa0000000);
    167       1.1  tsutsui 		for (j = 0; j < n; j++)
    168       1.1  tsutsui 			*p++ = *q++;
    169       1.1  tsutsui 		len -= n;
    170       1.1  tsutsui #if 1
    171       1.1  tsutsui 		tmd->tmd2 = -max(n, 64) | 0xf000;
    172       1.1  tsutsui #else
    173       1.1  tsutsui 		tmd->tmd2 = -n | 0xf000;
    174       1.1  tsutsui #endif
    175       1.1  tsutsui 		tmd->tmd3 = 0;
    176       1.1  tsutsui 		if (len == 0) {
    177       1.1  tsutsui 			tmd->tmd1_bits |= LE_T1_ENP;
    178       1.1  tsutsui 			break;
    179       1.1  tsutsui 		}
    180       1.1  tsutsui 		tmd = &lance_mem.letmd[current];
    181       1.1  tsutsui 	}
    182       1.1  tsutsui 
    183       1.1  tsutsui 	n = i + 1;
    184       1.1  tsutsui 
    185       1.1  tsutsui 	for (i = 0; i < n; i++) {
    186       1.1  tsutsui 		tmd = &lance_mem.letmd[start + i];
    187       1.1  tsutsui 		*LANCE_RDP = LE_C0_INEA;
    188       1.1  tsutsui 		tmd->tmd1_bits |= LE_T1_OWN;
    189       1.1  tsutsui 		j = 0;
    190       1.1  tsutsui 		do {
    191       1.1  tsutsui 			*LANCE_RAP;
    192       1.1  tsutsui 			r = *LANCE_RDP;
    193       1.1  tsutsui 			if (r & LE_C0_ERR) {
    194       1.1  tsutsui 				printf("Error. CSR0=%x\n", r);
    195       1.3  thorpej 				return false;
    196       1.1  tsutsui 			}
    197       1.1  tsutsui 			if (j++ > 0xa0000) {
    198       1.1  tsutsui 				printf("Timeout CSR0=%x\n", r);
    199       1.3  thorpej 				return false;
    200       1.1  tsutsui 			}
    201       1.1  tsutsui 		} while ((r & (LE_C0_TINT | LE_C0_INTR)) == 0);
    202       1.1  tsutsui 
    203       1.1  tsutsui 		*LANCE_RDP = LE_C0_TINT;
    204       1.1  tsutsui 	}
    205       1.1  tsutsui 
    206       1.1  tsutsui 	for (i = 0; i < n; i++) {
    207       1.1  tsutsui 		uint8_t *bits = &lance_mem.letmd[i].tmd1_bits;
    208       1.1  tsutsui 		if (*bits & LE_T1_OWN || *bits & LE_T1_ERR) {
    209       1.1  tsutsui 			printf("desc%d not transmitted. cause=%x\n", i, *bits);
    210       1.3  thorpej 			return false;
    211       1.1  tsutsui 		}
    212       1.1  tsutsui 		*bits = 0;
    213       1.1  tsutsui 	}
    214       1.1  tsutsui 
    215       1.3  thorpej 	return true;
    216       1.1  tsutsui }
    217       1.1  tsutsui 
    218       1.2  thorpej bool
    219       1.1  tsutsui lance_set_initblock(struct leinit *leinit)
    220       1.1  tsutsui {
    221       1.1  tsutsui 	uint16_t test_data[] = { 0xffff, 0xaaaa, 0x5555, 0x0000 };
    222       1.1  tsutsui 	uint16_t t;
    223       1.1  tsutsui 	uint32_t addr = (uint32_t)leinit;
    224       1.1  tsutsui 	int i;
    225       1.1  tsutsui 
    226       1.1  tsutsui 	/* Control and status register */
    227       1.1  tsutsui 	for (i = 3; i >= 0; i--) {
    228       1.1  tsutsui 		*LANCE_RAP = i;
    229       1.1  tsutsui 		if ((*LANCE_RAP & 3) != i)
    230       1.1  tsutsui 			goto reg_rw_error;
    231       1.1  tsutsui 	}
    232       1.1  tsutsui 	*LANCE_RDP = LE_C0_STOP;	/* disable all external activity */
    233       1.1  tsutsui 	if (*LANCE_RDP != LE_C0_STOP)
    234       1.1  tsutsui 		goto reg_rw_error;
    235       1.1  tsutsui 
    236       1.1  tsutsui 	/* Low address of init block */
    237       1.1  tsutsui 	for (i = 0; i < 4; i++) {
    238       1.1  tsutsui 		t = test_data[i] & 0xfffe;
    239       1.1  tsutsui 		*LANCE_RAP = LE_CSR1;
    240       1.1  tsutsui 		*LANCE_RDP = t;
    241       1.1  tsutsui 		if (*LANCE_RDP != t)
    242       1.1  tsutsui 			goto reg_rw_error;
    243       1.1  tsutsui 	}
    244       1.1  tsutsui 	*LANCE_RDP = addr & 0xfffe;
    245       1.1  tsutsui #if DEBUG
    246       1.1  tsutsui 	printf("initblock low addr=%x\n", *LANCE_RDP);
    247       1.1  tsutsui #endif
    248       1.1  tsutsui 
    249       1.1  tsutsui 	/* High address of init block */
    250       1.1  tsutsui 	for (i = 0; i < 4; i++) {
    251       1.1  tsutsui 		t = test_data[i] & 0x00ff;
    252       1.1  tsutsui 		*LANCE_RAP = LE_CSR2;
    253       1.1  tsutsui 		*LANCE_RDP = t;
    254       1.1  tsutsui 		if (*LANCE_RDP != t)
    255       1.1  tsutsui 			goto reg_rw_error;
    256       1.1  tsutsui 	}
    257       1.1  tsutsui 	*LANCE_RDP = (addr >> 16) & 0x00ff;
    258       1.1  tsutsui #ifdef DEBUG
    259       1.1  tsutsui 	printf("initblock high addr=%x\n", *LANCE_RDP);
    260       1.1  tsutsui #endif
    261       1.1  tsutsui 
    262       1.1  tsutsui 	/* Bus master and control */
    263       1.1  tsutsui 	*LANCE_RAP = LE_CSR3;
    264       1.1  tsutsui 	*LANCE_RDP = 7;
    265       1.1  tsutsui 	if (*LANCE_RDP != 7)
    266       1.1  tsutsui 		goto reg_rw_error;
    267       1.1  tsutsui 
    268       1.1  tsutsui 	*LANCE_RAP = LE_CSR3;
    269       1.1  tsutsui 	*LANCE_RDP = 0;
    270       1.1  tsutsui 	if (*LANCE_RDP != 0)
    271       1.1  tsutsui 		goto reg_rw_error;
    272       1.1  tsutsui 
    273       1.1  tsutsui 	*LANCE_RDP = LE_C3_BSWP | LE_C3_BCON;
    274       1.1  tsutsui 
    275       1.3  thorpej 	return true;
    276       1.1  tsutsui 
    277       1.1  tsutsui  reg_rw_error:
    278       1.1  tsutsui 	printf("LANCE register r/w error.\n");
    279       1.3  thorpej 	return false;
    280       1.1  tsutsui }
    281       1.1  tsutsui 
    282       1.2  thorpej bool
    283  1.5.44.1      tls lance_do_initialize(void)
    284       1.1  tsutsui {
    285       1.1  tsutsui 
    286       1.1  tsutsui 	/* Initialze LANCE */
    287       1.1  tsutsui 	*LANCE_RAP = LE_CSR0;
    288       1.1  tsutsui 	*LANCE_RDP = LE_C0_INEA | LE_C0_INIT;
    289       1.1  tsutsui 
    290       1.1  tsutsui 	/* Wait interrupt */
    291       1.1  tsutsui 	if (!__poll_interrupt())
    292       1.3  thorpej 		return false;
    293       1.1  tsutsui 	*LANCE_RDP = *LANCE_RDP;
    294       1.1  tsutsui 
    295       1.3  thorpej 	return true;
    296       1.1  tsutsui }
    297       1.1  tsutsui 
    298       1.1  tsutsui void
    299       1.1  tsutsui lance_setup(void)
    300       1.1  tsutsui {
    301       1.1  tsutsui 	struct leinit *init = &lance_mem.leinit;
    302       1.1  tsutsui 	struct lermd *lermd = lance_mem.lermd;
    303       1.1  tsutsui 	struct letmd *letmd = lance_mem.letmd;
    304       1.1  tsutsui 	uint32_t addr;
    305       1.1  tsutsui 	uint8_t *eaddr;
    306       1.1  tsutsui 	int i;
    307       1.1  tsutsui 
    308       1.1  tsutsui 	memset(&lance_mem, 0, sizeof lance_mem);
    309       1.1  tsutsui 	/* Ethernet address from NVSRAM */
    310       1.1  tsutsui 	eaddr = lance_mem.eaddr;
    311       1.1  tsutsui 	for (i = 0; i < 6; i++)
    312       1.1  tsutsui 		eaddr[i] = *(uint8_t *)(0xbe491008 + i * 4);
    313       1.1  tsutsui 
    314       1.1  tsutsui 	/* Init block */
    315       1.1  tsutsui 	init->init_mode = 0;
    316       1.1  tsutsui 	init->init_padr[0] = (eaddr[1] << 8) | eaddr[0];
    317       1.1  tsutsui 	init->init_padr[1] = (eaddr[3] << 8) | eaddr[2];
    318       1.1  tsutsui 	init->init_padr[2] = (eaddr[5] << 8) | eaddr[4];
    319       1.1  tsutsui 	/* Logical address filter */
    320       1.1  tsutsui 	for (i = 0; i < 4; i++)
    321       1.1  tsutsui 		init->init_ladrf[i] = 0x0000;
    322       1.1  tsutsui 
    323       1.1  tsutsui 	/* Location of Rx descriptor ring */
    324       1.1  tsutsui 	addr = (uint32_t)lermd;
    325       1.1  tsutsui 	init->init_rdra = addr & 0xffff;
    326       1.1  tsutsui 	init->init_rlen = ((ffs(RX_DESC_NUM) - 1) << 13) |
    327       1.1  tsutsui 	    ((addr >> 16) & 0xff);
    328       1.1  tsutsui 
    329       1.1  tsutsui 	/* Location of Tx descriptor ring */
    330       1.1  tsutsui 	addr = (uint32_t)letmd;
    331       1.1  tsutsui 	init->init_tdra = addr & 0xffff;
    332       1.1  tsutsui 	init->init_tlen = ((ffs(RX_DESC_NUM) - 1) << 13) |
    333       1.1  tsutsui 	    ((addr >> 16) & 0xff);
    334       1.1  tsutsui 
    335       1.1  tsutsui 	/* Rx descriptor */
    336       1.1  tsutsui 	addr = (uint32_t)lance_mem.rxdata;
    337       1.1  tsutsui 	for (i = 0; i < RX_DESC_NUM; i++, lermd++) {
    338       1.1  tsutsui 		lermd->rmd0 = (addr & 0xffff) +  i * 512; /* data block size */
    339       1.1  tsutsui 		lermd->rmd1_hadr = (addr >> 16) & 0xff;
    340       1.1  tsutsui 		lermd->rmd1_bits = LE_R1_OWN;
    341       1.1  tsutsui 		lermd->rmd2 = -512;
    342       1.1  tsutsui 		lermd->rmd3 = 0;
    343       1.1  tsutsui 	}
    344       1.1  tsutsui 
    345       1.1  tsutsui 	/* Tx descriptor */
    346       1.1  tsutsui 	addr = (uint32_t)lance_mem.txdata;
    347       1.1  tsutsui 	for (i = 0; i < TX_DESC_NUM; i++, letmd++) {
    348       1.1  tsutsui 		letmd->tmd0 = (addr & 0xffff) + i * 512; /* data block size */
    349       1.1  tsutsui 		letmd->tmd1_hadr = (addr >> 16) & 0xff;
    350       1.1  tsutsui 		letmd->tmd1_bits = 0;
    351       1.1  tsutsui 		letmd->tmd2 = 0;
    352       1.1  tsutsui 		letmd->tmd3 = 0;
    353       1.1  tsutsui 	}
    354       1.1  tsutsui }
    355       1.1  tsutsui 
    356       1.1  tsutsui /*
    357       1.1  tsutsui  * Internal loopback test.
    358       1.1  tsutsui  */
    359       1.2  thorpej bool
    360       1.1  tsutsui lance_test(void)
    361       1.1  tsutsui {
    362       1.1  tsutsui 
    363       1.1  tsutsui 	/* Internal loop back test. (no CRC) */
    364       1.3  thorpej 	if (!lance_internal_loopback_test(false))
    365       1.3  thorpej 		return false;
    366       1.1  tsutsui 
    367       1.1  tsutsui 	/* Internal loop back test. (with CRC) */
    368       1.3  thorpej 	if (!lance_internal_loopback_test(true))
    369       1.3  thorpej 		return false;
    370       1.1  tsutsui 
    371       1.3  thorpej 	return true;
    372       1.1  tsutsui }
    373       1.1  tsutsui 
    374       1.2  thorpej bool
    375       1.2  thorpej lance_internal_loopback_test(bool crc)
    376       1.1  tsutsui {
    377       1.1  tsutsui 
    378       1.1  tsutsui 	lance_internal_loopback_setup(crc);
    379       1.1  tsutsui 
    380       1.1  tsutsui 	if (!lance_set_initblock(&lance_mem.leinit))
    381       1.3  thorpej 		return false;
    382       1.1  tsutsui 
    383  1.5.44.1      tls 	if (!lance_do_initialize())
    384       1.3  thorpej 		return false;
    385       1.1  tsutsui 
    386       1.1  tsutsui 	/* Transmit Start */
    387       1.1  tsutsui 	*LANCE_RAP = LE_CSR0;	/* Control and status register */
    388       1.1  tsutsui 	*LANCE_RDP = LE_C0_INEA | LE_C0_STRT;
    389       1.1  tsutsui 
    390       1.1  tsutsui 	/* Check trasmited data. */
    391       1.1  tsutsui 	return lance_internal_loopback_data_check(crc);
    392       1.1  tsutsui }
    393       1.1  tsutsui 
    394       1.1  tsutsui void
    395       1.2  thorpej lance_internal_loopback_setup(bool crc)
    396       1.1  tsutsui {
    397       1.1  tsutsui 	struct leinit *init = &lance_mem.leinit;
    398       1.1  tsutsui 	struct lermd *lermd = lance_mem.lermd;
    399       1.1  tsutsui 	struct letmd *letmd = lance_mem.letmd;
    400       1.1  tsutsui 	uint32_t addr;
    401       1.1  tsutsui 	int i;
    402       1.1  tsutsui 
    403       1.1  tsutsui 	memset(&lance_mem, 0, sizeof lance_mem);
    404       1.1  tsutsui 
    405       1.1  tsutsui 	/* Init block */
    406       1.1  tsutsui 	init->init_mode = LE_C15_INTL | LE_C15_LOOP;
    407       1.1  tsutsui 	if (!crc)
    408       1.1  tsutsui 		init->init_mode |= LE_C15_DXMTFCS;
    409       1.1  tsutsui 
    410       1.1  tsutsui 	init->init_padr[0] = 0x0000;
    411       1.1  tsutsui 	init->init_padr[1] = 0x8400;
    412       1.1  tsutsui 	init->init_padr[2] = 0x0000;
    413       1.1  tsutsui 	for (i = 0; i < 4; i++)
    414       1.1  tsutsui 		init->init_ladrf[i] = 0x0000;
    415       1.1  tsutsui 
    416       1.1  tsutsui 	addr = (uint32_t)lermd;
    417       1.1  tsutsui 	init->init_rdra = addr & 0xffff;
    418       1.1  tsutsui 	init->init_rlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff);
    419       1.1  tsutsui 	addr = (uint32_t)letmd;
    420       1.1  tsutsui 	init->init_tdra = addr & 0xffff;
    421       1.1  tsutsui 	init->init_tlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff);
    422       1.1  tsutsui 
    423       1.1  tsutsui 	/* Rx descriptor */
    424       1.1  tsutsui 	addr = (uint32_t)lance_mem.rxdata;
    425       1.1  tsutsui 	for (i = 0; i < RX_DESC_NUM; i++, lermd++) {
    426       1.1  tsutsui 		lermd->rmd0 = (addr & 0xffff) +  i * 64; /* data block size */
    427       1.1  tsutsui 		lermd->rmd1_hadr = (addr >> 16) & 0xff;
    428       1.1  tsutsui 		lermd->rmd1_bits = LE_R1_OWN;
    429       1.1  tsutsui 		lermd->rmd2 = -64;
    430       1.1  tsutsui 		lermd->rmd3 = 0;
    431       1.1  tsutsui 	}
    432       1.1  tsutsui 
    433       1.1  tsutsui 	/* Tx descriptor */
    434       1.1  tsutsui 	addr = (uint32_t)lance_mem.txdata;
    435       1.1  tsutsui 	for (i = 0; i < TX_DESC_NUM; i++, letmd++) {
    436       1.1  tsutsui 		letmd->tmd0 = (addr & 0xffff) + i * 64;	/* data block size */
    437       1.1  tsutsui 		letmd->tmd1_hadr = (addr >> 16) & 0xff;
    438       1.1  tsutsui 		letmd->tmd1_bits = LE_T1_STP | LE_T1_ENP;
    439       1.1  tsutsui 		if (crc)
    440       1.1  tsutsui 			letmd->tmd2 = -28;
    441       1.1  tsutsui 		else
    442       1.1  tsutsui 			letmd->tmd2 = -32;
    443       1.1  tsutsui 		letmd->tmd3 = 0;
    444       1.1  tsutsui 	}
    445       1.1  tsutsui 
    446       1.1  tsutsui 	lance_internal_loopback_testdata();
    447       1.1  tsutsui }
    448       1.1  tsutsui 
    449       1.1  tsutsui void
    450       1.1  tsutsui lance_internal_loopback_testdata(void)
    451       1.1  tsutsui {
    452       1.1  tsutsui 	uint16_t test_data[] = {
    453       1.1  tsutsui 		0x55aa, 0xff00, 0x0102, 0x0304, 0x0506, 0x0708, 0x0910,
    454       1.1  tsutsui 		0x40db, 0xdfcf, /* CRC */
    455       1.1  tsutsui 		0x23dc, 0x23dc, 0x1918, 0x1716, 0x1514, 0x1312, 0x1110,
    456       1.1  tsutsui 		0x7081, 0x90cb, /* CRC */
    457       1.1  tsutsui 		0x6699, 0xaa55, 0x0515, 0x2535, 0x4555, 0x6575,	0x8595,
    458       1.1  tsutsui 		0x55f6, 0xa448, /* CRC */
    459       1.1  tsutsui 		0x4e4e, 0x5a5a, 0x6969, 0x7878, 0x0f0f,	0x1e1e, 0x2d2d,
    460       1.1  tsutsui 		0xa548, 0x7404, /* CRC */
    461       1.1  tsutsui 	};
    462       1.1  tsutsui 	uint16_t test_header[] = {
    463       1.1  tsutsui 		0x0000, 0x0084, 0x0000,	/* dst */
    464       1.1  tsutsui 		0x0000, 0x0084, 0x0000,	/* src */
    465       1.1  tsutsui 		0x000e
    466       1.1  tsutsui 	};
    467       1.1  tsutsui 	uint16_t *p = (uint16_t *)lance_mem.txdata;
    468       1.1  tsutsui 	int i, j, k;
    469       1.1  tsutsui 
    470       1.1  tsutsui 	for (i = 0; i < 2; i++) {			/* 64byte * 8 */
    471       1.1  tsutsui 		uint16_t *r = test_data;
    472       1.1  tsutsui 		for (j = 0; j < 4; j++) {		/* 64byte * 4 */
    473       1.1  tsutsui 			uint16_t *q = test_header;
    474       1.1  tsutsui 			for (k = 0; k < 7; k++)		/* 14byte */
    475       1.1  tsutsui 				*p++ = *q++;
    476       1.1  tsutsui 			for (k = 0; k < 9; k++)		/* 18byte */
    477       1.1  tsutsui 				*p++ = *r++;
    478       1.1  tsutsui 			p += 16;			/* 32byte skip */
    479       1.1  tsutsui 		}
    480       1.1  tsutsui 	}
    481       1.1  tsutsui }
    482       1.1  tsutsui 
    483       1.2  thorpej bool
    484       1.2  thorpej lance_internal_loopback_data_check(bool crc_check)
    485       1.1  tsutsui {
    486       1.1  tsutsui 	uint32_t *p = (uint32_t *)lance_mem.txdata;
    487       1.1  tsutsui 	uint32_t *q = (uint32_t *)lance_mem.rxdata;
    488       1.1  tsutsui 	int i, j;
    489       1.1  tsutsui 
    490       1.1  tsutsui 	/* Read all data block */
    491       1.1  tsutsui 	for (i = 0; i < 8; i++) {
    492       1.1  tsutsui 		printf("block %d ", i);
    493       1.1  tsutsui 		lance_mem.letmd[i].tmd1_bits |= LE_T1_OWN;/* buffer is filled */
    494       1.1  tsutsui 		/* wait interrupt */
    495       1.1  tsutsui 		if (!__poll_interrupt())
    496       1.1  tsutsui 			goto timeout_error;
    497       1.1  tsutsui 		/* wait LANCE status */
    498       1.1  tsutsui 		if (!__poll_lance_c0(LE_C0_RINT | LE_C0_TINT | LE_C0_INTR |
    499       1.1  tsutsui 		    LE_C0_INEA | LE_C0_RXON | LE_C0_TXON | LE_C0_STRT |
    500       1.1  tsutsui 		    LE_C0_INIT))
    501       1.1  tsutsui 			goto timeout_error;
    502       1.1  tsutsui 
    503       1.1  tsutsui 		/* check Tx descriptor */
    504       1.1  tsutsui 		if (lance_mem.letmd[i].tmd1_bits & LE_T1_ERR) {
    505       1.1  tsutsui 			printf("tx desc error.\n");
    506       1.1  tsutsui 			goto tx_rx_error;
    507       1.1  tsutsui 		}
    508       1.1  tsutsui 
    509       1.1  tsutsui 		/* check Rx descriptor */
    510       1.1  tsutsui 		if (lance_mem.lermd[i].rmd1_bits & LE_R1_ERR) {
    511       1.1  tsutsui 			printf("rx desc error.\n");
    512       1.1  tsutsui 			goto tx_rx_error;
    513       1.1  tsutsui 		}
    514       1.1  tsutsui 
    515       1.1  tsutsui 		/* Compare transmitted data */
    516       1.1  tsutsui 		for (j = 0; j < 7; j++)	/* first 28byte */
    517       1.1  tsutsui 			if (*p++ != *q++) {
    518       1.1  tsutsui 				printf("data error.\n");
    519       1.1  tsutsui 				goto tx_rx_error;
    520       1.1  tsutsui 			}
    521       1.1  tsutsui 
    522       1.1  tsutsui 		/* check CRC */
    523       1.1  tsutsui 		if (crc_check) {
    524       1.1  tsutsui 			printf("CRC=%x ", *p);
    525       1.1  tsutsui 			if (*p != *q) {	/* CRC */
    526       1.1  tsutsui 				goto crc_error;
    527       1.1  tsutsui 			}
    528       1.1  tsutsui 		}
    529       1.1  tsutsui 		printf("ok.\n");
    530       1.1  tsutsui 
    531       1.1  tsutsui 		p += 9;	/* 36byte skip */
    532       1.1  tsutsui 		q += 9;
    533       1.1  tsutsui 	}
    534       1.3  thorpej 	return true;
    535       1.1  tsutsui  timeout_error:
    536       1.1  tsutsui 	printf("LANCE timeout.\n");
    537       1.3  thorpej 	return false;
    538       1.1  tsutsui  tx_rx_error:
    539       1.1  tsutsui 	printf("LANCE Tx/Rx data error.\n");
    540       1.3  thorpej 	return false;
    541       1.1  tsutsui  crc_error:
    542       1.1  tsutsui 	printf("LANCE CRC error.\n");
    543       1.3  thorpej 	return false;
    544       1.1  tsutsui }
    545       1.1  tsutsui 
    546       1.2  thorpej bool
    547       1.1  tsutsui __poll_interrupt(void)
    548       1.1  tsutsui {
    549       1.1  tsutsui 	int j;
    550       1.1  tsutsui 
    551       1.1  tsutsui 	for (j = 0; j < 0x10000; j++) {
    552       1.1  tsutsui 		*LANCE_RAP;
    553       1.1  tsutsui 		if (*(volatile uint32_t *)0xbe40a008 & 1)
    554       1.1  tsutsui 			break;
    555       1.1  tsutsui 	}
    556       1.1  tsutsui 	if (j == 0x10000) {
    557       1.1  tsutsui 		printf ("interrupt timeout.\n");
    558       1.3  thorpej 		return false;
    559       1.1  tsutsui 	}
    560       1.1  tsutsui 
    561       1.3  thorpej 	return true;
    562       1.1  tsutsui }
    563       1.1  tsutsui 
    564       1.2  thorpej bool
    565       1.1  tsutsui __poll_lance_c0(uint16_t r)
    566       1.1  tsutsui {
    567       1.1  tsutsui 	int j;
    568       1.1  tsutsui 
    569       1.1  tsutsui 	for (j = 0; j < 0x60000; j++)
    570       1.1  tsutsui 		if (*LANCE_RDP == r)
    571       1.1  tsutsui 			break;
    572       1.1  tsutsui 	if (j == 0x60000) {
    573       1.1  tsutsui 		printf("lance CSR0 %x != %x\n", *LANCE_RDP, r);
    574       1.3  thorpej 		return false;
    575       1.1  tsutsui 	}
    576       1.1  tsutsui 
    577       1.1  tsutsui 	*LANCE_RDP = (LE_C0_RINT | LE_C0_TINT| LE_C0_INEA) & r;
    578       1.1  tsutsui 
    579       1.3  thorpej 	return true;
    580       1.1  tsutsui }
    581