1/* $NecBSD: dp83932subr.c,v 1.5.6.2 1999/10/09 05:47:23 kmatsuda Exp $ */ 2/* $NetBSD$ */ 3 4/*- 5 * Copyright (c) 1997, 1998, 1999 6 * Kouichi Matsuda. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Kouichi Matsuda for 19 * NetBSD/pc98. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD$"); 37/* 38 * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R 39 * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda. 40 * 41 * These cards use National Semiconductor DP83934AVQB as Ethernet Controller 42 * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM. 43 */ 44 45/* 46 * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki. 47 */ 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/protosw.h> 52#include <sys/socket.h> 53 54#include <net/ethernet.h> 55#include <net/if.h> 56#include <net/if_arp.h> 57#include <net/if_media.h> 58 59#include <sys/bus.h> 60#include <machine/bus.h> 61 62#include <dev/snc/dp83932reg.h> 63#include <dev/snc/dp83932var.h> 64#include <dev/snc/if_sncreg.h> 65#include <dev/snc/dp83932subr.h> 66 67static __inline u_int16_t snc_nec16_select_bank 68 (struct snc_softc *, u_int32_t, u_int32_t); 69 70/* 71 * Interface exists: make available by filling in network interface 72 * record. System will initialize the interface when it is ready 73 * to accept packets. 74 */ 75int 76sncsetup(struct snc_softc *sc, u_int8_t *lladdr) 77{ 78 u_int32_t p, pp; 79 int i; 80 int offset; 81 82 /* 83 * Put the pup in reset mode (sncinit() will fix it later), 84 * stop the timer, disable all interrupts and clear any interrupts. 85 */ 86 NIC_PUT(sc, SNCR_CR, CR_STP); 87 wbflush(); 88 NIC_PUT(sc, SNCR_CR, CR_RST); 89 wbflush(); 90 NIC_PUT(sc, SNCR_IMR, 0); 91 wbflush(); 92 NIC_PUT(sc, SNCR_ISR, ISR_ALL); 93 wbflush(); 94 95 /* 96 * because the SONIC is basically 16bit device it 'concatenates' 97 * a higher buffer address to a 16 bit offset--this will cause wrap 98 * around problems near the end of 64k !! 99 */ 100 p = pp = 0; 101 102 for (i = 0; i < NRRA; i++) { 103 sc->v_rra[i] = SONIC_GETDMA(p); 104 p += RXRSRC_SIZE(sc); 105 } 106 sc->v_rea = SONIC_GETDMA(p); 107 108 p = SOALIGN(sc, p); 109 110 sc->v_cda = SONIC_GETDMA(p); 111 p += CDA_SIZE(sc); 112 113 p = SOALIGN(sc, p); 114 115 for (i = 0; i < NTDA; i++) { 116 struct mtd *mtdp = &sc->mtda[i]; 117 mtdp->mtd_vtxp = SONIC_GETDMA(p); 118 p += TXP_SIZE(sc); 119 } 120 121 p = SOALIGN(sc, p); 122 123 if ((p - pp) > PAGE_SIZE) { 124 device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +" 125 "TDA (%ld) > PAGE_SIZE (%d). Punt!\n", 126 (u_long)sc->v_cda - (u_long)sc->v_rra[0], 127 (u_long)sc->mtda[0].mtd_vtxp - (u_long)sc->v_cda, 128 (u_long)p - (u_long)sc->mtda[0].mtd_vtxp, 129 PAGE_SIZE); 130 return(1); 131 } 132 133 p = pp + PAGE_SIZE; 134 pp = p; 135 136 sc->sc_nrda = PAGE_SIZE / RXPKT_SIZE(sc); 137 sc->v_rda = SONIC_GETDMA(p); 138 139 p = pp + PAGE_SIZE; 140 141 for (i = 0; i < NRBA; i++) { 142 sc->rbuf[i] = p; 143 p += PAGE_SIZE; 144 } 145 146 pp = p; 147 offset = TXBSIZE; 148 for (i = 0; i < NTDA; i++) { 149 struct mtd *mtdp = &sc->mtda[i]; 150 151 mtdp->mtd_vbuf = SONIC_GETDMA(p); 152 offset += TXBSIZE; 153 if (offset < PAGE_SIZE) { 154 p += TXBSIZE; 155 } else { 156 p = pp + PAGE_SIZE; 157 pp = p; 158 offset = TXBSIZE; 159 } 160 } 161 162 return (0); 163} 164 165/* 166 * miscellaneous NEC/SONIC detect functions. 167 */ 168 169/* 170 * check if a specified irq is acceptable. 171 */ 172u_int8_t 173snc_nec16_validate_irq(int irq) 174{ 175 const u_int8_t encoded_irq[16] = { 176 -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1 177 }; 178 179 return encoded_irq[irq]; 180} 181 182/* 183 * specify irq to board. 184 */ 185int 186snc_nec16_register_irq(struct snc_softc *sc, int irq) 187{ 188 bus_space_tag_t iot = sc->sc_iot; 189 bus_space_handle_t ioh = sc->sc_ioh; 190 u_int8_t encoded_irq; 191 192 encoded_irq = snc_nec16_validate_irq(irq); 193 if (encoded_irq == (u_int8_t) -1) { 194 printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq); 195 return 0; 196 } 197 198 /* select SNECR_IRQSEL register */ 199 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL); 200 /* write encoded irq value */ 201 bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq); 202 203 return 1; 204} 205 206/* 207 * check if a specified memory base address is acceptable. 208 */ 209int 210snc_nec16_validate_mem(int maddr) 211{ 212 213 /* Check on Normal mode with max range, only */ 214 if ((maddr & ~0x1E000) != 0xC0000) { 215 printf("snc_nec16_validate_mem: " 216 "unsupported window base (0x%x)\n", maddr); 217 return 0; 218 } 219 220 return 1; 221} 222 223/* 224 * specify memory base address to board and map to first bank. 225 */ 226int 227snc_nec16_register_mem(struct snc_softc *sc, int maddr) 228{ 229 bus_space_tag_t iot = sc->sc_iot; 230 bus_space_handle_t ioh = sc->sc_ioh; 231 232 if (snc_nec16_validate_mem(maddr) == 0) 233 return 0; 234 235 /* select SNECR_MEMSEL register */ 236 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL); 237 /* write encoded memory base select value */ 238 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr)); 239 240 /* 241 * set current bank to 0 (bottom) and map 242 */ 243 /* select SNECR_MEMBS register */ 244 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 245 /* select new bank */ 246 bus_space_write_1(iot, ioh, SNEC_CTRLB, 247 SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN); 248 /* set current bank to 0 */ 249 sc->curbank = 0; 250 251 return 1; 252} 253 254int 255snc_nec16_check_memory(bus_space_tag_t iot, bus_space_handle_t ioh, 256 bus_space_tag_t memt, bus_space_handle_t memh) 257{ 258 u_int16_t val; 259 int i, j; 260 261 val = 0; 262 for (i = 0; i < SNEC_NBANK; i++) { 263 /* select new bank */ 264 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 265 bus_space_write_1(iot, ioh, SNEC_CTRLB, 266 SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 267 268 /* write test pattern */ 269 for (j = 0; j < SNEC_NMEMS / 2; j++) { 270 bus_space_write_2(memt, memh, j * 2, val + j); 271 } 272 val += 0x1000; 273 } 274 275 val = 0; 276 for (i = 0; i < SNEC_NBANK; i++) { 277 /* select new bank */ 278 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 279 bus_space_write_1(iot, ioh, SNEC_CTRLB, 280 SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 281 282 /* read test pattern */ 283 for (j = 0; j < SNEC_NMEMS / 2; j++) { 284 if (bus_space_read_2(memt, memh, j * 2) != val + j) 285 break; 286 } 287 288 if (j < SNEC_NMEMS / 2) { 289 printf("snc_nec16_check_memory: " 290 "memory check failed at 0x%04x%04x" 291 "val 0x%04x != expected 0x%04x\n", i, j, 292 bus_space_read_2(memt, memh, j * 2), 293 val + j); 294 return 0; 295 } 296 val += 0x1000; 297 } 298 299 /* zero clear mem */ 300 for (i = 0; i < SNEC_NBANK; i++) { 301 /* select new bank */ 302 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 303 bus_space_write_1(iot, ioh, SNEC_CTRLB, 304 SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 305 306 bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2); 307 } 308 309 /* again read test if these are 0 */ 310 for (i = 0; i < SNEC_NBANK; i++) { 311 /* select new bank */ 312 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 313 bus_space_write_1(iot, ioh, SNEC_CTRLB, 314 SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 315 316 /* check if cleared */ 317 for (j = 0; j < SNEC_NMEMS; j += 2) { 318 if (bus_space_read_2(memt, memh, j) != 0) 319 break; 320 } 321 322 if (j != SNEC_NMEMS) { 323 printf("snc_nec16_check_memory: " 324 "memory zero clear failed at 0x%04x%04x\n", i, j); 325 return 0; 326 } 327 } 328 329 return 1; 330} 331 332int 333snc_nec16_detectsubr(bus_space_tag_t iot, bus_space_handle_t ioh, 334 bus_space_tag_t memt, bus_space_handle_t memh, int irq, int maddr, 335 u_int8_t type) 336{ 337 u_int16_t cr; 338 u_int8_t ident; 339 int rv = 0; 340 341 if (snc_nec16_validate_irq(irq) == (u_int8_t) -1) 342 return 0; 343 /* XXX: maddr already checked */ 344 if (snc_nec16_validate_mem(maddr) == 0) 345 return 0; 346 347 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT); 348 ident = bus_space_read_1(iot, ioh, SNEC_CTRLB); 349 if (ident == 0xff || ident == 0x00) { 350 /* not found */ 351 return 0; 352 } 353 354 switch (type) { 355 case SNEC_TYPE_LEGACY: 356 rv = (ident == SNECR_IDENT_LEGACY_CBUS); 357 break; 358 case SNEC_TYPE_PNP: 359 rv = ((ident == SNECR_IDENT_PNP_CBUS) || 360 (ident == SNECR_IDENT_PNP_PCMCIABUS)); 361 break; 362 default: 363 break; 364 } 365 366 if (rv == 0) { 367 printf("snc_nec16_detectsubr: parent bus mismatch\n"); 368 return 0; 369 } 370 371 /* select SONIC register SNCR_CR */ 372 bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR); 373 bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST); 374 DELAY(400); 375 376 cr = bus_space_read_2(iot, ioh, SNEC_CTRL); 377 if (cr != (CR_RXDIS | CR_STP | CR_RST)) { 378#ifdef DIAGNOSTIC 379 printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n", 380 cr); 381#endif 382 return 0; 383 } 384 385 if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0) 386 return 0; 387 388 return 1; 389} 390 391/* XXX */ 392#define SNC_VENDOR_NEC 0x00004c 393#define SNC_NEC_SERIES_LEGACY_CBUS 0xa5 394#define SNC_NEC_SERIES_PNP_PCMCIA 0xd5 395#define SNC_NEC_SERIES_PNP_PCMCIA2 0x6d /* XXX */ 396#define SNC_NEC_SERIES_PNP_CBUS 0x0d 397#define SNC_NEC_SERIES_PNP_CBUS2 0x3d 398 399u_int8_t * 400snc_nec16_detect_type(u_int8_t *myea) 401{ 402 u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2]; 403 u_int8_t series = myea[3]; 404 u_int8_t type = myea[4] & 0x80; 405 u_int8_t *typestr; 406 407 switch (vendor) { 408 case SNC_VENDOR_NEC: 409 switch (series) { 410 case SNC_NEC_SERIES_LEGACY_CBUS: 411 if (type) 412 typestr = "NEC PC-9801-84"; 413 else 414 typestr = "NEC PC-9801-83"; 415 break; 416 case SNC_NEC_SERIES_PNP_CBUS: 417 case SNC_NEC_SERIES_PNP_CBUS2: 418 if (type) 419 typestr = "NEC PC-9801-104"; 420 else 421 typestr = "NEC PC-9801-103"; 422 break; 423 case SNC_NEC_SERIES_PNP_PCMCIA: 424 case SNC_NEC_SERIES_PNP_PCMCIA2: 425 /* XXX: right ? */ 426 if (type) 427 typestr = "NEC PC-9801N-J02R"; 428 else 429 typestr = "NEC PC-9801N-J02"; 430 break; 431 default: 432 typestr = "NEC unknown (PC-9801N-25?)"; 433 break; 434 } 435 break; 436 default: 437 typestr = "unknown (3rd vendor?)"; 438 break; 439 } 440 441 return typestr; 442} 443 444int 445snc_nec16_get_enaddr(bus_space_tag_t iot, bus_space_handle_t ioh, 446 u_int8_t *myea) 447{ 448 u_int8_t eeprom[SNEC_EEPROM_SIZE]; 449 u_int8_t rom_sum, sum = 0x00; 450 int i; 451 452 snc_nec16_read_eeprom(iot, ioh, eeprom); 453 454 for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) { 455 sum = sum ^ eeprom[i]; 456 } 457 458 rom_sum = eeprom[SNEC_EEPROM_CKSUM]; 459 460 if (sum != rom_sum) { 461 printf("snc_nec16_get_enaddr: " 462 "checksum mismatch; calculated %02x != read %02x", 463 sum, rom_sum); 464 return 0; 465 } 466 467 for (i = 0; i < ETHER_ADDR_LEN; i++) 468 myea[i] = eeprom[SNEC_EEPROM_SA0 + i]; 469 470 return 1; 471} 472 473/* 474 * read from NEC/SONIC NIC register. 475 */ 476u_int16_t 477snc_nec16_nic_get(struct snc_softc *sc, u_int8_t reg) 478{ 479 u_int16_t val; 480 481 /* select SONIC register */ 482 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); 483 val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL); 484 485 return val; 486} 487 488/* 489 * write to NEC/SONIC NIC register. 490 */ 491void 492snc_nec16_nic_put(struct snc_softc *sc, u_int8_t reg, u_int16_t val) 493{ 494 495 /* select SONIC register */ 496 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); 497 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val); 498} 499 500 501/* 502 * select memory bank and map 503 * where exists specified (internal buffer memory) offset. 504 */ 505static __inline u_int16_t 506snc_nec16_select_bank(struct snc_softc *sc, u_int32_t base, u_int32_t offset) 507{ 508 bus_space_tag_t iot = sc->sc_iot; 509 bus_space_handle_t ioh = sc->sc_ioh; 510 u_int8_t bank; 511 u_int16_t noffset; 512 513 /* bitmode is fixed to 16 bit. */ 514 bank = (base + offset * 2) >> 13; 515 noffset = (base + offset * 2) & (SNEC_NMEMS - 1); 516 517#ifdef SNCDEBUG 518 if (noffset % 2) { 519 device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n", 520 noffset); 521 } 522#endif /* SNCDEBUG */ 523 524 if (sc->curbank != bank) { 525 /* select SNECR_MEMBS register */ 526 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 527 /* select new bank */ 528 bus_space_write_1(iot, ioh, SNEC_CTRLB, 529 SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN); 530 /* update current bank */ 531 sc->curbank = bank; 532 } 533 534 return noffset; 535} 536 537/* 538 * write to SONIC descriptors. 539 */ 540void 541snc_nec16_writetodesc(struct snc_softc *sc, u_int32_t base, u_int32_t offset, 542 u_int16_t val) 543{ 544 bus_space_tag_t memt = sc->sc_memt; 545 bus_space_handle_t memh = sc->sc_memh; 546 u_int16_t noffset; 547 548 noffset = snc_nec16_select_bank(sc, base, offset); 549 550 bus_space_write_2(memt, memh, noffset, val); 551} 552 553/* 554 * read from SONIC descriptors. 555 */ 556u_int16_t 557snc_nec16_readfromdesc(struct snc_softc *sc, u_int32_t base, u_int32_t offset) 558{ 559 bus_space_tag_t memt = sc->sc_memt; 560 bus_space_handle_t memh = sc->sc_memh; 561 u_int16_t noffset; 562 563 noffset = snc_nec16_select_bank(sc, base, offset); 564 565 return bus_space_read_2(memt, memh, noffset); 566} 567 568/* 569 * read from SONIC data buffer. 570 */ 571void 572snc_nec16_copyfrombuf(struct snc_softc *sc, void *dst, u_int32_t offset, 573 size_t size) 574{ 575 bus_space_tag_t memt = sc->sc_memt; 576 bus_space_handle_t memh = sc->sc_memh; 577 u_int16_t noffset; 578 u_int8_t* bptr = dst; 579 580 noffset = snc_nec16_select_bank(sc, offset, 0); 581 582 /* XXX: should check if offset + size < 0x2000. */ 583 584 bus_space_barrier(memt, memh, noffset, size, 585 BUS_SPACE_BARRIER_READ); 586 587 if (size > 3) { 588 if (noffset & 3) { 589 size_t asize = 4 - (noffset & 3); 590 591 bus_space_read_region_1(memt, memh, noffset, 592 bptr, asize); 593 bptr += asize; 594 noffset += asize; 595 size -= asize; 596 } 597 bus_space_read_region_4(memt, memh, noffset, 598 (u_int32_t *) bptr, size >> 2); 599 bptr += size & ~3; 600 noffset += size & ~3; 601 size &= 3; 602 } 603 if (size) 604 bus_space_read_region_1(memt, memh, noffset, bptr, size); 605} 606 607/* 608 * write to SONIC data buffer. 609 */ 610void 611snc_nec16_copytobuf(struct snc_softc *sc, void *src, u_int32_t offset, 612 size_t size) 613{ 614 bus_space_tag_t memt = sc->sc_memt; 615 bus_space_handle_t memh = sc->sc_memh; 616 u_int16_t noffset, onoffset; 617 size_t osize = size; 618 u_int8_t* bptr = src; 619 620 noffset = snc_nec16_select_bank(sc, offset, 0); 621 onoffset = noffset; 622 623 /* XXX: should check if offset + size < 0x2000. */ 624 625 if (size > 3) { 626 if (noffset & 3) { 627 size_t asize = 4 - (noffset & 3); 628 629 bus_space_write_region_1(memt, memh, noffset, 630 bptr, asize); 631 bptr += asize; 632 noffset += asize; 633 size -= asize; 634 } 635 bus_space_write_region_4(memt, memh, noffset, 636 (u_int32_t *)bptr, size >> 2); 637 bptr += size & ~3; 638 noffset += size & ~3; 639 size -= size & ~3; 640 } 641 if (size) 642 bus_space_write_region_1(memt, memh, noffset, bptr, size); 643 644 bus_space_barrier(memt, memh, onoffset, osize, 645 BUS_SPACE_BARRIER_WRITE); 646} 647 648/* 649 * write (fill) 0 to SONIC data buffer. 650 */ 651void 652snc_nec16_zerobuf(struct snc_softc *sc, u_int32_t offset, size_t size) 653{ 654 bus_space_tag_t memt = sc->sc_memt; 655 bus_space_handle_t memh = sc->sc_memh; 656 u_int16_t noffset, onoffset; 657 size_t osize = size; 658 659 noffset = snc_nec16_select_bank(sc, offset, 0); 660 onoffset = noffset; 661 662 /* XXX: should check if offset + size < 0x2000. */ 663 664 if (size > 3) { 665 if (noffset & 3) { 666 size_t asize = 4 - (noffset & 3); 667 668 bus_space_set_region_1(memt, memh, noffset, 0, asize); 669 noffset += asize; 670 size -= asize; 671 } 672 bus_space_set_region_4(memt, memh, noffset, 0, size >> 2); 673 noffset += size & ~3; 674 size -= size & ~3; 675 } 676 if (size) 677 bus_space_set_region_1(memt, memh, noffset, 0, size); 678 679 bus_space_barrier(memt, memh, onoffset, osize, 680 BUS_SPACE_BARRIER_WRITE); 681} 682 683 684/* 685 * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83, 686 * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98. 687 * Ported by Kouichi Matsuda. 688 * 689 * This algorism is generic to read data sequentially from 4-Wire 690 * Microwire Serial EEPROM. 691 */ 692 693#define SNEC_EEP_DELAY 1000 694 695void 696snc_nec16_read_eeprom(bus_space_tag_t iot, bus_space_handle_t ioh, 697 u_int8_t *data) 698{ 699 u_int8_t n, val, bit; 700 701 /* Read bytes from EEPROM; two bytes per an iteration. */ 702 for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) { 703 /* select SNECR_EEP */ 704 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP); 705 706 bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); 707 DELAY(SNEC_EEP_DELAY); 708 709 /* Start EEPROM access. */ 710 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 711 DELAY(SNEC_EEP_DELAY); 712 713 bus_space_write_1(iot, ioh, SNEC_CTRLB, 714 SNECR_EEP_CS | SNECR_EEP_SK); 715 DELAY(SNEC_EEP_DELAY); 716 717 bus_space_write_1(iot, ioh, SNEC_CTRLB, 718 SNECR_EEP_CS | SNECR_EEP_DI); 719 DELAY(SNEC_EEP_DELAY); 720 721 bus_space_write_1(iot, ioh, SNEC_CTRLB, 722 SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); 723 DELAY(SNEC_EEP_DELAY); 724 725 bus_space_write_1(iot, ioh, SNEC_CTRLB, 726 SNECR_EEP_CS | SNECR_EEP_DI); 727 DELAY(SNEC_EEP_DELAY); 728 729 bus_space_write_1(iot, ioh, SNEC_CTRLB, 730 SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); 731 DELAY(SNEC_EEP_DELAY); 732 733 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 734 DELAY(SNEC_EEP_DELAY); 735 736 bus_space_write_1(iot, ioh, SNEC_CTRLB, 737 SNECR_EEP_CS | SNECR_EEP_SK); 738 DELAY(SNEC_EEP_DELAY); 739 740 /* Pass the iteration count to the chip. */ 741 for (bit = 0x20; bit != 0x00; bit >>= 1) { 742 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS | 743 ((n & bit) ? SNECR_EEP_DI : 0x00)); 744 DELAY(SNEC_EEP_DELAY); 745 746 bus_space_write_1(iot, ioh, SNEC_CTRLB, 747 SNECR_EEP_CS | SNECR_EEP_SK | 748 ((n & bit) ? SNECR_EEP_DI : 0x00)); 749 DELAY(SNEC_EEP_DELAY); 750 } 751 752 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 753 (void) bus_space_read_1(iot, ioh, SNEC_CTRLB); /* ACK */ 754 DELAY(SNEC_EEP_DELAY); 755 756 /* Read a byte. */ 757 val = 0; 758 for (bit = 0x80; bit != 0x00; bit >>= 1) { 759 bus_space_write_1(iot, ioh, SNEC_CTRLB, 760 SNECR_EEP_CS | SNECR_EEP_SK); 761 DELAY(SNEC_EEP_DELAY); 762 763 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 764 765 if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) 766 val |= bit; 767 } 768 *data++ = val; 769 770 /* Read one more byte. */ 771 val = 0; 772 for (bit = 0x80; bit != 0x00; bit >>= 1) { 773 bus_space_write_1(iot, ioh, SNEC_CTRLB, 774 SNECR_EEP_CS | SNECR_EEP_SK); 775 DELAY(SNEC_EEP_DELAY); 776 777 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 778 779 if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) 780 val |= bit; 781 } 782 *data++ = val; 783 784 bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); 785 DELAY(SNEC_EEP_DELAY); 786 } 787 788#ifdef SNCDEBUG 789 /* Report what we got. */ 790 data -= SNEC_EEPROM_SIZE; 791 log(LOG_INFO, "%s: EEPROM:" 792 " %02x%02x%02x%02x %02x%02x%02x%02x -" 793 " %02x%02x%02x%02x %02x%02x%02x%02x -" 794 " %02x%02x%02x%02x %02x%02x%02x%02x -" 795 " %02x%02x%02x%02x %02x%02x%02x%02x\n", 796 "snc_nec16_read_eeprom", 797 data[ 0], data[ 1], data[ 2], data[ 3], 798 data[ 4], data[ 5], data[ 6], data[ 7], 799 data[ 8], data[ 9], data[10], data[11], 800 data[12], data[13], data[14], data[15], 801 data[16], data[17], data[18], data[19], 802 data[20], data[21], data[22], data[23], 803 data[24], data[25], data[26], data[27], 804 data[28], data[29], data[30], data[31]); 805#endif 806} 807 808#ifdef SNCDEBUG 809void 810snc_nec16_dump_reg(bus_space_tag_t iot, bus_space_handle_t ioh) 811{ 812 u_int8_t n; 813 u_int16_t val; 814 815 printf("SONIC registers (word):"); 816 for (n = 0; n < SNC_NREGS; n++) { 817 /* select required SONIC register */ 818 bus_space_write_1(iot, ioh, SNEC_ADDR, n); 819 DELAY(10); 820 val = bus_space_read_2(iot, ioh, SNEC_CTRL); 821 if ((n % 0x10) == 0) 822 printf("\n%04x ", val); 823 else 824 printf("%04x ", val); 825 } 826 printf("\n"); 827 828 printf("NEC/SONIC registers (byte):\n"); 829 for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) { 830 /* select required SONIC register */ 831 bus_space_write_1(iot, ioh, SNEC_ADDR, n); 832 DELAY(10); 833 val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB); 834 printf("%04x ", val); 835 } 836 printf("\n"); 837} 838 839#endif /* SNCDEBUG */ 840