Annotation of sys/dev/sbus/stp4020.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: stp4020.c,v 1.14 2005/11/23 11:39:37 mickey 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_size_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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
608: stp4020_chip_mem_free(pch, pcmhp)
609: pcmcia_chipset_handle_t pch;
610: struct pcmcia_mem_handle *pcmhp;
611: {
612: }
613:
614: int
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_size_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
639: stp4020_chip_mem_unmap(pch, win)
640: pcmcia_chipset_handle_t pch;
641: int win;
642: {
643: }
644:
645: int
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
662: stp4020_chip_io_free(pch, pcihp)
663: pcmcia_chipset_handle_t pch;
664: struct pcmcia_io_handle *pcihp;
665: {
666: }
667:
668: int
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
687: stp4020_chip_io_unmap(pch, win)
688: pcmcia_chipset_handle_t pch;
689: int win;
690: {
691: }
692:
693: void
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
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 *
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
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 *
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
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
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 */
CVSweb