1 /* $OpenBSD: stp4020.c,v 1.23 2023/04/11 00:45:09 jsg Exp $ */
2 /* $NetBSD: stp4020.c,v 1.23 2002/06/01 23:51:03 lukem Exp $ */
3
4 /*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Paul Kranenburg.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * STP4020: SBus/PCMCIA bridge supporting one Type-3 PCMCIA card, or up to
35 * two Type-1 and Type-2 PCMCIA cards..
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/errno.h>
41 #include <sys/extent.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h>
44 #include <sys/kthread.h>
45 #include <sys/device.h>
46
47 #include <dev/pcmcia/pcmciareg.h>
48 #include <dev/pcmcia/pcmciavar.h>
49 #include <dev/pcmcia/pcmciachip.h>
50
51 #include <machine/bus.h>
52 #include <machine/intr.h>
53
54 #include <dev/sbus/stp4020reg.h>
55 #include <dev/sbus/stp4020var.h>
56
57 /*
58 * We use the three available windows per socket in a simple, fixed
59 * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
60 * spaces into sbus space.
61 */
62 #define STP_WIN_ATTR 0 /* index of the attribute memory space window */
63 #define STP_WIN_MEM 1 /* index of the common memory space window */
64 #define STP_WIN_IO 2 /* index of the io space window */
65
66 #ifdef STP4020_DEBUG
67 int stp4020_debug = 0;
68 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0)
69 #else
70 #define DPRINTF(x)
71 #endif
72
73 int stp4020print(void *, const char *);
74 void stp4020_map_window(struct stp4020_socket *, int, int);
75 void stp4020_calc_speed(int, int, int *, int *);
76 void stp4020_intr_dispatch(void *);
77
78 struct cfdriver stp_cd = {
79 NULL, "stp", DV_DULL
80 };
81
82 #ifdef STP4020_DEBUG
83 static void stp4020_dump_regs(struct stp4020_socket *);
84 #endif
85
86 static u_int16_t stp4020_rd_sockctl(struct stp4020_socket *, int);
87 static void stp4020_wr_sockctl(struct stp4020_socket *, int, u_int16_t);
88 static void stp4020_wr_winctl(struct stp4020_socket *, int, int, u_int16_t);
89
90 void stp4020_delay(unsigned int);
91 void stp4020_attach_socket(struct stp4020_socket *, int);
92 void stp4020_create_event_thread(void *);
93 void stp4020_event_thread(void *);
94 void stp4020_queue_event(struct stp4020_softc *, int);
95
96 int stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
97 struct pcmcia_mem_handle *);
98 void stp4020_chip_mem_free(pcmcia_chipset_handle_t,
99 struct pcmcia_mem_handle *);
100 int stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
101 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
102 void stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int);
103
104 int stp4020_chip_io_alloc(pcmcia_chipset_handle_t,
105 bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle *);
106 void stp4020_chip_io_free(pcmcia_chipset_handle_t,
107 struct pcmcia_io_handle *);
108 int stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
109 bus_size_t, struct pcmcia_io_handle *, int *);
110 void stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int);
111
112 void stp4020_chip_socket_enable(pcmcia_chipset_handle_t);
113 void stp4020_chip_socket_disable(pcmcia_chipset_handle_t);
114 void *stp4020_chip_intr_establish(pcmcia_chipset_handle_t,
115 struct pcmcia_function *, int, int (*) (void *), void *, char *);
116 void stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
117 const char *stp4020_chip_intr_string(pcmcia_chipset_handle_t, void *);
118
119 /* Our PCMCIA chipset methods */
120 static struct pcmcia_chip_functions stp4020_functions = {
121 stp4020_chip_mem_alloc,
122 stp4020_chip_mem_free,
123 stp4020_chip_mem_map,
124 stp4020_chip_mem_unmap,
125
126 stp4020_chip_io_alloc,
127 stp4020_chip_io_free,
128 stp4020_chip_io_map,
129 stp4020_chip_io_unmap,
130
131 stp4020_chip_intr_establish,
132 stp4020_chip_intr_disestablish,
133 stp4020_chip_intr_string,
134
135 stp4020_chip_socket_enable,
136 stp4020_chip_socket_disable
137 };
138
139
140 static __inline__ u_int16_t
stp4020_rd_sockctl(struct stp4020_socket * h,int idx)141 stp4020_rd_sockctl(struct stp4020_socket *h, int idx)
142 {
143 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
144 return (bus_space_read_2(h->tag, h->regs, o));
145 }
146
147 static __inline__ void
stp4020_wr_sockctl(struct stp4020_socket * h,int idx,u_int16_t v)148 stp4020_wr_sockctl(struct stp4020_socket *h, int idx, u_int16_t v)
149 {
150 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
151 bus_space_write_2(h->tag, h->regs, o, v);
152 }
153
154 static __inline__ void
stp4020_wr_winctl(struct stp4020_socket * h,int win,int idx,u_int16_t v)155 stp4020_wr_winctl(struct stp4020_socket *h, int win, int idx, u_int16_t v)
156 {
157 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
158 (STP4020_WINREGS_SIZE * win) + idx;
159 bus_space_write_2(h->tag, h->regs, o, v);
160 }
161
162
163 int
stp4020print(void * aux,const char * busname)164 stp4020print(void *aux, const char *busname)
165 {
166 struct pcmciabus_attach_args *paa = aux;
167 struct stp4020_socket *h = paa->pch;
168
169 printf(" socket %d", h->sock);
170 return (UNCONF);
171 }
172
173 /*
174 * Attach all the sub-devices we can find
175 */
176 void
stpattach_common(struct stp4020_softc * sc,int clockfreq)177 stpattach_common(struct stp4020_softc *sc, int clockfreq)
178 {
179 int i, rev;
180
181 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
182 STP4020_ISR1_REV_M;
183 printf(": rev %x\n", rev);
184
185 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
186
187 /*
188 * Arrange that a kernel thread be created to handle
189 * insert/removal events.
190 */
191 sc->events = 0;
192 kthread_create_deferred(stp4020_create_event_thread, sc);
193
194 for (i = 0; i < STP4020_NSOCK; i++) {
195 struct stp4020_socket *h = &sc->sc_socks[i];
196 h->sock = i;
197 h->sc = sc;
198 #ifdef STP4020_DEBUG
199 if (stp4020_debug)
200 stp4020_dump_regs(h);
201 #endif
202 stp4020_attach_socket(h, clockfreq);
203 }
204 }
205
206 void
stp4020_attach_socket(struct stp4020_socket * h,int speed)207 stp4020_attach_socket(struct stp4020_socket *h, int speed)
208 {
209 struct pcmciabus_attach_args paa;
210 int v;
211
212 /* no interrupt handlers yet */
213 h->intrhandler = NULL;
214 h->intrarg = NULL;
215 h->softint = NULL;
216 h->int_enable = h->int_disable = 0;
217
218 /* Map all three windows */
219 stp4020_map_window(h, STP_WIN_ATTR, speed);
220 stp4020_map_window(h, STP_WIN_MEM, speed);
221 stp4020_map_window(h, STP_WIN_IO, speed);
222
223 /* Configure one pcmcia device per socket */
224 paa.paa_busname = "pcmcia";
225 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
226 paa.pch = (pcmcia_chipset_handle_t)h;
227 paa.iobase = 0;
228 paa.iosize = STP4020_WINDOW_SIZE;
229
230 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
231
232 if (h->pcmcia == NULL)
233 return;
234
235 /*
236 * There's actually a pcmcia bus attached; initialize the slot.
237 */
238
239 /*
240 * Clear things up before we enable status change interrupts.
241 * This seems to not be fully initialized by the PROM.
242 */
243 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
244 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
245 stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
246 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
247
248 /*
249 * Enable socket status change interrupts.
250 * We use SB_INT[1] for status change interrupts.
251 */
252 v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
253 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
254
255 /* Get live status bits from ISR0 */
256 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
257 h->sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
258 if (h->sense != 0) {
259 h->flags |= STP4020_SOCKET_BUSY;
260 pcmcia_card_attach(h->pcmcia);
261 }
262 }
263
264
265 /*
266 * Deferred thread creation callback.
267 */
268 void
stp4020_create_event_thread(void * arg)269 stp4020_create_event_thread(void *arg)
270 {
271 struct stp4020_softc *sc = arg;
272
273 if (kthread_create(stp4020_event_thread, sc, &sc->event_thread,
274 sc->sc_dev.dv_xname)) {
275 panic("%s: unable to create event thread", sc->sc_dev.dv_xname);
276 }
277 }
278
279 /*
280 * The actual event handling thread.
281 */
282 void
stp4020_event_thread(void * arg)283 stp4020_event_thread(void *arg)
284 {
285 struct stp4020_softc *sc = arg;
286 int s, sense;
287 unsigned int socket;
288
289 for (;;) {
290 struct stp4020_socket *h;
291
292 s = splhigh();
293 if ((socket = ffs(sc->events)) == 0) {
294 splx(s);
295 tsleep_nsec(&sc->events, PWAIT, "stp4020_ev", INFSLP);
296 continue;
297 }
298 socket--;
299 sc->events &= ~(1 << socket);
300 splx(s);
301
302 if (socket >= STP4020_NSOCK) {
303 #ifdef DEBUG
304 printf("stp4020_event_thread: wayward socket number %d\n",
305 socket);
306 #endif
307 continue;
308 }
309
310 h = &sc->sc_socks[socket];
311
312 /* Read socket's ISR0 for the interrupt status bits */
313 sense = stp4020_rd_sockctl(h, STP4020_ISR0_IDX) &
314 (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
315
316 if (sense > h->sense) {
317 /*
318 * If at least one more sensor is asserted, this is
319 * a card insertion.
320 */
321 h->sense = sense;
322 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
323 h->flags |= STP4020_SOCKET_BUSY;
324 pcmcia_card_attach(h->pcmcia);
325 }
326 } else if (sense < h->sense) {
327 /*
328 * If at least one less sensor is asserted, this is
329 * a card removal.
330 */
331 h->sense = sense;
332 if (h->flags & STP4020_SOCKET_BUSY) {
333 h->flags &= ~STP4020_SOCKET_BUSY;
334 pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
335 }
336 }
337 }
338 }
339
340 void
stp4020_queue_event(struct stp4020_softc * sc,int sock)341 stp4020_queue_event(struct stp4020_softc *sc, int sock)
342 {
343 int s;
344
345 s = splhigh();
346 sc->events |= (1 << sock);
347 splx(s);
348 wakeup(&sc->events);
349 }
350
351 /*
352 * Software interrupt called to invoke the real driver interrupt handler.
353 */
354 void
stp4020_intr_dispatch(void * arg)355 stp4020_intr_dispatch(void *arg)
356 {
357 struct stp4020_socket *h = (struct stp4020_socket *)arg;
358 int s;
359
360 /* invoke driver handler */
361 h->intrhandler(h->intrarg);
362
363 /* enable SBUS interrupts for PCMCIA interrupts again */
364 s = splhigh();
365 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
366 splx(s);
367 }
368
369 int
stp4020_statintr(void * arg)370 stp4020_statintr(void *arg)
371 {
372 struct stp4020_softc *sc = arg;
373 int i, sense, r = 0;
374 int s;
375
376 /* protect hardware access against soft interrupts */
377 s = splhigh();
378
379 /*
380 * Check each socket for pending requests.
381 */
382 for (i = 0 ; i < STP4020_NSOCK; i++) {
383 struct stp4020_socket *h;
384 int v;
385
386 h = &sc->sc_socks[i];
387
388 /* Read socket's ISR0 for the interrupt status bits */
389 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
390 sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
391
392 #ifdef STP4020_DEBUG
393 if (stp4020_debug != 0)
394 printf("stp4020_statintr: ISR0=%b\n",
395 v, STP4020_ISR0_IOBITS);
396 #endif
397
398 /* Ack all interrupts at once */
399 stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
400 STP4020_ISR0_ALL_STATUS_IRQ);
401
402 if ((v & STP4020_ISR0_CDCHG) != 0) {
403 r = 1;
404
405 /*
406 * Card detect status changed. In an ideal world,
407 * both card detect sensors should be set if a card
408 * is in the slot, and clear if it is not.
409 *
410 * Unfortunately, it turns out that we can get the
411 * notification before both sensors are set (or
412 * clear).
413 *
414 * This can be very funny if only one sensor is set.
415 * Is this a removal or an insertion operation?
416 * Defer appropriate action to the worker thread.
417 */
418 if (sense != h->sense)
419 stp4020_queue_event(sc, i);
420
421 }
422
423 /* informational messages */
424 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
425 DPRINTF(("stp4020[%d]: Battery change 1\n",
426 h->sock));
427 r = 1;
428 }
429
430 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
431 DPRINTF(("stp4020[%d]: Battery change 2\n",
432 h->sock));
433 r = 1;
434 }
435
436 if ((v & STP4020_ISR0_RDYCHG) != 0) {
437 DPRINTF(("stp4020[%d]: Ready/Busy change\n",
438 h->sock));
439 r = 1;
440 }
441
442 if ((v & STP4020_ISR0_WPCHG) != 0) {
443 DPRINTF(("stp4020[%d]: Write protect change\n",
444 h->sock));
445 r = 1;
446 }
447
448 if ((v & STP4020_ISR0_PCTO) != 0) {
449 DPRINTF(("stp4020[%d]: Card access timeout\n",
450 h->sock));
451 r = 1;
452 }
453
454 if ((v & STP4020_ISR0_SCINT) != 0) {
455 DPRINTF(("stp4020[%d]: Status change\n",
456 h->sock));
457 r = 1;
458 }
459
460 /*
461 * Not interrupts flag per se, but interrupts can occur when
462 * they are asserted, at least during our slot enable routine.
463 */
464 if ((h->flags & STP4020_SOCKET_ENABLING) &&
465 (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON)))
466 r = 1;
467 }
468
469 splx(s);
470
471 return (r);
472 }
473
474 int
stp4020_iointr(void * arg)475 stp4020_iointr(void *arg)
476 {
477 struct stp4020_softc *sc = arg;
478 int i, r = 0;
479 int s;
480
481 /* protect hardware access against soft interrupts */
482 s = splhigh();
483
484 /*
485 * Check each socket for pending requests.
486 */
487 for (i = 0 ; i < STP4020_NSOCK; i++) {
488 struct stp4020_socket *h;
489 int v;
490
491 h = &sc->sc_socks[i];
492 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
493
494 if ((v & STP4020_ISR0_IOINT) != 0) {
495 /* we can not deny this is ours, no matter what the
496 card driver says. */
497 r = 1;
498
499 /* ack interrupt */
500 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
501
502 /* It's a card interrupt */
503 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
504 printf("stp4020[%d]: spurious interrupt?\n",
505 h->sock);
506 continue;
507 }
508 /* Call card handler, if any */
509 if (h->softint != NULL) {
510 softintr_schedule(h->softint);
511
512 /*
513 * Disable this sbus interrupt, until the
514 * softintr handler had a chance to run.
515 */
516 stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
517 h->int_disable);
518 }
519 }
520
521 }
522
523 splx(s);
524
525 return (r);
526 }
527
528 /*
529 * The function gets the sbus speed and a access time and calculates
530 * values for the CMDLNG and CMDDLAY registers.
531 */
532 void
stp4020_calc_speed(int bus_speed,int ns,int * length,int * delay)533 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
534 {
535 int result;
536
537 if (ns < STP4020_MEM_SPEED_MIN)
538 ns = STP4020_MEM_SPEED_MIN;
539 else if (ns > STP4020_MEM_SPEED_MAX)
540 ns = STP4020_MEM_SPEED_MAX;
541 result = ns * (bus_speed / 1000);
542 if (result % 1000000)
543 result = result / 1000000 + 1;
544 else
545 result /= 1000000;
546 *length = result;
547
548 /* the sbus frequency range is limited, so we can keep this simple */
549 *delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2;
550 }
551
552 void
stp4020_map_window(struct stp4020_socket * h,int win,int speed)553 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
554 {
555 int v, length, delay;
556
557 /*
558 * According to the PC Card standard 300ns access timing should be
559 * used for attribute memory access. Our pcmcia framework does not
560 * seem to propagate timing information, so we use that
561 * everywhere.
562 */
563 stp4020_calc_speed(speed, 300, &length, &delay);
564
565 /*
566 * Fill in the Address Space Select and Base Address
567 * fields of this windows control register 0.
568 */
569 v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) |
570 ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M);
571 switch (win) {
572 case STP_WIN_ATTR:
573 v |= STP4020_WCR0_ASPSEL_AM;
574 break;
575 case STP_WIN_MEM:
576 v |= STP4020_WCR0_ASPSEL_CM;
577 break;
578 case STP_WIN_IO:
579 v |= STP4020_WCR0_ASPSEL_IO;
580 break;
581 }
582 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
583 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
584 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX,
585 1 << STP4020_WCR1_WAITREQ_S);
586 }
587
588 int
stp4020_chip_mem_alloc(pcmcia_chipset_handle_t pch,bus_size_t size,struct pcmcia_mem_handle * pcmhp)589 stp4020_chip_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
590 struct pcmcia_mem_handle *pcmhp)
591 {
592 struct stp4020_socket *h = (struct stp4020_socket *)pch;
593
594 /* we can not do much here, defere work to _mem_map */
595 pcmhp->memt = h->wintag;
596 pcmhp->size = size;
597 pcmhp->addr = 0;
598 pcmhp->mhandle = 0;
599 pcmhp->realsize = size;
600
601 return (0);
602 }
603
604 void
stp4020_chip_mem_free(pcmcia_chipset_handle_t pch,struct pcmcia_mem_handle * pcmhp)605 stp4020_chip_mem_free(pcmcia_chipset_handle_t pch,
606 struct pcmcia_mem_handle *pcmhp)
607 {
608 }
609
610 int
stp4020_chip_mem_map(pcmcia_chipset_handle_t pch,int kind,bus_addr_t card_addr,bus_size_t size,struct pcmcia_mem_handle * pcmhp,bus_size_t * offsetp,int * windowp)611 stp4020_chip_mem_map(pcmcia_chipset_handle_t pch, int kind,
612 bus_addr_t card_addr, bus_size_t size, struct pcmcia_mem_handle *pcmhp,
613 bus_size_t *offsetp, int *windowp)
614 {
615 struct stp4020_socket *h = (struct stp4020_socket *)pch;
616 int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM;
617
618 pcmhp->memt = h->wintag;
619 bus_space_subregion(h->wintag, h->windows[win].winaddr,
620 card_addr, size, &pcmhp->memh);
621 pcmhp->size = size;
622 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
623 *offsetp = 0;
624 *windowp = win;
625
626 return (0);
627 }
628
629 void
stp4020_chip_mem_unmap(pcmcia_chipset_handle_t pch,int win)630 stp4020_chip_mem_unmap(pcmcia_chipset_handle_t pch, int win)
631 {
632 }
633
634 int
stp4020_chip_io_alloc(pcmcia_chipset_handle_t pch,bus_addr_t start,bus_size_t size,bus_size_t align,struct pcmcia_io_handle * pcihp)635 stp4020_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
636 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp)
637 {
638 struct stp4020_socket *h = (struct stp4020_socket *)pch;
639
640 pcihp->iot = h->wintag;
641 pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
642 pcihp->size = size;
643 return (0);
644 }
645
646 void
stp4020_chip_io_free(pcmcia_chipset_handle_t pch,struct pcmcia_io_handle * pcihp)647 stp4020_chip_io_free(pcmcia_chipset_handle_t pch,
648 struct pcmcia_io_handle *pcihp)
649 {
650 }
651
652 int
stp4020_chip_io_map(pcmcia_chipset_handle_t pch,int width,bus_addr_t offset,bus_size_t size,struct pcmcia_io_handle * pcihp,int * windowp)653 stp4020_chip_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
654 bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp)
655 {
656 struct stp4020_socket *h = (struct stp4020_socket *)pch;
657
658 pcihp->iot = h->wintag;
659 bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr,
660 offset, size, &pcihp->ioh);
661 *windowp = 0;
662 return (0);
663 }
664
665 void
stp4020_chip_io_unmap(pcmcia_chipset_handle_t pch,int win)666 stp4020_chip_io_unmap(pcmcia_chipset_handle_t pch, int win)
667 {
668 }
669
670 void
stp4020_chip_socket_enable(pcmcia_chipset_handle_t pch)671 stp4020_chip_socket_enable(pcmcia_chipset_handle_t pch)
672 {
673 struct stp4020_socket *h = (struct stp4020_socket *)pch;
674 int i, v;
675
676 h->flags |= STP4020_SOCKET_ENABLING;
677
678 /* this bit is mostly stolen from pcic_attach_card */
679
680 /* Power down the socket to reset it, clear the card reset pin */
681 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
682
683 /*
684 * wait 300ms until power fails (Tpf). Then, wait 100ms since
685 * we are changing Vcc (Toff).
686 */
687 stp4020_delay((300 + 100) * 1000);
688
689 /* Power up the socket */
690 v = STP4020_ICR1_MSTPWR;
691 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
692
693 /*
694 * wait 100ms until power raise (Tpr) and 20ms to become
695 * stable (Tsu(Vcc)).
696 *
697 * some machines require some more time to be settled
698 * (another 200ms is added here).
699 */
700 stp4020_delay((100 + 20 + 200) * 1000);
701
702 v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC;
703 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
704
705 /*
706 * hold RESET at least 20us.
707 */
708 stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
709 stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET);
710 delay(20);
711 stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
712 stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET);
713
714 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
715 stp4020_delay(20000);
716
717 /* Wait for the chip to finish initializing (5 seconds max) */
718 for (i = 10000; i > 0; i--) {
719 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
720 /* If the card has been removed, abort */
721 if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) {
722 h->flags &= ~STP4020_SOCKET_ENABLING;
723 return;
724 }
725 if ((v & STP4020_ISR0_RDYST) != 0)
726 break;
727 delay(500);
728 }
729 if (i <= 0) {
730 #ifdef STP4020_DEBUG
731 printf("stp4020_chip_socket_enable: not ready: status %b\n",
732 v, STP4020_ISR0_IOBITS);
733 #endif
734 h->flags &= ~STP4020_SOCKET_ENABLING;
735 return;
736 }
737
738 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
739
740 /*
741 * Check the card type.
742 * Enable socket I/O interrupts for IO cards.
743 * We use level SB_INT[0] for I/O interrupts.
744 */
745 if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
746 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE);
747 v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE |
748 STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN;
749 h->int_enable = v;
750 h->int_disable = v & ~STP4020_ICR0_IOIE;
751 DPRINTF(("%s: configuring card for IO usage\n",
752 h->sc->sc_dev.dv_xname));
753 } else {
754 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
755 STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
756 v |= STP4020_ICR0_IFTYPE_MEM;
757 h->int_enable = h->int_disable = v;
758 DPRINTF(("%s: configuring card for MEM ONLY usage\n",
759 h->sc->sc_dev.dv_xname));
760 }
761 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
762
763 h->flags &= ~STP4020_SOCKET_ENABLING;
764 }
765
766 void
stp4020_chip_socket_disable(pcmcia_chipset_handle_t pch)767 stp4020_chip_socket_disable(pcmcia_chipset_handle_t pch)
768 {
769 struct stp4020_socket *h = (struct stp4020_socket *)pch;
770 int v;
771
772 /*
773 * Disable socket I/O interrupts.
774 */
775 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
776 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
777 STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
778 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
779
780 /* Power down the socket */
781 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
782
783 /*
784 * wait 300ms until power fails (Tpf).
785 */
786 stp4020_delay(300 * 1000);
787 }
788
789 void *
stp4020_chip_intr_establish(pcmcia_chipset_handle_t pch,struct pcmcia_function * pf,int ipl,int (* handler)(void *),void * arg,char * xname)790 stp4020_chip_intr_establish(pcmcia_chipset_handle_t pch,
791 struct pcmcia_function *pf, int ipl, int (*handler) (void *), void *arg,
792 char *xname)
793 {
794 struct stp4020_socket *h = (struct stp4020_socket *)pch;
795
796 /*
797 * Note that this code relies on softintr_establish() to be
798 * used with real, hardware ipl values. All platforms with
799 * SBus support this.
800 */
801 h->intrhandler = handler;
802 h->intrarg = arg;
803 h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h);
804
805 return h->softint != NULL ? h : NULL;
806 }
807
808 void
stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t pch,void * ih)809 stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
810 {
811 struct stp4020_socket *h = (struct stp4020_socket *)pch;
812
813 if (h->softint != NULL) {
814 softintr_disestablish(h->softint);
815 h->softint = NULL;
816 }
817 h->intrhandler = NULL;
818 h->intrarg = NULL;
819 }
820
821 const char *
stp4020_chip_intr_string(pcmcia_chipset_handle_t pch,void * ih)822 stp4020_chip_intr_string(pcmcia_chipset_handle_t pch, void *ih)
823 {
824 if (ih == NULL)
825 return ("couldn't establish interrupt");
826 else
827 return (""); /* nothing for now */
828 }
829
830 /*
831 * Delay and possibly yield CPU.
832 * XXX - assumes a context
833 */
834 void
stp4020_delay(unsigned int usecs)835 stp4020_delay(unsigned int usecs)
836 {
837 int chan;
838
839 if (cold || usecs < tick) {
840 delay(usecs);
841 return;
842 }
843
844 #ifdef DEBUG
845 if (USEC_TO_NSEC(usecs) > SEC_TO_NSEC(60))
846 panic("stp4020: preposterous delay: %uus", usecs);
847 #endif
848 tsleep_nsec(&chan, 0, "stp4020_delay", USEC_TO_NSEC(usecs));
849 }
850
851 #ifdef STP4020_DEBUG
852 void
stp4020_dump_regs(struct stp4020_socket * h)853 stp4020_dump_regs(struct stp4020_socket *h)
854 {
855 /*
856 * Dump control and status registers.
857 */
858 printf("socket[%d] registers:\n"
859 "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock,
860 stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS,
861 stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS,
862 stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS,
863 stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
864 }
865 #endif /* STP4020_DEBUG */
866