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