stp4020.c revision 1.5.8.1 1 /* $NetBSD: stp4020.c,v 1.5.8.1 1999/12/27 18:35:33 wrstuden 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 < 7) {
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_CTRL 4
297 for (i = 0; i < 8; i++) {
298 int s, w;
299 /*
300 * STP4020 Register address map:
301 * bank 0: Forth PROM
302 * banks 1-3: socket 0, windows 0-2
303 * bank 4: control registers
304 * banks 5-7: socket 1, windows 0-2
305 */
306 if (i == STP4020_BANK_CTRL) {
307 if (sbus_bus_map(sa->sa_bustag,
308 sa->sa_reg[i].sbr_slot,
309 sa->sa_reg[i].sbr_offset,
310 sa->sa_reg[i].sbr_size,
311 BUS_SPACE_MAP_LINEAR, 0,
312 &bh) != 0) {
313 printf("%s: attach: cannot map registers\n",
314 self->dv_xname);
315 return;
316 }
317 /*
318 * Copy tag and handle to both socket structures
319 * for easy access in control/status IO functions.
320 */
321 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
322 }
323
324 if (i < STP4020_BANK_CTRL)
325 s = 0, w = i; /* banks 0-2 */
326 else
327 s = 1, w = i - 4; /* banks 4-6 */
328
329 if (sbus_bus_map(sa->sa_bustag,
330 sa->sa_reg[i].sbr_slot,
331 sa->sa_reg[i].sbr_offset,
332 sa->sa_reg[i].sbr_size,
333 BUS_SPACE_MAP_LINEAR, 0,
334 &sc->sc_socks[s].windows[w].winaddr) != 0) {
335 printf("%s: attach: cannot map registers\n",
336 self->dv_xname);
337 return;
338 }
339 }
340
341 sbus_establish(&sc->sc_sd, &sc->sc_dev);
342
343 #if 0 /*XXX-think about tracking boot devices*/
344 /* Propagate bootpath */
345 if (sa->sa_bp != NULL)
346 bp = sa->sa_bp + 1;
347 else
348 bp = NULL;
349 #endif
350
351 /*
352 * We get to use two SBus interrupt levels.
353 * The higher level we use for status change interrupts;
354 * the lower level for PC card I/O.
355 */
356 if (sa->sa_nintr != 0) {
357 bus_intr_establish(sa->sa_bustag, sa->sa_intr[1].sbi_pri,
358 0, stp4020_statintr, sc);
359
360 bus_intr_establish(sa->sa_bustag, sa->sa_intr[0].sbi_pri,
361 0, stp4020_iointr, sc);
362 }
363
364 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
365 STP4020_ISR1_REV_M;
366 printf(": rev %x\n", rev);
367
368 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
369
370 /*
371 * Arrange that a kernel thread be created to handle
372 * insert/removal events.
373 */
374 SIMPLEQ_INIT(&sc->events);
375 kthread_create(stp4020_create_event_thread, sc);
376
377 for (i = 0; i < STP4020_NSOCK; i++) {
378 struct stp4020_socket *h = &sc->sc_socks[i];
379 h->sock = i;
380 h->sc = sc;
381 #ifdef STP4020_DEBUG
382 stp4020_dump_regs(h);
383 #endif
384 stp4020_attach_socket(h);
385 }
386 }
387
388 void
389 stp4020_attach_socket(h)
390 struct stp4020_socket *h;
391 {
392 struct pcmciabus_attach_args paa;
393 int v;
394
395 /* Initialize the rest of the handle */
396 h->winalloc = 0;
397
398 /* Configure one pcmcia device per socket */
399 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
400 paa.pch = (pcmcia_chipset_handle_t)h;
401 paa.iobase = 0;
402 paa.iosize = 0;
403
404 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
405
406 if (h->pcmcia == NULL)
407 return;
408
409 /*
410 * There's actually a pcmcia bus attached; initialize the slot.
411 */
412
413 /*
414 * Enable socket status change interrupts.
415 * We use SB_INT[1] for status change interrupts.
416 */
417 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
418 v |= STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
419 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
420
421 /* Get live status bits from ISR0 */
422 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
423 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
424 return;
425
426 pcmcia_card_attach(h->pcmcia);
427 h->flags |= STP4020_SOCKET_BUSY;
428 }
429
430
431 /*
432 * Deferred thread creation callback.
433 */
434 void
435 stp4020_create_event_thread(arg)
436 void *arg;
437 {
438 struct stp4020_softc *sc = arg;
439 const char *name = sc->sc_dev.dv_xname;
440
441 if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread,
442 "%s", name)) {
443 panic("%s: unable to create event thread", name);
444 }
445 }
446
447 /*
448 * The actual event handling thread.
449 */
450 void
451 stp4020_event_thread(arg)
452 void *arg;
453 {
454 struct stp4020_softc *sc = arg;
455 struct stp4020_event *e;
456 int s;
457
458 while (1) {
459 struct stp4020_socket *h;
460 int n;
461
462 s = splhigh();
463 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
464 splx(s);
465 (void)tsleep(&sc->events, PWAIT, "pcicev", 0);
466 continue;
467 }
468 SIMPLEQ_REMOVE_HEAD(&sc->events, e, se_q);
469 splx(s);
470
471 n = e->se_sock;
472 if (n < 0 || n >= STP4020_NSOCK)
473 panic("stp4020_event_thread: wayward socket number %d",
474 n);
475
476 h = &sc->sc_socks[n];
477 switch (e->se_type) {
478 case STP4020_EVENT_INSERTION:
479 pcmcia_card_attach(h->pcmcia);
480 break;
481 case STP4020_EVENT_REMOVAL:
482 pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
483 break;
484 default:
485 panic("stp4020_event_thread: unknown event type %d",
486 e->se_type);
487 }
488 free(e, M_TEMP);
489 }
490 }
491
492 void
493 stp4020_queue_event(sc, sock, event)
494 struct stp4020_softc *sc;
495 int sock, event;
496 {
497 struct stp4020_event *e;
498 int s;
499
500 e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
501 if (e == NULL)
502 panic("stp4020_queue_event: can't allocate event");
503
504 e->se_type = event;
505 e->se_sock = sock;
506 s = splhigh();
507 SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
508 splx(s);
509 wakeup(&sc->events);
510 }
511
512 int
513 stp4020_statintr(arg)
514 void *arg;
515 {
516 struct stp4020_softc *sc = arg;
517 int i, r = 0;
518
519 /*
520 * Check each socket for pending requests.
521 */
522 for (i = 0 ; i < STP4020_NSOCK; i++) {
523 struct stp4020_socket *h;
524 int v;
525
526 h = &sc->sc_socks[i];
527
528 /* Read socket's ISR0 for the interrupt status bits */
529 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
530
531 #ifdef STP4020_DEBUG
532 if (stp4020_debug != 0) {
533 char bits[64];
534 bitmask_snprintf(v, STP4020_ISR0_IOBITS,
535 bits, sizeof(bits));
536 printf("stp4020_statintr: ISR0=%s\n", bits);
537 }
538 #endif
539
540 /* Ack all interrupts at once */
541 stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
542 STP4020_ISR0_ALL_STATUS_IRQ);
543
544 if ((v & STP4020_ISR0_CDCHG) != 0) {
545 /*
546 * Card status change detect
547 */
548 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) != 0){
549 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
550 stp4020_queue_event(sc, i,
551 STP4020_EVENT_INSERTION);
552 h->flags |= STP4020_SOCKET_BUSY;
553 }
554 }
555 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
556 if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
557 stp4020_queue_event(sc, i,
558 STP4020_EVENT_REMOVAL);
559 h->flags &= ~STP4020_SOCKET_BUSY;
560 }
561 }
562 }
563
564 /* XXX - a bunch of unhandled conditions */
565 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
566 printf("stp4020[%d]: Battery change 1\n", h->sock);
567 }
568
569 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
570 printf("stp4020[%d]: Battery change 2\n", h->sock);
571 }
572
573 if ((v & STP4020_ISR0_RDYCHG) != 0) {
574 printf("stp4020[%d]: Ready/Busy change\n", h->sock);
575 }
576
577 if ((v & STP4020_ISR0_WPCHG) != 0) {
578 printf("stp4020[%d]: Write protect change\n", h->sock);
579 }
580
581 if ((v & STP4020_ISR0_PCTO) != 0) {
582 printf("stp4020[%d]: Card access timeout\n", h->sock);
583 }
584 }
585
586 return (r);
587 }
588
589 int
590 stp4020_iointr(arg)
591 void *arg;
592 {
593 struct stp4020_softc *sc = arg;
594 int i, r = 0;
595
596 /*
597 * Check each socket for pending requests.
598 */
599 for (i = 0 ; i < STP4020_NSOCK; i++) {
600 struct stp4020_socket *h;
601 int v;
602
603 h = &sc->sc_socks[i];
604 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
605
606 if ((v & STP4020_ISR0_IOINT) != 0) {
607 /* It's a card interrupt */
608 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
609 printf("stp4020[%d]: spurious interrupt?\n",
610 h->sock);
611 continue;
612 }
613 /* Call card handler, if any */
614 if (h->intrhandler != NULL)
615 r |= (*h->intrhandler)(h->intrarg);
616 }
617
618 }
619
620 return (r);
621 }
622
623 int
624 stp4020_chip_mem_alloc(pch, size, pcmhp)
625 pcmcia_chipset_handle_t pch;
626 bus_size_t size;
627 struct pcmcia_mem_handle *pcmhp;
628 {
629 struct stp4020_socket *h = (struct stp4020_socket *)pch;
630 int i, win;
631
632 /*
633 * Allocate a window.
634 */
635 if (size > STP4020_WINDOW_SIZE)
636 return (1);
637
638 for (win = -1, i = 0; i < STP4020_NWIN; i++) {
639 if ((h->winalloc & (1 << i)) == 0) {
640 win = i;
641 h->winalloc |= (1 << i);
642 break;
643 }
644 }
645
646 if (win == -1)
647 return (1);
648
649 pcmhp->memt = 0;
650 pcmhp->memh = h->windows[win].winaddr;
651 pcmhp->addr = 0; /* What is it used for? */
652 pcmhp->size = size;
653 pcmhp->mhandle = win; /* Use our window number as a handle */
654 pcmhp->realsize = STP4020_WINDOW_SIZE;
655
656 return (0);
657 }
658
659 void
660 stp4020_chip_mem_free(pch, pcmhp)
661 pcmcia_chipset_handle_t pch;
662 struct pcmcia_mem_handle *pcmhp;
663 {
664
665 return;
666 }
667
668 int
669 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
670 pcmcia_chipset_handle_t pch;
671 int kind;
672 bus_addr_t card_addr;
673 bus_size_t size;
674 struct pcmcia_mem_handle *pcmhp;
675 bus_addr_t *offsetp;
676 int *windowp;
677 {
678 struct stp4020_socket *h = (struct stp4020_socket *)pch;
679 bus_addr_t offset;
680 int win, v;
681
682 win = pcmhp->mhandle;
683 *windowp = win;
684
685 /*
686 * Compute the address offset to the pcmcia address space
687 * for the window.
688 */
689 offset = card_addr & -STP4020_WINDOW_SIZE;
690 card_addr -= offset;
691 *offsetp = offset;
692
693 /*
694 * Fill in the Address Space Select and Base Address
695 * fields of this windows control register 0.
696 */
697 v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX);
698 v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M);
699 v |= (kind == PCMCIA_MEM_ATTR)
700 ? STP4020_WCR0_ASPSEL_AM
701 : STP4020_WCR0_ASPSEL_CM;
702 v |= (STP4020_ADDR2PAGE(card_addr) & STP4020_WCR0_BASE_M);
703 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
704
705 return (0);
706 }
707
708 void
709 stp4020_chip_mem_unmap(pch, win)
710 pcmcia_chipset_handle_t pch;
711 int win;
712 {
713 struct stp4020_socket *h = (struct stp4020_socket *)pch;
714
715 #ifdef DIAGNOSTIC
716 if (win < 0 || win > 2)
717 panic("stp4020_chip_mem_unmap: window (%d) out of range", win);
718 #endif
719 h->winalloc &= ~(1 << win);
720 /*
721 * If possible, invalidate hardware mapping here; but
722 * I don't think the stp4020 has provided for that.
723 */
724 }
725
726 int
727 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
728 pcmcia_chipset_handle_t pch;
729 bus_addr_t start;
730 bus_size_t size;
731 bus_size_t align;
732 struct pcmcia_io_handle *pcihp;
733 {
734 struct stp4020_socket *h = (struct stp4020_socket *)pch;
735
736 if (start) {
737 /* How on earth can `start' be interpreted??
738 WHERE DOES THE CARD DRIVER GET IT FROM?
739 */
740 }
741
742 pcihp->iot = h->tag;
743 pcihp->ioh = 0;
744 pcihp->addr = 0;
745 pcihp->size = size;
746 pcihp->flags = 0;
747
748 return (0);
749 }
750
751 void
752 stp4020_chip_io_free(pch, pcihp)
753 pcmcia_chipset_handle_t pch;
754 struct pcmcia_io_handle *pcihp;
755 {
756
757 return;
758 }
759
760 int
761 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
762 pcmcia_chipset_handle_t pch;
763 int width;
764 bus_addr_t offset;
765 bus_size_t size;
766 struct pcmcia_io_handle *pcihp;
767 int *windowp;
768 {
769 struct stp4020_socket *h = (struct stp4020_socket *)pch;
770 int i, win, v;
771
772 /*
773 * Allocate a window.
774 */
775 if (size > STP4020_WINDOW_SIZE)
776 return (1);
777
778 for (win = -1, i = 0; i < STP4020_NWIN; i++) {
779 if ((h->winalloc & (1 << i)) == 0) {
780 win = i;
781 h->winalloc |= (1 << i);
782 break;
783 }
784 }
785
786 if (win == -1)
787 return (1);
788
789 *windowp = win;
790
791 /*
792 * Fill in the Address Space Select and Base Address
793 * fields of this windows control register 0.
794 */
795 v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX);
796 v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M);
797 v |= STP4020_WCR0_ASPSEL_IO;
798 v |= (STP4020_ADDR2PAGE(pcihp->addr+offset) & STP4020_WCR0_BASE_M);
799 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
800
801 return (0);
802 }
803
804 void
805 stp4020_chip_io_unmap(pch, win)
806 pcmcia_chipset_handle_t pch;
807 int win;
808 {
809 struct stp4020_socket *h = (struct stp4020_socket *)pch;
810
811 #ifdef DIAGNOSTIC
812 if (win < 0 || win > 2)
813 panic("stp4020_chip_io_unmap: window (%d) out of range", win);
814 #endif
815
816 h->winalloc &= ~(1 << win);
817 }
818
819 void
820 stp4020_chip_socket_enable(pch)
821 pcmcia_chipset_handle_t pch;
822 {
823 struct stp4020_socket *h = (struct stp4020_socket *)pch;
824 int i, v, cardtype;
825
826 /* this bit is mostly stolen from pcic_attach_card */
827
828 /* Power down the socket to reset it, clear the card reset pin */
829 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
830 v &= ~STP4020_ICR1_MSTPWR;
831 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
832
833 /*
834 * wait 300ms until power fails (Tpf). Then, wait 100ms since
835 * we are changing Vcc (Toff).
836 */
837 stp4020_delay((300 + 100) * 1000);
838
839 /* Power up the socket */
840 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
841 v |= STP4020_ICR1_MSTPWR;
842 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
843
844 /*
845 * wait 100ms until power raise (Tpr) and 20ms to become
846 * stable (Tsu(Vcc)).
847 */
848 stp4020_delay((100 + 20) * 1000);
849
850 v |= STP4020_ICR1_PCIFOE;
851 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
852
853 /*
854 * hold RESET at least 10us.
855 */
856 delay(10);
857
858 /* Clear reset flag */
859 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
860 v &= ~STP4020_ICR0_RESET;
861 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
862
863 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
864 stp4020_delay(20000);
865
866 /* Wait for the chip to finish initializing (5 seconds max) */
867 for (i = 10000; i > 0; i--) {
868 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
869 if ((v & STP4020_ISR0_RDYST) != 0)
870 break;
871 delay(500);
872 }
873 if (i <= 0) {
874 char bits[64];
875 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
876 STP4020_ISR0_IOBITS, bits, sizeof(bits));
877 printf("stp4020_chip_socket_enable: not ready: status %s\n",
878 bits);
879 return;
880 }
881
882 /* Set the card type */
883 cardtype = pcmcia_card_gettype(h->pcmcia);
884
885 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
886 v &= ~STP4020_ICR0_IFTYPE;
887 v |= (cardtype == PCMCIA_IFTYPE_IO)
888 ? STP4020_ICR0_IFTYPE_IO
889 : STP4020_ICR0_IFTYPE_MEM;
890 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
891
892 DPRINTF(("%s: stp4020_chip_socket_enable %02x cardtype %s\n",
893 h->sc->sc_dev.dv_xname, h->sock,
894 ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem")));
895
896 /*
897 * Enable socket I/O interrupts.
898 * We use level SB_INT[0] for I/O interrupts.
899 */
900 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
901 v &= ~STP4020_ICR0_IOILVL;
902 v |= STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL_SB0;
903 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
904
905 #if 0
906 /* Reinstall all the memory and io mappings */
907 for (win = 0; win < STP4020_NWIN; win++)
908 if (h->winalloc & (1 << win))
909 ___chip_mem_map(h, win);
910
911 #endif
912 }
913
914 void
915 stp4020_chip_socket_disable(pch)
916 pcmcia_chipset_handle_t pch;
917 {
918 struct stp4020_socket *h = (struct stp4020_socket *)pch;
919 int v;
920
921 DPRINTF(("stp4020_chip_socket_disable\n"));
922
923 /*
924 * Disable socket I/O interrupts.
925 */
926 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
927 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL);
928 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
929
930 /* Power down the socket */
931 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
932 v &= ~STP4020_ICR1_MSTPWR;
933 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
934
935 /*
936 * wait 300ms until power fails (Tpf).
937 */
938 stp4020_delay(300 * 1000);
939 }
940
941 void *
942 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
943 pcmcia_chipset_handle_t pch;
944 struct pcmcia_function *pf;
945 int ipl;
946 int (*handler) __P((void *));
947 void *arg;
948 {
949 struct stp4020_socket *h = (struct stp4020_socket *)pch;
950
951 h->intrhandler = handler;
952 h->intrarg = arg;
953 h->ipl = ipl;
954 return (NULL);
955 }
956
957 void
958 stp4020_chip_intr_disestablish(pch, ih)
959 pcmcia_chipset_handle_t pch;
960 void *ih;
961 {
962 struct stp4020_socket *h = (struct stp4020_socket *)pch;
963
964 h->intrhandler = NULL;
965 h->intrarg = NULL;
966 }
967
968 /*
969 * Delay and possibly yield CPU.
970 * XXX - assumes a context
971 */
972 void
973 stp4020_delay(ms)
974 unsigned int ms;
975 {
976 unsigned int ticks;
977 extern int cold;
978
979 /* Convert to ticks */
980 ticks = (ms * hz ) / 1000000;
981
982 if (cold || ticks == 0) {
983 delay(ms);
984 return;
985 }
986
987 #ifdef DIAGNOSTIC
988 if (ticks > 60*hz)
989 panic("stp4020: preposterous delay: %u", ticks);
990 #endif
991 tsleep(&ticks, 0, "stp4020_delay", ticks);
992 }
993
994 #ifdef STP4020_DEBUG
995 void
996 stp4020_dump_regs(h)
997 struct stp4020_socket *h;
998 {
999 char bits[64];
1000 /*
1001 * Dump control and status registers.
1002 */
1003 printf("socket[%d] registers:\n", h->sock);
1004 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX),
1005 STP4020_ICR0_BITS, bits, sizeof(bits));
1006 printf("\tICR0=%s\n", bits);
1007
1008 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX),
1009 STP4020_ICR1_BITS, bits, sizeof(bits));
1010 printf("\tICR1=%s\n", bits);
1011
1012 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
1013 STP4020_ISR0_IOBITS, bits, sizeof(bits));
1014 printf("\tISR0=%s\n", bits);
1015
1016 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX),
1017 STP4020_ISR1_BITS, bits, sizeof(bits));
1018 printf("\tISR1=%s\n", bits);
1019 }
1020 #endif /* STP4020_DEBUG */
1021