1 /* $NetBSD: lance.c,v 1.4 2007/12/15 00:39:17 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* LANCE driver for EWS4800/360 */ 40 41 #include <lib/libsa/stand.h> 42 #include <lib/libkern/libkern.h> 43 44 #include <dev/ic/am7990reg.h> 45 #include <dev/ic/lancereg.h> 46 47 #include "local.h" 48 49 /* Register Address Pointer */ 50 #define LANCE_RAP ((volatile uint16_t *)0xbe400006) 51 /* Register Data Port */ 52 #define LANCE_RDP ((volatile uint16_t *)0xbe400000) 53 54 #define RX_DESC_NUM 8 55 #define TX_DESC_NUM 8 56 #define TX_BUFSIZE 0x1000 57 #define RX_BUFSIZE 0x1000 58 struct { 59 struct leinit leinit; 60 struct lermd lermd[RX_DESC_NUM]; 61 struct letmd letmd[TX_DESC_NUM]; 62 uint8_t eaddr[6]; 63 uint8_t txdata[TX_BUFSIZE] __attribute__((__aligned__(0x1000))); 64 uint8_t rxdata[RX_BUFSIZE] __attribute__((__aligned__(0x1000))); 65 } lance_mem __attribute__((__aligned__(64))); 66 67 bool lance_init(void); 68 void lance_eaddr(uint8_t *); 69 bool lance_get(void *, size_t); 70 bool lance_put(void *, size_t); 71 72 void lance_setup(void); 73 bool lance_set_initblock(struct leinit *); 74 bool lacne_do_initialize(void); 75 76 bool lance_test(void); 77 bool lance_internal_loopback_test(bool); 78 void lance_internal_loopback_setup(bool); 79 void lance_internal_loopback_testdata(void); 80 bool lance_internal_loopback_data_check(bool); 81 bool __poll_interrupt(void); 82 bool __poll_lance_c0(uint16_t); 83 84 bool 85 lance_init(void) 86 { 87 88 lance_setup(); 89 90 if (!lance_set_initblock(&lance_mem.leinit)) 91 return false; 92 93 if (!lacne_do_initialize()) 94 return false; 95 96 *LANCE_RDP = LE_C0_STRT; 97 98 return true; 99 } 100 101 void 102 lance_eaddr(uint8_t *p) 103 { 104 int i; 105 106 for (i = 0; i < 6; i++) 107 p[i] = lance_mem.eaddr[i]; 108 } 109 110 bool 111 lance_get(void *data, size_t len) 112 { 113 static int current; 114 struct lermd *rmd; 115 int i, j, k, n; 116 int start, end; 117 uint8_t *q, *p = data, *p_end = p + len; 118 119 while ((*LANCE_RDP & (LE_C0_RINT | LE_C0_INTR)) == 0) 120 ; 121 *LANCE_RDP = LE_C0_RINT; 122 123 start = end = -1; 124 n = 0; 125 for (i = 0; i < 8; i++) { 126 rmd = &lance_mem.lermd[(current + i) & 0x7]; 127 if (rmd->rmd1_bits & LE_R1_STP) 128 start = i; 129 if (rmd->rmd1_bits & LE_R1_ENP) { 130 end = i; 131 n = rmd->rmd3; /* total amount of packet */ 132 break; 133 } 134 } 135 #ifdef DEBUG 136 printf("%s: %d [%d,%d] %d\n", __func__, len, start, end, n); 137 #endif 138 if (start < 0 || end < 0) 139 return false; 140 141 for (i = start; i <= end; i++) { 142 rmd = &lance_mem.lermd[(current + i) & 0x7]; 143 q = (uint8_t *)((rmd->rmd1_hadr << 16) | rmd->rmd0 | 144 0xa0000000); 145 j = i == end ? n : -rmd->rmd2; 146 for (k = 0; k < j; k++) 147 if (p < p_end) 148 *p++ = *q++; 149 n -= j; 150 rmd->rmd1_bits = LE_R1_OWN; /* return to LANCE */ 151 } 152 current = (current + i) & 0x7; 153 154 return true; 155 } 156 157 bool 158 lance_put(void *data, size_t len) 159 { 160 static int current; 161 struct letmd *tmd; 162 uint16_t r; 163 uint8_t *p, *q = data; 164 int i, j, n, start; 165 166 start = current; 167 tmd = &lance_mem.letmd[current]; 168 tmd->tmd1_bits = LE_T1_STP; 169 for (i = 0; i < 8; i++) { 170 current = (current + 1) & 0x7; 171 n = min(len, 512); 172 p = (uint8_t *)((tmd->tmd1_hadr << 16) | tmd->tmd0 | 173 0xa0000000); 174 for (j = 0; j < n; j++) 175 *p++ = *q++; 176 len -= n; 177 #if 1 178 tmd->tmd2 = -max(n, 64) | 0xf000; 179 #else 180 tmd->tmd2 = -n | 0xf000; 181 #endif 182 tmd->tmd3 = 0; 183 if (len == 0) { 184 tmd->tmd1_bits |= LE_T1_ENP; 185 break; 186 } 187 tmd = &lance_mem.letmd[current]; 188 } 189 190 n = i + 1; 191 192 for (i = 0; i < n; i++) { 193 tmd = &lance_mem.letmd[start + i]; 194 *LANCE_RDP = LE_C0_INEA; 195 tmd->tmd1_bits |= LE_T1_OWN; 196 j = 0; 197 do { 198 *LANCE_RAP; 199 r = *LANCE_RDP; 200 if (r & LE_C0_ERR) { 201 printf("Error. CSR0=%x\n", r); 202 return false; 203 } 204 if (j++ > 0xa0000) { 205 printf("Timeout CSR0=%x\n", r); 206 return false; 207 } 208 } while ((r & (LE_C0_TINT | LE_C0_INTR)) == 0); 209 210 *LANCE_RDP = LE_C0_TINT; 211 } 212 213 for (i = 0; i < n; i++) { 214 uint8_t *bits = &lance_mem.letmd[i].tmd1_bits; 215 if (*bits & LE_T1_OWN || *bits & LE_T1_ERR) { 216 printf("desc%d not transmitted. cause=%x\n", i, *bits); 217 return false; 218 } 219 *bits = 0; 220 } 221 222 return true; 223 } 224 225 bool 226 lance_set_initblock(struct leinit *leinit) 227 { 228 uint16_t test_data[] = { 0xffff, 0xaaaa, 0x5555, 0x0000 }; 229 uint16_t t; 230 uint32_t addr = (uint32_t)leinit; 231 int i; 232 233 /* Control and status register */ 234 for (i = 3; i >= 0; i--) { 235 *LANCE_RAP = i; 236 if ((*LANCE_RAP & 3) != i) 237 goto reg_rw_error; 238 } 239 *LANCE_RDP = LE_C0_STOP; /* disable all external activity */ 240 if (*LANCE_RDP != LE_C0_STOP) 241 goto reg_rw_error; 242 243 /* Low address of init block */ 244 for (i = 0; i < 4; i++) { 245 t = test_data[i] & 0xfffe; 246 *LANCE_RAP = LE_CSR1; 247 *LANCE_RDP = t; 248 if (*LANCE_RDP != t) 249 goto reg_rw_error; 250 } 251 *LANCE_RDP = addr & 0xfffe; 252 #if DEBUG 253 printf("initblock low addr=%x\n", *LANCE_RDP); 254 #endif 255 256 /* High address of init block */ 257 for (i = 0; i < 4; i++) { 258 t = test_data[i] & 0x00ff; 259 *LANCE_RAP = LE_CSR2; 260 *LANCE_RDP = t; 261 if (*LANCE_RDP != t) 262 goto reg_rw_error; 263 } 264 *LANCE_RDP = (addr >> 16) & 0x00ff; 265 #ifdef DEBUG 266 printf("initblock high addr=%x\n", *LANCE_RDP); 267 #endif 268 269 /* Bus master and control */ 270 *LANCE_RAP = LE_CSR3; 271 *LANCE_RDP = 7; 272 if (*LANCE_RDP != 7) 273 goto reg_rw_error; 274 275 *LANCE_RAP = LE_CSR3; 276 *LANCE_RDP = 0; 277 if (*LANCE_RDP != 0) 278 goto reg_rw_error; 279 280 *LANCE_RDP = LE_C3_BSWP | LE_C3_BCON; 281 282 return true; 283 284 reg_rw_error: 285 printf("LANCE register r/w error.\n"); 286 return false; 287 } 288 289 bool 290 lacne_do_initialize(void) 291 { 292 293 /* Initialze LANCE */ 294 *LANCE_RAP = LE_CSR0; 295 *LANCE_RDP = LE_C0_INEA | LE_C0_INIT; 296 297 /* Wait interrupt */ 298 if (!__poll_interrupt()) 299 return false; 300 *LANCE_RDP = *LANCE_RDP; 301 302 return true; 303 } 304 305 void 306 lance_setup(void) 307 { 308 struct leinit *init = &lance_mem.leinit; 309 struct lermd *lermd = lance_mem.lermd; 310 struct letmd *letmd = lance_mem.letmd; 311 uint32_t addr; 312 uint8_t *eaddr; 313 int i; 314 315 memset(&lance_mem, 0, sizeof lance_mem); 316 /* Ethernet address from NVSRAM */ 317 eaddr = lance_mem.eaddr; 318 for (i = 0; i < 6; i++) 319 eaddr[i] = *(uint8_t *)(0xbe491008 + i * 4); 320 321 /* Init block */ 322 init->init_mode = 0; 323 init->init_padr[0] = (eaddr[1] << 8) | eaddr[0]; 324 init->init_padr[1] = (eaddr[3] << 8) | eaddr[2]; 325 init->init_padr[2] = (eaddr[5] << 8) | eaddr[4]; 326 /* Logical address filter */ 327 for (i = 0; i < 4; i++) 328 init->init_ladrf[i] = 0x0000; 329 330 /* Location of Rx descriptor ring */ 331 addr = (uint32_t)lermd; 332 init->init_rdra = addr & 0xffff; 333 init->init_rlen = ((ffs(RX_DESC_NUM) - 1) << 13) | 334 ((addr >> 16) & 0xff); 335 336 /* Location of Tx descriptor ring */ 337 addr = (uint32_t)letmd; 338 init->init_tdra = addr & 0xffff; 339 init->init_tlen = ((ffs(RX_DESC_NUM) - 1) << 13) | 340 ((addr >> 16) & 0xff); 341 342 /* Rx descriptor */ 343 addr = (uint32_t)lance_mem.rxdata; 344 for (i = 0; i < RX_DESC_NUM; i++, lermd++) { 345 lermd->rmd0 = (addr & 0xffff) + i * 512; /* data block size */ 346 lermd->rmd1_hadr = (addr >> 16) & 0xff; 347 lermd->rmd1_bits = LE_R1_OWN; 348 lermd->rmd2 = -512; 349 lermd->rmd3 = 0; 350 } 351 352 /* Tx descriptor */ 353 addr = (uint32_t)lance_mem.txdata; 354 for (i = 0; i < TX_DESC_NUM; i++, letmd++) { 355 letmd->tmd0 = (addr & 0xffff) + i * 512; /* data block size */ 356 letmd->tmd1_hadr = (addr >> 16) & 0xff; 357 letmd->tmd1_bits = 0; 358 letmd->tmd2 = 0; 359 letmd->tmd3 = 0; 360 } 361 } 362 363 /* 364 * Internal loopback test. 365 */ 366 bool 367 lance_test(void) 368 { 369 370 /* Internal loop back test. (no CRC) */ 371 if (!lance_internal_loopback_test(false)) 372 return false; 373 374 /* Internal loop back test. (with CRC) */ 375 if (!lance_internal_loopback_test(true)) 376 return false; 377 378 return true; 379 } 380 381 bool 382 lance_internal_loopback_test(bool crc) 383 { 384 385 lance_internal_loopback_setup(crc); 386 387 if (!lance_set_initblock(&lance_mem.leinit)) 388 return false; 389 390 if (!lacne_do_initialize()) 391 return false; 392 393 /* Transmit Start */ 394 *LANCE_RAP = LE_CSR0; /* Control and status register */ 395 *LANCE_RDP = LE_C0_INEA | LE_C0_STRT; 396 397 /* Check trasmited data. */ 398 return lance_internal_loopback_data_check(crc); 399 } 400 401 void 402 lance_internal_loopback_setup(bool crc) 403 { 404 struct leinit *init = &lance_mem.leinit; 405 struct lermd *lermd = lance_mem.lermd; 406 struct letmd *letmd = lance_mem.letmd; 407 uint32_t addr; 408 int i; 409 410 memset(&lance_mem, 0, sizeof lance_mem); 411 412 /* Init block */ 413 init->init_mode = LE_C15_INTL | LE_C15_LOOP; 414 if (!crc) 415 init->init_mode |= LE_C15_DXMTFCS; 416 417 init->init_padr[0] = 0x0000; 418 init->init_padr[1] = 0x8400; 419 init->init_padr[2] = 0x0000; 420 for (i = 0; i < 4; i++) 421 init->init_ladrf[i] = 0x0000; 422 423 addr = (uint32_t)lermd; 424 init->init_rdra = addr & 0xffff; 425 init->init_rlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff); 426 addr = (uint32_t)letmd; 427 init->init_tdra = addr & 0xffff; 428 init->init_tlen = (ffs(RX_DESC_NUM) << 13) | ((addr >> 16) & 0xff); 429 430 /* Rx descriptor */ 431 addr = (uint32_t)lance_mem.rxdata; 432 for (i = 0; i < RX_DESC_NUM; i++, lermd++) { 433 lermd->rmd0 = (addr & 0xffff) + i * 64; /* data block size */ 434 lermd->rmd1_hadr = (addr >> 16) & 0xff; 435 lermd->rmd1_bits = LE_R1_OWN; 436 lermd->rmd2 = -64; 437 lermd->rmd3 = 0; 438 } 439 440 /* Tx descriptor */ 441 addr = (uint32_t)lance_mem.txdata; 442 for (i = 0; i < TX_DESC_NUM; i++, letmd++) { 443 letmd->tmd0 = (addr & 0xffff) + i * 64; /* data block size */ 444 letmd->tmd1_hadr = (addr >> 16) & 0xff; 445 letmd->tmd1_bits = LE_T1_STP | LE_T1_ENP; 446 if (crc) 447 letmd->tmd2 = -28; 448 else 449 letmd->tmd2 = -32; 450 letmd->tmd3 = 0; 451 } 452 453 lance_internal_loopback_testdata(); 454 } 455 456 void 457 lance_internal_loopback_testdata(void) 458 { 459 uint16_t test_data[] = { 460 0x55aa, 0xff00, 0x0102, 0x0304, 0x0506, 0x0708, 0x0910, 461 0x40db, 0xdfcf, /* CRC */ 462 0x23dc, 0x23dc, 0x1918, 0x1716, 0x1514, 0x1312, 0x1110, 463 0x7081, 0x90cb, /* CRC */ 464 0x6699, 0xaa55, 0x0515, 0x2535, 0x4555, 0x6575, 0x8595, 465 0x55f6, 0xa448, /* CRC */ 466 0x4e4e, 0x5a5a, 0x6969, 0x7878, 0x0f0f, 0x1e1e, 0x2d2d, 467 0xa548, 0x7404, /* CRC */ 468 }; 469 uint16_t test_header[] = { 470 0x0000, 0x0084, 0x0000, /* dst */ 471 0x0000, 0x0084, 0x0000, /* src */ 472 0x000e 473 }; 474 uint16_t *p = (uint16_t *)lance_mem.txdata; 475 int i, j, k; 476 477 for (i = 0; i < 2; i++) { /* 64byte * 8 */ 478 uint16_t *r = test_data; 479 for (j = 0; j < 4; j++) { /* 64byte * 4 */ 480 uint16_t *q = test_header; 481 for (k = 0; k < 7; k++) /* 14byte */ 482 *p++ = *q++; 483 for (k = 0; k < 9; k++) /* 18byte */ 484 *p++ = *r++; 485 p += 16; /* 32byte skip */ 486 } 487 } 488 } 489 490 bool 491 lance_internal_loopback_data_check(bool crc_check) 492 { 493 uint32_t *p = (uint32_t *)lance_mem.txdata; 494 uint32_t *q = (uint32_t *)lance_mem.rxdata; 495 int i, j; 496 497 /* Read all data block */ 498 for (i = 0; i < 8; i++) { 499 printf("block %d ", i); 500 lance_mem.letmd[i].tmd1_bits |= LE_T1_OWN;/* buffer is filled */ 501 /* wait interrupt */ 502 if (!__poll_interrupt()) 503 goto timeout_error; 504 /* wait LANCE status */ 505 if (!__poll_lance_c0(LE_C0_RINT | LE_C0_TINT | LE_C0_INTR | 506 LE_C0_INEA | LE_C0_RXON | LE_C0_TXON | LE_C0_STRT | 507 LE_C0_INIT)) 508 goto timeout_error; 509 510 /* check Tx descriptor */ 511 if (lance_mem.letmd[i].tmd1_bits & LE_T1_ERR) { 512 printf("tx desc error.\n"); 513 goto tx_rx_error; 514 } 515 516 /* check Rx descriptor */ 517 if (lance_mem.lermd[i].rmd1_bits & LE_R1_ERR) { 518 printf("rx desc error.\n"); 519 goto tx_rx_error; 520 } 521 522 /* Compare transmitted data */ 523 for (j = 0; j < 7; j++) /* first 28byte */ 524 if (*p++ != *q++) { 525 printf("data error.\n"); 526 goto tx_rx_error; 527 } 528 529 /* check CRC */ 530 if (crc_check) { 531 printf("CRC=%x ", *p); 532 if (*p != *q) { /* CRC */ 533 goto crc_error; 534 } 535 } 536 printf("ok.\n"); 537 538 p += 9; /* 36byte skip */ 539 q += 9; 540 } 541 return true; 542 timeout_error: 543 printf("LANCE timeout.\n"); 544 return false; 545 tx_rx_error: 546 printf("LANCE Tx/Rx data error.\n"); 547 return false; 548 crc_error: 549 printf("LANCE CRC error.\n"); 550 return false; 551 } 552 553 bool 554 __poll_interrupt(void) 555 { 556 int j; 557 558 for (j = 0; j < 0x10000; j++) { 559 *LANCE_RAP; 560 if (*(volatile uint32_t *)0xbe40a008 & 1) 561 break; 562 } 563 if (j == 0x10000) { 564 printf ("interrupt timeout.\n"); 565 return false; 566 } 567 568 return true; 569 } 570 571 bool 572 __poll_lance_c0(uint16_t r) 573 { 574 int j; 575 576 for (j = 0; j < 0x60000; j++) 577 if (*LANCE_RDP == r) 578 break; 579 if (j == 0x60000) { 580 printf("lance CSR0 %x != %x\n", *LANCE_RDP, r); 581 return false; 582 } 583 584 *LANCE_RDP = (LE_C0_RINT | LE_C0_TINT| LE_C0_INEA) & r; 585 586 return true; 587 } 588