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