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