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