Home | History | Annotate | Line # | Download | only in common
lance.c revision 1.5
      1  1.5   martin /*	$NetBSD: lance.c,v 1.5 2008/04/28 20:23:18 martin 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