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