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