stp4020.c revision 1.10 1 /* $NetBSD: stp4020.c,v 1.10 2000/02/22 12:24:53 pk Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards.
41 */
42
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/malloc.h>
48 #include <sys/proc.h>
49 #include <sys/kernel.h>
50 #include <sys/kthread.h>
51 #include <sys/device.h>
52
53 #include <dev/pcmcia/pcmciareg.h>
54 #include <dev/pcmcia/pcmciavar.h>
55 #include <dev/pcmcia/pcmciachip.h>
56
57 #include <machine/bus.h>
58 #include <machine/autoconf.h>
59
60 #include <dev/sbus/sbusvar.h>
61 #include <dev/sbus/stp4020reg.h>
62
63 #define STP4020_DEBUG 1 /* XXX-temp */
64
65 #if defined(STP4020_DEBUG)
66 int stp4020_debug = 0;
67 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0)
68 #else
69 #define DPRINTF(x)
70 #endif
71
72 /*
73 * Event queue; events detected in an interrupt context go here
74 * awaiting attention from our event handling thread.
75 */
76 struct stp4020_event {
77 SIMPLEQ_ENTRY(stp4020_event) se_q;
78 int se_type;
79 int se_sock;
80 };
81 /* Defined event types */
82 #define STP4020_EVENT_INSERTION 0
83 #define STP4020_EVENT_REMOVAL 1
84
85 /*
86 * Per socket data.
87 */
88 struct stp4020_socket {
89 struct stp4020_softc *sc; /* Back link */
90 int flags;
91 #define STP4020_SOCKET_BUSY 0x0001
92 #define STP4020_SOCKET_SHUTDOWN 0x0002
93 int sock; /* Socket number (0 or 1) */
94 bus_space_tag_t tag; /* socket control space */
95 bus_space_handle_t regs; /* */
96 struct device *pcmcia; /* Associated PCMCIA device */
97 int (*intrhandler) /* Card driver interrupt handler */
98 __P((void *));
99 void *intrarg; /* Card interrupt handler argument */
100 int ipl; /* Interrupt level suggested by card */
101 int winalloc; /* Windows allocated (bitmask) */
102 struct {
103 bus_space_handle_t winaddr;/* this window's address */
104 } windows[STP4020_NWIN];
105
106 };
107
108 struct stp4020_softc {
109 struct device sc_dev; /* Base device */
110 struct sbusdev sc_sd; /* SBus device */
111 bus_space_tag_t sc_bustag;
112 bus_dma_tag_t sc_dmatag;
113 pcmcia_chipset_tag_t sc_pct; /* Chipset methods */
114
115 struct proc *event_thread; /* event handling thread */
116 SIMPLEQ_HEAD(, stp4020_event) events; /* Pending events for thread */
117
118 struct stp4020_socket sc_socks[STP4020_NSOCK];
119 };
120
121
122 static int stp4020print __P((void *, const char *));
123 static int stp4020match __P((struct device *, struct cfdata *, void *));
124 static void stp4020attach __P((struct device *, struct device *, void *));
125 static int stp4020_iointr __P((void *));
126 static int stp4020_statintr __P((void *));
127
128 struct cfattach nell_ca = {
129 sizeof(struct stp4020_softc), stp4020match, stp4020attach
130 };
131
132 #ifdef STP4020_DEBUG
133 static void stp4020_dump_regs __P((struct stp4020_socket *));
134 #endif
135
136 static int stp4020_rd_sockctl __P((struct stp4020_socket *, int));
137 static void stp4020_wr_sockctl __P((struct stp4020_socket *, int, int));
138 static int stp4020_rd_winctl __P((struct stp4020_socket *, int, int));
139 static void stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int));
140
141 void stp4020_delay __P((unsigned int));
142 void stp4020_attach_socket __P((struct stp4020_socket *));
143 void stp4020_create_event_thread __P((void *));
144 void stp4020_event_thread __P((void *));
145 void stp4020_queue_event __P((struct stp4020_softc *, int, int));
146
147 int stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
148 struct pcmcia_mem_handle *));
149 void stp4020_chip_mem_free __P((pcmcia_chipset_handle_t,
150 struct pcmcia_mem_handle *));
151 int stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
152 bus_size_t, struct pcmcia_mem_handle *,
153 bus_addr_t *, int *));
154 void stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int));
155
156 int stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t,
157 bus_addr_t, bus_size_t, bus_size_t,
158 struct pcmcia_io_handle *));
159 void stp4020_chip_io_free __P((pcmcia_chipset_handle_t,
160 struct pcmcia_io_handle *));
161 int stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
162 bus_size_t, struct pcmcia_io_handle *, int *));
163 void stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
164
165 void stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t));
166 void stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t));
167 void *stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t,
168 struct pcmcia_function *, int,
169 int (*) __P((void *)), void *));
170 void stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
171
172
173 /* Our PCMCIA chipset methods */
174 static struct pcmcia_chip_functions stp4020_functions = {
175 stp4020_chip_mem_alloc,
176 stp4020_chip_mem_free,
177 stp4020_chip_mem_map,
178 stp4020_chip_mem_unmap,
179
180 stp4020_chip_io_alloc,
181 stp4020_chip_io_free,
182 stp4020_chip_io_map,
183 stp4020_chip_io_unmap,
184
185 stp4020_chip_intr_establish,
186 stp4020_chip_intr_disestablish,
187
188 stp4020_chip_socket_enable,
189 stp4020_chip_socket_disable
190 };
191
192
193 static __inline__ int
194 stp4020_rd_sockctl(h, idx)
195 struct stp4020_socket *h;
196 int idx;
197 {
198 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
199 return (bus_space_read_2(h->tag, h->regs, o));
200 }
201
202 static __inline__ void
203 stp4020_wr_sockctl(h, idx, v)
204 struct stp4020_socket *h;
205 int idx;
206 int v;
207 {
208 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
209 bus_space_write_2(h->tag, h->regs, o, v);
210 }
211
212 static __inline__ int
213 stp4020_rd_winctl(h, win, idx)
214 struct stp4020_socket *h;
215 int win;
216 int idx;
217 {
218 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
219 (STP4020_WINREGS_SIZE * win) + idx;
220 return (bus_space_read_2(h->tag, h->regs, o));
221 }
222
223 static __inline__ void
224 stp4020_wr_winctl(h, win, idx, v)
225 struct stp4020_socket *h;
226 int win;
227 int idx;
228 int v;
229 {
230 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
231 (STP4020_WINREGS_SIZE * win) + idx;
232
233 bus_space_write_2(h->tag, h->regs, o, v);
234 }
235
236
237 int
238 stp4020print(aux, busname)
239 void *aux;
240 const char *busname;
241 {
242 struct pcmciabus_attach_args *paa = aux;
243 struct stp4020_socket *h = paa->pch;
244
245 printf(" socket %d", h->sock);
246 return (UNCONF);
247 }
248
249 int
250 stp4020match(parent, cf, aux)
251 struct device *parent;
252 struct cfdata *cf;
253 void *aux;
254 {
255 struct sbus_attach_args *sa = aux;
256
257 return (strcmp("SUNW,pcmcia", sa->sa_name) == 0);
258 }
259
260 /*
261 * Attach all the sub-devices we can find
262 */
263 void
264 stp4020attach(parent, self, aux)
265 struct device *parent, *self;
266 void *aux;
267 {
268 struct sbus_attach_args *sa = aux;
269 struct stp4020_softc *sc = (void *)self;
270 int node, rev;
271 int i;
272 bus_space_handle_t bh;
273
274 node = sa->sa_node;
275
276 /* Transfer bus tags */
277 sc->sc_bustag = sa->sa_bustag;
278 sc->sc_dmatag = sa->sa_dmatag;
279
280 /* Set up per-socket static initialization */
281 sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
282 sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag;
283
284 if (sa->sa_nreg < 8) {
285 printf("%s: only %d register sets\n",
286 self->dv_xname, sa->sa_nreg);
287 return;
288 }
289
290 if (sa->sa_nintr != 2) {
291 printf("%s: expect 2 interrupt Sbus levels; got %d\n",
292 self->dv_xname, sa->sa_nintr);
293 return;
294 }
295
296 #define STP4020_BANK_PROM 0
297 #define STP4020_BANK_CTRL 4
298 for (i = 0; i < 8; i++) {
299
300 /*
301 * STP4020 Register address map:
302 * bank 0: Forth PROM
303 * banks 1-3: socket 0, windows 0-2
304 * bank 4: control registers
305 * banks 5-7: socket 1, windows 0-2
306 */
307
308 if (i == STP4020_BANK_PROM)
309 /* Skip the PROM */
310 continue;
311
312 if (sbus_bus_map(sa->sa_bustag,
313 sa->sa_reg[i].sbr_slot,
314 sa->sa_reg[i].sbr_offset,
315 sa->sa_reg[i].sbr_size,
316 BUS_SPACE_MAP_LINEAR, 0,
317 &bh) != 0) {
318 printf("%s: attach: cannot map registers\n",
319 self->dv_xname);
320 return;
321 }
322
323 if (i == STP4020_BANK_CTRL) {
324 /*
325 * Copy tag and handle to both socket structures
326 * for easy access in control/status IO functions.
327 */
328 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
329 } else if (i < STP4020_BANK_CTRL) {
330 /* banks 1-3 */
331 sc->sc_socks[0].windows[i-1].winaddr = bh;
332 } else {
333 /* banks 5-7 */
334 sc->sc_socks[1].windows[i-5].winaddr = bh;
335 }
336 }
337
338 sbus_establish(&sc->sc_sd, &sc->sc_dev);
339
340 /*
341 * We get to use two SBus interrupt levels.
342 * The higher level we use for status change interrupts;
343 * the lower level for PC card I/O.
344 */
345 if (sa->sa_nintr != 0) {
346 bus_intr_establish(sa->sa_bustag, sa->sa_intr[1].sbi_pri,
347 0, stp4020_statintr, sc);
348
349 bus_intr_establish(sa->sa_bustag, sa->sa_intr[0].sbi_pri,
350 0, stp4020_iointr, sc);
351 }
352
353 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
354 STP4020_ISR1_REV_M;
355 printf(": rev %x\n", rev);
356
357 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
358
359 /*
360 * Arrange that a kernel thread be created to handle
361 * insert/removal events.
362 */
363 SIMPLEQ_INIT(&sc->events);
364 kthread_create(stp4020_create_event_thread, sc);
365
366 for (i = 0; i < STP4020_NSOCK; i++) {
367 struct stp4020_socket *h = &sc->sc_socks[i];
368 h->sock = i;
369 h->sc = sc;
370 #ifdef STP4020_DEBUG
371 stp4020_dump_regs(h);
372 #endif
373 stp4020_attach_socket(h);
374 }
375 }
376
377 void
378 stp4020_attach_socket(h)
379 struct stp4020_socket *h;
380 {
381 struct pcmciabus_attach_args paa;
382 int v;
383
384 /* Initialize the rest of the handle */
385 h->winalloc = 0;
386
387 /* Configure one pcmcia device per socket */
388 paa.paa_busname = "pcmcia";
389 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
390 paa.pch = (pcmcia_chipset_handle_t)h;
391 paa.iobase = 0;
392 paa.iosize = 0;
393
394 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
395
396 if (h->pcmcia == NULL)
397 return;
398
399 /*
400 * There's actually a pcmcia bus attached; initialize the slot.
401 */
402
403 /*
404 * Enable socket status change interrupts.
405 * We use SB_INT[1] for status change interrupts.
406 */
407 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
408 v |= STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
409 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
410
411 /* Get live status bits from ISR0 */
412 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
413 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
414 return;
415
416 pcmcia_card_attach(h->pcmcia);
417 h->flags |= STP4020_SOCKET_BUSY;
418 }
419
420
421 /*
422 * Deferred thread creation callback.
423 */
424 void
425 stp4020_create_event_thread(arg)
426 void *arg;
427 {
428 struct stp4020_softc *sc = arg;
429 const char *name = sc->sc_dev.dv_xname;
430
431 if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread,
432 "%s", name)) {
433 panic("%s: unable to create event thread", name);
434 }
435 }
436
437 /*
438 * The actual event handling thread.
439 */
440 void
441 stp4020_event_thread(arg)
442 void *arg;
443 {
444 struct stp4020_softc *sc = arg;
445 struct stp4020_event *e;
446 int s;
447
448 while (1) {
449 struct stp4020_socket *h;
450 int n;
451
452 s = splhigh();
453 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
454 splx(s);
455 (void)tsleep(&sc->events, PWAIT, "pcicev", 0);
456 continue;
457 }
458 SIMPLEQ_REMOVE_HEAD(&sc->events, e, se_q);
459 splx(s);
460
461 n = e->se_sock;
462 if (n < 0 || n >= STP4020_NSOCK)
463 panic("stp4020_event_thread: wayward socket number %d",
464 n);
465
466 h = &sc->sc_socks[n];
467 switch (e->se_type) {
468 case STP4020_EVENT_INSERTION:
469 pcmcia_card_attach(h->pcmcia);
470 break;
471 case STP4020_EVENT_REMOVAL:
472 pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
473 break;
474 default:
475 panic("stp4020_event_thread: unknown event type %d",
476 e->se_type);
477 }
478 free(e, M_TEMP);
479 }
480 }
481
482 void
483 stp4020_queue_event(sc, sock, event)
484 struct stp4020_softc *sc;
485 int sock, event;
486 {
487 struct stp4020_event *e;
488 int s;
489
490 e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
491 if (e == NULL)
492 panic("stp4020_queue_event: can't allocate event");
493
494 e->se_type = event;
495 e->se_sock = sock;
496 s = splhigh();
497 SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
498 splx(s);
499 wakeup(&sc->events);
500 }
501
502 int
503 stp4020_statintr(arg)
504 void *arg;
505 {
506 struct stp4020_softc *sc = arg;
507 int i, r = 0;
508
509 /*
510 * Check each socket for pending requests.
511 */
512 for (i = 0 ; i < STP4020_NSOCK; i++) {
513 struct stp4020_socket *h;
514 int v;
515
516 h = &sc->sc_socks[i];
517
518 /* Read socket's ISR0 for the interrupt status bits */
519 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
520
521 #ifdef STP4020_DEBUG
522 if (stp4020_debug != 0) {
523 char bits[64];
524 bitmask_snprintf(v, STP4020_ISR0_IOBITS,
525 bits, sizeof(bits));
526 printf("stp4020_statintr: ISR0=%s\n", bits);
527 }
528 #endif
529
530 /* Ack all interrupts at once */
531 stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
532 STP4020_ISR0_ALL_STATUS_IRQ);
533
534 if ((v & STP4020_ISR0_CDCHG) != 0) {
535 /*
536 * Card status change detect
537 */
538 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) != 0){
539 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
540 stp4020_queue_event(sc, i,
541 STP4020_EVENT_INSERTION);
542 h->flags |= STP4020_SOCKET_BUSY;
543 }
544 }
545 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
546 if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
547 stp4020_queue_event(sc, i,
548 STP4020_EVENT_REMOVAL);
549 h->flags &= ~STP4020_SOCKET_BUSY;
550 }
551 }
552 }
553
554 /* XXX - a bunch of unhandled conditions */
555 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
556 printf("stp4020[%d]: Battery change 1\n", h->sock);
557 }
558
559 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
560 printf("stp4020[%d]: Battery change 2\n", h->sock);
561 }
562
563 if ((v & STP4020_ISR0_RDYCHG) != 0) {
564 printf("stp4020[%d]: Ready/Busy change\n", h->sock);
565 }
566
567 if ((v & STP4020_ISR0_WPCHG) != 0) {
568 printf("stp4020[%d]: Write protect change\n", h->sock);
569 }
570
571 if ((v & STP4020_ISR0_PCTO) != 0) {
572 printf("stp4020[%d]: Card access timeout\n", h->sock);
573 }
574 }
575
576 return (r);
577 }
578
579 int
580 stp4020_iointr(arg)
581 void *arg;
582 {
583 struct stp4020_softc *sc = arg;
584 int i, r = 0;
585
586 /*
587 * Check each socket for pending requests.
588 */
589 for (i = 0 ; i < STP4020_NSOCK; i++) {
590 struct stp4020_socket *h;
591 int v;
592
593 h = &sc->sc_socks[i];
594 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
595
596 if ((v & STP4020_ISR0_IOINT) != 0) {
597 /* It's a card interrupt */
598 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
599 printf("stp4020[%d]: spurious interrupt?\n",
600 h->sock);
601 continue;
602 }
603 /* Call card handler, if any */
604 if (h->intrhandler != NULL)
605 r |= (*h->intrhandler)(h->intrarg);
606 }
607
608 }
609
610 return (r);
611 }
612
613 int
614 stp4020_chip_mem_alloc(pch, size, pcmhp)
615 pcmcia_chipset_handle_t pch;
616 bus_size_t size;
617 struct pcmcia_mem_handle *pcmhp;
618 {
619 struct stp4020_socket *h = (struct stp4020_socket *)pch;
620 int i, win;
621
622 /*
623 * Allocate a window.
624 */
625 if (size > STP4020_WINDOW_SIZE)
626 return (1);
627
628 for (win = -1, i = 0; i < STP4020_NWIN; i++) {
629 if ((h->winalloc & (1 << i)) == 0) {
630 win = i;
631 h->winalloc |= (1 << i);
632 break;
633 }
634 }
635
636 if (win == -1)
637 return (1);
638
639 pcmhp->memt = 0;
640 pcmhp->memh = h->windows[win].winaddr;
641 pcmhp->addr = 0; /* What is it used for? */
642 pcmhp->size = size;
643 pcmhp->mhandle = win; /* Use our window number as a handle */
644 pcmhp->realsize = STP4020_WINDOW_SIZE;
645
646 return (0);
647 }
648
649 void
650 stp4020_chip_mem_free(pch, pcmhp)
651 pcmcia_chipset_handle_t pch;
652 struct pcmcia_mem_handle *pcmhp;
653 {
654
655 return;
656 }
657
658 int
659 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
660 pcmcia_chipset_handle_t pch;
661 int kind;
662 bus_addr_t card_addr;
663 bus_size_t size;
664 struct pcmcia_mem_handle *pcmhp;
665 bus_addr_t *offsetp;
666 int *windowp;
667 {
668 struct stp4020_socket *h = (struct stp4020_socket *)pch;
669 bus_addr_t offset;
670 int win, v;
671
672 int mem8 = (kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8;
673 kind &= ~PCMCIA_WIDTH_MEM_MASK;
674
675 if(mem8) {
676 /* XXX Fix 8-bit memory accesses (can this be done at all?) */
677 #ifdef DIAGNOSTIC
678 printf("stp4020_chip_mem_map: can't handle 8-bit memory\n");
679 #endif
680 return (-1);
681 }
682
683 win = pcmhp->mhandle;
684 *windowp = win;
685
686 /*
687 * Compute the address offset to the pcmcia address space
688 * for the window.
689 */
690 offset = card_addr & -STP4020_WINDOW_SIZE;
691 card_addr -= offset;
692 *offsetp = offset;
693
694 /*
695 * Fill in the Address Space Select and Base Address
696 * fields of this windows control register 0.
697 */
698 v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX);
699 v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M);
700 v |= (kind == PCMCIA_MEM_ATTR)
701 ? STP4020_WCR0_ASPSEL_AM
702 : STP4020_WCR0_ASPSEL_CM;
703 v |= (STP4020_ADDR2PAGE(card_addr) & STP4020_WCR0_BASE_M);
704 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
705
706 return (0);
707 }
708
709 void
710 stp4020_chip_mem_unmap(pch, win)
711 pcmcia_chipset_handle_t pch;
712 int win;
713 {
714 struct stp4020_socket *h = (struct stp4020_socket *)pch;
715
716 #ifdef DIAGNOSTIC
717 if (win < 0 || win > 2)
718 panic("stp4020_chip_mem_unmap: window (%d) out of range", win);
719 #endif
720 h->winalloc &= ~(1 << win);
721 /*
722 * If possible, invalidate hardware mapping here; but
723 * I don't think the stp4020 has provided for that.
724 */
725 }
726
727 int
728 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
729 pcmcia_chipset_handle_t pch;
730 bus_addr_t start;
731 bus_size_t size;
732 bus_size_t align;
733 struct pcmcia_io_handle *pcihp;
734 {
735 struct stp4020_socket *h = (struct stp4020_socket *)pch;
736
737 if (start) {
738 /* How on earth can `start' be interpreted??
739 WHERE DOES THE CARD DRIVER GET IT FROM?
740 */
741 }
742
743 pcihp->iot = h->tag;
744 pcihp->ioh = 0;
745 pcihp->addr = 0;
746 pcihp->size = size;
747 pcihp->flags = 0;
748
749 return (0);
750 }
751
752 void
753 stp4020_chip_io_free(pch, pcihp)
754 pcmcia_chipset_handle_t pch;
755 struct pcmcia_io_handle *pcihp;
756 {
757
758 return;
759 }
760
761 int
762 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
763 pcmcia_chipset_handle_t pch;
764 int width;
765 bus_addr_t offset;
766 bus_size_t size;
767 struct pcmcia_io_handle *pcihp;
768 int *windowp;
769 {
770 struct stp4020_socket *h = (struct stp4020_socket *)pch;
771 int i, win, v;
772
773 /*
774 * Allocate a window.
775 */
776 if (size > STP4020_WINDOW_SIZE)
777 return (1);
778
779 for (win = -1, i = 0; i < STP4020_NWIN; i++) {
780 if ((h->winalloc & (1 << i)) == 0) {
781 win = i;
782 h->winalloc |= (1 << i);
783 break;
784 }
785 }
786
787 if (win == -1)
788 return (1);
789
790 *windowp = win;
791
792 /*
793 * Fill in the Address Space Select and Base Address
794 * fields of this windows control register 0.
795 */
796 v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX);
797 v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M);
798 v |= STP4020_WCR0_ASPSEL_IO;
799 v |= (STP4020_ADDR2PAGE(pcihp->addr+offset) & STP4020_WCR0_BASE_M);
800 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
801
802 return (0);
803 }
804
805 void
806 stp4020_chip_io_unmap(pch, win)
807 pcmcia_chipset_handle_t pch;
808 int win;
809 {
810 struct stp4020_socket *h = (struct stp4020_socket *)pch;
811
812 #ifdef DIAGNOSTIC
813 if (win < 0 || win > 2)
814 panic("stp4020_chip_io_unmap: window (%d) out of range", win);
815 #endif
816
817 h->winalloc &= ~(1 << win);
818 }
819
820 void
821 stp4020_chip_socket_enable(pch)
822 pcmcia_chipset_handle_t pch;
823 {
824 struct stp4020_socket *h = (struct stp4020_socket *)pch;
825 int i, v, cardtype;
826
827 /* this bit is mostly stolen from pcic_attach_card */
828
829 /* Power down the socket to reset it, clear the card reset pin */
830 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
831 v &= ~STP4020_ICR1_MSTPWR;
832 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
833
834 /*
835 * wait 300ms until power fails (Tpf). Then, wait 100ms since
836 * we are changing Vcc (Toff).
837 */
838 stp4020_delay((300 + 100) * 1000);
839
840 /* Power up the socket */
841 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
842 v |= STP4020_ICR1_MSTPWR;
843 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
844
845 /*
846 * wait 100ms until power raise (Tpr) and 20ms to become
847 * stable (Tsu(Vcc)).
848 */
849 stp4020_delay((100 + 20) * 1000);
850
851 v |= STP4020_ICR1_PCIFOE;
852 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
853
854 /*
855 * hold RESET at least 10us.
856 */
857 delay(10);
858
859 /* Clear reset flag */
860 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
861 v &= ~STP4020_ICR0_RESET;
862 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
863
864 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
865 stp4020_delay(20000);
866
867 /* Wait for the chip to finish initializing (5 seconds max) */
868 for (i = 10000; i > 0; i--) {
869 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
870 if ((v & STP4020_ISR0_RDYST) != 0)
871 break;
872 delay(500);
873 }
874 if (i <= 0) {
875 char bits[64];
876 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
877 STP4020_ISR0_IOBITS, bits, sizeof(bits));
878 printf("stp4020_chip_socket_enable: not ready: status %s\n",
879 bits);
880 return;
881 }
882
883 /* Set the card type */
884 cardtype = pcmcia_card_gettype(h->pcmcia);
885
886 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
887 v &= ~STP4020_ICR0_IFTYPE;
888 v |= (cardtype == PCMCIA_IFTYPE_IO)
889 ? STP4020_ICR0_IFTYPE_IO
890 : STP4020_ICR0_IFTYPE_MEM;
891 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
892
893 DPRINTF(("%s: stp4020_chip_socket_enable %02x cardtype %s\n",
894 h->sc->sc_dev.dv_xname, h->sock,
895 ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem")));
896
897 /*
898 * Enable socket I/O interrupts.
899 * We use level SB_INT[0] for I/O interrupts.
900 */
901 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
902 v &= ~STP4020_ICR0_IOILVL;
903 v |= STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL_SB0;
904 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
905
906 #if 0
907 /* Reinstall all the memory and io mappings */
908 for (win = 0; win < STP4020_NWIN; win++)
909 if (h->winalloc & (1 << win))
910 ___chip_mem_map(h, win);
911
912 #endif
913 }
914
915 void
916 stp4020_chip_socket_disable(pch)
917 pcmcia_chipset_handle_t pch;
918 {
919 struct stp4020_socket *h = (struct stp4020_socket *)pch;
920 int v;
921
922 DPRINTF(("stp4020_chip_socket_disable\n"));
923
924 /*
925 * Disable socket I/O interrupts.
926 */
927 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
928 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL);
929 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
930
931 /* Power down the socket */
932 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
933 v &= ~STP4020_ICR1_MSTPWR;
934 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
935
936 /*
937 * wait 300ms until power fails (Tpf).
938 */
939 stp4020_delay(300 * 1000);
940 }
941
942 void *
943 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
944 pcmcia_chipset_handle_t pch;
945 struct pcmcia_function *pf;
946 int ipl;
947 int (*handler) __P((void *));
948 void *arg;
949 {
950 struct stp4020_socket *h = (struct stp4020_socket *)pch;
951
952 h->intrhandler = handler;
953 h->intrarg = arg;
954 h->ipl = ipl;
955 return (NULL);
956 }
957
958 void
959 stp4020_chip_intr_disestablish(pch, ih)
960 pcmcia_chipset_handle_t pch;
961 void *ih;
962 {
963 struct stp4020_socket *h = (struct stp4020_socket *)pch;
964
965 h->intrhandler = NULL;
966 h->intrarg = NULL;
967 }
968
969 /*
970 * Delay and possibly yield CPU.
971 * XXX - assumes a context
972 */
973 void
974 stp4020_delay(ms)
975 unsigned int ms;
976 {
977 unsigned int ticks;
978 extern int cold;
979
980 /* Convert to ticks */
981 ticks = (ms * hz ) / 1000000;
982
983 if (cold || ticks == 0) {
984 delay(ms);
985 return;
986 }
987
988 #ifdef DIAGNOSTIC
989 if (ticks > 60*hz)
990 panic("stp4020: preposterous delay: %u", ticks);
991 #endif
992 tsleep(&ticks, 0, "stp4020_delay", ticks);
993 }
994
995 #ifdef STP4020_DEBUG
996 void
997 stp4020_dump_regs(h)
998 struct stp4020_socket *h;
999 {
1000 char bits[64];
1001 /*
1002 * Dump control and status registers.
1003 */
1004 printf("socket[%d] registers:\n", h->sock);
1005 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX),
1006 STP4020_ICR0_BITS, bits, sizeof(bits));
1007 printf("\tICR0=%s\n", bits);
1008
1009 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX),
1010 STP4020_ICR1_BITS, bits, sizeof(bits));
1011 printf("\tICR1=%s\n", bits);
1012
1013 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
1014 STP4020_ISR0_IOBITS, bits, sizeof(bits));
1015 printf("\tISR0=%s\n", bits);
1016
1017 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX),
1018 STP4020_ISR1_BITS, bits, sizeof(bits));
1019 printf("\tISR1=%s\n", bits);
1020 }
1021 #endif /* STP4020_DEBUG */
1022