Home | History | Annotate | Line # | Download | only in common
lance.c revision 1.4.6.1
      1  1.4.6.1      mjf /*	$NetBSD: lance.c,v 1.4.6.1 2008/06/02 13:22:06 mjf 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.2  thorpej bool lacne_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.1  tsutsui 	if (!lacne_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.1  tsutsui lacne_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.1  tsutsui 	if (!lacne_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