xref: /openbsd/sys/dev/sbus/stp4020.c (revision 76d0caae)
1 /*	$OpenBSD: stp4020.c,v 1.22 2020/02/18 00:10:22 cheloha 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
605 stp4020_chip_mem_free(pcmcia_chipset_handle_t pch,
606     struct pcmcia_mem_handle *pcmhp)
607 {
608 }
609 
610 int
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
630 stp4020_chip_mem_unmap(pcmcia_chipset_handle_t pch, int win)
631 {
632 }
633 
634 int
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
647 stp4020_chip_io_free(pcmcia_chipset_handle_t pch,
648     struct pcmcia_io_handle *pcihp)
649 {
650 }
651 
652 int
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
666 stp4020_chip_io_unmap(pcmcia_chipset_handle_t pch, int win)
667 {
668 }
669 
670 void
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
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 *
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 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
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 *
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
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
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