166550Snyan/* $NecBSD: dp83932subr.c,v 1.5.6.2 1999/10/09 05:47:23 kmatsuda Exp $ */ 266550Snyan/* $NetBSD$ */ 366550Snyan 4139749Simp/*- 566550Snyan * Copyright (c) 1997, 1998, 1999 666550Snyan * Kouichi Matsuda. All rights reserved. 766550Snyan * 866550Snyan * Redistribution and use in source and binary forms, with or without 966550Snyan * modification, are permitted provided that the following conditions 1066550Snyan * are met: 1166550Snyan * 1. Redistributions of source code must retain the above copyright 1266550Snyan * notice, this list of conditions and the following disclaimer. 1366550Snyan * 2. Redistributions in binary form must reproduce the above copyright 1466550Snyan * notice, this list of conditions and the following disclaimer in the 1566550Snyan * documentation and/or other materials provided with the distribution. 1666550Snyan * 3. All advertising materials mentioning features or use of this software 1766550Snyan * must display the following acknowledgement: 1866550Snyan * This product includes software developed by Kouichi Matsuda for 1966550Snyan * NetBSD/pc98. 2066550Snyan * 4. The name of the author may not be used to endorse or promote products 2166550Snyan * derived from this software without specific prior written permission 2266550Snyan * 2366550Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2466550Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2566550Snyan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2666550Snyan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2766550Snyan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2866550Snyan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2966550Snyan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3066550Snyan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3166550Snyan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3266550Snyan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3366550Snyan */ 34119419Sobrien 35119419Sobrien#include <sys/cdefs.h> 36119419Sobrien__FBSDID("$FreeBSD$"); 3766550Snyan/* 3866550Snyan * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R 3966550Snyan * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda. 4066550Snyan * 4166550Snyan * These cards use National Semiconductor DP83934AVQB as Ethernet Controller 4266550Snyan * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM. 4366550Snyan */ 4466550Snyan 4566550Snyan/* 4666550Snyan * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki. 4766550Snyan */ 4866550Snyan 4966550Snyan#include <sys/param.h> 5066550Snyan#include <sys/systm.h> 5166550Snyan#include <sys/protosw.h> 5266550Snyan#include <sys/socket.h> 5366550Snyan 5466550Snyan#include <net/ethernet.h> 5566550Snyan#include <net/if.h> 5666550Snyan#include <net/if_arp.h> 5766550Snyan#include <net/if_media.h> 5866550Snyan 5966550Snyan#include <sys/bus.h> 6066550Snyan#include <machine/bus.h> 6166550Snyan 6266550Snyan#include <dev/snc/dp83932reg.h> 6366550Snyan#include <dev/snc/dp83932var.h> 6466550Snyan#include <dev/snc/if_sncreg.h> 6566550Snyan#include <dev/snc/dp83932subr.h> 6666550Snyan 67179442Sjhbstatic __inline u_int16_t snc_nec16_select_bank 6892739Salfred (struct snc_softc *, u_int32_t, u_int32_t); 6966550Snyan 7066550Snyan/* 7166550Snyan * Interface exists: make available by filling in network interface 7266550Snyan * record. System will initialize the interface when it is ready 7366550Snyan * to accept packets. 7466550Snyan */ 7566550Snyanint 76242871Snyansncsetup(struct snc_softc *sc, u_int8_t *lladdr) 7766550Snyan{ 7866550Snyan u_int32_t p, pp; 7966550Snyan int i; 8066550Snyan int offset; 8166550Snyan 8266550Snyan /* 8366550Snyan * Put the pup in reset mode (sncinit() will fix it later), 8466550Snyan * stop the timer, disable all interrupts and clear any interrupts. 8566550Snyan */ 8666550Snyan NIC_PUT(sc, SNCR_CR, CR_STP); 8766550Snyan wbflush(); 8866550Snyan NIC_PUT(sc, SNCR_CR, CR_RST); 8966550Snyan wbflush(); 9066550Snyan NIC_PUT(sc, SNCR_IMR, 0); 9166550Snyan wbflush(); 9266550Snyan NIC_PUT(sc, SNCR_ISR, ISR_ALL); 9366550Snyan wbflush(); 9466550Snyan 9566550Snyan /* 9666550Snyan * because the SONIC is basically 16bit device it 'concatenates' 9766550Snyan * a higher buffer address to a 16 bit offset--this will cause wrap 9866550Snyan * around problems near the end of 64k !! 9966550Snyan */ 10066550Snyan p = pp = 0; 10166550Snyan 10266550Snyan for (i = 0; i < NRRA; i++) { 10366550Snyan sc->v_rra[i] = SONIC_GETDMA(p); 10466550Snyan p += RXRSRC_SIZE(sc); 10566550Snyan } 10666550Snyan sc->v_rea = SONIC_GETDMA(p); 10766550Snyan 10866550Snyan p = SOALIGN(sc, p); 10966550Snyan 11066550Snyan sc->v_cda = SONIC_GETDMA(p); 11166550Snyan p += CDA_SIZE(sc); 11266550Snyan 11366550Snyan p = SOALIGN(sc, p); 11466550Snyan 11566550Snyan for (i = 0; i < NTDA; i++) { 11666550Snyan struct mtd *mtdp = &sc->mtda[i]; 11766550Snyan mtdp->mtd_vtxp = SONIC_GETDMA(p); 11866550Snyan p += TXP_SIZE(sc); 11966550Snyan } 12066550Snyan 12166550Snyan p = SOALIGN(sc, p); 12266550Snyan 123179442Sjhb if ((p - pp) > PAGE_SIZE) { 12466550Snyan device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +" 125179442Sjhb "TDA (%ld) > PAGE_SIZE (%d). Punt!\n", 126179442Sjhb (u_long)sc->v_cda - (u_long)sc->v_rra[0], 127179442Sjhb (u_long)sc->mtda[0].mtd_vtxp - (u_long)sc->v_cda, 128179442Sjhb (u_long)p - (u_long)sc->mtda[0].mtd_vtxp, 129179442Sjhb PAGE_SIZE); 13066550Snyan return(1); 13166550Snyan } 13266550Snyan 133179442Sjhb p = pp + PAGE_SIZE; 13466550Snyan pp = p; 13566550Snyan 136179442Sjhb sc->sc_nrda = PAGE_SIZE / RXPKT_SIZE(sc); 13766550Snyan sc->v_rda = SONIC_GETDMA(p); 13866550Snyan 139179442Sjhb p = pp + PAGE_SIZE; 14066550Snyan 14166550Snyan for (i = 0; i < NRBA; i++) { 14266550Snyan sc->rbuf[i] = p; 143179442Sjhb p += PAGE_SIZE; 14466550Snyan } 14566550Snyan 14666550Snyan pp = p; 14766550Snyan offset = TXBSIZE; 14866550Snyan for (i = 0; i < NTDA; i++) { 14966550Snyan struct mtd *mtdp = &sc->mtda[i]; 15066550Snyan 15166550Snyan mtdp->mtd_vbuf = SONIC_GETDMA(p); 15266550Snyan offset += TXBSIZE; 153179442Sjhb if (offset < PAGE_SIZE) { 15466550Snyan p += TXBSIZE; 15566550Snyan } else { 156179442Sjhb p = pp + PAGE_SIZE; 15766550Snyan pp = p; 15866550Snyan offset = TXBSIZE; 15966550Snyan } 16066550Snyan } 16166550Snyan 16266550Snyan return (0); 16366550Snyan} 16466550Snyan 16566550Snyan/* 16666550Snyan * miscellaneous NEC/SONIC detect functions. 16766550Snyan */ 16866550Snyan 16966550Snyan/* 17066550Snyan * check if a specified irq is acceptable. 17166550Snyan */ 17266550Snyanu_int8_t 173242871Snyansnc_nec16_validate_irq(int irq) 17466550Snyan{ 17566550Snyan const u_int8_t encoded_irq[16] = { 17666550Snyan -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1 17766550Snyan }; 17866550Snyan 17966550Snyan return encoded_irq[irq]; 18066550Snyan} 18166550Snyan 18266550Snyan/* 18366550Snyan * specify irq to board. 18466550Snyan */ 18566550Snyanint 186242871Snyansnc_nec16_register_irq(struct snc_softc *sc, int irq) 18766550Snyan{ 18866550Snyan bus_space_tag_t iot = sc->sc_iot; 18966550Snyan bus_space_handle_t ioh = sc->sc_ioh; 19066550Snyan u_int8_t encoded_irq; 19166550Snyan 19266550Snyan encoded_irq = snc_nec16_validate_irq(irq); 19366550Snyan if (encoded_irq == (u_int8_t) -1) { 19466550Snyan printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq); 19566550Snyan return 0; 19666550Snyan } 19766550Snyan 19866550Snyan /* select SNECR_IRQSEL register */ 19966550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL); 20066550Snyan /* write encoded irq value */ 20166550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq); 20266550Snyan 20366550Snyan return 1; 20466550Snyan} 20566550Snyan 20666550Snyan/* 20766550Snyan * check if a specified memory base address is acceptable. 20866550Snyan */ 20966550Snyanint 210242871Snyansnc_nec16_validate_mem(int maddr) 21166550Snyan{ 21266550Snyan 21366550Snyan /* Check on Normal mode with max range, only */ 21466550Snyan if ((maddr & ~0x1E000) != 0xC0000) { 21566550Snyan printf("snc_nec16_validate_mem: " 21666550Snyan "unsupported window base (0x%x)\n", maddr); 21766550Snyan return 0; 21866550Snyan } 21966550Snyan 22066550Snyan return 1; 22166550Snyan} 22266550Snyan 22366550Snyan/* 22466550Snyan * specify memory base address to board and map to first bank. 22566550Snyan */ 22666550Snyanint 227242871Snyansnc_nec16_register_mem(struct snc_softc *sc, int maddr) 22866550Snyan{ 22966550Snyan bus_space_tag_t iot = sc->sc_iot; 23066550Snyan bus_space_handle_t ioh = sc->sc_ioh; 23166550Snyan 23266550Snyan if (snc_nec16_validate_mem(maddr) == 0) 23366550Snyan return 0; 23466550Snyan 23566550Snyan /* select SNECR_MEMSEL register */ 23666550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL); 23766550Snyan /* write encoded memory base select value */ 23866550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr)); 23966550Snyan 24066550Snyan /* 24166550Snyan * set current bank to 0 (bottom) and map 24266550Snyan */ 24366550Snyan /* select SNECR_MEMBS register */ 24466550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 24566550Snyan /* select new bank */ 24666550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 24766550Snyan SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN); 24866550Snyan /* set current bank to 0 */ 24966550Snyan sc->curbank = 0; 25066550Snyan 25166550Snyan return 1; 25266550Snyan} 25366550Snyan 25466550Snyanint 255242871Snyansnc_nec16_check_memory(bus_space_tag_t iot, bus_space_handle_t ioh, 256242871Snyan bus_space_tag_t memt, bus_space_handle_t memh) 25766550Snyan{ 25866550Snyan u_int16_t val; 25966550Snyan int i, j; 26066550Snyan 26166550Snyan val = 0; 26266550Snyan for (i = 0; i < SNEC_NBANK; i++) { 26366550Snyan /* select new bank */ 26466550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 26566550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 26666550Snyan SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 26766550Snyan 26866550Snyan /* write test pattern */ 26966550Snyan for (j = 0; j < SNEC_NMEMS / 2; j++) { 27066550Snyan bus_space_write_2(memt, memh, j * 2, val + j); 27166550Snyan } 27266550Snyan val += 0x1000; 27366550Snyan } 27466550Snyan 27566550Snyan val = 0; 27666550Snyan for (i = 0; i < SNEC_NBANK; i++) { 27766550Snyan /* select new bank */ 27866550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 27966550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 28066550Snyan SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 28166550Snyan 28266550Snyan /* read test pattern */ 28366550Snyan for (j = 0; j < SNEC_NMEMS / 2; j++) { 28466550Snyan if (bus_space_read_2(memt, memh, j * 2) != val + j) 28566550Snyan break; 28666550Snyan } 28766550Snyan 28866550Snyan if (j < SNEC_NMEMS / 2) { 28966550Snyan printf("snc_nec16_check_memory: " 29066550Snyan "memory check failed at 0x%04x%04x" 29166550Snyan "val 0x%04x != expected 0x%04x\n", i, j, 29266550Snyan bus_space_read_2(memt, memh, j * 2), 29366550Snyan val + j); 29466550Snyan return 0; 29566550Snyan } 29666550Snyan val += 0x1000; 29766550Snyan } 29866550Snyan 29966550Snyan /* zero clear mem */ 30066550Snyan for (i = 0; i < SNEC_NBANK; i++) { 30166550Snyan /* select new bank */ 30266550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 30366550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 30466550Snyan SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 30566550Snyan 30666550Snyan bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2); 30766550Snyan } 30866550Snyan 30966550Snyan /* again read test if these are 0 */ 31066550Snyan for (i = 0; i < SNEC_NBANK; i++) { 31166550Snyan /* select new bank */ 31266550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 31366550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 31466550Snyan SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); 31566550Snyan 31666550Snyan /* check if cleared */ 31766550Snyan for (j = 0; j < SNEC_NMEMS; j += 2) { 31866550Snyan if (bus_space_read_2(memt, memh, j) != 0) 31966550Snyan break; 32066550Snyan } 32166550Snyan 32266550Snyan if (j != SNEC_NMEMS) { 32366550Snyan printf("snc_nec16_check_memory: " 32466550Snyan "memory zero clear failed at 0x%04x%04x\n", i, j); 32566550Snyan return 0; 32666550Snyan } 32766550Snyan } 32866550Snyan 32966550Snyan return 1; 33066550Snyan} 33166550Snyan 33266550Snyanint 333242871Snyansnc_nec16_detectsubr(bus_space_tag_t iot, bus_space_handle_t ioh, 334242871Snyan bus_space_tag_t memt, bus_space_handle_t memh, int irq, int maddr, 335242871Snyan u_int8_t type) 33666550Snyan{ 33766550Snyan u_int16_t cr; 33866550Snyan u_int8_t ident; 33966550Snyan int rv = 0; 34066550Snyan 34166550Snyan if (snc_nec16_validate_irq(irq) == (u_int8_t) -1) 34266550Snyan return 0; 34366550Snyan /* XXX: maddr already checked */ 34466550Snyan if (snc_nec16_validate_mem(maddr) == 0) 34566550Snyan return 0; 34666550Snyan 34766550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT); 34866550Snyan ident = bus_space_read_1(iot, ioh, SNEC_CTRLB); 34966550Snyan if (ident == 0xff || ident == 0x00) { 35066550Snyan /* not found */ 35166550Snyan return 0; 35266550Snyan } 35366550Snyan 35466550Snyan switch (type) { 35566550Snyan case SNEC_TYPE_LEGACY: 35666550Snyan rv = (ident == SNECR_IDENT_LEGACY_CBUS); 35766550Snyan break; 35866550Snyan case SNEC_TYPE_PNP: 35966550Snyan rv = ((ident == SNECR_IDENT_PNP_CBUS) || 36066550Snyan (ident == SNECR_IDENT_PNP_PCMCIABUS)); 36166550Snyan break; 36266550Snyan default: 36366550Snyan break; 36466550Snyan } 36566550Snyan 36666550Snyan if (rv == 0) { 36766550Snyan printf("snc_nec16_detectsubr: parent bus mismatch\n"); 36866550Snyan return 0; 36966550Snyan } 37066550Snyan 37166550Snyan /* select SONIC register SNCR_CR */ 37266550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR); 37366550Snyan bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST); 374179442Sjhb DELAY(400); 37566550Snyan 37666550Snyan cr = bus_space_read_2(iot, ioh, SNEC_CTRL); 37766550Snyan if (cr != (CR_RXDIS | CR_STP | CR_RST)) { 37866550Snyan#ifdef DIAGNOSTIC 37966550Snyan printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n", 38066550Snyan cr); 38166550Snyan#endif 38266550Snyan return 0; 38366550Snyan } 38466550Snyan 38566550Snyan if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0) 38666550Snyan return 0; 38766550Snyan 38866550Snyan return 1; 38966550Snyan} 39066550Snyan 39166550Snyan/* XXX */ 39266550Snyan#define SNC_VENDOR_NEC 0x00004c 39366550Snyan#define SNC_NEC_SERIES_LEGACY_CBUS 0xa5 39466550Snyan#define SNC_NEC_SERIES_PNP_PCMCIA 0xd5 39566550Snyan#define SNC_NEC_SERIES_PNP_PCMCIA2 0x6d /* XXX */ 39666550Snyan#define SNC_NEC_SERIES_PNP_CBUS 0x0d 39766550Snyan#define SNC_NEC_SERIES_PNP_CBUS2 0x3d 39866550Snyan 39966550Snyanu_int8_t * 400242871Snyansnc_nec16_detect_type(u_int8_t *myea) 40166550Snyan{ 40266550Snyan u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2]; 40366550Snyan u_int8_t series = myea[3]; 40466550Snyan u_int8_t type = myea[4] & 0x80; 40566550Snyan u_int8_t *typestr; 40666550Snyan 40766550Snyan switch (vendor) { 40866550Snyan case SNC_VENDOR_NEC: 40966550Snyan switch (series) { 41066550Snyan case SNC_NEC_SERIES_LEGACY_CBUS: 41166550Snyan if (type) 41266550Snyan typestr = "NEC PC-9801-84"; 41366550Snyan else 41466550Snyan typestr = "NEC PC-9801-83"; 41566550Snyan break; 41666550Snyan case SNC_NEC_SERIES_PNP_CBUS: 41766550Snyan case SNC_NEC_SERIES_PNP_CBUS2: 41866550Snyan if (type) 41966550Snyan typestr = "NEC PC-9801-104"; 42066550Snyan else 42166550Snyan typestr = "NEC PC-9801-103"; 42266550Snyan break; 42366550Snyan case SNC_NEC_SERIES_PNP_PCMCIA: 42466550Snyan case SNC_NEC_SERIES_PNP_PCMCIA2: 42566550Snyan /* XXX: right ? */ 42666550Snyan if (type) 42766550Snyan typestr = "NEC PC-9801N-J02R"; 42866550Snyan else 42966550Snyan typestr = "NEC PC-9801N-J02"; 43066550Snyan break; 43166550Snyan default: 43266550Snyan typestr = "NEC unknown (PC-9801N-25?)"; 43366550Snyan break; 43466550Snyan } 43566550Snyan break; 43666550Snyan default: 43766550Snyan typestr = "unknown (3rd vendor?)"; 43866550Snyan break; 43966550Snyan } 44066550Snyan 44166550Snyan return typestr; 44266550Snyan} 44366550Snyan 44466550Snyanint 445242871Snyansnc_nec16_get_enaddr(bus_space_tag_t iot, bus_space_handle_t ioh, 446242871Snyan u_int8_t *myea) 44766550Snyan{ 44866550Snyan u_int8_t eeprom[SNEC_EEPROM_SIZE]; 44966550Snyan u_int8_t rom_sum, sum = 0x00; 45066550Snyan int i; 45166550Snyan 45266550Snyan snc_nec16_read_eeprom(iot, ioh, eeprom); 45366550Snyan 45466550Snyan for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) { 45566550Snyan sum = sum ^ eeprom[i]; 45666550Snyan } 45766550Snyan 45866550Snyan rom_sum = eeprom[SNEC_EEPROM_CKSUM]; 45966550Snyan 46066550Snyan if (sum != rom_sum) { 46166550Snyan printf("snc_nec16_get_enaddr: " 46266550Snyan "checksum mismatch; calculated %02x != read %02x", 46366550Snyan sum, rom_sum); 46466550Snyan return 0; 46566550Snyan } 46666550Snyan 46766550Snyan for (i = 0; i < ETHER_ADDR_LEN; i++) 46866550Snyan myea[i] = eeprom[SNEC_EEPROM_SA0 + i]; 46966550Snyan 47066550Snyan return 1; 47166550Snyan} 47266550Snyan 47366550Snyan/* 47466550Snyan * read from NEC/SONIC NIC register. 47566550Snyan */ 47666550Snyanu_int16_t 477242871Snyansnc_nec16_nic_get(struct snc_softc *sc, u_int8_t reg) 47866550Snyan{ 47966550Snyan u_int16_t val; 48066550Snyan 48166550Snyan /* select SONIC register */ 48266550Snyan bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); 48366550Snyan val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL); 48466550Snyan 48566550Snyan return val; 48666550Snyan} 48766550Snyan 48866550Snyan/* 48966550Snyan * write to NEC/SONIC NIC register. 49066550Snyan */ 49166550Snyanvoid 492242871Snyansnc_nec16_nic_put(struct snc_softc *sc, u_int8_t reg, u_int16_t val) 49366550Snyan{ 49466550Snyan 49566550Snyan /* select SONIC register */ 49666550Snyan bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); 49766550Snyan bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val); 49866550Snyan} 49966550Snyan 50066550Snyan 50166550Snyan/* 50266550Snyan * select memory bank and map 50366550Snyan * where exists specified (internal buffer memory) offset. 50466550Snyan */ 505179442Sjhbstatic __inline u_int16_t 506242871Snyansnc_nec16_select_bank(struct snc_softc *sc, u_int32_t base, u_int32_t offset) 50766550Snyan{ 50866550Snyan bus_space_tag_t iot = sc->sc_iot; 50966550Snyan bus_space_handle_t ioh = sc->sc_ioh; 51066550Snyan u_int8_t bank; 51166550Snyan u_int16_t noffset; 51266550Snyan 51366550Snyan /* bitmode is fixed to 16 bit. */ 51466550Snyan bank = (base + offset * 2) >> 13; 51566550Snyan noffset = (base + offset * 2) & (SNEC_NMEMS - 1); 51666550Snyan 51766550Snyan#ifdef SNCDEBUG 51866550Snyan if (noffset % 2) { 51966550Snyan device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n", 52066550Snyan noffset); 52166550Snyan } 52266550Snyan#endif /* SNCDEBUG */ 52366550Snyan 52466550Snyan if (sc->curbank != bank) { 52566550Snyan /* select SNECR_MEMBS register */ 52666550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); 52766550Snyan /* select new bank */ 52866550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 52966550Snyan SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN); 53066550Snyan /* update current bank */ 53166550Snyan sc->curbank = bank; 53266550Snyan } 53366550Snyan 53466550Snyan return noffset; 53566550Snyan} 53666550Snyan 53766550Snyan/* 53866550Snyan * write to SONIC descriptors. 53966550Snyan */ 54066550Snyanvoid 541242871Snyansnc_nec16_writetodesc(struct snc_softc *sc, u_int32_t base, u_int32_t offset, 542242871Snyan u_int16_t val) 54366550Snyan{ 54466550Snyan bus_space_tag_t memt = sc->sc_memt; 54566550Snyan bus_space_handle_t memh = sc->sc_memh; 54666550Snyan u_int16_t noffset; 54766550Snyan 54866550Snyan noffset = snc_nec16_select_bank(sc, base, offset); 54966550Snyan 55066550Snyan bus_space_write_2(memt, memh, noffset, val); 55166550Snyan} 55266550Snyan 55366550Snyan/* 55466550Snyan * read from SONIC descriptors. 55566550Snyan */ 55666550Snyanu_int16_t 557242871Snyansnc_nec16_readfromdesc(struct snc_softc *sc, u_int32_t base, u_int32_t offset) 55866550Snyan{ 55966550Snyan bus_space_tag_t memt = sc->sc_memt; 56066550Snyan bus_space_handle_t memh = sc->sc_memh; 56166550Snyan u_int16_t noffset; 56266550Snyan 56366550Snyan noffset = snc_nec16_select_bank(sc, base, offset); 56466550Snyan 56566550Snyan return bus_space_read_2(memt, memh, noffset); 56666550Snyan} 56766550Snyan 56866550Snyan/* 56966550Snyan * read from SONIC data buffer. 57066550Snyan */ 57166550Snyanvoid 572242871Snyansnc_nec16_copyfrombuf(struct snc_softc *sc, void *dst, u_int32_t offset, 573242871Snyan size_t size) 57466550Snyan{ 57566550Snyan bus_space_tag_t memt = sc->sc_memt; 57666550Snyan bus_space_handle_t memh = sc->sc_memh; 57766550Snyan u_int16_t noffset; 57866550Snyan u_int8_t* bptr = dst; 57966550Snyan 58066550Snyan noffset = snc_nec16_select_bank(sc, offset, 0); 58166550Snyan 58266550Snyan /* XXX: should check if offset + size < 0x2000. */ 58366550Snyan 58466550Snyan bus_space_barrier(memt, memh, noffset, size, 58566550Snyan BUS_SPACE_BARRIER_READ); 58666550Snyan 58766550Snyan if (size > 3) { 58866550Snyan if (noffset & 3) { 589114561Snyan size_t asize = 4 - (noffset & 3); 59066550Snyan 59166550Snyan bus_space_read_region_1(memt, memh, noffset, 59266550Snyan bptr, asize); 59366550Snyan bptr += asize; 59466550Snyan noffset += asize; 59566550Snyan size -= asize; 59666550Snyan } 59766550Snyan bus_space_read_region_4(memt, memh, noffset, 59866550Snyan (u_int32_t *) bptr, size >> 2); 59966550Snyan bptr += size & ~3; 60066550Snyan noffset += size & ~3; 60166550Snyan size &= 3; 60266550Snyan } 60366550Snyan if (size) 60466550Snyan bus_space_read_region_1(memt, memh, noffset, bptr, size); 60566550Snyan} 60666550Snyan 60766550Snyan/* 60866550Snyan * write to SONIC data buffer. 60966550Snyan */ 61066550Snyanvoid 611242871Snyansnc_nec16_copytobuf(struct snc_softc *sc, void *src, u_int32_t offset, 612242871Snyan size_t size) 61366550Snyan{ 61466550Snyan bus_space_tag_t memt = sc->sc_memt; 61566550Snyan bus_space_handle_t memh = sc->sc_memh; 61666550Snyan u_int16_t noffset, onoffset; 61766550Snyan size_t osize = size; 61866550Snyan u_int8_t* bptr = src; 61966550Snyan 62066550Snyan noffset = snc_nec16_select_bank(sc, offset, 0); 62166550Snyan onoffset = noffset; 62266550Snyan 62366550Snyan /* XXX: should check if offset + size < 0x2000. */ 62466550Snyan 62566550Snyan if (size > 3) { 62666550Snyan if (noffset & 3) { 627114561Snyan size_t asize = 4 - (noffset & 3); 62866550Snyan 62966550Snyan bus_space_write_region_1(memt, memh, noffset, 63066550Snyan bptr, asize); 63166550Snyan bptr += asize; 63266550Snyan noffset += asize; 63366550Snyan size -= asize; 63466550Snyan } 63566550Snyan bus_space_write_region_4(memt, memh, noffset, 63666550Snyan (u_int32_t *)bptr, size >> 2); 63766550Snyan bptr += size & ~3; 63866550Snyan noffset += size & ~3; 63966550Snyan size -= size & ~3; 64066550Snyan } 64166550Snyan if (size) 64266550Snyan bus_space_write_region_1(memt, memh, noffset, bptr, size); 64366550Snyan 64466550Snyan bus_space_barrier(memt, memh, onoffset, osize, 64566550Snyan BUS_SPACE_BARRIER_WRITE); 64666550Snyan} 64766550Snyan 64866550Snyan/* 64966550Snyan * write (fill) 0 to SONIC data buffer. 65066550Snyan */ 65166550Snyanvoid 652242871Snyansnc_nec16_zerobuf(struct snc_softc *sc, u_int32_t offset, size_t size) 65366550Snyan{ 65466550Snyan bus_space_tag_t memt = sc->sc_memt; 65566550Snyan bus_space_handle_t memh = sc->sc_memh; 65666550Snyan u_int16_t noffset, onoffset; 65766550Snyan size_t osize = size; 65866550Snyan 65966550Snyan noffset = snc_nec16_select_bank(sc, offset, 0); 66066550Snyan onoffset = noffset; 66166550Snyan 66266550Snyan /* XXX: should check if offset + size < 0x2000. */ 66366550Snyan 66466550Snyan if (size > 3) { 66566550Snyan if (noffset & 3) { 666114561Snyan size_t asize = 4 - (noffset & 3); 66766550Snyan 66866550Snyan bus_space_set_region_1(memt, memh, noffset, 0, asize); 66966550Snyan noffset += asize; 67066550Snyan size -= asize; 67166550Snyan } 67266550Snyan bus_space_set_region_4(memt, memh, noffset, 0, size >> 2); 67366550Snyan noffset += size & ~3; 67466550Snyan size -= size & ~3; 67566550Snyan } 67666550Snyan if (size) 67766550Snyan bus_space_set_region_1(memt, memh, noffset, 0, size); 67866550Snyan 67966550Snyan bus_space_barrier(memt, memh, onoffset, osize, 68066550Snyan BUS_SPACE_BARRIER_WRITE); 68166550Snyan} 68266550Snyan 68366550Snyan 68466550Snyan/* 68566550Snyan * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83, 68666550Snyan * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98. 68766550Snyan * Ported by Kouichi Matsuda. 68866550Snyan * 68966550Snyan * This algorism is generic to read data sequentially from 4-Wire 69066550Snyan * Microwire Serial EEPROM. 69166550Snyan */ 69266550Snyan 69366550Snyan#define SNEC_EEP_DELAY 1000 69466550Snyan 69566550Snyanvoid 696242871Snyansnc_nec16_read_eeprom(bus_space_tag_t iot, bus_space_handle_t ioh, 697242871Snyan u_int8_t *data) 69866550Snyan{ 69966550Snyan u_int8_t n, val, bit; 70066550Snyan 70166550Snyan /* Read bytes from EEPROM; two bytes per an iteration. */ 70266550Snyan for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) { 70366550Snyan /* select SNECR_EEP */ 70466550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP); 70566550Snyan 70666550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); 707179442Sjhb DELAY(SNEC_EEP_DELAY); 70866550Snyan 70966550Snyan /* Start EEPROM access. */ 71066550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 711179442Sjhb DELAY(SNEC_EEP_DELAY); 71266550Snyan 71366550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 71466550Snyan SNECR_EEP_CS | SNECR_EEP_SK); 715179442Sjhb DELAY(SNEC_EEP_DELAY); 71666550Snyan 71766550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 71866550Snyan SNECR_EEP_CS | SNECR_EEP_DI); 719179442Sjhb DELAY(SNEC_EEP_DELAY); 72066550Snyan 72166550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 72266550Snyan SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); 723179442Sjhb DELAY(SNEC_EEP_DELAY); 72466550Snyan 72566550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 72666550Snyan SNECR_EEP_CS | SNECR_EEP_DI); 727179442Sjhb DELAY(SNEC_EEP_DELAY); 72866550Snyan 72966550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 73066550Snyan SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); 731179442Sjhb DELAY(SNEC_EEP_DELAY); 73266550Snyan 73366550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 734179442Sjhb DELAY(SNEC_EEP_DELAY); 73566550Snyan 73666550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 73766550Snyan SNECR_EEP_CS | SNECR_EEP_SK); 738179442Sjhb DELAY(SNEC_EEP_DELAY); 73966550Snyan 74066550Snyan /* Pass the iteration count to the chip. */ 74166550Snyan for (bit = 0x20; bit != 0x00; bit >>= 1) { 74266550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS | 74366550Snyan ((n & bit) ? SNECR_EEP_DI : 0x00)); 744179442Sjhb DELAY(SNEC_EEP_DELAY); 74566550Snyan 74666550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 74766550Snyan SNECR_EEP_CS | SNECR_EEP_SK | 74866550Snyan ((n & bit) ? SNECR_EEP_DI : 0x00)); 749179442Sjhb DELAY(SNEC_EEP_DELAY); 75066550Snyan } 75166550Snyan 75266550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 75366550Snyan (void) bus_space_read_1(iot, ioh, SNEC_CTRLB); /* ACK */ 754179442Sjhb DELAY(SNEC_EEP_DELAY); 75566550Snyan 75666550Snyan /* Read a byte. */ 75766550Snyan val = 0; 75866550Snyan for (bit = 0x80; bit != 0x00; bit >>= 1) { 75966550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 76066550Snyan SNECR_EEP_CS | SNECR_EEP_SK); 761179442Sjhb DELAY(SNEC_EEP_DELAY); 76266550Snyan 76366550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 76466550Snyan 76566550Snyan if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) 76666550Snyan val |= bit; 76766550Snyan } 76866550Snyan *data++ = val; 76966550Snyan 77066550Snyan /* Read one more byte. */ 77166550Snyan val = 0; 77266550Snyan for (bit = 0x80; bit != 0x00; bit >>= 1) { 77366550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 77466550Snyan SNECR_EEP_CS | SNECR_EEP_SK); 775179442Sjhb DELAY(SNEC_EEP_DELAY); 77666550Snyan 77766550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); 77866550Snyan 77966550Snyan if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) 78066550Snyan val |= bit; 78166550Snyan } 78266550Snyan *data++ = val; 78366550Snyan 78466550Snyan bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); 785179442Sjhb DELAY(SNEC_EEP_DELAY); 78666550Snyan } 78766550Snyan 78866550Snyan#ifdef SNCDEBUG 78966550Snyan /* Report what we got. */ 79066550Snyan data -= SNEC_EEPROM_SIZE; 79166550Snyan log(LOG_INFO, "%s: EEPROM:" 79266550Snyan " %02x%02x%02x%02x %02x%02x%02x%02x -" 79366550Snyan " %02x%02x%02x%02x %02x%02x%02x%02x -" 79466550Snyan " %02x%02x%02x%02x %02x%02x%02x%02x -" 79566550Snyan " %02x%02x%02x%02x %02x%02x%02x%02x\n", 79666550Snyan "snc_nec16_read_eeprom", 79766550Snyan data[ 0], data[ 1], data[ 2], data[ 3], 79866550Snyan data[ 4], data[ 5], data[ 6], data[ 7], 79966550Snyan data[ 8], data[ 9], data[10], data[11], 80066550Snyan data[12], data[13], data[14], data[15], 80166550Snyan data[16], data[17], data[18], data[19], 80266550Snyan data[20], data[21], data[22], data[23], 80366550Snyan data[24], data[25], data[26], data[27], 80466550Snyan data[28], data[29], data[30], data[31]); 80566550Snyan#endif 80666550Snyan} 80766550Snyan 80866550Snyan#ifdef SNCDEBUG 80966550Snyanvoid 810242871Snyansnc_nec16_dump_reg(bus_space_tag_t iot, bus_space_handle_t ioh) 81166550Snyan{ 81266550Snyan u_int8_t n; 81366550Snyan u_int16_t val; 81466550Snyan 81566550Snyan printf("SONIC registers (word):"); 81666550Snyan for (n = 0; n < SNC_NREGS; n++) { 81766550Snyan /* select required SONIC register */ 81866550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, n); 819179442Sjhb DELAY(10); 82066550Snyan val = bus_space_read_2(iot, ioh, SNEC_CTRL); 82166550Snyan if ((n % 0x10) == 0) 82266550Snyan printf("\n%04x ", val); 82366550Snyan else 82466550Snyan printf("%04x ", val); 82566550Snyan } 82666550Snyan printf("\n"); 82766550Snyan 82866550Snyan printf("NEC/SONIC registers (byte):\n"); 82966550Snyan for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) { 83066550Snyan /* select required SONIC register */ 83166550Snyan bus_space_write_1(iot, ioh, SNEC_ADDR, n); 832179442Sjhb DELAY(10); 83366550Snyan val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB); 83466550Snyan printf("%04x ", val); 83566550Snyan } 83666550Snyan printf("\n"); 83766550Snyan} 83866550Snyan 83966550Snyan#endif /* SNCDEBUG */ 840