diff options
author | nyan <nyan@FreeBSD.org> | 2000-10-02 14:27:20 +0000 |
---|---|---|
committer | nyan <nyan@FreeBSD.org> | 2000-10-02 14:27:20 +0000 |
commit | bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26 (patch) | |
tree | 7b40f1f273ca32e8c8eaf31dc2de4a944e5022f8 /sys/dev/snc/dp83932subr.c | |
parent | ca9093b327311b17a6c77820abb0c66abf6a94f4 (diff) | |
download | FreeBSD-src-bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26.zip FreeBSD-src-bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26.tar.gz |
Added NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and PC-9801N-J02R
support which use National Semiconductor DP8393X (SONIC) as ethernet
controller. Currently, this driver is used on only PC-98.
Submitted by: Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
Obtained from: NetBSD/pc98
Diffstat (limited to 'sys/dev/snc/dp83932subr.c')
-rw-r--r-- | sys/dev/snc/dp83932subr.c | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/sys/dev/snc/dp83932subr.c b/sys/dev/snc/dp83932subr.c new file mode 100644 index 0000000..65b9de9 --- /dev/null +++ b/sys/dev/snc/dp83932subr.c @@ -0,0 +1,902 @@ +/* $FreeBSD$ */ +/* $NecBSD: dp83932subr.c,v 1.5.6.2 1999/10/09 05:47:23 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * Copyright (c) 1997, 1998, 1999 + * Kouichi Matsuda. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Kouichi Matsuda for + * NetBSD/pc98. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R + * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda. + * + * These cards use National Semiconductor DP83934AVQB as Ethernet Controller + * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM. + */ + +/* + * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/errno.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_media.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_inarp.h> +#endif + +#include <net/bpf.h> + +#include <sys/bus.h> +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> + +#include <dev/snc/dp83932reg.h> +#include <dev/snc/dp83932var.h> +#include <dev/snc/if_sncreg.h> +#include <dev/snc/dp83932subr.h> + +integrate u_int16_t snc_nec16_select_bank + __P((struct snc_softc *, u_int32_t, u_int32_t)); + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +int +sncsetup(sc, lladdr) + struct snc_softc *sc; + u_int8_t *lladdr; +{ + u_int32_t p, pp; + int i; + int offset; + + /* + * Put the pup in reset mode (sncinit() will fix it later), + * stop the timer, disable all interrupts and clear any interrupts. + */ + NIC_PUT(sc, SNCR_CR, CR_STP); + wbflush(); + NIC_PUT(sc, SNCR_CR, CR_RST); + wbflush(); + NIC_PUT(sc, SNCR_IMR, 0); + wbflush(); + NIC_PUT(sc, SNCR_ISR, ISR_ALL); + wbflush(); + + /* + * because the SONIC is basically 16bit device it 'concatenates' + * a higher buffer address to a 16 bit offset--this will cause wrap + * around problems near the end of 64k !! + */ + p = pp = 0; + + for (i = 0; i < NRRA; i++) { + sc->v_rra[i] = SONIC_GETDMA(p); + p += RXRSRC_SIZE(sc); + } + sc->v_rea = SONIC_GETDMA(p); + + p = SOALIGN(sc, p); + + sc->v_cda = SONIC_GETDMA(p); + p += CDA_SIZE(sc); + + p = SOALIGN(sc, p); + + for (i = 0; i < NTDA; i++) { + struct mtd *mtdp = &sc->mtda[i]; + mtdp->mtd_vtxp = SONIC_GETDMA(p); + p += TXP_SIZE(sc); + } + + p = SOALIGN(sc, p); + + if ((p - pp) > NBPG) { + device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +" + "TDA (%ld) > NBPG (%d). Punt!\n", + (ulong)sc->v_cda - (ulong)sc->v_rra[0], + (ulong)sc->mtda[0].mtd_vtxp - (ulong)sc->v_cda, + (ulong)p - (ulong)sc->mtda[0].mtd_vtxp, + NBPG); + return(1); + } + + p = pp + NBPG; + pp = p; + + sc->sc_nrda = NBPG / RXPKT_SIZE(sc); + sc->v_rda = SONIC_GETDMA(p); + + p = pp + NBPG; + + for (i = 0; i < NRBA; i++) { + sc->rbuf[i] = p; + p += NBPG; + } + + pp = p; + offset = TXBSIZE; + for (i = 0; i < NTDA; i++) { + struct mtd *mtdp = &sc->mtda[i]; + + mtdp->mtd_vbuf = SONIC_GETDMA(p); + offset += TXBSIZE; + if (offset < NBPG) { + p += TXBSIZE; + } else { + p = pp + NBPG; + pp = p; + offset = TXBSIZE; + } + } + + return (0); +} + +/* + * miscellaneous NEC/SONIC detect functions. + */ + +/* + * check if a specified irq is acceptable. + */ +u_int8_t +snc_nec16_validate_irq(irq) + int irq; +{ + const u_int8_t encoded_irq[16] = { + -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1 + }; + + return encoded_irq[irq]; +} + +/* + * specify irq to board. + */ +int +snc_nec16_register_irq(sc, irq) + struct snc_softc *sc; + int irq; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t encoded_irq; + + encoded_irq = snc_nec16_validate_irq(irq); + if (encoded_irq == (u_int8_t) -1) { + printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq); + return 0; + } + + /* select SNECR_IRQSEL register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL); + /* write encoded irq value */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq); + + return 1; +} + +/* + * check if a specified memory base address is acceptable. + */ +int +snc_nec16_validate_mem(maddr) + int maddr; +{ + + /* Check on Normal mode with max range, only */ + if ((maddr & ~0x1E000) != 0xC0000) { + printf("snc_nec16_validate_mem: " + "unsupported window base (0x%x)\n", maddr); + return 0; + } + + return 1; +} + +/* + * specify memory base address to board and map to first bank. + */ +int +snc_nec16_register_mem(sc, maddr) + struct snc_softc *sc; + int maddr; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + if (snc_nec16_validate_mem(maddr) == 0) + return 0; + + /* select SNECR_MEMSEL register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL); + /* write encoded memory base select value */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr)); + + /* + * set current bank to 0 (bottom) and map + */ + /* select SNECR_MEMBS register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN); + /* set current bank to 0 */ + sc->curbank = 0; + + return 1; +} + +int +snc_nec16_check_memory(iot, ioh, memt, memh) + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_space_tag_t memt; + bus_space_handle_t memh; +{ + u_int16_t val; + int i, j; + + val = 0; + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + /* write test pattern */ + for (j = 0; j < SNEC_NMEMS / 2; j++) { + bus_space_write_2(memt, memh, j * 2, val + j); + } + val += 0x1000; + } + + val = 0; + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + /* read test pattern */ + for (j = 0; j < SNEC_NMEMS / 2; j++) { + if (bus_space_read_2(memt, memh, j * 2) != val + j) + break; + } + + if (j < SNEC_NMEMS / 2) { + printf("snc_nec16_check_memory: " + "memory check failed at 0x%04x%04x" + "val 0x%04x != expected 0x%04x\n", i, j, + bus_space_read_2(memt, memh, j * 2), + val + j); + return 0; + } + val += 0x1000; + } + + /* zero clear mem */ + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2); + } + + /* again read test if these are 0 */ + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + /* check if cleared */ + for (j = 0; j < SNEC_NMEMS; j += 2) { + if (bus_space_read_2(memt, memh, j) != 0) + break; + } + + if (j != SNEC_NMEMS) { + printf("snc_nec16_check_memory: " + "memory zero clear failed at 0x%04x%04x\n", i, j); + return 0; + } + } + + return 1; +} + +int +snc_nec16_detectsubr(iot, ioh, memt, memh, irq, maddr, type) + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_space_tag_t memt; + bus_space_handle_t memh; + int irq; + int maddr; + u_int8_t type; +{ + u_int16_t cr; + u_int8_t ident; + int rv = 0; + + if (snc_nec16_validate_irq(irq) == (u_int8_t) -1) + return 0; + /* XXX: maddr already checked */ + if (snc_nec16_validate_mem(maddr) == 0) + return 0; + + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT); + ident = bus_space_read_1(iot, ioh, SNEC_CTRLB); + if (ident == 0xff || ident == 0x00) { + /* not found */ + return 0; + } + + switch (type) { + case SNEC_TYPE_LEGACY: + rv = (ident == SNECR_IDENT_LEGACY_CBUS); + break; + case SNEC_TYPE_PNP: + rv = ((ident == SNECR_IDENT_PNP_CBUS) || + (ident == SNECR_IDENT_PNP_PCMCIABUS)); + break; + default: + break; + } + + if (rv == 0) { + printf("snc_nec16_detectsubr: parent bus mismatch\n"); + return 0; + } + + /* select SONIC register SNCR_CR */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR); + bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST); + delay(400); + + cr = bus_space_read_2(iot, ioh, SNEC_CTRL); + if (cr != (CR_RXDIS | CR_STP | CR_RST)) { +#ifdef DIAGNOSTIC + printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n", + cr); +#endif + return 0; + } + + if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0) + return 0; + + return 1; +} + +/* XXX */ +#define SNC_VENDOR_NEC 0x00004c +#define SNC_NEC_SERIES_LEGACY_CBUS 0xa5 +#define SNC_NEC_SERIES_PNP_PCMCIA 0xd5 +#define SNC_NEC_SERIES_PNP_PCMCIA2 0x6d /* XXX */ +#define SNC_NEC_SERIES_PNP_CBUS 0x0d +#define SNC_NEC_SERIES_PNP_CBUS2 0x3d + +u_int8_t * +snc_nec16_detect_type(myea) + u_int8_t *myea; +{ + u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2]; + u_int8_t series = myea[3]; + u_int8_t type = myea[4] & 0x80; + u_int8_t *typestr; + + switch (vendor) { + case SNC_VENDOR_NEC: + switch (series) { + case SNC_NEC_SERIES_LEGACY_CBUS: + if (type) + typestr = "NEC PC-9801-84"; + else + typestr = "NEC PC-9801-83"; + break; + case SNC_NEC_SERIES_PNP_CBUS: + case SNC_NEC_SERIES_PNP_CBUS2: + if (type) + typestr = "NEC PC-9801-104"; + else + typestr = "NEC PC-9801-103"; + break; + case SNC_NEC_SERIES_PNP_PCMCIA: + case SNC_NEC_SERIES_PNP_PCMCIA2: + /* XXX: right ? */ + if (type) + typestr = "NEC PC-9801N-J02R"; + else + typestr = "NEC PC-9801N-J02"; + break; + default: + typestr = "NEC unknown (PC-9801N-25?)"; + break; + } + break; + default: + typestr = "unknown (3rd vendor?)"; + break; + } + + return typestr; +} + +int +snc_nec16_get_enaddr(iot, ioh, myea) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int8_t *myea; +{ + u_int8_t eeprom[SNEC_EEPROM_SIZE]; + u_int8_t rom_sum, sum = 0x00; + int i; + + snc_nec16_read_eeprom(iot, ioh, eeprom); + + for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) { + sum = sum ^ eeprom[i]; + } + + rom_sum = eeprom[SNEC_EEPROM_CKSUM]; + + if (sum != rom_sum) { + printf("snc_nec16_get_enaddr: " + "checksum mismatch; calculated %02x != read %02x", + sum, rom_sum); + return 0; + } + + for (i = 0; i < ETHER_ADDR_LEN; i++) + myea[i] = eeprom[SNEC_EEPROM_SA0 + i]; + + return 1; +} + +/* + * read from NEC/SONIC NIC register. + */ +u_int16_t +snc_nec16_nic_get(sc, reg) + struct snc_softc *sc; + u_int8_t reg; +{ + u_int16_t val; + + /* select SONIC register */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); + val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL); + + return val; +} + +/* + * write to NEC/SONIC NIC register. + */ +void +snc_nec16_nic_put(sc, reg, val) + struct snc_softc *sc; + u_int8_t reg; + u_int16_t val; +{ + + /* select SONIC register */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val); +} + + +/* + * select memory bank and map + * where exists specified (internal buffer memory) offset. + */ +integrate u_int16_t +snc_nec16_select_bank(sc, base, offset) + struct snc_softc *sc; + u_int32_t base; + u_int32_t offset; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t bank; + u_int16_t noffset; + + /* bitmode is fixed to 16 bit. */ + bank = (base + offset * 2) >> 13; + noffset = (base + offset * 2) & (SNEC_NMEMS - 1); + +#ifdef SNCDEBUG + if (noffset % 2) { + device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n", + noffset); + } +#endif /* SNCDEBUG */ + + if (sc->curbank != bank) { + /* select SNECR_MEMBS register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN); + /* update current bank */ + sc->curbank = bank; + } + + return noffset; +} + +/* + * write to SONIC descriptors. + */ +void +snc_nec16_writetodesc(sc, base, offset, val) + struct snc_softc *sc; + u_int32_t base; + u_int32_t offset; + u_int16_t val; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset; + + noffset = snc_nec16_select_bank(sc, base, offset); + + bus_space_write_2(memt, memh, noffset, val); +} + +/* + * read from SONIC descriptors. + */ +u_int16_t +snc_nec16_readfromdesc(sc, base, offset) + struct snc_softc *sc; + u_int32_t base; + u_int32_t offset; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset; + + noffset = snc_nec16_select_bank(sc, base, offset); + + return bus_space_read_2(memt, memh, noffset); +} + +/* + * read from SONIC data buffer. + */ +void +snc_nec16_copyfrombuf(sc, dst, offset, size) + struct snc_softc *sc; + void *dst; + u_int32_t offset; + size_t size; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset; + u_int8_t* bptr = dst; + + noffset = snc_nec16_select_bank(sc, offset, 0); + + /* XXX: should check if offset + size < 0x2000. */ + + bus_space_barrier(memt, memh, noffset, size, + BUS_SPACE_BARRIER_READ); + + if (size > 3) { + if (noffset & 3) { + size_t asize = (~noffset & 3); + + bus_space_read_region_1(memt, memh, noffset, + bptr, asize); + bptr += asize; + noffset += asize; + size -= asize; + } + bus_space_read_region_4(memt, memh, noffset, + (u_int32_t *) bptr, size >> 2); + bptr += size & ~3; + noffset += size & ~3; + size &= 3; + } + if (size) + bus_space_read_region_1(memt, memh, noffset, bptr, size); +} + +/* + * write to SONIC data buffer. + */ +void +snc_nec16_copytobuf(sc, src, offset, size) + struct snc_softc *sc; + void *src; + u_int32_t offset; + size_t size; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset, onoffset; + size_t osize = size; + u_int8_t* bptr = src; + + noffset = snc_nec16_select_bank(sc, offset, 0); + onoffset = noffset; + + /* XXX: should check if offset + size < 0x2000. */ + + if (size > 3) { + if (noffset & 3) { + size_t asize = (~noffset & 3); + + bus_space_write_region_1(memt, memh, noffset, + bptr, asize); + bptr += asize; + noffset += asize; + size -= asize; + } + bus_space_write_region_4(memt, memh, noffset, + (u_int32_t *)bptr, size >> 2); + bptr += size & ~3; + noffset += size & ~3; + size -= size & ~3; + } + if (size) + bus_space_write_region_1(memt, memh, noffset, bptr, size); + + bus_space_barrier(memt, memh, onoffset, osize, + BUS_SPACE_BARRIER_WRITE); +} + +/* + * write (fill) 0 to SONIC data buffer. + */ +void +snc_nec16_zerobuf(sc, offset, size) + struct snc_softc *sc; + u_int32_t offset; + size_t size; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset, onoffset; + size_t osize = size; + + noffset = snc_nec16_select_bank(sc, offset, 0); + onoffset = noffset; + + /* XXX: should check if offset + size < 0x2000. */ + + if (size > 3) { + if (noffset & 3) { + size_t asize = (~noffset & 3); + + bus_space_set_region_1(memt, memh, noffset, 0, asize); + noffset += asize; + size -= asize; + } + bus_space_set_region_4(memt, memh, noffset, 0, size >> 2); + noffset += size & ~3; + size -= size & ~3; + } + if (size) + bus_space_set_region_1(memt, memh, noffset, 0, size); + + bus_space_barrier(memt, memh, onoffset, osize, + BUS_SPACE_BARRIER_WRITE); +} + + +/* + * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83, + * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98. + * Ported by Kouichi Matsuda. + * + * This algorism is generic to read data sequentially from 4-Wire + * Microwire Serial EEPROM. + */ + +#define SNEC_EEP_DELAY 1000 + +void +snc_nec16_read_eeprom(iot, ioh, data) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int8_t *data; +{ + u_int8_t n, val, bit; + + /* Read bytes from EEPROM; two bytes per an iteration. */ + for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) { + /* select SNECR_EEP */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); + delay(SNEC_EEP_DELAY); + + /* Start EEPROM access. */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + /* Pass the iteration count to the chip. */ + for (bit = 0x20; bit != 0x00; bit >>= 1) { + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS | + ((n & bit) ? SNECR_EEP_DI : 0x00)); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK | + ((n & bit) ? SNECR_EEP_DI : 0x00)); + delay(SNEC_EEP_DELAY); + } + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + (void) bus_space_read_1(iot, ioh, SNEC_CTRLB); /* ACK */ + delay(SNEC_EEP_DELAY); + + /* Read a byte. */ + val = 0; + for (bit = 0x80; bit != 0x00; bit >>= 1) { + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + + if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) + val |= bit; + } + *data++ = val; + + /* Read one more byte. */ + val = 0; + for (bit = 0x80; bit != 0x00; bit >>= 1) { + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + + if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) + val |= bit; + } + *data++ = val; + + bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); + delay(SNEC_EEP_DELAY); + } + +#ifdef SNCDEBUG + /* Report what we got. */ + data -= SNEC_EEPROM_SIZE; + log(LOG_INFO, "%s: EEPROM:" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x\n", + "snc_nec16_read_eeprom", + data[ 0], data[ 1], data[ 2], data[ 3], + data[ 4], data[ 5], data[ 6], data[ 7], + data[ 8], data[ 9], data[10], data[11], + data[12], data[13], data[14], data[15], + data[16], data[17], data[18], data[19], + data[20], data[21], data[22], data[23], + data[24], data[25], data[26], data[27], + data[28], data[29], data[30], data[31]); +#endif +} + +#ifdef SNCDEBUG +void +snc_nec16_dump_reg(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + u_int8_t n; + u_int16_t val; + + printf("SONIC registers (word):"); + for (n = 0; n < SNC_NREGS; n++) { + /* select required SONIC register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, n); + delay(10); + val = bus_space_read_2(iot, ioh, SNEC_CTRL); + if ((n % 0x10) == 0) + printf("\n%04x ", val); + else + printf("%04x ", val); + } + printf("\n"); + + printf("NEC/SONIC registers (byte):\n"); + for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) { + /* select required SONIC register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, n); + delay(10); + val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB); + printf("%04x ", val); + } + printf("\n"); +} + +#endif /* SNCDEBUG */ |