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