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