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