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