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