stp4020.c revision 1.32 1 /* $NetBSD: stp4020.c,v 1.32 2003/01/03 11:57:49 mrg 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.32 2003/01/03 11:57:49 mrg 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/extent.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 /*
69 * We use the three available windows per socket in a simple, fixed
70 * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
71 * spaces into sbus space.
72 */
73 #define STP_WIN_ATTR 0 /* index of the attribute memory space window */
74 #define STP_WIN_MEM 1 /* index of the common memory space window */
75 #define STP_WIN_IO 2 /* index of the io space window */
76
77
78 #if defined(STP4020_DEBUG)
79 int stp4020_debug = 0;
80 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0)
81 #else
82 #define DPRINTF(x)
83 #endif
84
85 /*
86 * Event queue; events detected in an interrupt context go here
87 * awaiting attention from our event handling thread.
88 */
89 struct stp4020_event {
90 SIMPLEQ_ENTRY(stp4020_event) se_q;
91 int se_type;
92 int se_sock;
93 };
94 /* Defined event types */
95 #define STP4020_EVENT_INSERTION 0
96 #define STP4020_EVENT_REMOVAL 1
97
98 /*
99 * Per socket data.
100 */
101 struct stp4020_socket {
102 struct stp4020_softc *sc; /* Back link */
103 int flags;
104 #define STP4020_SOCKET_BUSY 0x0001
105 #define STP4020_SOCKET_SHUTDOWN 0x0002
106 int sock; /* Socket number (0 or 1) */
107 int sbus_intno; /* Do we use first (0) or second (1)
108 interrupt? */
109 int int_enable; /* ICR0 value for interrupt enabled */
110 int int_disable; /* ICR0 value for interrupt disabled */
111 bus_space_tag_t tag; /* socket control space */
112 bus_space_handle_t regs; /* */
113 struct device *pcmcia; /* Associated PCMCIA device */
114 int (*intrhandler) /* Card driver interrupt handler */
115 __P((void *));
116 void *intrarg; /* Card interrupt handler argument */
117 void *softint; /* cookie for the softintr */
118
119 struct {
120 bus_space_handle_t winaddr;/* this window's address */
121 } windows[STP4020_NWIN];
122
123 };
124
125 struct stp4020_softc {
126 struct device sc_dev; /* Base device */
127 struct sbusdev sc_sd; /* SBus device */
128 bus_space_tag_t sc_bustag;
129 bus_dma_tag_t sc_dmatag;
130 pcmcia_chipset_tag_t sc_pct; /* Chipset methods */
131
132 struct proc *event_thread; /* event handling thread */
133 SIMPLEQ_HEAD(, stp4020_event) events; /* Pending events for thread */
134
135 struct stp4020_socket sc_socks[STP4020_NSOCK];
136 };
137
138
139 static int stp4020print __P((void *, const char *));
140 static int stp4020match __P((struct device *, struct cfdata *, void *));
141 static void stp4020attach __P((struct device *, struct device *, void *));
142 static int stp4020_intr __P((void *));
143 static void stp4020_map_window(struct stp4020_socket *h, int win, int speed);
144 static void stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay);
145 static void stp4020_intr_dispatch(void *arg);
146
147 CFATTACH_DECL(nell, sizeof(struct stp4020_softc),
148 stp4020match, stp4020attach, NULL, NULL);
149
150 #ifdef STP4020_DEBUG
151 static void stp4020_dump_regs __P((struct stp4020_socket *));
152 #endif
153
154 static int stp4020_rd_sockctl __P((struct stp4020_socket *, int));
155 static void stp4020_wr_sockctl __P((struct stp4020_socket *, int, int));
156 static int stp4020_rd_winctl __P((struct stp4020_socket *, int, int));
157 static void stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int));
158
159 void stp4020_delay __P((unsigned int));
160 void stp4020_attach_socket __P((struct stp4020_socket *, int));
161 void stp4020_create_event_thread __P((void *));
162 void stp4020_event_thread __P((void *));
163 void stp4020_queue_event __P((struct stp4020_softc *, int, int));
164
165 int stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
166 struct pcmcia_mem_handle *));
167 void stp4020_chip_mem_free __P((pcmcia_chipset_handle_t,
168 struct pcmcia_mem_handle *));
169 int stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
170 bus_size_t, struct pcmcia_mem_handle *,
171 bus_size_t *, int *));
172 void stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int));
173
174 int stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t,
175 bus_addr_t, bus_size_t, bus_size_t,
176 struct pcmcia_io_handle *));
177 void stp4020_chip_io_free __P((pcmcia_chipset_handle_t,
178 struct pcmcia_io_handle *));
179 int stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
180 bus_size_t, struct pcmcia_io_handle *, int *));
181 void stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
182
183 void stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t));
184 void stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t));
185 void *stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t,
186 struct pcmcia_function *, int,
187 int (*) __P((void *)), void *));
188 void stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
189
190 /* Our PCMCIA chipset methods */
191 static struct pcmcia_chip_functions stp4020_functions = {
192 stp4020_chip_mem_alloc,
193 stp4020_chip_mem_free,
194 stp4020_chip_mem_map,
195 stp4020_chip_mem_unmap,
196
197 stp4020_chip_io_alloc,
198 stp4020_chip_io_free,
199 stp4020_chip_io_map,
200 stp4020_chip_io_unmap,
201
202 stp4020_chip_intr_establish,
203 stp4020_chip_intr_disestablish,
204
205 stp4020_chip_socket_enable,
206 stp4020_chip_socket_disable
207 };
208
209
210 static __inline__ int
211 stp4020_rd_sockctl(h, idx)
212 struct stp4020_socket *h;
213 int idx;
214 {
215 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
216 return (bus_space_read_2(h->tag, h->regs, o));
217 }
218
219 static __inline__ void
220 stp4020_wr_sockctl(h, idx, v)
221 struct stp4020_socket *h;
222 int idx;
223 int v;
224 {
225 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
226 bus_space_write_2(h->tag, h->regs, o, v);
227 }
228
229 static __inline__ int
230 stp4020_rd_winctl(h, win, idx)
231 struct stp4020_socket *h;
232 int win;
233 int idx;
234 {
235 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
236 (STP4020_WINREGS_SIZE * win) + idx;
237 return (bus_space_read_2(h->tag, h->regs, o));
238 }
239
240 static __inline__ void
241 stp4020_wr_winctl(h, win, idx, v)
242 struct stp4020_socket *h;
243 int win;
244 int idx;
245 int v;
246 {
247 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
248 (STP4020_WINREGS_SIZE * win) + idx;
249
250 bus_space_write_2(h->tag, h->regs, o, v);
251 }
252
253 #if __FULL_SPARC_BUS_SPACE
254 #ifdef sparc64
255 #error "sparc64 does not want (need) __FULL_SPARC_BUS_SPACE"
256 #endif
257 static u_int16_t stp4020_read_2(bus_space_tag_t,
258 bus_space_handle_t,
259 bus_size_t);
260 static u_int32_t stp4020_read_4(bus_space_tag_t,
261 bus_space_handle_t,
262 bus_size_t);
263 static u_int64_t stp4020_read_8(bus_space_tag_t,
264 bus_space_handle_t,
265 bus_size_t);
266 static void stp4020_write_2(bus_space_tag_t,
267 bus_space_handle_t,
268 bus_size_t,
269 u_int16_t);
270 static void stp4020_write_4(bus_space_tag_t,
271 bus_space_handle_t,
272 bus_size_t,
273 u_int32_t);
274 static void stp4020_write_8(bus_space_tag_t,
275 bus_space_handle_t,
276 bus_size_t,
277 u_int64_t);
278
279 static u_int16_t
280 stp4020_read_2(space, handle, offset)
281 bus_space_tag_t space;
282 bus_space_handle_t handle;
283 bus_size_t offset;
284 {
285 return (le16toh(*(volatile u_int16_t *)(handle + offset)));
286 }
287
288 static u_int32_t
289 stp4020_read_4(space, handle, offset)
290 bus_space_tag_t space;
291 bus_space_handle_t handle;
292 bus_size_t offset;
293 {
294 return (le32toh(*(volatile u_int32_t *)(handle + offset)));
295 }
296
297 static u_int64_t
298 stp4020_read_8(space, handle, offset)
299 bus_space_tag_t space;
300 bus_space_handle_t handle;
301 bus_size_t offset;
302 {
303 return (le64toh(*(volatile u_int64_t *)(handle + offset)));
304 }
305
306 static void
307 stp4020_write_2(space, handle, offset, value)
308 bus_space_tag_t space;
309 bus_space_handle_t handle;
310 bus_size_t offset;
311 u_int16_t value;
312 {
313 (*(volatile u_int16_t *)(handle + offset)) = htole16(value);
314 }
315
316 static void
317 stp4020_write_4(space, handle, offset, value)
318 bus_space_tag_t space;
319 bus_space_handle_t handle;
320 bus_size_t offset;
321 u_int32_t value;
322 {
323 (*(volatile u_int32_t *)(handle + offset)) = htole32(value);
324 }
325
326 static void
327 stp4020_write_8(space, handle, offset, value)
328 bus_space_tag_t space;
329 bus_space_handle_t handle;
330 bus_size_t offset;
331 u_int64_t value;
332 {
333 (*(volatile u_int64_t *)(handle + offset)) = htole64(value);
334 }
335 #else
336 #if 0 /* XXX */
337 #error "stp4020 needs __FULL_SPARC_BUS_SPACE defined as well"
338 #endif
339 #endif
340
341 int
342 stp4020print(aux, busname)
343 void *aux;
344 const char *busname;
345 {
346 struct pcmciabus_attach_args *paa = aux;
347 struct stp4020_socket *h = paa->pch;
348
349 aprint_normal(" socket %d", h->sock);
350 return (UNCONF);
351 }
352
353 int
354 stp4020match(parent, cf, aux)
355 struct device *parent;
356 struct cfdata *cf;
357 void *aux;
358 {
359 struct sbus_attach_args *sa = aux;
360
361 return (strcmp("SUNW,pcmcia", sa->sa_name) == 0);
362 }
363
364 /*
365 * Attach all the sub-devices we can find
366 */
367 void
368 stp4020attach(parent, self, aux)
369 struct device *parent, *self;
370 void *aux;
371 {
372 struct sbus_attach_args *sa = aux;
373 struct stp4020_softc *sc = (void *)self;
374 bus_space_tag_t tag;
375 int rev;
376 int i, sbus_intno;
377 bus_space_handle_t bh;
378
379 /* lsb of our config flags decides which interrupt we use */
380 sbus_intno = sc->sc_dev.dv_cfdata->cf_flags & 1;
381
382 /* Transfer bus tags */
383 #if __FULL_SPARC_BUS_SPACE
384 tag = (bus_space_tag_t)
385 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT);
386 *tag = *sa->sa_bustag;
387 tag->sparc_read_2 = stp4020_read_2;
388 tag->sparc_read_4 = stp4020_read_4;
389 tag->sparc_read_8 = stp4020_read_8;
390 tag->sparc_write_2 = stp4020_write_2;
391 tag->sparc_write_4 = stp4020_write_4;
392 tag->sparc_write_8 = stp4020_write_8;
393 #else
394 tag = sa->sa_bustag;
395 #endif
396 sc->sc_bustag = tag;
397 sc->sc_dmatag = sa->sa_dmatag;
398
399 /* Set up per-socket static initialization */
400 sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
401 sc->sc_socks[0].tag = sc->sc_socks[1].tag = tag;
402 sc->sc_socks[0].sbus_intno =
403 sc->sc_socks[1].sbus_intno = sbus_intno;
404
405 if (sa->sa_nreg < 8) {
406 printf("%s: only %d register sets\n",
407 self->dv_xname, sa->sa_nreg);
408 return;
409 }
410
411 if (sa->sa_nintr != 2) {
412 printf("%s: expect 2 interrupt Sbus levels; got %d\n",
413 self->dv_xname, sa->sa_nintr);
414 return;
415 }
416
417 #define STP4020_BANK_PROM 0
418 #define STP4020_BANK_CTRL 4
419 for (i = 0; i < 8; i++) {
420
421 /*
422 * STP4020 Register address map:
423 * bank 0: Forth PROM
424 * banks 1-3: socket 0, windows 0-2
425 * bank 4: control registers
426 * banks 5-7: socket 1, windows 0-2
427 */
428
429 if (i == STP4020_BANK_PROM)
430 /* Skip the PROM */
431 continue;
432
433 if (sbus_bus_map(sa->sa_bustag,
434 sa->sa_reg[i].oa_space,
435 sa->sa_reg[i].oa_base,
436 sa->sa_reg[i].oa_size,
437 0, &bh) != 0) {
438 printf("%s: attach: cannot map registers\n",
439 self->dv_xname);
440 return;
441 }
442
443 if (i == STP4020_BANK_CTRL) {
444 /*
445 * Copy tag and handle to both socket structures
446 * for easy access in control/status IO functions.
447 */
448 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
449 } else if (i < STP4020_BANK_CTRL) {
450 /* banks 1-3 */
451 sc->sc_socks[0].windows[i-1].winaddr = bh;
452 } else {
453 /* banks 5-7 */
454 sc->sc_socks[1].windows[i-5].winaddr = bh;
455 }
456 }
457
458 sbus_establish(&sc->sc_sd, &sc->sc_dev);
459
460 /* We only use one interrupt level. */
461 if (sa->sa_nintr > sbus_intno) {
462 bus_intr_establish(sa->sa_bustag,
463 sa->sa_intr[sbus_intno].oi_pri,
464 IPL_NONE, stp4020_intr, sc);
465 }
466
467 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
468 STP4020_ISR1_REV_M;
469 printf(": rev %x\n", rev);
470
471 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
472
473 /*
474 * Arrange that a kernel thread be created to handle
475 * insert/removal events.
476 */
477 SIMPLEQ_INIT(&sc->events);
478 kthread_create(stp4020_create_event_thread, sc);
479
480 for (i = 0; i < STP4020_NSOCK; i++) {
481 struct stp4020_socket *h = &sc->sc_socks[i];
482 h->sock = i;
483 h->sc = sc;
484 #ifdef STP4020_DEBUG
485 if (stp4020_debug)
486 stp4020_dump_regs(h);
487 #endif
488 stp4020_attach_socket(h, sa->sa_frequency);
489 }
490 }
491
492 void
493 stp4020_attach_socket(h, speed)
494 struct stp4020_socket *h;
495 int speed;
496 {
497 struct pcmciabus_attach_args paa;
498 int v;
499
500 /* no interrupt handlers yet */
501 h->intrhandler = NULL;
502 h->intrarg = NULL;
503 h->softint = NULL;
504 h->int_enable = 0;
505 h->int_disable = 0;
506
507 /* Map all three windows */
508 stp4020_map_window(h, STP_WIN_ATTR, speed);
509 stp4020_map_window(h, STP_WIN_MEM, speed);
510 stp4020_map_window(h, STP_WIN_IO, speed);
511
512 /* Configure one pcmcia device per socket */
513 paa.paa_busname = "pcmcia";
514 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
515 paa.pch = (pcmcia_chipset_handle_t)h;
516 paa.iobase = 0;
517 paa.iosize = STP4020_WINDOW_SIZE;
518
519 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
520
521 if (h->pcmcia == NULL)
522 return;
523
524 /*
525 * There's actually a pcmcia bus attached; initialize the slot.
526 */
527
528 /*
529 * Clear things up before we enable status change interrupts.
530 * This seems to not be fully initialized by the PROM.
531 */
532 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
533 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
534 stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
535 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
536
537 /*
538 * Enable socket status change interrupts.
539 * We only use one common interrupt for status change
540 * and IO, to avoid locking issues.
541 */
542 v = STP4020_ICR0_ALL_STATUS_IE
543 | (h->sbus_intno ? STP4020_ICR0_SCILVL_SB1
544 : STP4020_ICR0_SCILVL_SB0);
545 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
546
547 /* Get live status bits from ISR0 */
548 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
549 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
550 return;
551
552 pcmcia_card_attach(h->pcmcia);
553 h->flags |= STP4020_SOCKET_BUSY;
554 }
555
556
557 /*
558 * Deferred thread creation callback.
559 */
560 void
561 stp4020_create_event_thread(arg)
562 void *arg;
563 {
564 struct stp4020_softc *sc = arg;
565 const char *name = sc->sc_dev.dv_xname;
566
567 if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread,
568 "%s", name)) {
569 panic("%s: unable to create event thread", name);
570 }
571 }
572
573 /*
574 * The actual event handling thread.
575 */
576 void
577 stp4020_event_thread(arg)
578 void *arg;
579 {
580 struct stp4020_softc *sc = arg;
581 struct stp4020_event *e;
582 int s;
583
584 while (1) {
585 struct stp4020_socket *h;
586 int n;
587
588 s = splhigh();
589 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
590 splx(s);
591 (void)tsleep(&sc->events, PWAIT, "pcicev", 0);
592 continue;
593 }
594 SIMPLEQ_REMOVE_HEAD(&sc->events, se_q);
595 splx(s);
596
597 n = e->se_sock;
598 if (n < 0 || n >= STP4020_NSOCK)
599 panic("stp4020_event_thread: wayward socket number %d",
600 n);
601
602 h = &sc->sc_socks[n];
603 switch (e->se_type) {
604 case STP4020_EVENT_INSERTION:
605 pcmcia_card_attach(h->pcmcia);
606 break;
607 case STP4020_EVENT_REMOVAL:
608 pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
609 break;
610 default:
611 panic("stp4020_event_thread: unknown event type %d",
612 e->se_type);
613 }
614 free(e, M_TEMP);
615 }
616 }
617
618 void
619 stp4020_queue_event(sc, sock, event)
620 struct stp4020_softc *sc;
621 int sock, event;
622 {
623 struct stp4020_event *e;
624 int s;
625
626 e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
627 if (e == NULL)
628 panic("stp4020_queue_event: can't allocate event");
629
630 e->se_type = event;
631 e->se_sock = sock;
632 s = splhigh();
633 SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
634 splx(s);
635 wakeup(&sc->events);
636 }
637
638 /*
639 * Softinterrupt called to invoke the real driver interrupt handler.
640 */
641 static void
642 stp4020_intr_dispatch(arg)
643 void *arg;
644 {
645 struct stp4020_socket *h = arg;
646 int s;
647
648 /* invoke driver handler */
649 h->intrhandler(h->intrarg);
650
651 /* enable SBUS interrupts for pcmcia interrupts again */
652 s = splhigh();
653 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
654 splx(s);
655 }
656
657 int
658 stp4020_intr(arg)
659 void *arg;
660 {
661 struct stp4020_softc *sc = arg;
662 int i, s, r = 0, cd_change = 0;
663
664
665 /* protect hardware access by splhigh against softint */
666 s = splhigh();
667
668 /*
669 * Check each socket for pending requests.
670 */
671 for (i = 0 ; i < STP4020_NSOCK; i++) {
672 struct stp4020_socket *h;
673 int v;
674
675 h = &sc->sc_socks[i];
676
677 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
678
679 /* Ack all interrupts at once. */
680 stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
681 STP4020_ISR0_ALL_STATUS_IRQ);
682
683 #ifdef STP4020_DEBUG
684 if (stp4020_debug != 0) {
685 char bits[64];
686 bitmask_snprintf(v, STP4020_ISR0_IOBITS,
687 bits, sizeof(bits));
688 printf("stp4020_statintr: ISR0=%s\n", bits);
689 }
690 #endif
691
692 if ((v & STP4020_ISR0_CDCHG) != 0) {
693 /*
694 * Card status change detect
695 */
696 cd_change = 1;
697 r = 1;
698 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)){
699 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
700 stp4020_queue_event(sc, i,
701 STP4020_EVENT_INSERTION);
702 h->flags |= STP4020_SOCKET_BUSY;
703 }
704 }
705 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
706 if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
707 stp4020_queue_event(sc, i,
708 STP4020_EVENT_REMOVAL);
709 h->flags &= ~STP4020_SOCKET_BUSY;
710 }
711 }
712 }
713
714 if ((v & STP4020_ISR0_IOINT) != 0) {
715 /* we can not deny this is ours, no matter what the
716 card driver says. */
717 r = 1;
718
719 /* It's a card interrupt */
720 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
721 printf("stp4020[%d]: spurious interrupt?\n",
722 h->sock);
723 continue;
724 }
725
726 /*
727 * Schedule softint to invoke driver interrupt
728 * handler
729 */
730 if (h->softint != NULL)
731 softintr_schedule(h->softint);
732 /*
733 * Disable this sbus interrupt, until the soft-int
734 * handler had a chance to run
735 */
736 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_disable);
737 }
738
739 /* informational messages */
740 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
741 /* ignore if this is caused by insert or removal */
742 if (!cd_change)
743 printf("stp4020[%d]: Battery change 1\n", h->sock);
744 r = 1;
745 }
746
747 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
748 /* ignore if this is caused by insert or removal */
749 if (!cd_change)
750 printf("stp4020[%d]: Battery change 2\n", h->sock);
751 r = 1;
752 }
753
754 if ((v & STP4020_ISR0_RDYCHG) != 0) {
755 DPRINTF(("stp4020[%d]: Ready/Busy change\n", h->sock));
756 r = 1;
757 }
758
759 if ((v & STP4020_ISR0_WPCHG) != 0) {
760 DPRINTF(("stp4020[%d]: Write protect change\n", h->sock));
761 r = 1;
762 }
763
764 if ((v & STP4020_ISR0_PCTO) != 0) {
765 DPRINTF(("stp4020[%d]: Card access timeout\n", h->sock));
766 r = 1;
767 }
768
769 }
770 splx(s);
771
772 return (r);
773 }
774
775 /*
776 * The function gets the sbus speed and a access time and calculates
777 * values for the CMDLNG and CMDDLAY registers.
778 */
779 static void
780 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
781 {
782 int result;
783
784 if (ns < STP4020_MEM_SPEED_MIN)
785 ns = STP4020_MEM_SPEED_MIN;
786 else if (ns > STP4020_MEM_SPEED_MAX)
787 ns = STP4020_MEM_SPEED_MAX;
788 result = ns*(bus_speed/1000);
789 if (result % 1000000)
790 result = result/1000000 + 1;
791 else
792 result /= 1000000;
793 *length = result;
794
795 /* the sbus frequency range is limited, so we can keep this simple */
796 *delay = ns <= STP4020_MEM_SPEED_MIN? 1 : 2;
797 }
798
799 static void
800 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
801 {
802 int v, length, delay;
803
804 /*
805 * According to the PC Card standard 300ns access timing should be
806 * used for attribute memory access. Our pcmcia framework does not
807 * seem to propagate timing information, so we use that
808 * everywhere.
809 */
810 stp4020_calc_speed(speed, (win==STP_WIN_ATTR)? 300 : 100, &length, &delay);
811
812 /*
813 * Fill in the Address Space Select and Base Address
814 * fields of this windows control register 0.
815 */
816 v = ((delay << STP4020_WCR0_CMDDLY_S)&STP4020_WCR0_CMDDLY_M)
817 | ((length << STP4020_WCR0_CMDLNG_S)&STP4020_WCR0_CMDLNG_M);
818 switch (win) {
819 case STP_WIN_ATTR:
820 v |= STP4020_WCR0_ASPSEL_AM;
821 break;
822 case STP_WIN_MEM:
823 v |= STP4020_WCR0_ASPSEL_CM;
824 break;
825 case STP_WIN_IO:
826 v |= STP4020_WCR0_ASPSEL_IO;
827 break;
828 }
829 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
830 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
831 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 1<<STP4020_WCR1_WAITREQ_S);
832 }
833
834 int
835 stp4020_chip_mem_alloc(pch, size, pcmhp)
836 pcmcia_chipset_handle_t pch;
837 bus_size_t size;
838 struct pcmcia_mem_handle *pcmhp;
839 {
840 struct stp4020_socket *h = (struct stp4020_socket *)pch;
841
842 /* we can not do much here, defere work to _mem_map */
843 pcmhp->memt = h->tag;
844 pcmhp->size = size;
845 pcmhp->addr = 0;
846 pcmhp->mhandle = 0;
847 pcmhp->realsize = size;
848
849 return (0);
850 }
851
852 void
853 stp4020_chip_mem_free(pch, pcmhp)
854 pcmcia_chipset_handle_t pch;
855 struct pcmcia_mem_handle *pcmhp;
856 {
857 }
858
859 int
860 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
861 pcmcia_chipset_handle_t pch;
862 int kind;
863 bus_addr_t card_addr;
864 bus_size_t size;
865 struct pcmcia_mem_handle *pcmhp;
866 bus_size_t *offsetp;
867 int *windowp;
868 {
869 struct stp4020_socket *h = (struct stp4020_socket *)pch;
870 int win = (kind&PCMCIA_MEM_ATTR)? STP_WIN_ATTR : STP_WIN_MEM;
871
872 pcmhp->memt = h->tag;
873 bus_space_subregion(h->tag, h->windows[win].winaddr, card_addr, size, &pcmhp->memh);
874 pcmhp->size = size;
875 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
876 *offsetp = 0;
877 *windowp = 0;
878
879 return (0);
880 }
881
882 void
883 stp4020_chip_mem_unmap(pch, win)
884 pcmcia_chipset_handle_t pch;
885 int win;
886 {
887 }
888
889 int
890 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
891 pcmcia_chipset_handle_t pch;
892 bus_addr_t start;
893 bus_size_t size;
894 bus_size_t align;
895 struct pcmcia_io_handle *pcihp;
896 {
897 struct stp4020_socket *h = (struct stp4020_socket *)pch;
898
899 pcihp->iot = h->tag;
900 pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
901 return 0;
902 }
903
904 void
905 stp4020_chip_io_free(pch, pcihp)
906 pcmcia_chipset_handle_t pch;
907 struct pcmcia_io_handle *pcihp;
908 {
909 }
910
911 int
912 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
913 pcmcia_chipset_handle_t pch;
914 int width;
915 bus_addr_t offset;
916 bus_size_t size;
917 struct pcmcia_io_handle *pcihp;
918 int *windowp;
919 {
920 struct stp4020_socket *h = (struct stp4020_socket *)pch;
921
922 pcihp->iot = h->tag;
923 bus_space_subregion(h->tag, h->windows[STP_WIN_IO].winaddr, offset, size, &pcihp->ioh);
924 *windowp = 0;
925 return 0;
926 }
927
928 void
929 stp4020_chip_io_unmap(pch, win)
930 pcmcia_chipset_handle_t pch;
931 int win;
932 {
933 }
934
935 void
936 stp4020_chip_socket_enable(pch)
937 pcmcia_chipset_handle_t pch;
938 {
939 struct stp4020_socket *h = (struct stp4020_socket *)pch;
940 int i, v;
941
942 /* this bit is mostly stolen from pcic_attach_card */
943
944 /* Power down the socket to reset it, clear the card reset pin */
945 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
946
947 /*
948 * wait 300ms until power fails (Tpf). Then, wait 100ms since
949 * we are changing Vcc (Toff).
950 */
951 stp4020_delay((300 + 100) * 1000);
952
953 /* Power up the socket */
954 v = STP4020_ICR1_MSTPWR;
955 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
956
957 /*
958 * wait 100ms until power raise (Tpr) and 20ms to become
959 * stable (Tsu(Vcc)).
960 */
961 stp4020_delay((100 + 20) * 1000);
962
963 v |= STP4020_ICR1_PCIFOE|STP4020_ICR1_VPP1_VCC;
964 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
965
966 /*
967 * hold RESET at least 10us.
968 */
969 delay(10);
970
971 /* Clear reset flag */
972 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
973 v &= ~STP4020_ICR0_RESET;
974 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
975
976 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
977 stp4020_delay(20000);
978
979 /* Wait for the chip to finish initializing (5 seconds max) */
980 for (i = 10000; i > 0; i--) {
981 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
982 if ((v & STP4020_ISR0_RDYST) != 0)
983 break;
984 delay(500);
985 }
986 if (i <= 0) {
987 char bits[64];
988 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
989 STP4020_ISR0_IOBITS, bits, sizeof(bits));
990 printf("stp4020_chip_socket_enable: not ready: status %s\n",
991 bits);
992 return;
993 }
994
995 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
996
997 /*
998 * Check the card type.
999 * Enable socket I/O interrupts for IO cards.
1000 * We use level SB_INT[0] for I/O interrupts.
1001 */
1002 if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
1003 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE);
1004 v |= STP4020_ICR0_IFTYPE_IO|STP4020_ICR0_IOIE
1005 |STP4020_ICR0_SPKREN;
1006 v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1
1007 : STP4020_ICR0_IOILVL_SB0;
1008 h->int_enable = v;
1009 h->int_disable = v & ~STP4020_ICR0_IOIE;
1010 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
1011 } else {
1012 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE
1013 |STP4020_ICR0_SPKREN);
1014 v |= STP4020_ICR0_IFTYPE_MEM;
1015 DPRINTF(("%s: configuring card for MEM ONLY useage\n", h->sc->sc_dev.dv_xname));
1016 }
1017 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
1018 }
1019
1020 void
1021 stp4020_chip_socket_disable(pch)
1022 pcmcia_chipset_handle_t pch;
1023 {
1024 struct stp4020_socket *h = (struct stp4020_socket *)pch;
1025 int v;
1026
1027 /*
1028 * Disable socket I/O interrupts.
1029 */
1030 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
1031 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL);
1032 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
1033
1034 /* Power down the socket */
1035 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
1036
1037 /*
1038 * wait 300ms until power fails (Tpf).
1039 */
1040 stp4020_delay(300 * 1000);
1041 }
1042
1043 void *
1044 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
1045 pcmcia_chipset_handle_t pch;
1046 struct pcmcia_function *pf;
1047 int ipl;
1048 int (*handler) __P((void *));
1049 void *arg;
1050 {
1051 struct stp4020_socket *h = (struct stp4020_socket *)pch;
1052
1053 /* only one interrupt handler per slot */
1054 if (h->intrhandler != NULL) return NULL;
1055
1056 h->intrhandler = handler;
1057 h->intrarg = arg;
1058 h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h);
1059 return h->softint;
1060 }
1061
1062 void
1063 stp4020_chip_intr_disestablish(pch, ih)
1064 pcmcia_chipset_handle_t pch;
1065 void *ih;
1066 {
1067 struct stp4020_socket *h = (struct stp4020_socket *)pch;
1068
1069 h->intrhandler = NULL;
1070 h->intrarg = NULL;
1071 if (h->softint) {
1072 softintr_disestablish(h->softint);
1073 h->softint = NULL;
1074 }
1075 }
1076
1077 /*
1078 * Delay and possibly yield CPU.
1079 * XXX - assumes a context
1080 */
1081 void
1082 stp4020_delay(ms)
1083 unsigned int ms;
1084 {
1085 unsigned int ticks;
1086
1087 /* Convert to ticks */
1088 ticks = (ms * hz ) / 1000000;
1089
1090 if (cold || ticks == 0) {
1091 delay(ms);
1092 return;
1093 }
1094
1095 #ifdef DIAGNOSTIC
1096 if (ticks > 60*hz)
1097 panic("stp4020: preposterous delay: %u", ticks);
1098 #endif
1099 tsleep(&ticks, 0, "stp4020_delay", ticks);
1100 }
1101
1102 #ifdef STP4020_DEBUG
1103 void
1104 stp4020_dump_regs(h)
1105 struct stp4020_socket *h;
1106 {
1107 char bits[64];
1108 /*
1109 * Dump control and status registers.
1110 */
1111 printf("socket[%d] registers:\n", h->sock);
1112 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX),
1113 STP4020_ICR0_BITS, bits, sizeof(bits));
1114 printf("\tICR0=%s\n", bits);
1115
1116 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX),
1117 STP4020_ICR1_BITS, bits, sizeof(bits));
1118 printf("\tICR1=%s\n", bits);
1119
1120 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
1121 STP4020_ISR0_IOBITS, bits, sizeof(bits));
1122 printf("\tISR0=%s\n", bits);
1123
1124 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX),
1125 STP4020_ISR1_BITS, bits, sizeof(bits));
1126 printf("\tISR1=%s\n", bits);
1127 }
1128 #endif /* STP4020_DEBUG */
1129