Home | History | Annotate | Line # | Download | only in common
lance.c revision 1.4
      1  1.4    perry /*	$NetBSD: lance.c,v 1.4 2007/12/15 00:39:17 perry 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.4    perry 	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