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