1 /* $NetBSD: if_le_vme.c,v 1.30 2010/04/13 11:31:11 tsutsui 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.30 2010/04/13 11:31:11 tsutsui Exp $"); 78 79 #include "opt_inet.h" 80 81 #include <sys/param.h> 82 #include <sys/systm.h> 83 #include <sys/mbuf.h> 84 #include <sys/syslog.h> 85 #include <sys/socket.h> 86 #include <sys/device.h> 87 88 #include <net/if.h> 89 #include <net/if_media.h> 90 #include <net/if_ether.h> 91 92 #ifdef INET 93 #include <netinet/in.h> 94 #include <netinet/if_inarp.h> 95 #endif 96 97 #include <machine/cpu.h> 98 #include <machine/bus.h> 99 #include <machine/iomap.h> 100 #include <machine/scu.h> 101 #include <machine/intr.h> 102 103 #include <atari/atari/device.h> 104 105 #include <dev/ic/lancereg.h> 106 #include <dev/ic/lancevar.h> 107 #include <dev/ic/am7990reg.h> 108 #include <dev/ic/am7990var.h> 109 110 #include <atari/vme/vmevar.h> 111 #include <atari/vme/if_levar.h> 112 113 /* 114 * All cards except BVME410 have 64KB RAM. However.... On the Riebl cards the 115 * area between the offsets 0xee70-0xeec0 is used to store config data. 116 */ 117 struct le_addresses { 118 u_long reg_addr; 119 u_long mem_addr; 120 int irq; 121 int reg_size; 122 int mem_size; 123 int type_hint; 124 } lestd[] = { 125 { 0xfe00fff0, 0xfe010000, IRQUNK, 16, 64*1024, 126 LE_OLD_RIEBL|LE_NEW_RIEBL }, /* Riebl */ 127 { 0xfecffff0, 0xfecf0000, 5, 16, 64*1024, 128 LE_PAM }, /* PAM */ 129 { 0xfecffff0, 0xfecf0000, 5, 16, 64*1024, 130 LE_ROTHRON }, /* Rhotron */ 131 { 0xfeff4100, 0xfe000000, 4, 8, VMECF_MEMSIZ_DEFAULT, 132 LE_BVME410 } /* BVME410 */ 133 }; 134 135 #define NLESTD __arraycount(lestd) 136 137 /* 138 * Default mac for RIEBL cards without a (working) battery. The first 4 bytes 139 * are the manufacturer id. 140 */ 141 static u_char riebl_def_mac[] = { 142 0x00, 0x00, 0x36, 0x04, 0x00, 0x00 143 }; 144 145 static int le_intr(struct le_softc *, int); 146 static void lepseudointr(struct le_softc *, void *); 147 static int le_vme_match(device_t, cfdata_t, void *); 148 static void le_vme_attach(device_t, device_t, void *); 149 static int probe_addresses(bus_space_tag_t *, bus_space_tag_t *, 150 bus_space_handle_t *, bus_space_handle_t *); 151 static void riebl_skip_reserved_area(struct lance_softc *); 152 static int nm93c06_read(bus_space_tag_t, bus_space_handle_t, int); 153 static int bvme410_probe(bus_space_tag_t, bus_space_handle_t); 154 static int bvme410_mem_size(bus_space_tag_t, u_long); 155 static void bvme410_copytobuf(struct lance_softc *, void *, int, int); 156 static void bvme410_zerobuf(struct lance_softc *, int, int); 157 158 CFATTACH_DECL_NEW(le_vme, sizeof(struct le_softc), 159 le_vme_match, le_vme_attach, NULL, NULL); 160 161 #if defined(_KERNEL_OPT) 162 #include "opt_ddb.h" 163 #endif 164 165 #ifdef DDB 166 #define integrate 167 #define hide 168 #else 169 #define integrate static inline 170 #define hide static 171 #endif 172 173 hide void lewrcsr(struct lance_softc *, uint16_t, uint16_t); 174 hide uint16_t lerdcsr(struct lance_softc *, uint16_t); 175 176 hide void 177 lewrcsr(struct lance_softc *sc, uint16_t port, uint16_t val) 178 { 179 struct le_softc *lesc = (struct le_softc *)sc; 180 int s; 181 182 s = splhigh(); 183 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 184 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP, val); 185 splx(s); 186 } 187 188 hide uint16_t 189 lerdcsr(struct lance_softc *sc, uint16_t port) 190 { 191 struct le_softc *lesc = (struct le_softc *)sc; 192 uint16_t val; 193 int s; 194 195 s = splhigh(); 196 bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LER_RAP, port); 197 val = bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LER_RDP); 198 splx(s); 199 200 return val; 201 } 202 203 static int 204 le_vme_match(device_t parent, cfdata_t cfp, void *aux) 205 { 206 struct vme_attach_args *va = aux; 207 int i; 208 bus_space_tag_t iot; 209 bus_space_tag_t memt; 210 bus_space_handle_t ioh; 211 bus_space_handle_t memh; 212 213 iot = va->va_iot; 214 memt = va->va_memt; 215 216 for (i = 0; i < NLESTD; i++) { 217 struct le_addresses *le_ap = &lestd[i]; 218 int found = 0; 219 220 if ((va->va_iobase != IOBASEUNK) 221 && (va->va_iobase != le_ap->reg_addr)) 222 continue; 223 224 if ((va->va_maddr != MADDRUNK) 225 && (va->va_maddr != le_ap->mem_addr)) 226 continue; 227 228 if ((le_ap->irq != IRQUNK) && (va->va_irq != le_ap->irq)) 229 continue; 230 231 if (bus_space_map(iot, le_ap->reg_addr, le_ap->reg_size, 0, 232 &ioh)) { 233 aprint_error("leprobe: cannot map io-area\n"); 234 return 0; 235 } 236 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 237 if (bvme410_probe(iot, ioh)) { 238 bus_space_write_2(iot, ioh, 239 BVME410_BAR, 0x1); /* XXX */ 240 le_ap->mem_size = 241 bvme410_mem_size(memt, le_ap->mem_addr); 242 } 243 } 244 if (le_ap->mem_size == VMECF_MEMSIZ_DEFAULT) { 245 bus_space_unmap(iot, ioh, le_ap->reg_size); 246 continue; 247 } 248 249 if (bus_space_map(memt, le_ap->mem_addr, le_ap->mem_size, 0, 250 &memh)) { 251 bus_space_unmap(iot, ioh, le_ap->reg_size); 252 aprint_error("leprobe: cannot map memory-area\n"); 253 return 0; 254 } 255 found = probe_addresses(&iot, &memt, &ioh, &memh); 256 bus_space_unmap(iot, ioh, le_ap->reg_size); 257 bus_space_unmap(memt, memh, le_ap->mem_size); 258 259 if (found) { 260 va->va_iobase = le_ap->reg_addr; 261 va->va_iosize = le_ap->reg_size; 262 va->va_maddr = le_ap->mem_addr; 263 va->va_msize = le_ap->mem_size; 264 va->va_aux = le_ap; 265 if (va->va_irq == IRQUNK) 266 va->va_irq = le_ap->irq; 267 return 1; 268 } 269 } 270 return 0; 271 } 272 273 static int 274 probe_addresses(bus_space_tag_t *iot, bus_space_tag_t *memt, 275 bus_space_handle_t *ioh, bus_space_handle_t *memh) 276 { 277 278 /* 279 * Test accesibility of register and memory area 280 */ 281 if (!bus_space_peek_2(*iot, *ioh, LER_RDP)) 282 return 0; 283 if (!bus_space_peek_1(*memt, *memh, 0)) 284 return 0; 285 286 /* 287 * Test for writable memory 288 */ 289 bus_space_write_2(*memt, *memh, 0, 0xa5a5); 290 if (bus_space_read_2(*memt, *memh, 0) != 0xa5a5) 291 return 0; 292 293 /* 294 * Test writability of selector port. 295 */ 296 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR1); 297 if (bus_space_read_2(*iot, *ioh, LER_RAP) != LE_CSR1) 298 return 0; 299 300 /* 301 * Do a small register test 302 */ 303 bus_space_write_2(*iot, *ioh, LER_RAP, LE_CSR0); 304 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_INIT | LE_C0_STOP); 305 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 306 return 0; 307 308 bus_space_write_2(*iot, *ioh, LER_RDP, LE_C0_STOP); 309 if (bus_space_read_2(*iot, *ioh, LER_RDP) != LE_C0_STOP) 310 return 0; 311 312 return 1; 313 } 314 315 /* 316 * Interrupt mess. Because the card's interrupt is hardwired to either 317 * ipl5 or ipl3 (mostly on ipl5) and raising splnet to spl5() just won't do 318 * (it kills the serial at the least), we use a 2-level interrupt scheme. The 319 * card interrupt is routed to 'le_intr'. If the previous ipl was below 320 * splnet, just call the mi-function. If not, save the interrupt status, 321 * turn off card interrupts (the card is *very* persistent) and arrange 322 * for a softint 'callback' through 'lepseudointr'. 323 */ 324 static int 325 le_intr(struct le_softc *lesc, int sr) 326 { 327 struct lance_softc *sc = &lesc->sc_am7990.lsc; 328 uint16_t csr0; 329 330 if ((sr & PSL_IPL) < (ipl2psl_table[IPL_NET] & PSL_IPL)) 331 am7990_intr(sc); 332 else { 333 sc->sc_saved_csr0 = csr0 = lerdcsr(sc, LE_CSR0); 334 lewrcsr(sc, LE_CSR0, csr0 & ~LE_C0_INEA); 335 add_sicallback((si_farg)lepseudointr, lesc, sc); 336 } 337 return 1; 338 } 339 340 341 static void 342 lepseudointr(struct le_softc *lesc, void *sc) 343 { 344 int s; 345 346 s = splx(lesc->sc_splval); 347 am7990_intr(sc); 348 splx(s); 349 } 350 351 static void 352 le_vme_attach(device_t parent, device_t self, void *aux) 353 { 354 struct le_softc *lesc = device_private(self); 355 struct lance_softc *sc = &lesc->sc_am7990.lsc; 356 struct vme_attach_args *va = aux; 357 bus_space_handle_t ioh; 358 bus_space_handle_t memh; 359 struct le_addresses *le_ap; 360 int i; 361 362 sc->sc_dev = self; 363 aprint_normal("\n%s: ", device_xname(self)); 364 365 if (bus_space_map(va->va_iot, va->va_iobase, va->va_iosize, 0, &ioh)) 366 panic("leattach: cannot map io-area"); 367 if (bus_space_map(va->va_memt, va->va_maddr, va->va_msize, 0, &memh)) 368 panic("leattach: cannot map mem-area"); 369 370 lesc->sc_iot = va->va_iot; 371 lesc->sc_ioh = ioh; 372 lesc->sc_memt = va->va_memt; 373 lesc->sc_memh = memh; 374 lesc->sc_splval = (va->va_irq << 8) | PSL_S; /* XXX */ 375 le_ap = (struct le_addresses *)va->va_aux; 376 377 /* 378 * Go on to find board type 379 */ 380 if ((le_ap->type_hint & LE_PAM) && 381 bus_space_peek_1(va->va_iot, ioh, LER_EEPROM)) { 382 aprint_normal("PAM card"); 383 lesc->sc_type = LE_PAM; 384 bus_space_read_1(va->va_iot, ioh, LER_MEME); 385 } else if ((le_ap->type_hint & LE_BVME410) && 386 bvme410_probe(va->va_iot, ioh)) { 387 aprint_normal("BVME410"); 388 lesc->sc_type = LE_BVME410; 389 } else if (le_ap->type_hint & (LE_NEW_RIEBL|LE_OLD_RIEBL)) { 390 aprint_normal("Riebl card"); 391 if (bus_space_read_4(va->va_memt, memh, RIEBL_MAGIC_ADDR) == 392 RIEBL_MAGIC) 393 lesc->sc_type = LE_NEW_RIEBL; 394 else { 395 aprint_normal("(without battery) "); 396 lesc->sc_type = LE_OLD_RIEBL; 397 } 398 } else 399 aprint_error("le_vme_attach: Unsupported card!"); 400 401 switch (lesc->sc_type) { 402 case LE_BVME410: 403 sc->sc_copytodesc = bvme410_copytobuf; 404 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 405 sc->sc_copytobuf = bvme410_copytobuf; 406 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 407 sc->sc_zerobuf = bvme410_zerobuf; 408 break; 409 default: 410 sc->sc_copytodesc = lance_copytobuf_contig; 411 sc->sc_copyfromdesc = lance_copyfrombuf_contig; 412 sc->sc_copytobuf = lance_copytobuf_contig; 413 sc->sc_copyfrombuf = lance_copyfrombuf_contig; 414 sc->sc_zerobuf = lance_zerobuf_contig; 415 break; 416 } 417 418 sc->sc_rdcsr = lerdcsr; 419 sc->sc_wrcsr = lewrcsr; 420 sc->sc_hwinit = NULL; 421 sc->sc_conf3 = LE_C3_BSWP; 422 sc->sc_addr = 0; 423 sc->sc_memsize = va->va_msize; 424 sc->sc_mem = (void *)memh; /* XXX */ 425 426 /* 427 * Get MAC address 428 */ 429 switch (lesc->sc_type) { 430 case LE_OLD_RIEBL: 431 memcpy(sc->sc_enaddr, riebl_def_mac, 432 sizeof(sc->sc_enaddr)); 433 break; 434 case LE_NEW_RIEBL: 435 for (i = 0; i < sizeof(sc->sc_enaddr); i++) 436 sc->sc_enaddr[i] = 437 bus_space_read_1(va->va_memt, memh, i + RIEBL_MAC_ADDR); 438 break; 439 case LE_PAM: 440 i = bus_space_read_1(va->va_iot, ioh, LER_EEPROM); 441 for (i = 0; i < sizeof(sc->sc_enaddr); i++) { 442 sc->sc_enaddr[i] = 443 (bus_space_read_2(va->va_memt, memh, 2 * i) << 4) | 444 (bus_space_read_2(va->va_memt, memh, 2 * i + 1) & 0xf); 445 } 446 i = bus_space_read_1(va->va_iot, ioh, LER_MEME); 447 break; 448 case LE_BVME410: 449 for (i = 0; i < (sizeof(sc->sc_enaddr) >> 1); i++) { 450 uint16_t tmp; 451 452 tmp = nm93c06_read(va->va_iot, ioh, i); 453 sc->sc_enaddr[2 * i] = (tmp >> 8) & 0xff; 454 sc->sc_enaddr[2 * i + 1] = tmp & 0xff; 455 } 456 bus_space_write_2(va->va_iot, ioh, BVME410_BAR, 0x1); /* XXX */ 457 } 458 459 am7990_config(&lesc->sc_am7990); 460 461 if ((lesc->sc_type == LE_OLD_RIEBL) || (lesc->sc_type == LE_NEW_RIEBL)) 462 riebl_skip_reserved_area(sc); 463 464 /* 465 * XXX: We always use uservector 64.... 466 */ 467 if ((lesc->sc_intr = intr_establish(64, USER_VEC, 0, 468 (hw_ifun_t)le_intr, lesc)) == NULL) { 469 aprint_error("le_vme_attach: Can't establish interrupt\n"); 470 return; 471 } 472 473 /* 474 * Notify the card of the vector 475 */ 476 switch (lesc->sc_type) { 477 case LE_OLD_RIEBL: 478 case LE_NEW_RIEBL: 479 bus_space_write_2(va->va_memt, memh, 480 RIEBL_IVEC_ADDR, 64 + 64); 481 break; 482 case LE_PAM: 483 bus_space_write_1(va->va_iot, ioh, 484 LER_IVEC, 64 + 64); 485 break; 486 case LE_BVME410: 487 bus_space_write_2(va->va_iot, ioh, 488 BVME410_IVEC, 64 + 64); 489 break; 490 } 491 492 /* 493 * Unmask the VME-interrupt we're on 494 */ 495 if (machineid & ATARI_TT) 496 SCU->vme_mask |= 1 << va->va_irq; 497 } 498 499 /* 500 * True if 'addr' containe within [start,len] 501 */ 502 #define WITHIN(start, len, addr) \ 503 ((addr >= start) && ((addr) <= ((start) + (len)))) 504 static void 505 riebl_skip_reserved_area(struct lance_softc *sc) 506 { 507 int offset = 0; 508 int i; 509 510 for (i = 0; i < sc->sc_nrbuf; i++) { 511 if (WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_START) || 512 WITHIN(sc->sc_rbufaddr[i], LEBLEN, RIEBL_RES_END)) { 513 offset = RIEBL_RES_END - sc->sc_rbufaddr[i]; 514 } 515 sc->sc_rbufaddr[i] += offset; 516 } 517 518 for (i = 0; i < sc->sc_ntbuf; i++) { 519 if (WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_START) || 520 WITHIN(sc->sc_tbufaddr[i], LEBLEN, RIEBL_RES_END)) { 521 offset = RIEBL_RES_END - sc->sc_tbufaddr[i]; 522 } 523 sc->sc_tbufaddr[i] += offset; 524 } 525 } 526 527 static int 528 nm93c06_read(bus_space_tag_t iot, bus_space_handle_t ioh, int nm93c06reg) 529 { 530 int bar; 531 int shift; 532 int bits = 0x180 | (nm93c06reg & 0xf); 533 int data = 0; 534 535 bar = 1 << BVME410_CS_SHIFT; 536 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 537 delay(1); /* tCSS = 1 us */ 538 for (shift = 9; shift >= 0; shift--) { 539 if (((bits >> shift) & 1) == 1) 540 bar |= 1 << BVME410_DIN_SHIFT; 541 else 542 bar &= ~(1 << BVME410_DIN_SHIFT); 543 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 544 delay(1); /* tDIS = 0.4 us */ 545 bar |= 1 << BVME410_CLK_SHIFT; 546 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 547 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 548 bar &= ~(1 << BVME410_CLK_SHIFT); 549 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 550 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 551 } 552 bar &= ~(1 << BVME410_DIN_SHIFT); 553 for (shift = 15; shift >= 0; shift--) { 554 delay(1); /* tDIS = 100 ns, BVM manual says 0.4 us */ 555 bar |= 1 << BVME410_CLK_SHIFT; 556 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 557 delay(2); /* tSKH = 1 us, tSKH + tSKL >= 4 us */ 558 data |= (bus_space_read_2(iot, ioh, BVME410_BAR) & 1) << shift; 559 bar &= ~(1 << BVME410_CLK_SHIFT); 560 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 561 delay(2); /* tSKL = 1 us, tSKH + tSKL >= 4 us */ 562 } 563 bar &= ~(1 << BVME410_CS_SHIFT); 564 bus_space_write_2(iot, ioh, BVME410_BAR, bar); 565 delay(1); /* tCS = 1 us */ 566 return data; 567 } 568 569 static int 570 bvme410_probe(bus_space_tag_t iot, bus_space_handle_t ioh) 571 { 572 573 if (!bus_space_peek_2(iot, ioh, BVME410_IVEC)) 574 return 0; 575 576 bus_space_write_2(iot, ioh, BVME410_IVEC, 0x0000); 577 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xff00) 578 return 0; 579 580 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xffff); 581 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffff) 582 return 0; 583 584 bus_space_write_2(iot, ioh, BVME410_IVEC, 0xa5a5); 585 if (bus_space_read_2(iot, ioh, BVME410_IVEC) != 0xffa5) 586 return 0; 587 588 return 1; 589 } 590 591 static int 592 bvme410_mem_size(bus_space_tag_t memt, u_long mem_addr) 593 { 594 bus_space_handle_t memh; 595 int r; 596 597 if (bus_space_map(memt, mem_addr, 256 * 1024, 0, &memh)) 598 return VMECF_MEMSIZ_DEFAULT; 599 if (!bus_space_peek_1(memt, memh, 0)) { 600 bus_space_unmap(memt, memh, 256 * 1024); 601 return VMECF_MEMSIZ_DEFAULT; 602 } 603 bus_space_write_1(memt, memh, 0, 128); 604 bus_space_write_1(memt, memh, 64 * 1024, 32); 605 bus_space_write_1(memt, memh, 32 * 1024, 8); 606 r = (int)(bus_space_read_1(memt, memh, 0) * 2048); 607 bus_space_unmap(memt, memh, 256 * 1024); 608 return r; 609 } 610 611 /* 612 * Need to be careful when writing to the bvme410 dual port memory. 613 * Continue writing each byte until it reads back the same. 614 */ 615 616 static void 617 bvme410_copytobuf(struct lance_softc *sc, void *from, int boff, int len) 618 { 619 volatile char *buf = (volatile char *)sc->sc_mem; 620 char *f = (char *)from; 621 622 for (buf += boff; len; buf++,f++,len--) 623 do { 624 *buf = *f; 625 } while (*buf != *f); 626 } 627 628 static void 629 bvme410_zerobuf(struct lance_softc *sc, int boff, int len) 630 { 631 volatile char *buf = (volatile char *)sc->sc_mem; 632 633 for (buf += boff; len; buf++,len--) 634 do { 635 *buf = '\0'; 636 } while (*buf != '\0'); 637 } 638 639