stp4020.c revision 1.27 1 /* $NetBSD: stp4020.c,v 1.27 2002/10/02 16:52:44 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards.
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.27 2002/10/02 16:52:44 thorpej 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, int speed);
140 static void stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay);
141
142 CFATTACH_DECL(nell, sizeof(struct stp4020_softc),
143 stp4020match, stp4020attach, NULL, NULL);
144
145 #ifdef STP4020_DEBUG
146 static void stp4020_dump_regs __P((struct stp4020_socket *));
147 #endif
148
149 static int stp4020_rd_sockctl __P((struct stp4020_socket *, int));
150 static void stp4020_wr_sockctl __P((struct stp4020_socket *, int, int));
151 static int stp4020_rd_winctl __P((struct stp4020_socket *, int, int));
152 static void stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int));
153
154 void stp4020_delay __P((unsigned int));
155 void stp4020_attach_socket __P((struct stp4020_socket *, int));
156 void stp4020_create_event_thread __P((void *));
157 void stp4020_event_thread __P((void *));
158 void stp4020_queue_event __P((struct stp4020_softc *, int, int));
159
160 int stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
161 struct pcmcia_mem_handle *));
162 void stp4020_chip_mem_free __P((pcmcia_chipset_handle_t,
163 struct pcmcia_mem_handle *));
164 int stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
165 bus_size_t, struct pcmcia_mem_handle *,
166 bus_size_t *, int *));
167 void stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int));
168
169 int stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t,
170 bus_addr_t, bus_size_t, bus_size_t,
171 struct pcmcia_io_handle *));
172 void stp4020_chip_io_free __P((pcmcia_chipset_handle_t,
173 struct pcmcia_io_handle *));
174 int stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
175 bus_size_t, struct pcmcia_io_handle *, int *));
176 void stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
177
178 void stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t));
179 void stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t));
180 void *stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t,
181 struct pcmcia_function *, int,
182 int (*) __P((void *)), void *));
183 void stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
184
185 /* Our PCMCIA chipset methods */
186 static struct pcmcia_chip_functions stp4020_functions = {
187 stp4020_chip_mem_alloc,
188 stp4020_chip_mem_free,
189 stp4020_chip_mem_map,
190 stp4020_chip_mem_unmap,
191
192 stp4020_chip_io_alloc,
193 stp4020_chip_io_free,
194 stp4020_chip_io_map,
195 stp4020_chip_io_unmap,
196
197 stp4020_chip_intr_establish,
198 stp4020_chip_intr_disestablish,
199
200 stp4020_chip_socket_enable,
201 stp4020_chip_socket_disable
202 };
203
204
205 static __inline__ int
206 stp4020_rd_sockctl(h, idx)
207 struct stp4020_socket *h;
208 int idx;
209 {
210 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
211 return (bus_space_read_2(h->tag, h->regs, o));
212 }
213
214 static __inline__ void
215 stp4020_wr_sockctl(h, idx, v)
216 struct stp4020_socket *h;
217 int idx;
218 int v;
219 {
220 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
221 bus_space_write_2(h->tag, h->regs, o, v);
222 }
223
224 static __inline__ int
225 stp4020_rd_winctl(h, win, idx)
226 struct stp4020_socket *h;
227 int win;
228 int idx;
229 {
230 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
231 (STP4020_WINREGS_SIZE * win) + idx;
232 return (bus_space_read_2(h->tag, h->regs, o));
233 }
234
235 static __inline__ void
236 stp4020_wr_winctl(h, win, idx, v)
237 struct stp4020_socket *h;
238 int win;
239 int idx;
240 int v;
241 {
242 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
243 (STP4020_WINREGS_SIZE * win) + idx;
244
245 bus_space_write_2(h->tag, h->regs, o, v);
246 }
247
248
249 int
250 stp4020print(aux, busname)
251 void *aux;
252 const char *busname;
253 {
254 struct pcmciabus_attach_args *paa = aux;
255 struct stp4020_socket *h = paa->pch;
256
257 printf(" socket %d", h->sock);
258 return (UNCONF);
259 }
260
261 int
262 stp4020match(parent, cf, aux)
263 struct device *parent;
264 struct cfdata *cf;
265 void *aux;
266 {
267 struct sbus_attach_args *sa = aux;
268
269 return (strcmp("SUNW,pcmcia", sa->sa_name) == 0);
270 }
271
272 /*
273 * Attach all the sub-devices we can find
274 */
275 void
276 stp4020attach(parent, self, aux)
277 struct device *parent, *self;
278 void *aux;
279 {
280 struct sbus_attach_args *sa = aux;
281 struct stp4020_softc *sc = (void *)self;
282 int node, rev;
283 int i;
284 bus_space_handle_t bh;
285
286 node = sa->sa_node;
287
288 /* Transfer bus tags */
289 sc->sc_bustag = sa->sa_bustag;
290 sc->sc_dmatag = sa->sa_dmatag;
291
292 /* Set up per-socket static initialization */
293 sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
294 sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag;
295
296 if (sa->sa_nreg < 8) {
297 printf("%s: only %d register sets\n",
298 self->dv_xname, sa->sa_nreg);
299 return;
300 }
301
302 if (sa->sa_nintr != 2) {
303 printf("%s: expect 2 interrupt Sbus levels; got %d\n",
304 self->dv_xname, sa->sa_nintr);
305 return;
306 }
307
308 #define STP4020_BANK_PROM 0
309 #define STP4020_BANK_CTRL 4
310 for (i = 0; i < 8; i++) {
311
312 /*
313 * STP4020 Register address map:
314 * bank 0: Forth PROM
315 * banks 1-3: socket 0, windows 0-2
316 * bank 4: control registers
317 * banks 5-7: socket 1, windows 0-2
318 */
319
320 if (i == STP4020_BANK_PROM)
321 /* Skip the PROM */
322 continue;
323
324 if (sbus_bus_map(sa->sa_bustag,
325 sa->sa_reg[i].oa_space,
326 sa->sa_reg[i].oa_base,
327 sa->sa_reg[i].oa_size,
328 0, &bh) != 0) {
329 printf("%s: attach: cannot map registers\n",
330 self->dv_xname);
331 return;
332 }
333
334 if (i == STP4020_BANK_CTRL) {
335 /*
336 * Copy tag and handle to both socket structures
337 * for easy access in control/status IO functions.
338 */
339 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
340 } else if (i < STP4020_BANK_CTRL) {
341 /* banks 1-3 */
342 sc->sc_socks[0].windows[i-1].winaddr = bh;
343 } else {
344 /* banks 5-7 */
345 sc->sc_socks[1].windows[i-5].winaddr = bh;
346 }
347 }
348
349 sbus_establish(&sc->sc_sd, &sc->sc_dev);
350
351 /*
352 * We get to use two SBus interrupt levels.
353 * The higher level we use for status change interrupts;
354 * the lower level for PC card I/O.
355 */
356 if (sa->sa_nintr != 0) {
357 bus_intr_establish(sa->sa_bustag, sa->sa_intr[1].oi_pri,
358 IPL_NONE, 0, stp4020_statintr, sc);
359
360 bus_intr_establish(sa->sa_bustag, sa->sa_intr[0].oi_pri,
361 IPL_NONE, 0, stp4020_iointr, sc);
362 }
363
364 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
365 STP4020_ISR1_REV_M;
366 printf(": rev %x\n", rev);
367
368 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
369
370 /*
371 * Arrange that a kernel thread be created to handle
372 * insert/removal events.
373 */
374 SIMPLEQ_INIT(&sc->events);
375 kthread_create(stp4020_create_event_thread, sc);
376
377 for (i = 0; i < STP4020_NSOCK; i++) {
378 struct stp4020_socket *h = &sc->sc_socks[i];
379 h->sock = i;
380 h->sc = sc;
381 #ifdef STP4020_DEBUG
382 if (stp4020_debug)
383 stp4020_dump_regs(h);
384 #endif
385 stp4020_attach_socket(h, sa->sa_frequency);
386 }
387 }
388
389 void
390 stp4020_attach_socket(h, speed)
391 struct stp4020_socket *h;
392 int speed;
393 {
394 struct pcmciabus_attach_args paa;
395 int v;
396
397 /* Map all three windows */
398 stp4020_map_window(h, STP_WIN_ATTR, speed);
399 stp4020_map_window(h, STP_WIN_MEM, speed);
400 stp4020_map_window(h, STP_WIN_IO, speed);
401
402 /* Configure one pcmcia device per socket */
403 paa.paa_busname = "pcmcia";
404 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
405 paa.pch = (pcmcia_chipset_handle_t)h;
406 paa.iobase = 0;
407 paa.iosize = STP4020_WINDOW_SIZE;
408
409 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
410
411 if (h->pcmcia == NULL)
412 return;
413
414 /*
415 * There's actually a pcmcia bus attached; initialize the slot.
416 */
417
418 /*
419 * Clear things up before we enable status change interrupts.
420 * This seems to not be fully initialized by the PROM.
421 */
422 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
423 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
424 stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
425 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
426
427 /*
428 * Enable socket status change interrupts.
429 * We use SB_INT[1] for status change interrupts.
430 */
431 v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
432 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
433
434 /* Get live status bits from ISR0 */
435 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
436 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
437 return;
438
439 pcmcia_card_attach(h->pcmcia);
440 h->flags |= STP4020_SOCKET_BUSY;
441 }
442
443
444 /*
445 * Deferred thread creation callback.
446 */
447 void
448 stp4020_create_event_thread(arg)
449 void *arg;
450 {
451 struct stp4020_softc *sc = arg;
452 const char *name = sc->sc_dev.dv_xname;
453
454 if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread,
455 "%s", name)) {
456 panic("%s: unable to create event thread", name);
457 }
458 }
459
460 /*
461 * The actual event handling thread.
462 */
463 void
464 stp4020_event_thread(arg)
465 void *arg;
466 {
467 struct stp4020_softc *sc = arg;
468 struct stp4020_event *e;
469 int s;
470
471 while (1) {
472 struct stp4020_socket *h;
473 int n;
474
475 s = splhigh();
476 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
477 splx(s);
478 (void)tsleep(&sc->events, PWAIT, "pcicev", 0);
479 continue;
480 }
481 SIMPLEQ_REMOVE_HEAD(&sc->events, se_q);
482 splx(s);
483
484 n = e->se_sock;
485 if (n < 0 || n >= STP4020_NSOCK)
486 panic("stp4020_event_thread: wayward socket number %d",
487 n);
488
489 h = &sc->sc_socks[n];
490 switch (e->se_type) {
491 case STP4020_EVENT_INSERTION:
492 pcmcia_card_attach(h->pcmcia);
493 break;
494 case STP4020_EVENT_REMOVAL:
495 pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
496 break;
497 default:
498 panic("stp4020_event_thread: unknown event type %d",
499 e->se_type);
500 }
501 free(e, M_TEMP);
502 }
503 }
504
505 void
506 stp4020_queue_event(sc, sock, event)
507 struct stp4020_softc *sc;
508 int sock, event;
509 {
510 struct stp4020_event *e;
511 int s;
512
513 e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
514 if (e == NULL)
515 panic("stp4020_queue_event: can't allocate event");
516
517 e->se_type = event;
518 e->se_sock = sock;
519 s = splhigh();
520 SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
521 splx(s);
522 wakeup(&sc->events);
523 }
524
525 int
526 stp4020_statintr(arg)
527 void *arg;
528 {
529 struct stp4020_softc *sc = arg;
530 int i, r = 0;
531
532 /*
533 * Check each socket for pending requests.
534 */
535 for (i = 0 ; i < STP4020_NSOCK; i++) {
536 struct stp4020_socket *h;
537 int v, cd_change = 0;
538
539 h = &sc->sc_socks[i];
540
541 /* Read socket's ISR0 for the interrupt status bits */
542 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
543
544 #ifdef STP4020_DEBUG
545 if (stp4020_debug != 0) {
546 char bits[64];
547 bitmask_snprintf(v, STP4020_ISR0_IOBITS,
548 bits, sizeof(bits));
549 printf("stp4020_statintr: ISR0=%s\n", bits);
550 }
551 #endif
552
553 /* Ack all interrupts at once */
554 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, STP4020_ISR0_ALL_STATUS_IRQ);
555
556 if ((v & STP4020_ISR0_CDCHG) != 0) {
557 /*
558 * Card status change detect
559 */
560 cd_change = 1;
561 r = 1;
562 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)){
563 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
564 stp4020_queue_event(sc, i,
565 STP4020_EVENT_INSERTION);
566 h->flags |= STP4020_SOCKET_BUSY;
567 }
568 }
569 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
570 if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
571 stp4020_queue_event(sc, i,
572 STP4020_EVENT_REMOVAL);
573 h->flags &= ~STP4020_SOCKET_BUSY;
574 }
575 }
576 }
577
578 /* informational messages */
579 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
580 /* ignore if this is caused by insert or removal */
581 if (!cd_change)
582 printf("stp4020[%d]: Battery change 1\n", h->sock);
583 r = 1;
584 }
585
586 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
587 /* ignore if this is caused by insert or removal */
588 if (!cd_change)
589 printf("stp4020[%d]: Battery change 2\n", h->sock);
590 r = 1;
591 }
592
593 if ((v & STP4020_ISR0_RDYCHG) != 0) {
594 DPRINTF(("stp4020[%d]: Ready/Busy change\n", h->sock));
595 r = 1;
596 }
597
598 if ((v & STP4020_ISR0_WPCHG) != 0) {
599 DPRINTF(("stp4020[%d]: Write protect change\n", h->sock));
600 r = 1;
601 }
602
603 if ((v & STP4020_ISR0_PCTO) != 0) {
604 DPRINTF(("stp4020[%d]: Card access timeout\n", h->sock));
605 r = 1;
606 }
607
608 }
609
610 return (r);
611 }
612
613 int
614 stp4020_iointr(arg)
615 void *arg;
616 {
617 struct stp4020_softc *sc = arg;
618 int i, r = 0;
619
620 /*
621 * Check each socket for pending requests.
622 */
623 for (i = 0 ; i < STP4020_NSOCK; i++) {
624 struct stp4020_socket *h;
625 int v;
626
627 h = &sc->sc_socks[i];
628 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
629
630 if ((v & STP4020_ISR0_IOINT) != 0) {
631 /* we can not deny this is ours, no matter what the
632 card driver says. */
633 r = 1;
634
635 /* ack interrupt */
636 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
637
638 /* It's a card interrupt */
639 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
640 printf("stp4020[%d]: spurious interrupt?\n",
641 h->sock);
642 continue;
643 }
644 /* Call card handler, if any */
645 if (h->intrhandler != NULL) {
646 /*
647 * Called without handling of it's requested
648 * protection level (h->ipl), since we have
649 * no general queuing mechanism available
650 * right now and we know for sure we are
651 * running at a higher protection level
652 * right now.
653 */
654 (*h->intrhandler)(h->intrarg);
655 }
656 }
657
658 }
659
660 return (r);
661 }
662
663 /*
664 * The function gets the sbus speed and a access time and calculates
665 * values for the CMDLNG and CMDDLAY registers.
666 */
667 static void
668 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
669 {
670 int result;
671
672 if (ns < STP4020_MEM_SPEED_MIN)
673 ns = STP4020_MEM_SPEED_MIN;
674 else if (ns > STP4020_MEM_SPEED_MAX)
675 ns = STP4020_MEM_SPEED_MAX;
676 result = ns*(bus_speed/1000);
677 if (result % 1000000)
678 result = result/1000000 + 1;
679 else
680 result /= 1000000;
681 *length = result;
682
683 /* the sbus frequency range is limited, so we can keep this simple */
684 *delay = ns <= STP4020_MEM_SPEED_MIN? 1 : 2;
685 }
686
687 static void
688 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
689 {
690 int v, length, delay;
691
692 /*
693 * According to the PC Card standard 300ns access timing should be
694 * used for attribute memory access. Our pcmcia framework does not
695 * seem to propagate timing information, so we use that
696 * everywhere.
697 */
698 stp4020_calc_speed(speed, (win==STP_WIN_ATTR)? 300 : 100, &length, &delay);
699
700 /*
701 * Fill in the Address Space Select and Base Address
702 * fields of this windows control register 0.
703 */
704 v = ((delay << STP4020_WCR0_CMDDLY_S)&STP4020_WCR0_CMDDLY_M)
705 | ((length << STP4020_WCR0_CMDLNG_S)&STP4020_WCR0_CMDLNG_M);
706 switch (win) {
707 case STP_WIN_ATTR:
708 v |= STP4020_WCR0_ASPSEL_AM;
709 break;
710 case STP_WIN_MEM:
711 v |= STP4020_WCR0_ASPSEL_CM;
712 break;
713 case STP_WIN_IO:
714 v |= STP4020_WCR0_ASPSEL_IO;
715 break;
716 }
717 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
718 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
719 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 1<<STP4020_WCR1_WAITREQ_S);
720 }
721
722 int
723 stp4020_chip_mem_alloc(pch, size, pcmhp)
724 pcmcia_chipset_handle_t pch;
725 bus_size_t size;
726 struct pcmcia_mem_handle *pcmhp;
727 {
728 struct stp4020_socket *h = (struct stp4020_socket *)pch;
729
730 /* we can not do much here, defere work to _mem_map */
731 pcmhp->memt = h->tag;
732 pcmhp->size = size;
733 pcmhp->addr = 0;
734 pcmhp->mhandle = 0;
735 pcmhp->realsize = size;
736
737 return (0);
738 }
739
740 void
741 stp4020_chip_mem_free(pch, pcmhp)
742 pcmcia_chipset_handle_t pch;
743 struct pcmcia_mem_handle *pcmhp;
744 {
745 }
746
747 int
748 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
749 pcmcia_chipset_handle_t pch;
750 int kind;
751 bus_addr_t card_addr;
752 bus_size_t size;
753 struct pcmcia_mem_handle *pcmhp;
754 bus_size_t *offsetp;
755 int *windowp;
756 {
757 struct stp4020_socket *h = (struct stp4020_socket *)pch;
758 int win = (kind&PCMCIA_MEM_ATTR)? STP_WIN_ATTR : STP_WIN_MEM;
759
760 pcmhp->memt = h->tag;
761 bus_space_subregion(h->tag, h->windows[win].winaddr, card_addr, size, &pcmhp->memh);
762 pcmhp->size = size;
763 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
764 *offsetp = 0;
765 *windowp = 0;
766
767 return (0);
768 }
769
770 void
771 stp4020_chip_mem_unmap(pch, win)
772 pcmcia_chipset_handle_t pch;
773 int win;
774 {
775 }
776
777 int
778 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
779 pcmcia_chipset_handle_t pch;
780 bus_addr_t start;
781 bus_size_t size;
782 bus_size_t align;
783 struct pcmcia_io_handle *pcihp;
784 {
785 struct stp4020_socket *h = (struct stp4020_socket *)pch;
786
787 pcihp->iot = h->tag;
788 pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
789 return 0;
790 }
791
792 void
793 stp4020_chip_io_free(pch, pcihp)
794 pcmcia_chipset_handle_t pch;
795 struct pcmcia_io_handle *pcihp;
796 {
797 }
798
799 int
800 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
801 pcmcia_chipset_handle_t pch;
802 int width;
803 bus_addr_t offset;
804 bus_size_t size;
805 struct pcmcia_io_handle *pcihp;
806 int *windowp;
807 {
808 struct stp4020_socket *h = (struct stp4020_socket *)pch;
809
810 pcihp->iot = h->tag;
811 bus_space_subregion(h->tag, h->windows[STP_WIN_IO].winaddr, offset, size, &pcihp->ioh);
812 *windowp = 0;
813 return 0;
814 }
815
816 void
817 stp4020_chip_io_unmap(pch, win)
818 pcmcia_chipset_handle_t pch;
819 int win;
820 {
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;
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 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
834
835 /*
836 * wait 300ms until power fails (Tpf). Then, wait 100ms since
837 * we are changing Vcc (Toff).
838 */
839 stp4020_delay((300 + 100) * 1000);
840
841 /* Power up the socket */
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|STP4020_ICR1_VPP1_VCC;
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
883 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
884
885 /*
886 * Check the card type.
887 * Enable socket I/O interrupts for IO cards.
888 * We use level SB_INT[0] for I/O interrupts.
889 */
890 if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
891 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE);
892 v |= STP4020_ICR0_IFTYPE_IO|STP4020_ICR0_IOIE
893 |STP4020_ICR0_IOILVL_SB0|STP4020_ICR0_SPKREN;
894 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
895 } else {
896 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE
897 |STP4020_ICR0_SPKREN|STP4020_ICR0_IOILVL_SB0
898 |STP4020_ICR0_IOILVL_SB1|STP4020_ICR0_SPKREN);
899 v |= STP4020_ICR0_IFTYPE_MEM;
900 DPRINTF(("%s: configuring card for MEM ONLY useage\n", h->sc->sc_dev.dv_xname));
901 }
902 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
903 }
904
905 void
906 stp4020_chip_socket_disable(pch)
907 pcmcia_chipset_handle_t pch;
908 {
909 struct stp4020_socket *h = (struct stp4020_socket *)pch;
910 int v;
911
912 /*
913 * Disable socket I/O interrupts.
914 */
915 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
916 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL);
917 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
918
919 /* Power down the socket */
920 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
921
922 /*
923 * wait 300ms until power fails (Tpf).
924 */
925 stp4020_delay(300 * 1000);
926 }
927
928 void *
929 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
930 pcmcia_chipset_handle_t pch;
931 struct pcmcia_function *pf;
932 int ipl;
933 int (*handler) __P((void *));
934 void *arg;
935 {
936 struct stp4020_socket *h = (struct stp4020_socket *)pch;
937
938 h->intrhandler = handler;
939 h->intrarg = arg;
940 h->ipl = ipl;
941 return h;
942 }
943
944 void
945 stp4020_chip_intr_disestablish(pch, ih)
946 pcmcia_chipset_handle_t pch;
947 void *ih;
948 {
949 struct stp4020_socket *h = (struct stp4020_socket *)pch;
950
951 h->intrhandler = NULL;
952 h->intrarg = NULL;
953 }
954
955 /*
956 * Delay and possibly yield CPU.
957 * XXX - assumes a context
958 */
959 void
960 stp4020_delay(ms)
961 unsigned int ms;
962 {
963 unsigned int ticks;
964
965 /* Convert to ticks */
966 ticks = (ms * hz ) / 1000000;
967
968 if (cold || ticks == 0) {
969 delay(ms);
970 return;
971 }
972
973 #ifdef DIAGNOSTIC
974 if (ticks > 60*hz)
975 panic("stp4020: preposterous delay: %u", ticks);
976 #endif
977 tsleep(&ticks, 0, "stp4020_delay", ticks);
978 }
979
980 #ifdef STP4020_DEBUG
981 void
982 stp4020_dump_regs(h)
983 struct stp4020_socket *h;
984 {
985 char bits[64];
986 /*
987 * Dump control and status registers.
988 */
989 printf("socket[%d] registers:\n", h->sock);
990 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX),
991 STP4020_ICR0_BITS, bits, sizeof(bits));
992 printf("\tICR0=%s\n", bits);
993
994 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX),
995 STP4020_ICR1_BITS, bits, sizeof(bits));
996 printf("\tICR1=%s\n", bits);
997
998 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
999 STP4020_ISR0_IOBITS, bits, sizeof(bits));
1000 printf("\tISR0=%s\n", bits);
1001
1002 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX),
1003 STP4020_ISR1_BITS, bits, sizeof(bits));
1004 printf("\tISR1=%s\n", bits);
1005 }
1006 #endif /* STP4020_DEBUG */
1007