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