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