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