1 /* $NetBSD: if_le_vme.c,v 1.22 2005/12/24 20:06:58 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 maximum entropy. All rights reserved. 5 * Copyright (c) 1997 Leo Weppelman. All rights reserved. 6 * Copyright (c) 1992, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Ralph Campbell and Rick Macklem. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 37 */ 38 39 /*- 40 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 41 * 42 * This code is derived from software contributed to Berkeley by 43 * Ralph Campbell and Rick Macklem. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. All advertising materials mentioning features or use of this software 54 * must display the following acknowledgement: 55 * This product includes software developed by the University of 56 * California, Berkeley and its contributors. 57 * 4. Neither the name of the University nor the names of its contributors 58 * may be used to endorse or promote products derived from this software 59 * without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * SUCH DAMAGE. 72 * 73 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 74 */ 75 76 #include <sys/cdefs.h> 77 __KERNEL_RCSID(0, "$NetBSD: if_le_vme.c,v 1.22 2005/12/24 20:06:58 perry Exp $"); 78 79 #include "opt_inet.h" 80 #include "bpfilter.h" 81 82 #include <sys/param.h> 83 #include <sys/systm.h> 84 #include <sys/mbuf.h> 85 #include <sys/syslog.h> 86 #include <sys/socket.h> 87 #include <sys/device.h> 88 89 #include <net/if.h> 90 #include <net/if_media.h> 91 #include <net/if_ether.h> 92 93 #ifdef INET 94 #include <netinet/in.h> 95 #include <netinet/if_inarp.h> 96 #endif 97 98 #include <machine/cpu.h> 99 #include <machine/bus.h> 100 #include <machine/iomap.h> 101 #include <machine/scu.h> 102 103 #include <atari/atari/device.h> 104 #include <atari/atari/intr.h> 105 106 #include <dev/ic/lancereg.h> 107 #include <dev/ic/lancevar.h> 108 #include <dev/ic/am7990reg.h> 109 #include <dev/ic/am7990var.h> 110 111 #include <atari/vme/vmevar.h> 112 #include <atari/vme/if_levar.h> 113 114 /* 115 * All cards except BVME410 have 64KB RAM. However.... On the Riebl cards the 116 * area between the offsets 0xee70-0xeec0 is used to store config data. 117 */ 118 struct le_addresses { 119 u_long reg_addr; 120 u_long mem_addr; 121 int irq; 122 int reg_size; 123 int mem_size; 124 int type_hint; 125 } lestd[] = { 126 { 0xfe00fff0, 0xfe010000, IRQUNK, 16, 64*1024, 127 LE_OLD_RIEBL|LE_NEW_RIEBL }, /* Riebl */ 128 { 0xffcffff0, 0xffcf0000, 5, 16, 64*1024, 129 LE_PAM }, /* PAM */ 130 { 0xfecffff0, 0xfecf0000, 5, 16, 64*1024, 131 LE_ROTHRON }, /* Rhotron */ 132 { 0xfeff4100, 0xfe000000, 4, 8, VMECF_MEMSIZ_DEFAULT, 133 LE_BVME410 } /* BVME410 */ 134 }; 135 136 #define NLESTD (sizeof(lestd) / sizeof(lestd[0])) 137 138 /* 139 * Default mac for RIEBL cards without a (working) battery. The first 4 bytes 140 * are the manufacturer id. 141 */ 142 static u_char riebl_def_mac[] = { 143 0x00, 0x00, 0x36, 0x04, 0x00, 0x00 144 }; 145 146 static int le_intr __P((struct le_softc *, int)); 147 static void lepseudointr __P((struct le_softc *, void *)); 148 static int le_vme_match __P((struct device *, struct cfdata *, void *)); 149 static void le_vme_attach __P((struct device *, struct device *, void *)); 150 static int probe_addresses __P((bus_space_tag_t *, bus_space_tag_t *, 151 bus_space_handle_t *, bus_space_handle_t *)); 152 static void riebl_skip_reserved_area __P((struct lance_softc *)); 153 static int nm93c06_read __P((bus_space_tag_t, bus_space_handle_t, int)); 154 static int bvme410_probe __P((bus_space_tag_t, bus_space_handle_t)); 155 static int bvme410_mem_size __P((bus_space_tag_t, u_long)); 156 static void bvme410_copytobuf __P((struct lance_softc *, void *, int, int)); 157 static void bvme410_zerobuf __P((struct lance_softc *, int, int)); 158 159 CFATTACH_DECL(le_vme, sizeof(struct le_softc), 160 le_vme_match, le_vme_attach, NULL, NULL); 161 162 #if defined(_KERNEL_OPT) 163 #include "opt_ddb.h" 164 #endif 165 166 #ifdef DDB 167 #define integrate 168 #define hide 169 #else 170 #define integrate static inline 171 #define hide static 172 #endif 173 174 hide void lewrcsr __P((struct lance_softc *, u_int16_t, u_int16_t)); 175 hide u_int16_t lerdcsr __P((struct lance_softc *, u_int16_t)); 176 177 hide void 178 lewrcsr(sc, port, val) 179 struct lance_softc *sc; 180 u_int16_t port, val; 181 { 182 struct le_softc *lesc = (struct le_softc *)sc; 183 int s; 184 185 s = splhigh(); 186 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 187 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP, val); 188 splx(s); 189 } 190 191 hide u_int16_t 192 lerdcsr(sc, port) 193 struct lance_softc *sc; 194 u_int16_t port; 195 { 196 struct le_softc *lesc = (struct le_softc *)sc; 197 u_int16_t val; 198 int s; 199 200 s = splhigh(); 201 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 202 val = bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP); 203 splx(s); 204 205 return (val); 206 } 207 208 static int 209 le_vme_match(parent, cfp, aux) 210 struct device *parent; 211 struct cfdata *cfp; 212 void *aux; 213 { 214 struct vme_attach_args *va = aux; 215 int i; 216 bus_space_tag_t iot; 217 bus_space_tag_t memt; 218 bus_space_handle_t ioh; 219 bus_space_handle_t memh; 220 221 iot = va->va_iot; 222 memt = va->va_memt; 223 224 for (i = 0; i < NLESTD; i++) { 225 struct le_addresses *le_ap = &lestd[i]; 226 int found = 0; 227 228 if ((va->va_iobase != IOBASEUNK) 229 && (va->va_iobase != le_ap->reg_addr)) 230 continue; 231 232 if ((va->va_maddr != MADDRUNK) 233 && (va->va_maddr != le_ap->mem_addr)) 234 continue; 235 236 if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq)) 237 continue; 238 239 if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, &ioh)) { 240 printf("leprobe: cannot map io-area\n"); 241 return (0); 242 } 243 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 244 if (bvme410_probe(iot, ioh)) { 245 bus_space_write_2(iot, ioh, BVME410_BAR, 0x1); /* XXX */ 246 le_ap->mem_size = bvme410_mem_size(memt, le_ap->mem_addr); 247 } 248 } 249 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 250 bus_space_unmap(iot, ioh, le_ap->reg_size); 251 continue; 252 } 253 254 if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, &memh)) { 255 bus_space_unmap(iot, ioh, le_ap->reg_size); 256 printf("leprobe: cannot map memory-area\n"); 257 return (0); 258 } 259 found = probe_addresses(&iot, &memt, &ioh, &memh); 260 bus_space_unmap(iot, ioh, le_ap->reg_size); 261 bus_space_unmap(memt, memh, le_ap->mem_size); 262 263 if (found) { 264 va->va_iobase = le_ap->reg_addr; 265 va->va_iosize = le_ap->reg_size; 266 va->va_maddr = le_ap->mem_addr; 267 va->va_msize = le_ap->mem_size; 268 va->va_aux = le_ap; 269 if (va->va_irq == IRQUNK) 270 va->va_irq = le_ap->irq; 271 return 1; 272 } 273 } 274 return (0); 275 } 276 277 static int 278 probe_addresses(iot, memt, ioh, memh) 279 bus_space_tag_t *iot; 280 bus_space_tag_t *memt; 281 bus_space_handle_t *ioh; 282 bus_space_handle_t *memh; 283 { 284 /* 285 * Test accesibility of register and memory area 286 */ 287 if(!bus_space_peek_2(*iot, *ioh, LER_RDP)) 288 return 0; 289 if(!bus_space_peek_1(*memt, *memh, 0)) 290 return 0; 291 292 /* 293 * Test for writable memory 294 */ 295 bus_space_write_2(*memt, *memh, 0, 0xa5a5); 296 if (bus_space_read_2(*memt, *memh, 0) != 0xa5a5) 297 return 0; 298 299 /* 300 * Test writability of selector port. 301 */ 302 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR1); 303 if (bus_space_read_2(*iot, *ioh, LER_RAP) != LE_CSR1) 304 return 0; 305 306 /* 307 * Do a small register test 308 */ 309 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR0); 310 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_INIT | LE_C0_STOP); 311 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 312 return 0; 313 314 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_STOP); 315 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 316 return 0; 317 318 return 1; 319 } 320 321 /* 322 * Interrupt mess. Because the card's interrupt is hardwired to either 323 * ipl5 or ipl3 (mostly on ipl5) and raising splnet to spl5() just won't do 324 * (it kills the serial at the least), we use a 2-level interrupt scheme. The 325 * card interrupt is routed to 'le_intr'. If the previous ipl was below 326 * splnet, just call the mi-function. If not, save the interrupt status, 327 * turn off card interrupts (the card is *very* persistent) and arrange 328 * for a softint 'callback' through 'lepseudointr'. 329 */ 330 static int 331 le_intr(lesc, sr) 332 struct le_softc *lesc; 333 int sr; 334 { 335 struct lance_softc *sc = &lesc->sc_am7990.lsc; 336 u_int16_t csr0; 337 338 if ((sr & PSL_IPL) < (IPL_NET & PSL_IPL)) 339 am7990_intr(sc); 340 else { 341 sc->sc_saved_csr0 = csr0 = lerdcsr(sc, LE_CSR0); 342 lewrcsr(sc, LE_CSR0, csr0 & ~LE_C0_INEA); 343 add_sicallback((si_farg)lepseudointr, lesc, sc); 344 } 345 return 1; 346 } 347 348 349 static void 350 lepseudointr(lesc, sc) 351 struct le_softc *lesc; 352 void *sc; 353 { 354 int s; 355 356 s = splx(lesc->sc_splval); 357 am7990_intr(sc); 358 splx(s); 359 } 360 361 static void 362 le_vme_attach(parent, self, aux) 363 struct device *parent, *self; 364 void *aux; 365 { 366 struct le_softc *lesc = (struct le_softc *)self; 367 struct lance_softc *sc = &lesc->sc_am7990.lsc; 368 struct vme_attach_args *va = aux; 369 bus_space_handle_t ioh; 370 bus_space_handle_t memh; 371 struct le_addresses *le_ap; 372 int i; 373 374 printf("\n%s: ", sc->sc_dev.dv_xname); 375 376 if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh)) 377 panic("leattach: cannot map io-area"); 378 if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh)) 379 panic("leattach: cannot map mem-area"); 380 381 lesc->sc_iot = va->va_iot; 382 lesc->sc_ioh = ioh; 383 lesc->sc_memt = va->va_memt; 384 lesc->sc_memh = memh; 385 lesc->sc_splval = (va->va_irq << 8) | PSL_S; /* XXX */ 386 le_ap = (struct le_addresses *)va->va_aux; 387 388 /* 389 * Go on to find board type 390 */ 391 if ((le_ap->type_hint & LE_PAM) 392 && bus_space_peek_1(va->va_iot, ioh, LER_EEPROM)) { 393 printf("PAM card"); 394 lesc->sc_type = LE_PAM; 395 bus_space_read_1(va->va_iot, ioh, LER_MEME); 396 } 397 else if((le_ap->type_hint & LE_BVME410) 398 && bvme410_probe(va->va_iot, ioh)) { 399 printf("BVME410"); 400 lesc->sc_type = LE_BVME410; 401 } 402 else if (le_ap->type_hint & (LE_NEW_RIEBL|LE_OLD_RIEBL)) { 403 printf("Riebl card"); 404 if(bus_space_read_4(va->va_memt, memh, RIEBL_MAGIC_ADDR) 405 == RIEBL_MAGIC) 406 lesc->sc_type = LE_NEW_RIEBL; 407 else { 408 printf("(without battery) "); 409 lesc->sc_type = LE_OLD_RIEBL; 410 } 411 } 412 else printf("le_vme_attach: Unsupported card!"); 413 414 switch (lesc->sc_type) { 415 case LE_BVME410: 416 sc->sc_copytodesc = bvme410_copytobuf; 417 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 418 sc->sc_copytobuf = bvme410_copytobuf; 419 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 420 sc->sc_zerobuf = bvme410_zerobuf; 421 break; 422 default: 423 sc->sc_copytodesc = lance_copytobuf_contig; 424 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 425 sc->sc_copytobuf = lance_copytobuf_contig; 426 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 427 sc->sc_zerobuf = lance_zerobuf_contig; 428 break; 429 } 430 431 sc->sc_rdcsr = lerdcsr; 432 sc->sc_wrcsr = lewrcsr; 433 sc->sc_hwinit = NULL; 434 sc->sc_conf3 = LE_C3_BSWP; 435 sc->sc_addr = 0; 436 sc->sc_memsize = va->va_msize; 437 sc->sc_mem = (void *)memh; /* XXX */ 438 439 /* 440 * Get MAC address 441 */ 442 switch (lesc->sc_type) { 443 case LE_OLD_RIEBL: 444 bcopy(riebl_def_mac, sc->sc_enaddr, 445 sizeof(sc->sc_enaddr)); 446 break; 447 case LE_NEW_RIEBL: 448 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 449 sc->sc_enaddr[i] = 450 bus_space_read_1(va->va_memt, memh, i + RIEBL_MAC_ADDR); 451 break; 452 case LE_PAM: 453 i = bus_space_read_1(va->va_iot, ioh, LER_EEPROM); 454 for (i = 0; i < sizeof(sc->sc_enaddr); i++) { 455 sc->sc_enaddr[i] = 456 (bus_space_read_2(va->va_memt, memh, 2 * i) << 4) | 457 (bus_space_read_2(va->va_memt, memh, 2 * i + 1) & 0xf); 458 } 459 i = bus_space_read_1(va->va_iot, ioh, LER_MEME); 460 break; 461 case LE_BVME410: 462 for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) { 463 u_int16_t tmp; 464 465 tmp = nm93c06_read(va->va_iot, ioh, i); 466 sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff; 467 sc->sc_enaddr[2 * i + 1] = tmp & 0xff; 468 } 469 bus_space_write_2(va->va_iot, ioh, BVME410_BAR, 0x1); /* XXX */ 470 } 471 472 am7990_config(&lesc->sc_am7990); 473 474 if ((lesc->sc_type == LE_OLD_RIEBL) || (lesc->sc_type == LE_NEW_RIEBL)) 475 riebl_skip_reserved_area(sc); 476 477 /* 478 * XXX: We always use uservector 64.... 479 */ 480 if ((lesc->sc_intr = intr_establish(64, USER_VEC, 0, 481 (hw_ifun_t)le_intr, lesc)) == NULL) { 482 printf("le_vme_attach: Can't establish interrupt\n"); 483 return; 484 } 485 486 /* 487 * Notify the card of the vector 488 */ 489 switch (lesc->sc_type) { 490 case LE_OLD_RIEBL: 491 case LE_NEW_RIEBL: 492 bus_space_write_2(va->va_memt, memh, RIEBL_IVEC_ADDR, 493 64 + 64); 494 break; 495 case LE_PAM: 496 bus_space_write_1(va->va_iot, ioh, LER_IVEC, 64 + 64); 497 break; 498 case LE_BVME410: 499 bus_space_write_2(va->va_iot, ioh, BVME410_IVEC, 64 + 64); 500 break; 501 } 502 503 /* 504 * Unmask the VME-interrupt we're on 505 */ 506 if (machineid & ATARI_TT) 507 SCU->vme_mask |= 1 << va->va_irq; 508 } 509 510 /* 511 * True if 'addr' containe within [start,len] 512 */ 513 #define WITHIN(start, len, addr) \ 514 ((addr >= start) && ((addr) <= ((start) + (len)))) 515 static void 516 riebl_skip_reserved_area(sc) 517 struct lance_softc *sc; 518 { 519 int offset = 0; 520 int i; 521 522 for(i = 0; i < sc->sc_nrbuf; i++) { 523 if (WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_START) 524 || WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_END)) { 525 offset = RIEBL_RES_END - sc->sc_rbufaddr[i]; 526 } 527 sc->sc_rbufaddr[i] += offset; 528 } 529 530 for(i = 0; i < sc->sc_ntbuf; i++) { 531 if (WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_START) 532 || WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_END)) { 533 offset = RIEBL_RES_END - sc->sc_tbufaddr[i]; 534 } 535 sc->sc_tbufaddr[i] += offset; 536 } 537 } 538 539 static int 540 nm93c06_read(iot, ioh, nm93c06reg) 541 bus_space_tag_t iot; 542 bus_space_handle_t ioh; 543 int nm93c06reg; 544 { 545 int bar; 546 int shift; 547 int bits = 0x180 | (nm93c06reg & 0xf); 548 int data = 0; 549 550 bar = 1<<BVME410_CS_SHIFT; 551 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 552 delay(1); /* tCSS = 1 us */ 553 for (shift = 9; shift >= 0; shift--) { 554 if (((bits >> shift) & 1) == 1) 555 bar |= 1<<BVME410_DIN_SHIFT; 556 else 557 bar &= ~(1<<BVME410_DIN_SHIFT); 558 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 559 delay(1); /* tDIS = 0.4 us */ 560 bar |= 1<<BVME410_CLK_SHIFT; 561 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 562 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 563 bar &= ~(1<<BVME410_CLK_SHIFT); 564 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 565 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 566 } 567 bar &= ~(1<<BVME410_DIN_SHIFT); 568 for (shift = 15; shift >= 0; shift--) { 569 delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */ 570 bar |= 1<<BVME410_CLK_SHIFT; 571 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 572 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 573 data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift; 574 bar &= ~(1<<BVME410_CLK_SHIFT); 575 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 576 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 577 } 578 bar &= ~(1<<BVME410_CS_SHIFT); 579 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 580 delay(1); /* tCS = 1 us */ 581 return data; 582 } 583 584 static int 585 bvme410_probe(iot, ioh) 586 bus_space_tag_t iot; 587 bus_space_handle_t ioh; 588 { 589 if (!bus_space_peek_2(iot, ioh, BVME410_IVEC)) 590 return 0; 591 592 bus_space_write_2(iot, ioh, BVME410_IVEC, 0x0000); 593 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xff00) 594 return 0; 595 596 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xffff); 597 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffff) 598 return 0; 599 600 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xa5a5); 601 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffa5) 602 return 0; 603 604 return 1; 605 } 606 607 static int 608 bvme410_mem_size(memt, mem_addr) 609 bus_space_tag_t memt; 610 u_long mem_addr; 611 { 612 bus_space_handle_t memh; 613 int r; 614 615 if (bus_space_map(memt, mem_addr, 256*1024, 0, &memh)) 616 return VMECF_MEMSIZ_DEFAULT; 617 if (!bus_space_peek_1(memt, memh, 0)) { 618 bus_space_unmap(memt, memh, 256*1024); 619 return VMECF_MEMSIZ_DEFAULT; 620 } 621 bus_space_write_1(memt, memh, 0, 128); 622 bus_space_write_1(memt, memh, 64*1024, 32); 623 bus_space_write_1(memt, memh, 32*1024, 8); 624 r = (int)(bus_space_read_1(memt, memh, 0) * 2048); 625 bus_space_unmap(memt, memh, 256*1024); 626 return r; 627 } 628 629 /* 630 * Need to be careful when writing to the bvme410 dual port memory. 631 * Continue writing each byte until it reads back the same. 632 */ 633 634 static void 635 bvme410_copytobuf(sc, from, boff, len) 636 struct lance_softc *sc; 637 void *from; 638 int boff, len; 639 { 640 volatile char *buf = (volatile char *) sc->sc_mem; 641 char *f = (char *) from; 642 643 for (buf += boff; len; buf++,f++,len--) 644 do { 645 *buf = *f; 646 } while (*buf != *f); 647 } 648 649 static void 650 bvme410_zerobuf(sc, boff, len) 651 struct lance_softc *sc; 652 int boff, len; 653 { 654 volatile char *buf = (volatile char *)sc->sc_mem; 655 656 for (buf += boff; len; buf++,len--) 657 do { 658 *buf = '\0'; 659 } while (*buf != '\0'); 660 } 661 662