xref: /openbsd-src/sys/dev/sbus/stp4020.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: stp4020.c,v 1.19 2016/03/19 11:34:22 mpi 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 u_int16_t stp4020_rd_winctl(struct stp4020_socket *, int, int);
89 static void	stp4020_wr_winctl(struct stp4020_socket *, int, int, u_int16_t);
90 
91 void	stp4020_delay(unsigned int);
92 void	stp4020_attach_socket(struct stp4020_socket *, int);
93 void	stp4020_create_event_thread(void *);
94 void	stp4020_event_thread(void *);
95 void	stp4020_queue_event(struct stp4020_softc *, int);
96 
97 int	stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
98 	    struct pcmcia_mem_handle *);
99 void	stp4020_chip_mem_free(pcmcia_chipset_handle_t,
100 	    struct pcmcia_mem_handle *);
101 int	stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
102 	    bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
103 void	stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int);
104 
105 int	stp4020_chip_io_alloc(pcmcia_chipset_handle_t,
106 	    bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle *);
107 void	stp4020_chip_io_free(pcmcia_chipset_handle_t,
108 	    struct pcmcia_io_handle *);
109 int	stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
110 	    bus_size_t, struct pcmcia_io_handle *, int *);
111 void	stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int);
112 
113 void	stp4020_chip_socket_enable(pcmcia_chipset_handle_t);
114 void	stp4020_chip_socket_disable(pcmcia_chipset_handle_t);
115 void	*stp4020_chip_intr_establish(pcmcia_chipset_handle_t,
116 	    struct pcmcia_function *, int, int (*) (void *), void *, char *);
117 void	stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
118 const char *stp4020_chip_intr_string(pcmcia_chipset_handle_t, void *);
119 
120 /* Our PCMCIA chipset methods */
121 static struct pcmcia_chip_functions stp4020_functions = {
122 	stp4020_chip_mem_alloc,
123 	stp4020_chip_mem_free,
124 	stp4020_chip_mem_map,
125 	stp4020_chip_mem_unmap,
126 
127 	stp4020_chip_io_alloc,
128 	stp4020_chip_io_free,
129 	stp4020_chip_io_map,
130 	stp4020_chip_io_unmap,
131 
132 	stp4020_chip_intr_establish,
133 	stp4020_chip_intr_disestablish,
134 	stp4020_chip_intr_string,
135 
136 	stp4020_chip_socket_enable,
137 	stp4020_chip_socket_disable
138 };
139 
140 
141 static __inline__ u_int16_t
142 stp4020_rd_sockctl(h, idx)
143 	struct stp4020_socket *h;
144 	int idx;
145 {
146 	int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
147 	return (bus_space_read_2(h->tag, h->regs, o));
148 }
149 
150 static __inline__ void
151 stp4020_wr_sockctl(h, idx, v)
152 	struct stp4020_socket *h;
153 	int idx;
154 	u_int16_t v;
155 {
156 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
157 	bus_space_write_2(h->tag, h->regs, o, v);
158 }
159 
160 static __inline__ u_int16_t
161 stp4020_rd_winctl(h, win, idx)
162 	struct stp4020_socket *h;
163 	int win;
164 	int idx;
165 {
166 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
167 	    (STP4020_WINREGS_SIZE * win) + idx;
168 	return (bus_space_read_2(h->tag, h->regs, o));
169 }
170 
171 static __inline__ void
172 stp4020_wr_winctl(h, win, idx, v)
173 	struct stp4020_socket *h;
174 	int win;
175 	int idx;
176 	u_int16_t v;
177 {
178 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
179 	    (STP4020_WINREGS_SIZE * win) + idx;
180 	bus_space_write_2(h->tag, h->regs, o, v);
181 }
182 
183 
184 int
185 stp4020print(aux, busname)
186 	void *aux;
187 	const char *busname;
188 {
189 	struct pcmciabus_attach_args *paa = aux;
190 	struct stp4020_socket *h = paa->pch;
191 
192 	printf(" socket %d", h->sock);
193 	return (UNCONF);
194 }
195 
196 /*
197  * Attach all the sub-devices we can find
198  */
199 void
200 stpattach_common(struct stp4020_softc *sc, int clockfreq)
201 {
202 	int i, rev;
203 
204 	rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
205 	    STP4020_ISR1_REV_M;
206 	printf(": rev %x\n", rev);
207 
208 	sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
209 
210 	/*
211 	 * Arrange that a kernel thread be created to handle
212 	 * insert/removal events.
213 	 */
214 	sc->events = 0;
215 	kthread_create_deferred(stp4020_create_event_thread, sc);
216 
217 	for (i = 0; i < STP4020_NSOCK; i++) {
218 		struct stp4020_socket *h = &sc->sc_socks[i];
219 		h->sock = i;
220 		h->sc = sc;
221 #ifdef STP4020_DEBUG
222 		if (stp4020_debug)
223 			stp4020_dump_regs(h);
224 #endif
225 		stp4020_attach_socket(h, clockfreq);
226 	}
227 }
228 
229 void
230 stp4020_attach_socket(h, speed)
231 	struct stp4020_socket *h;
232 	int speed;
233 {
234 	struct pcmciabus_attach_args paa;
235 	int v;
236 
237 	/* no interrupt handlers yet */
238 	h->intrhandler = NULL;
239 	h->intrarg = NULL;
240 	h->softint = NULL;
241 	h->int_enable = h->int_disable = 0;
242 
243 	/* Map all three windows */
244 	stp4020_map_window(h, STP_WIN_ATTR, speed);
245 	stp4020_map_window(h, STP_WIN_MEM, speed);
246 	stp4020_map_window(h, STP_WIN_IO, speed);
247 
248 	/* Configure one pcmcia device per socket */
249 	paa.paa_busname = "pcmcia";
250 	paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
251 	paa.pch = (pcmcia_chipset_handle_t)h;
252 	paa.iobase = 0;
253 	paa.iosize = STP4020_WINDOW_SIZE;
254 
255 	h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
256 
257 	if (h->pcmcia == NULL)
258 		return;
259 
260 	/*
261 	 * There's actually a pcmcia bus attached; initialize the slot.
262 	 */
263 
264 	/*
265 	 * Clear things up before we enable status change interrupts.
266 	 * This seems to not be fully initialized by the PROM.
267 	 */
268 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
269 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
270 	stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
271 	stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
272 
273 	/*
274 	 * Enable socket status change interrupts.
275 	 * We use SB_INT[1] for status change interrupts.
276 	 */
277 	v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
278 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
279 
280 	/* Get live status bits from ISR0 */
281 	v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
282 	h->sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
283 	if (h->sense != 0) {
284 		h->flags |= STP4020_SOCKET_BUSY;
285 		pcmcia_card_attach(h->pcmcia);
286 	}
287 }
288 
289 
290 /*
291  * Deferred thread creation callback.
292  */
293 void
294 stp4020_create_event_thread(arg)
295 	void *arg;
296 {
297 	struct stp4020_softc *sc = arg;
298 
299 	if (kthread_create(stp4020_event_thread, sc, &sc->event_thread,
300 	    sc->sc_dev.dv_xname)) {
301 		panic("%s: unable to create event thread", sc->sc_dev.dv_xname);
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 /*
381  * Software interrupt called to invoke the real driver interrupt handler.
382  */
383 void
384 stp4020_intr_dispatch(void *arg)
385 {
386 	struct stp4020_socket *h = (struct stp4020_socket *)arg;
387 	int s;
388 
389 	/* invoke driver handler */
390 	h->intrhandler(h->intrarg);
391 
392 	/* enable SBUS interrupts for PCMCIA interrupts again */
393 	s = splhigh();
394 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
395 	splx(s);
396 }
397 
398 int
399 stp4020_statintr(arg)
400 	void *arg;
401 {
402 	struct stp4020_softc *sc = arg;
403 	int i, sense, r = 0;
404 	int s;
405 
406 	/* protect hardware access against soft interrupts */
407 	s = splhigh();
408 
409 	/*
410 	 * Check each socket for pending requests.
411 	 */
412 	for (i = 0 ; i < STP4020_NSOCK; i++) {
413 		struct stp4020_socket *h;
414 		int v;
415 
416 		h = &sc->sc_socks[i];
417 
418 		/* Read socket's ISR0 for the interrupt status bits */
419 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
420 		sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
421 
422 #ifdef STP4020_DEBUG
423 		if (stp4020_debug != 0)
424 			printf("stp4020_statintr: ISR0=%b\n",
425 			    v, STP4020_ISR0_IOBITS);
426 #endif
427 
428 		/* Ack all interrupts at once */
429 		stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
430 		    STP4020_ISR0_ALL_STATUS_IRQ);
431 
432 		if ((v & STP4020_ISR0_CDCHG) != 0) {
433 			r = 1;
434 
435 			/*
436 			 * Card detect status changed. In an ideal world,
437 			 * both card detect sensors should be set if a card
438 			 * is in the slot, and clear if it is not.
439 			 *
440 			 * Unfortunately, it turns out that we can get the
441 			 * notification before both sensors are set (or
442 			 * clear).
443 			 *
444 			 * This can be very funny if only one sensor is set.
445 			 * Is this a removal or an insertion operation?
446 			 * Defer appropriate action to the worker thread.
447 			 */
448 			if (sense != h->sense)
449 				stp4020_queue_event(sc, i);
450 
451 		}
452 
453 		/* informational messages */
454 		if ((v & STP4020_ISR0_BVD1CHG) != 0) {
455 			DPRINTF(("stp4020[%d]: Battery change 1\n",
456 			    h->sock));
457 			r = 1;
458 		}
459 
460 		if ((v & STP4020_ISR0_BVD2CHG) != 0) {
461 			DPRINTF(("stp4020[%d]: Battery change 2\n",
462 			    h->sock));
463 			r = 1;
464 		}
465 
466 		if ((v & STP4020_ISR0_RDYCHG) != 0) {
467 			DPRINTF(("stp4020[%d]: Ready/Busy change\n",
468 			    h->sock));
469 			r = 1;
470 		}
471 
472 		if ((v & STP4020_ISR0_WPCHG) != 0) {
473 			DPRINTF(("stp4020[%d]: Write protect change\n",
474 			    h->sock));
475 			r = 1;
476 		}
477 
478 		if ((v & STP4020_ISR0_PCTO) != 0) {
479 			DPRINTF(("stp4020[%d]: Card access timeout\n",
480 			    h->sock));
481 			r = 1;
482 		}
483 
484 		if ((v & STP4020_ISR0_SCINT) != 0) {
485 			DPRINTF(("stp4020[%d]: Status change\n",
486 			    h->sock));
487 			r = 1;
488 		}
489 
490 		/*
491 		 * Not interrupts flag per se, but interrupts can occur when
492 		 * they are asserted, at least during our slot enable routine.
493 		 */
494 		if ((h->flags & STP4020_SOCKET_ENABLING) &&
495 		    (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON)))
496 			r = 1;
497 	}
498 
499 	splx(s);
500 
501 	return (r);
502 }
503 
504 int
505 stp4020_iointr(arg)
506 	void *arg;
507 {
508 	struct stp4020_softc *sc = arg;
509 	int i, r = 0;
510 	int s;
511 
512 	/* protect hardware access against soft interrupts */
513 	s = splhigh();
514 
515 	/*
516 	 * Check each socket for pending requests.
517 	 */
518 	for (i = 0 ; i < STP4020_NSOCK; i++) {
519 		struct stp4020_socket *h;
520 		int v;
521 
522 		h = &sc->sc_socks[i];
523 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
524 
525 		if ((v & STP4020_ISR0_IOINT) != 0) {
526 			/* we can not deny this is ours, no matter what the
527 			   card driver says. */
528 			r = 1;
529 
530 			/* ack interrupt */
531 			stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
532 
533 			/* It's a card interrupt */
534 			if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
535 				printf("stp4020[%d]: spurious interrupt?\n",
536 				    h->sock);
537 				continue;
538 			}
539 			/* Call card handler, if any */
540 			if (h->softint != NULL) {
541 				softintr_schedule(h->softint);
542 
543 				/*
544 				 * Disable this sbus interrupt, until the
545 				 * softintr handler had a chance to run.
546 				 */
547 				stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
548 				    h->int_disable);
549 			}
550 		}
551 
552 	}
553 
554 	splx(s);
555 
556 	return (r);
557 }
558 
559 /*
560  * The function gets the sbus speed and a access time and calculates
561  * values for the CMDLNG and CMDDLAY registers.
562  */
563 void
564 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
565 {
566 	int result;
567 
568 	if (ns < STP4020_MEM_SPEED_MIN)
569 		ns = STP4020_MEM_SPEED_MIN;
570 	else if (ns > STP4020_MEM_SPEED_MAX)
571 		ns = STP4020_MEM_SPEED_MAX;
572 	result = ns * (bus_speed / 1000);
573 	if (result % 1000000)
574 		result = result / 1000000 + 1;
575 	else
576 		result /= 1000000;
577 	*length = result;
578 
579 	/* the sbus frequency range is limited, so we can keep this simple */
580 	*delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2;
581 }
582 
583 void
584 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
585 {
586 	int v, length, delay;
587 
588 	/*
589 	 * According to the PC Card standard 300ns access timing should be
590 	 * used for attribute memory access. Our pcmcia framework does not
591 	 * seem to propagate timing information, so we use that
592 	 * everywhere.
593 	 */
594 	stp4020_calc_speed(speed, 300, &length, &delay);
595 
596 	/*
597 	 * Fill in the Address Space Select and Base Address
598 	 * fields of this windows control register 0.
599 	 */
600 	v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) |
601 	    ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M);
602 	switch (win) {
603 	case STP_WIN_ATTR:
604 		v |= STP4020_WCR0_ASPSEL_AM;
605 		break;
606 	case STP_WIN_MEM:
607 		v |= STP4020_WCR0_ASPSEL_CM;
608 		break;
609 	case STP_WIN_IO:
610 		v |= STP4020_WCR0_ASPSEL_IO;
611 		break;
612 	}
613 	v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
614 	stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
615 	stp4020_wr_winctl(h, win, STP4020_WCR1_IDX,
616 	    1 << STP4020_WCR1_WAITREQ_S);
617 }
618 
619 int
620 stp4020_chip_mem_alloc(pch, size, pcmhp)
621 	pcmcia_chipset_handle_t pch;
622 	bus_size_t size;
623 	struct pcmcia_mem_handle *pcmhp;
624 {
625 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
626 
627 	/* we can not do much here, defere work to _mem_map */
628 	pcmhp->memt = h->wintag;
629 	pcmhp->size = size;
630 	pcmhp->addr = 0;
631 	pcmhp->mhandle = 0;
632 	pcmhp->realsize = size;
633 
634 	return (0);
635 }
636 
637 void
638 stp4020_chip_mem_free(pch, pcmhp)
639 	pcmcia_chipset_handle_t pch;
640 	struct pcmcia_mem_handle *pcmhp;
641 {
642 }
643 
644 int
645 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
646 	pcmcia_chipset_handle_t pch;
647 	int kind;
648 	bus_addr_t card_addr;
649 	bus_size_t size;
650 	struct pcmcia_mem_handle *pcmhp;
651 	bus_size_t *offsetp;
652 	int *windowp;
653 {
654 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
655 	int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM;
656 
657 	pcmhp->memt = h->wintag;
658 	bus_space_subregion(h->wintag, h->windows[win].winaddr,
659 	    card_addr, size, &pcmhp->memh);
660 	pcmhp->size = size;
661 	pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
662 	*offsetp = 0;
663 	*windowp = win;
664 
665 	return (0);
666 }
667 
668 void
669 stp4020_chip_mem_unmap(pch, win)
670 	pcmcia_chipset_handle_t pch;
671 	int win;
672 {
673 }
674 
675 int
676 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
677 	pcmcia_chipset_handle_t pch;
678 	bus_addr_t start;
679 	bus_size_t size;
680 	bus_size_t align;
681 	struct pcmcia_io_handle *pcihp;
682 {
683 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
684 
685 	pcihp->iot = h->wintag;
686 	pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
687 	pcihp->size = size;
688 	return (0);
689 }
690 
691 void
692 stp4020_chip_io_free(pch, pcihp)
693 	pcmcia_chipset_handle_t pch;
694 	struct pcmcia_io_handle *pcihp;
695 {
696 }
697 
698 int
699 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
700 	pcmcia_chipset_handle_t pch;
701 	int width;
702 	bus_addr_t offset;
703 	bus_size_t size;
704 	struct pcmcia_io_handle *pcihp;
705 	int *windowp;
706 {
707 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
708 
709 	pcihp->iot = h->wintag;
710 	bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr,
711 	    offset, size, &pcihp->ioh);
712 	*windowp = 0;
713 	return (0);
714 }
715 
716 void
717 stp4020_chip_io_unmap(pch, win)
718 	pcmcia_chipset_handle_t pch;
719 	int win;
720 {
721 }
722 
723 void
724 stp4020_chip_socket_enable(pch)
725 	pcmcia_chipset_handle_t pch;
726 {
727 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
728 	int i, v;
729 
730 	h->flags |= STP4020_SOCKET_ENABLING;
731 
732 	/* this bit is mostly stolen from pcic_attach_card */
733 
734 	/* Power down the socket to reset it, clear the card reset pin */
735 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
736 
737 	/*
738 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
739 	 * we are changing Vcc (Toff).
740 	 */
741 	stp4020_delay((300 + 100) * 1000);
742 
743 	/* Power up the socket */
744 	v = STP4020_ICR1_MSTPWR;
745 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
746 
747 	/*
748 	 * wait 100ms until power raise (Tpr) and 20ms to become
749 	 * stable (Tsu(Vcc)).
750 	 *
751 	 * some machines require some more time to be settled
752 	 * (another 200ms is added here).
753 	 */
754 	stp4020_delay((100 + 20 + 200) * 1000);
755 
756 	v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC;
757 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
758 
759 	/*
760 	 * hold RESET at least 20us.
761 	 */
762 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
763 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET);
764 	delay(20);
765 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
766 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET);
767 
768 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
769 	stp4020_delay(20000);
770 
771 	/* Wait for the chip to finish initializing (5 seconds max) */
772 	for (i = 10000; i > 0; i--) {
773 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
774 		/* If the card has been removed, abort */
775 		if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) {
776 			h->flags &= ~STP4020_SOCKET_ENABLING;
777 			return;
778 		}
779 		if ((v & STP4020_ISR0_RDYST) != 0)
780 			break;
781 		delay(500);
782 	}
783 	if (i <= 0) {
784 #ifdef STP4020_DEBUG
785 		printf("stp4020_chip_socket_enable: not ready: status %b\n",
786 		    v, STP4020_ISR0_IOBITS);
787 #endif
788 		h->flags &= ~STP4020_SOCKET_ENABLING;
789 		return;
790 	}
791 
792 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
793 
794 	/*
795 	 * Check the card type.
796 	 * Enable socket I/O interrupts for IO cards.
797 	 * We use level SB_INT[0] for I/O interrupts.
798 	 */
799 	if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
800 		v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE);
801 		v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE |
802 		    STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN;
803 		h->int_enable = v;
804 		h->int_disable = v & ~STP4020_ICR0_IOIE;
805 		DPRINTF(("%s: configuring card for IO usage\n",
806 		    h->sc->sc_dev.dv_xname));
807 	} else {
808 		v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
809 		    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
810 		v |= STP4020_ICR0_IFTYPE_MEM;
811 		h->int_enable = h->int_disable = v;
812 		DPRINTF(("%s: configuring card for MEM ONLY usage\n",
813 		    h->sc->sc_dev.dv_xname));
814 	}
815 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
816 
817 	h->flags &= ~STP4020_SOCKET_ENABLING;
818 }
819 
820 void
821 stp4020_chip_socket_disable(pch)
822 	pcmcia_chipset_handle_t pch;
823 {
824 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
825 	int v;
826 
827 	/*
828 	 * Disable socket I/O interrupts.
829 	 */
830 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
831 	v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
832 	    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
833 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
834 
835 	/* Power down the socket */
836 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
837 
838 	/*
839 	 * wait 300ms until power fails (Tpf).
840 	 */
841 	stp4020_delay(300 * 1000);
842 }
843 
844 void *
845 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname)
846 	pcmcia_chipset_handle_t pch;
847 	struct pcmcia_function *pf;
848 	int ipl;
849 	int (*handler) (void *);
850 	void *arg;
851 	char *xname;
852 {
853 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
854 
855 	/*
856 	 * Note that this code relies on softintr_establish() to be
857 	 * used with real, hardware ipl values. All platforms with
858 	 * SBus support support this.
859 	 */
860 	h->intrhandler = handler;
861 	h->intrarg = arg;
862 	h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h);
863 
864 	return h->softint != NULL ? h : NULL;
865 }
866 
867 void
868 stp4020_chip_intr_disestablish(pch, ih)
869 	pcmcia_chipset_handle_t pch;
870 	void *ih;
871 {
872 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
873 
874 	if (h->softint != NULL) {
875 		softintr_disestablish(h->softint);
876 		h->softint = NULL;
877 	}
878 	h->intrhandler = NULL;
879 	h->intrarg = NULL;
880 }
881 
882 const char *
883 stp4020_chip_intr_string(pch, ih)
884 	pcmcia_chipset_handle_t pch;
885 	void *ih;
886 {
887 	if (ih == NULL)
888 		return ("couldn't establish interrupt");
889 	else
890 		return ("");	/* nothing for now */
891 }
892 
893 /*
894  * Delay and possibly yield CPU.
895  * XXX - assumes a context
896  */
897 void
898 stp4020_delay(ms)
899 	unsigned int ms;
900 {
901 	unsigned int nticks;
902 
903 	/* Convert to nticks */
904 	nticks = (ms * hz) / 1000000;
905 
906 	if (cold || nticks == 0) {
907 		delay(ms);
908 		return;
909 	}
910 
911 #ifdef DEBUG
912 	if (nticks > 60 * hz)
913 		panic("stp4020: preposterous delay: %u", nticks);
914 #endif
915 	tsleep(&nticks, 0, "stp4020_delay", nticks);
916 }
917 
918 #ifdef STP4020_DEBUG
919 void
920 stp4020_dump_regs(h)
921 	struct stp4020_socket *h;
922 {
923 	/*
924 	 * Dump control and status registers.
925 	 */
926 	printf("socket[%d] registers:\n"
927 	    "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock,
928 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS,
929 	    stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS,
930 	    stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS,
931 	    stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
932 }
933 #endif /* STP4020_DEBUG */
934