]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/snc/dp83932subr.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / snc / dp83932subr.c
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
67 static __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  */
75 int
76 sncsetup(sc, lladdr)
77         struct snc_softc        *sc;
78         u_int8_t *lladdr;
79 {
80         u_int32_t p, pp;
81         int     i;
82         int     offset;
83
84         /*
85          * Put the pup in reset mode (sncinit() will fix it later),
86          * stop the timer, disable all interrupts and clear any interrupts.
87          */
88         NIC_PUT(sc, SNCR_CR, CR_STP);
89         wbflush();
90         NIC_PUT(sc, SNCR_CR, CR_RST);
91         wbflush();
92         NIC_PUT(sc, SNCR_IMR, 0);
93         wbflush();
94         NIC_PUT(sc, SNCR_ISR, ISR_ALL);
95         wbflush();
96
97         /*
98          * because the SONIC is basically 16bit device it 'concatenates'
99          * a higher buffer address to a 16 bit offset--this will cause wrap
100          * around problems near the end of 64k !!
101          */
102         p = pp = 0;
103
104         for (i = 0; i < NRRA; i++) {
105                 sc->v_rra[i] = SONIC_GETDMA(p);
106                 p += RXRSRC_SIZE(sc);
107         }
108         sc->v_rea = SONIC_GETDMA(p);
109
110         p = SOALIGN(sc, p);
111
112         sc->v_cda = SONIC_GETDMA(p);
113         p += CDA_SIZE(sc);
114
115         p = SOALIGN(sc, p);
116
117         for (i = 0; i < NTDA; i++) {
118                 struct mtd *mtdp = &sc->mtda[i];
119                 mtdp->mtd_vtxp = SONIC_GETDMA(p);
120                 p += TXP_SIZE(sc);
121         }
122
123         p = SOALIGN(sc, p);
124
125         if ((p - pp) > PAGE_SIZE) {
126                 device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +"
127                     "TDA (%ld) > PAGE_SIZE (%d). Punt!\n",
128                     (u_long)sc->v_cda - (u_long)sc->v_rra[0],
129                     (u_long)sc->mtda[0].mtd_vtxp - (u_long)sc->v_cda,
130                     (u_long)p - (u_long)sc->mtda[0].mtd_vtxp,
131                     PAGE_SIZE);
132                 return(1);
133         }
134
135         p = pp + PAGE_SIZE;
136         pp = p;
137
138         sc->sc_nrda = PAGE_SIZE / RXPKT_SIZE(sc);
139         sc->v_rda = SONIC_GETDMA(p);
140
141         p = pp + PAGE_SIZE;
142
143         for (i = 0; i < NRBA; i++) {
144                 sc->rbuf[i] = p;
145                 p += PAGE_SIZE;
146         }
147
148         pp = p;
149         offset = TXBSIZE;
150         for (i = 0; i < NTDA; i++) {
151                 struct mtd *mtdp = &sc->mtda[i];
152
153                 mtdp->mtd_vbuf = SONIC_GETDMA(p);
154                 offset += TXBSIZE;
155                 if (offset < PAGE_SIZE) {
156                         p += TXBSIZE;
157                 } else {
158                         p = pp + PAGE_SIZE;
159                         pp = p;
160                         offset = TXBSIZE;
161                 }
162         }
163
164         return (0);
165 }
166
167 /*
168  * miscellaneous NEC/SONIC detect functions.
169  */
170
171 /*
172  * check if a specified irq is acceptable.
173  */
174 u_int8_t
175 snc_nec16_validate_irq(irq)
176         int irq;
177 {
178         const u_int8_t encoded_irq[16] = {
179             -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1
180         };
181
182         return encoded_irq[irq];
183 }
184
185 /*
186  * specify irq to board.
187  */
188 int
189 snc_nec16_register_irq(sc, irq)
190         struct snc_softc *sc;
191         int irq;
192 {
193         bus_space_tag_t iot = sc->sc_iot;
194         bus_space_handle_t ioh = sc->sc_ioh;
195         u_int8_t encoded_irq;
196
197         encoded_irq = snc_nec16_validate_irq(irq);
198         if (encoded_irq == (u_int8_t) -1) {
199                 printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq);
200                 return 0;
201         }
202
203         /* select SNECR_IRQSEL register */
204         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL);
205         /* write encoded irq value */
206         bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq);
207
208         return 1;
209 }
210
211 /*
212  * check if a specified memory base address is acceptable.
213  */
214 int
215 snc_nec16_validate_mem(maddr)
216         int maddr;
217 {
218
219         /* Check on Normal mode with max range, only */
220         if ((maddr & ~0x1E000) != 0xC0000) {
221                 printf("snc_nec16_validate_mem: "
222                     "unsupported window base (0x%x)\n", maddr);
223                 return 0;
224         }
225
226         return 1;
227 }
228
229 /*
230  * specify memory base address to board and map to first bank.
231  */
232 int
233 snc_nec16_register_mem(sc, maddr)
234         struct snc_softc *sc;
235         int maddr;
236 {
237         bus_space_tag_t iot = sc->sc_iot;
238         bus_space_handle_t ioh = sc->sc_ioh;
239
240         if (snc_nec16_validate_mem(maddr) == 0)
241                 return 0;
242
243         /* select SNECR_MEMSEL register */
244         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL);
245         /* write encoded memory base select value */
246         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr));
247
248         /*
249          * set current bank to 0 (bottom) and map
250          */
251         /* select SNECR_MEMBS register */
252         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
253         /* select new bank */
254         bus_space_write_1(iot, ioh, SNEC_CTRLB,
255             SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN);
256         /* set current bank to 0 */
257         sc->curbank = 0;
258
259         return 1;
260 }
261
262 int
263 snc_nec16_check_memory(iot, ioh, memt, memh)
264         bus_space_tag_t iot;
265         bus_space_handle_t ioh;
266         bus_space_tag_t memt;
267         bus_space_handle_t memh;
268 {
269         u_int16_t val;
270         int i, j;
271
272         val = 0;
273         for (i = 0; i < SNEC_NBANK; i++) {
274                 /* select new bank */
275                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
276                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
277                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
278
279                 /* write test pattern */
280                 for (j = 0; j < SNEC_NMEMS / 2; j++) {
281                         bus_space_write_2(memt, memh, j * 2, val + j);
282                 }
283                 val += 0x1000;
284         }
285
286         val = 0;
287         for (i = 0; i < SNEC_NBANK; i++) {
288                 /* select new bank */
289                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
290                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
291                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
292
293                 /* read test pattern */
294                 for (j = 0; j < SNEC_NMEMS / 2; j++) {
295                         if (bus_space_read_2(memt, memh, j * 2) != val + j)
296                                 break;
297                 }
298
299                 if (j < SNEC_NMEMS / 2) {
300                         printf("snc_nec16_check_memory: "
301                             "memory check failed at 0x%04x%04x"
302                             "val 0x%04x != expected 0x%04x\n", i, j,
303                             bus_space_read_2(memt, memh, j * 2),
304                             val + j);
305                         return 0;
306                 }
307                 val += 0x1000;
308         }
309
310         /* zero clear mem */
311         for (i = 0; i < SNEC_NBANK; i++) {
312                 /* select new bank */
313                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
314                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
315                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
316
317                 bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2);
318         }
319
320         /* again read test if these are 0 */
321         for (i = 0; i < SNEC_NBANK; i++) {
322                 /* select new bank */
323                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
324                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
325                     SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN);
326
327                 /* check if cleared */
328                 for (j = 0; j < SNEC_NMEMS; j += 2) {
329                         if (bus_space_read_2(memt, memh, j) != 0)
330                                 break;
331                 }
332
333                 if (j != SNEC_NMEMS) {
334                         printf("snc_nec16_check_memory: "
335                             "memory zero clear failed at 0x%04x%04x\n", i, j);
336                         return 0;
337                 }
338         }
339
340         return 1;
341 }
342
343 int
344 snc_nec16_detectsubr(iot, ioh, memt, memh, irq, maddr, type)
345         bus_space_tag_t iot;
346         bus_space_handle_t ioh;
347         bus_space_tag_t memt;
348         bus_space_handle_t memh;
349         int irq;
350         int maddr;
351         u_int8_t type;
352 {
353         u_int16_t cr;
354         u_int8_t ident;
355         int rv = 0;
356
357         if (snc_nec16_validate_irq(irq) == (u_int8_t) -1)
358                 return 0;
359         /* XXX: maddr already checked */
360         if (snc_nec16_validate_mem(maddr) == 0)
361                 return 0;
362
363         bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT);
364         ident = bus_space_read_1(iot, ioh, SNEC_CTRLB);
365         if (ident == 0xff || ident == 0x00) {
366                 /* not found */
367                 return 0;
368         }
369
370         switch (type) {
371         case SNEC_TYPE_LEGACY:
372                 rv = (ident == SNECR_IDENT_LEGACY_CBUS);
373                 break;
374         case SNEC_TYPE_PNP:
375                 rv = ((ident == SNECR_IDENT_PNP_CBUS) ||
376                     (ident == SNECR_IDENT_PNP_PCMCIABUS));
377                 break;
378         default:
379                 break;
380         }
381
382         if (rv == 0) {
383                 printf("snc_nec16_detectsubr: parent bus mismatch\n");
384                 return 0;
385         }
386
387         /* select SONIC register SNCR_CR */
388         bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR);
389         bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST);
390         DELAY(400);
391
392         cr = bus_space_read_2(iot, ioh, SNEC_CTRL);
393         if (cr != (CR_RXDIS | CR_STP | CR_RST)) {
394 #ifdef DIAGNOSTIC
395                 printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n",
396                     cr);
397 #endif
398                 return 0;
399         }
400
401         if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0)
402                 return 0;
403
404         return 1;
405 }
406
407 /* XXX */
408 #define SNC_VENDOR_NEC          0x00004c
409 #define SNC_NEC_SERIES_LEGACY_CBUS      0xa5
410 #define SNC_NEC_SERIES_PNP_PCMCIA       0xd5
411 #define SNC_NEC_SERIES_PNP_PCMCIA2      0x6d    /* XXX */
412 #define SNC_NEC_SERIES_PNP_CBUS         0x0d
413 #define SNC_NEC_SERIES_PNP_CBUS2        0x3d
414
415 u_int8_t *
416 snc_nec16_detect_type(myea)
417         u_int8_t *myea;
418 {
419         u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2];
420         u_int8_t series = myea[3];
421         u_int8_t type = myea[4] & 0x80;
422         u_int8_t *typestr;
423
424         switch (vendor) {
425         case SNC_VENDOR_NEC:
426                 switch (series) {
427                 case SNC_NEC_SERIES_LEGACY_CBUS:
428                         if (type)
429                                 typestr = "NEC PC-9801-84";
430                         else
431                                 typestr = "NEC PC-9801-83";
432                         break;
433                 case SNC_NEC_SERIES_PNP_CBUS:
434                 case SNC_NEC_SERIES_PNP_CBUS2:
435                         if (type)
436                                 typestr = "NEC PC-9801-104";
437                         else
438                                 typestr = "NEC PC-9801-103";
439                         break;
440                 case SNC_NEC_SERIES_PNP_PCMCIA:
441                 case SNC_NEC_SERIES_PNP_PCMCIA2:
442                         /* XXX: right ? */
443                         if (type)
444                                 typestr = "NEC PC-9801N-J02R";
445                         else
446                                 typestr = "NEC PC-9801N-J02";
447                         break;
448                 default:
449                         typestr = "NEC unknown (PC-9801N-25?)";
450                         break;
451                 }
452                 break;
453         default:
454                 typestr = "unknown (3rd vendor?)";
455                 break;
456         }
457
458         return typestr;
459 }
460
461 int
462 snc_nec16_get_enaddr(iot, ioh, myea)
463         bus_space_tag_t iot;
464         bus_space_handle_t ioh;
465         u_int8_t *myea;
466 {
467         u_int8_t eeprom[SNEC_EEPROM_SIZE];
468         u_int8_t rom_sum, sum = 0x00;
469         int i;
470
471         snc_nec16_read_eeprom(iot, ioh, eeprom);
472
473         for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) {
474                 sum = sum ^ eeprom[i];
475         }
476
477         rom_sum = eeprom[SNEC_EEPROM_CKSUM];
478
479         if (sum != rom_sum) {
480                 printf("snc_nec16_get_enaddr: "
481                     "checksum mismatch; calculated %02x != read %02x",
482                     sum, rom_sum);
483                 return 0;
484         }
485
486         for (i = 0; i < ETHER_ADDR_LEN; i++)
487                 myea[i] = eeprom[SNEC_EEPROM_SA0 + i];
488
489         return 1;
490 }
491
492 /*
493  * read from NEC/SONIC NIC register.
494  */
495 u_int16_t
496 snc_nec16_nic_get(sc, reg)
497         struct snc_softc *sc;
498         u_int8_t reg;
499 {
500         u_int16_t val;
501
502         /* select SONIC register */
503         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg);
504         val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL);
505
506         return val;
507 }
508
509 /*
510  * write to NEC/SONIC NIC register.
511  */
512 void
513 snc_nec16_nic_put(sc, reg, val)
514         struct snc_softc *sc;
515         u_int8_t reg;
516         u_int16_t val;
517 {
518
519         /* select SONIC register */
520         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg);
521         bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val);
522 }
523
524
525 /*
526  * select memory bank and map
527  * where exists specified (internal buffer memory) offset.
528  */
529 static __inline u_int16_t
530 snc_nec16_select_bank(sc, base, offset)
531         struct snc_softc *sc;
532         u_int32_t base;
533         u_int32_t offset;
534 {
535         bus_space_tag_t iot = sc->sc_iot;
536         bus_space_handle_t ioh = sc->sc_ioh;
537         u_int8_t bank;
538         u_int16_t noffset;
539
540         /* bitmode is fixed to 16 bit. */
541         bank = (base + offset * 2) >> 13;
542         noffset = (base + offset * 2) & (SNEC_NMEMS - 1);
543
544 #ifdef SNCDEBUG
545         if (noffset % 2) {
546                 device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n",
547                               noffset);
548         }
549 #endif  /* SNCDEBUG */
550
551         if (sc->curbank != bank) {
552                 /* select SNECR_MEMBS register */
553                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS);
554                 /* select new bank */
555                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
556                     SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN);
557                 /* update current bank */
558                 sc->curbank = bank;
559         }
560
561         return noffset;
562 }
563
564 /*
565  * write to SONIC descriptors.
566  */
567 void
568 snc_nec16_writetodesc(sc, base, offset, val)
569         struct snc_softc *sc;
570         u_int32_t base;
571         u_int32_t offset;
572         u_int16_t val;
573 {
574         bus_space_tag_t memt = sc->sc_memt;
575         bus_space_handle_t memh = sc->sc_memh;
576         u_int16_t noffset;
577
578         noffset = snc_nec16_select_bank(sc, base, offset);
579
580         bus_space_write_2(memt, memh, noffset, val);
581 }
582
583 /*
584  * read from SONIC descriptors.
585  */
586 u_int16_t
587 snc_nec16_readfromdesc(sc, base, offset)
588         struct snc_softc *sc;
589         u_int32_t base;
590         u_int32_t offset;
591 {
592         bus_space_tag_t memt = sc->sc_memt;
593         bus_space_handle_t memh = sc->sc_memh;
594         u_int16_t noffset;
595
596         noffset = snc_nec16_select_bank(sc, base, offset);
597
598         return bus_space_read_2(memt, memh, noffset);
599 }
600
601 /*
602  * read from SONIC data buffer.
603  */
604 void
605 snc_nec16_copyfrombuf(sc, dst, offset, size)
606         struct snc_softc *sc;
607         void *dst;
608         u_int32_t offset;
609         size_t size;
610 {
611         bus_space_tag_t memt = sc->sc_memt;
612         bus_space_handle_t memh = sc->sc_memh;
613         u_int16_t noffset;
614         u_int8_t* bptr = dst;
615
616         noffset = snc_nec16_select_bank(sc, offset, 0);
617
618         /* XXX: should check if offset + size < 0x2000. */
619
620         bus_space_barrier(memt, memh, noffset, size,
621                           BUS_SPACE_BARRIER_READ);
622
623         if (size > 3)  {
624                 if (noffset & 3)  {
625                         size_t asize = 4 - (noffset & 3);
626
627                         bus_space_read_region_1(memt, memh, noffset,
628                             bptr, asize);
629                         bptr += asize;
630                         noffset += asize;
631                         size -= asize;
632                 }
633                 bus_space_read_region_4(memt, memh, noffset,
634                     (u_int32_t *) bptr, size >> 2);
635                 bptr += size & ~3;
636                 noffset += size & ~3;
637                 size &= 3;
638         }
639         if (size)
640                 bus_space_read_region_1(memt, memh, noffset, bptr, size);
641 }
642
643 /*
644  * write to SONIC data buffer.
645  */
646 void
647 snc_nec16_copytobuf(sc, src, offset, size)
648         struct snc_softc *sc;
649         void *src;
650         u_int32_t offset;
651         size_t size;
652 {
653         bus_space_tag_t memt = sc->sc_memt;
654         bus_space_handle_t memh = sc->sc_memh;
655         u_int16_t noffset, onoffset;
656         size_t osize = size;
657         u_int8_t* bptr = src;
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_write_region_1(memt, memh, noffset,
669                             bptr, asize);
670                         bptr += asize;
671                         noffset += asize;
672                         size -= asize;
673                 }
674                 bus_space_write_region_4(memt, memh, noffset,
675                     (u_int32_t *)bptr, size >> 2);
676                 bptr += size & ~3;
677                 noffset += size & ~3;
678                 size -= size & ~3;
679         }
680         if (size)
681                 bus_space_write_region_1(memt, memh, noffset, bptr, size);
682
683         bus_space_barrier(memt, memh, onoffset, osize,
684                           BUS_SPACE_BARRIER_WRITE);
685 }
686
687 /*
688  * write (fill) 0 to SONIC data buffer.
689  */
690 void
691 snc_nec16_zerobuf(sc, offset, size)
692         struct snc_softc *sc;
693         u_int32_t offset;
694         size_t size;
695 {
696         bus_space_tag_t memt = sc->sc_memt;
697         bus_space_handle_t memh = sc->sc_memh;
698         u_int16_t noffset, onoffset;
699         size_t osize = size;
700
701         noffset = snc_nec16_select_bank(sc, offset, 0);
702         onoffset = noffset;
703
704         /* XXX: should check if offset + size < 0x2000. */
705
706         if (size > 3)  {
707                 if (noffset & 3)  {
708                         size_t asize = 4 - (noffset & 3);
709
710                         bus_space_set_region_1(memt, memh, noffset, 0, asize);
711                         noffset += asize;
712                         size -= asize;
713                 }
714                 bus_space_set_region_4(memt, memh, noffset, 0, size >> 2);
715                 noffset += size & ~3;
716                 size -= size & ~3;
717         }
718         if (size)
719                 bus_space_set_region_1(memt, memh, noffset, 0, size);
720
721         bus_space_barrier(memt, memh, onoffset, osize,
722                           BUS_SPACE_BARRIER_WRITE);
723 }
724
725
726 /* 
727  * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83,
728  * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98.
729  * Ported by Kouichi Matsuda.
730  * 
731  * This algorism is generic to read data sequentially from 4-Wire
732  * Microwire Serial EEPROM.
733  */
734
735 #define SNEC_EEP_DELAY  1000
736
737 void
738 snc_nec16_read_eeprom(iot, ioh, data)
739         bus_space_tag_t iot;
740         bus_space_handle_t ioh;
741         u_int8_t *data;
742 {
743         u_int8_t n, val, bit;
744
745         /* Read bytes from EEPROM; two bytes per an iteration. */
746         for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) {
747                 /* select SNECR_EEP */
748                 bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP);
749
750                 bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00);
751                 DELAY(SNEC_EEP_DELAY);
752
753                 /* Start EEPROM access. */
754                 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
755                 DELAY(SNEC_EEP_DELAY);
756
757                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
758                     SNECR_EEP_CS | SNECR_EEP_SK);
759                 DELAY(SNEC_EEP_DELAY);
760
761                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
762                     SNECR_EEP_CS | SNECR_EEP_DI);
763                 DELAY(SNEC_EEP_DELAY);
764
765                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
766                     SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI);
767                 DELAY(SNEC_EEP_DELAY);
768
769                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
770                     SNECR_EEP_CS | SNECR_EEP_DI);
771                 DELAY(SNEC_EEP_DELAY);
772
773                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
774                     SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI);
775                 DELAY(SNEC_EEP_DELAY);
776
777                 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
778                 DELAY(SNEC_EEP_DELAY);
779
780                 bus_space_write_1(iot, ioh, SNEC_CTRLB,
781                     SNECR_EEP_CS | SNECR_EEP_SK);
782                 DELAY(SNEC_EEP_DELAY);
783
784                 /* Pass the iteration count to the chip. */
785                 for (bit = 0x20; bit != 0x00; bit >>= 1) {
786                         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS |
787                             ((n & bit) ? SNECR_EEP_DI : 0x00));
788                         DELAY(SNEC_EEP_DELAY);
789
790                         bus_space_write_1(iot, ioh, SNEC_CTRLB,
791                             SNECR_EEP_CS | SNECR_EEP_SK |
792                             ((n & bit) ? SNECR_EEP_DI : 0x00));
793                         DELAY(SNEC_EEP_DELAY);
794                 }
795
796                 bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
797                 (void) bus_space_read_1(iot, ioh, SNEC_CTRLB);  /* ACK */
798                 DELAY(SNEC_EEP_DELAY);
799
800                 /* Read a byte. */
801                 val = 0;
802                 for (bit = 0x80; bit != 0x00; bit >>= 1) {
803                         bus_space_write_1(iot, ioh, SNEC_CTRLB,
804                             SNECR_EEP_CS | SNECR_EEP_SK);
805                         DELAY(SNEC_EEP_DELAY);
806
807                         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
808
809                         if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO)
810                                 val |= bit;
811                 }
812                 *data++ = val;
813
814                 /* Read one more byte. */
815                 val = 0;
816                 for (bit = 0x80; bit != 0x00; bit >>= 1) {
817                         bus_space_write_1(iot, ioh, SNEC_CTRLB,
818                             SNECR_EEP_CS | SNECR_EEP_SK);
819                         DELAY(SNEC_EEP_DELAY);
820
821                         bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS);
822
823                         if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO)
824                                 val |= bit;
825                 }
826                 *data++ = val;
827
828                 bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00);
829                 DELAY(SNEC_EEP_DELAY);
830         }
831
832 #ifdef  SNCDEBUG
833         /* Report what we got. */
834         data -= SNEC_EEPROM_SIZE;
835         log(LOG_INFO, "%s: EEPROM:"
836             " %02x%02x%02x%02x %02x%02x%02x%02x -"
837             " %02x%02x%02x%02x %02x%02x%02x%02x -"
838             " %02x%02x%02x%02x %02x%02x%02x%02x -"
839             " %02x%02x%02x%02x %02x%02x%02x%02x\n",
840             "snc_nec16_read_eeprom",
841             data[ 0], data[ 1], data[ 2], data[ 3],
842             data[ 4], data[ 5], data[ 6], data[ 7],
843             data[ 8], data[ 9], data[10], data[11],
844             data[12], data[13], data[14], data[15],
845             data[16], data[17], data[18], data[19],
846             data[20], data[21], data[22], data[23],
847             data[24], data[25], data[26], data[27],
848             data[28], data[29], data[30], data[31]);
849 #endif
850 }
851
852 #ifdef  SNCDEBUG
853 void
854 snc_nec16_dump_reg(iot, ioh)
855         bus_space_tag_t iot;
856         bus_space_handle_t ioh;
857 {
858         u_int8_t n;
859         u_int16_t val;
860
861         printf("SONIC registers (word):");
862         for (n = 0; n < SNC_NREGS; n++) {
863                 /* select required SONIC register */
864                 bus_space_write_1(iot, ioh, SNEC_ADDR, n);
865                 DELAY(10);
866                 val = bus_space_read_2(iot, ioh, SNEC_CTRL);
867                 if ((n % 0x10) == 0)
868                         printf("\n%04x ", val);
869                 else
870                         printf("%04x ", val);
871         }
872         printf("\n");
873
874         printf("NEC/SONIC registers (byte):\n");
875         for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) {
876                 /* select required SONIC register */
877                 bus_space_write_1(iot, ioh, SNEC_ADDR, n);
878                 DELAY(10);
879                 val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB);
880                 printf("%04x ", val);
881         }
882         printf("\n");
883 }
884
885 #endif  /* SNCDEBUG */