xref: /openbsd/sys/dev/sbus/stp4020.c (revision 404b540a)
1 /*	$OpenBSD: stp4020.c,v 1.16 2009/04/10 20:54:58 miod 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 	const char *name = sc->sc_dev.dv_xname;
299 
300 	if (kthread_create(stp4020_event_thread, sc, &sc->event_thread,
301 	    "%s", name)) {
302 		panic("%s: unable to create event thread", name);
303 	}
304 }
305 
306 /*
307  * The actual event handling thread.
308  */
309 void
310 stp4020_event_thread(arg)
311 	void *arg;
312 {
313 	struct stp4020_softc *sc = arg;
314 	int s, sense;
315 	unsigned int socket;
316 
317 	for (;;) {
318 		struct stp4020_socket *h;
319 
320 		s = splhigh();
321 		if ((socket = ffs(sc->events)) == 0) {
322 			splx(s);
323 			(void)tsleep(&sc->events, PWAIT, "stp4020_ev", 0);
324 			continue;
325 		}
326 		socket--;
327 		sc->events &= ~(1 << socket);
328 		splx(s);
329 
330 		if (socket >= STP4020_NSOCK) {
331 #ifdef DEBUG
332 			printf("stp4020_event_thread: wayward socket number %d\n",
333 			    socket);
334 #endif
335 			continue;
336 		}
337 
338 		h = &sc->sc_socks[socket];
339 
340 		/* Read socket's ISR0 for the interrupt status bits */
341 		sense = stp4020_rd_sockctl(h, STP4020_ISR0_IDX) &
342 		    (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
343 
344 		if (sense > h->sense) {
345 			/*
346 			 * If at least one more sensor is asserted, this is
347 			 * a card insertion.
348 			 */
349 			h->sense = sense;
350 			if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
351 				h->flags |= STP4020_SOCKET_BUSY;
352 				pcmcia_card_attach(h->pcmcia);
353 			}
354 		} else if (sense < h->sense) {
355 			/*
356 			 * If at least one less sensor is asserted, this is
357 			 * a card removal.
358 			 */
359 			h->sense = sense;
360 			if (h->flags & STP4020_SOCKET_BUSY) {
361 				h->flags &= ~STP4020_SOCKET_BUSY;
362 				pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
363 			}
364 		}
365 	}
366 }
367 
368 void
369 stp4020_queue_event(sc, sock)
370 	struct stp4020_softc *sc;
371 	int sock;
372 {
373 	int s;
374 
375 	s = splhigh();
376 	sc->events |= (1 << sock);
377 	splx(s);
378 	wakeup(&sc->events);
379 }
380 
381 /*
382  * Software interrupt called to invoke the real driver interrupt handler.
383  */
384 void
385 stp4020_intr_dispatch(void *arg)
386 {
387 	struct stp4020_socket *h = (struct stp4020_socket *)arg;
388 	int s;
389 
390 	/* invoke driver handler */
391 	h->intrhandler(h->intrarg);
392 
393 	/* enable SBUS interrupts for PCMCIA interrupts again */
394 	s = splhigh();
395 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
396 	splx(s);
397 }
398 
399 int
400 stp4020_statintr(arg)
401 	void *arg;
402 {
403 	struct stp4020_softc *sc = arg;
404 	int i, sense, r = 0;
405 	int s;
406 
407 	/* protect hardware access against soft interrupts */
408 	s = splhigh();
409 
410 	/*
411 	 * Check each socket for pending requests.
412 	 */
413 	for (i = 0 ; i < STP4020_NSOCK; i++) {
414 		struct stp4020_socket *h;
415 		int v;
416 
417 		h = &sc->sc_socks[i];
418 
419 		/* Read socket's ISR0 for the interrupt status bits */
420 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
421 		sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
422 
423 #ifdef STP4020_DEBUG
424 		if (stp4020_debug != 0)
425 			printf("stp4020_statintr: ISR0=%b\n",
426 			    v, STP4020_ISR0_IOBITS);
427 #endif
428 
429 		/* Ack all interrupts at once */
430 		stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
431 		    STP4020_ISR0_ALL_STATUS_IRQ);
432 
433 		if ((v & STP4020_ISR0_CDCHG) != 0) {
434 			r = 1;
435 
436 			/*
437 			 * Card detect status changed. In an ideal world,
438 			 * both card detect sensors should be set if a card
439 			 * is in the slot, and clear if it is not.
440 			 *
441 			 * Unfortunately, it turns out that we can get the
442 			 * notification before both sensors are set (or
443 			 * clear).
444 			 *
445 			 * This can be very funny if only one sensor is set.
446 			 * Is this a removal or an insertion operation?
447 			 * Defer appropriate action to the worker thread.
448 			 */
449 			if (sense != h->sense)
450 				stp4020_queue_event(sc, i);
451 
452 		}
453 
454 		/* informational messages */
455 		if ((v & STP4020_ISR0_BVD1CHG) != 0) {
456 			DPRINTF(("stp4020[%d]: Battery change 1\n",
457 			    h->sock));
458 			r = 1;
459 		}
460 
461 		if ((v & STP4020_ISR0_BVD2CHG) != 0) {
462 			DPRINTF(("stp4020[%d]: Battery change 2\n",
463 			    h->sock));
464 			r = 1;
465 		}
466 
467 		if ((v & STP4020_ISR0_RDYCHG) != 0) {
468 			DPRINTF(("stp4020[%d]: Ready/Busy change\n",
469 			    h->sock));
470 			r = 1;
471 		}
472 
473 		if ((v & STP4020_ISR0_WPCHG) != 0) {
474 			DPRINTF(("stp4020[%d]: Write protect change\n",
475 			    h->sock));
476 			r = 1;
477 		}
478 
479 		if ((v & STP4020_ISR0_PCTO) != 0) {
480 			DPRINTF(("stp4020[%d]: Card access timeout\n",
481 			    h->sock));
482 			r = 1;
483 		}
484 
485 		if ((v & STP4020_ISR0_SCINT) != 0) {
486 			DPRINTF(("stp4020[%d]: Status change\n",
487 			    h->sock));
488 			r = 1;
489 		}
490 
491 		/*
492 		 * Not interrupts flag per se, but interrupts can occur when
493 		 * they are asserted, at least during our slot enable routine.
494 		 */
495 		if ((h->flags & STP4020_SOCKET_ENABLING) &&
496 		    (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON)))
497 			r = 1;
498 	}
499 
500 	splx(s);
501 
502 	return (r);
503 }
504 
505 int
506 stp4020_iointr(arg)
507 	void *arg;
508 {
509 	struct stp4020_softc *sc = arg;
510 	int i, r = 0;
511 	int s;
512 
513 	/* protect hardware access against soft interrupts */
514 	s = splhigh();
515 
516 	/*
517 	 * Check each socket for pending requests.
518 	 */
519 	for (i = 0 ; i < STP4020_NSOCK; i++) {
520 		struct stp4020_socket *h;
521 		int v;
522 
523 		h = &sc->sc_socks[i];
524 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
525 
526 		if ((v & STP4020_ISR0_IOINT) != 0) {
527 			/* we can not deny this is ours, no matter what the
528 			   card driver says. */
529 			r = 1;
530 
531 			/* ack interrupt */
532 			stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
533 
534 			/* It's a card interrupt */
535 			if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
536 				printf("stp4020[%d]: spurious interrupt?\n",
537 				    h->sock);
538 				continue;
539 			}
540 			/* Call card handler, if any */
541 			if (h->softint != NULL) {
542 				softintr_schedule(h->softint);
543 
544 				/*
545 				 * Disable this sbus interrupt, until the
546 				 * softintr handler had a chance to run.
547 				 */
548 				stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
549 				    h->int_disable);
550 			}
551 		}
552 
553 	}
554 
555 	splx(s);
556 
557 	return (r);
558 }
559 
560 /*
561  * The function gets the sbus speed and a access time and calculates
562  * values for the CMDLNG and CMDDLAY registers.
563  */
564 void
565 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
566 {
567 	int result;
568 
569 	if (ns < STP4020_MEM_SPEED_MIN)
570 		ns = STP4020_MEM_SPEED_MIN;
571 	else if (ns > STP4020_MEM_SPEED_MAX)
572 		ns = STP4020_MEM_SPEED_MAX;
573 	result = ns * (bus_speed / 1000);
574 	if (result % 1000000)
575 		result = result / 1000000 + 1;
576 	else
577 		result /= 1000000;
578 	*length = result;
579 
580 	/* the sbus frequency range is limited, so we can keep this simple */
581 	*delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2;
582 }
583 
584 void
585 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
586 {
587 	int v, length, delay;
588 
589 	/*
590 	 * According to the PC Card standard 300ns access timing should be
591 	 * used for attribute memory access. Our pcmcia framework does not
592 	 * seem to propagate timing information, so we use that
593 	 * everywhere.
594 	 */
595 	stp4020_calc_speed(speed, 300, &length, &delay);
596 
597 	/*
598 	 * Fill in the Address Space Select and Base Address
599 	 * fields of this windows control register 0.
600 	 */
601 	v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) |
602 	    ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M);
603 	switch (win) {
604 	case STP_WIN_ATTR:
605 		v |= STP4020_WCR0_ASPSEL_AM;
606 		break;
607 	case STP_WIN_MEM:
608 		v |= STP4020_WCR0_ASPSEL_CM;
609 		break;
610 	case STP_WIN_IO:
611 		v |= STP4020_WCR0_ASPSEL_IO;
612 		break;
613 	}
614 	v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
615 	stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
616 	stp4020_wr_winctl(h, win, STP4020_WCR1_IDX,
617 	    1 << STP4020_WCR1_WAITREQ_S);
618 }
619 
620 int
621 stp4020_chip_mem_alloc(pch, size, pcmhp)
622 	pcmcia_chipset_handle_t pch;
623 	bus_size_t size;
624 	struct pcmcia_mem_handle *pcmhp;
625 {
626 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
627 
628 	/* we can not do much here, defere work to _mem_map */
629 	pcmhp->memt = h->wintag;
630 	pcmhp->size = size;
631 	pcmhp->addr = 0;
632 	pcmhp->mhandle = 0;
633 	pcmhp->realsize = size;
634 
635 	return (0);
636 }
637 
638 void
639 stp4020_chip_mem_free(pch, pcmhp)
640 	pcmcia_chipset_handle_t pch;
641 	struct pcmcia_mem_handle *pcmhp;
642 {
643 }
644 
645 int
646 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
647 	pcmcia_chipset_handle_t pch;
648 	int kind;
649 	bus_addr_t card_addr;
650 	bus_size_t size;
651 	struct pcmcia_mem_handle *pcmhp;
652 	bus_size_t *offsetp;
653 	int *windowp;
654 {
655 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
656 	int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM;
657 
658 	pcmhp->memt = h->wintag;
659 	bus_space_subregion(h->wintag, h->windows[win].winaddr,
660 	    card_addr, size, &pcmhp->memh);
661 	pcmhp->size = size;
662 	pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
663 	*offsetp = 0;
664 	*windowp = win;
665 
666 	return (0);
667 }
668 
669 void
670 stp4020_chip_mem_unmap(pch, win)
671 	pcmcia_chipset_handle_t pch;
672 	int win;
673 {
674 }
675 
676 int
677 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
678 	pcmcia_chipset_handle_t pch;
679 	bus_addr_t start;
680 	bus_size_t size;
681 	bus_size_t align;
682 	struct pcmcia_io_handle *pcihp;
683 {
684 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
685 
686 	pcihp->iot = h->wintag;
687 	pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
688 	pcihp->size = size;
689 	return (0);
690 }
691 
692 void
693 stp4020_chip_io_free(pch, pcihp)
694 	pcmcia_chipset_handle_t pch;
695 	struct pcmcia_io_handle *pcihp;
696 {
697 }
698 
699 int
700 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
701 	pcmcia_chipset_handle_t pch;
702 	int width;
703 	bus_addr_t offset;
704 	bus_size_t size;
705 	struct pcmcia_io_handle *pcihp;
706 	int *windowp;
707 {
708 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
709 
710 	pcihp->iot = h->wintag;
711 	bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr,
712 	    offset, size, &pcihp->ioh);
713 	*windowp = 0;
714 	return (0);
715 }
716 
717 void
718 stp4020_chip_io_unmap(pch, win)
719 	pcmcia_chipset_handle_t pch;
720 	int win;
721 {
722 }
723 
724 void
725 stp4020_chip_socket_enable(pch)
726 	pcmcia_chipset_handle_t pch;
727 {
728 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
729 	int i, v;
730 
731 	h->flags |= STP4020_SOCKET_ENABLING;
732 
733 	/* this bit is mostly stolen from pcic_attach_card */
734 
735 	/* Power down the socket to reset it, clear the card reset pin */
736 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
737 
738 	/*
739 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
740 	 * we are changing Vcc (Toff).
741 	 */
742 	stp4020_delay((300 + 100) * 1000);
743 
744 	/* Power up the socket */
745 	v = STP4020_ICR1_MSTPWR;
746 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
747 
748 	/*
749 	 * wait 100ms until power raise (Tpr) and 20ms to become
750 	 * stable (Tsu(Vcc)).
751 	 *
752 	 * some machines require some more time to be settled
753 	 * (another 200ms is added here).
754 	 */
755 	stp4020_delay((100 + 20 + 200) * 1000);
756 
757 	v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC;
758 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
759 
760 	/*
761 	 * hold RESET at least 20us.
762 	 */
763 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
764 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET);
765 	delay(20);
766 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
767 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET);
768 
769 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
770 	stp4020_delay(20000);
771 
772 	/* Wait for the chip to finish initializing (5 seconds max) */
773 	for (i = 10000; i > 0; i--) {
774 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
775 		/* If the card has been removed, abort */
776 		if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) {
777 			h->flags &= ~STP4020_SOCKET_ENABLING;
778 			return;
779 		}
780 		if ((v & STP4020_ISR0_RDYST) != 0)
781 			break;
782 		delay(500);
783 	}
784 	if (i <= 0) {
785 #ifdef STP4020_DEBUG
786 		printf("stp4020_chip_socket_enable: not ready: status %b\n",
787 		    v, STP4020_ISR0_IOBITS);
788 #endif
789 		h->flags &= ~STP4020_SOCKET_ENABLING;
790 		return;
791 	}
792 
793 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
794 
795 	/*
796 	 * Check the card type.
797 	 * Enable socket I/O interrupts for IO cards.
798 	 * We use level SB_INT[0] for I/O interrupts.
799 	 */
800 	if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
801 		v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE);
802 		v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE |
803 		    STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN;
804 		h->int_enable = v;
805 		h->int_disable = v & ~STP4020_ICR0_IOIE;
806 		DPRINTF(("%s: configuring card for IO usage\n",
807 		    h->sc->sc_dev.dv_xname));
808 	} else {
809 		v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
810 		    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
811 		v |= STP4020_ICR0_IFTYPE_MEM;
812 		h->int_enable = h->int_disable = v;
813 		DPRINTF(("%s: configuring card for MEM ONLY usage\n",
814 		    h->sc->sc_dev.dv_xname));
815 	}
816 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
817 
818 	h->flags &= ~STP4020_SOCKET_ENABLING;
819 }
820 
821 void
822 stp4020_chip_socket_disable(pch)
823 	pcmcia_chipset_handle_t pch;
824 {
825 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
826 	int v;
827 
828 	/*
829 	 * Disable socket I/O interrupts.
830 	 */
831 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
832 	v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
833 	    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
834 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
835 
836 	/* Power down the socket */
837 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
838 
839 	/*
840 	 * wait 300ms until power fails (Tpf).
841 	 */
842 	stp4020_delay(300 * 1000);
843 }
844 
845 void *
846 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname)
847 	pcmcia_chipset_handle_t pch;
848 	struct pcmcia_function *pf;
849 	int ipl;
850 	int (*handler) (void *);
851 	void *arg;
852 	char *xname;
853 {
854 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
855 
856 	/*
857 	 * Note that this code relies on softintr_establish() to be
858 	 * used with real, hardware ipl values. All platforms with
859 	 * SBus support support this.
860 	 */
861 	h->intrhandler = handler;
862 	h->intrarg = arg;
863 	h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h);
864 
865 	return h->softint != NULL ? h : NULL;
866 }
867 
868 void
869 stp4020_chip_intr_disestablish(pch, ih)
870 	pcmcia_chipset_handle_t pch;
871 	void *ih;
872 {
873 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
874 
875 	if (h->softint != NULL) {
876 		softintr_disestablish(h->softint);
877 		h->softint = NULL;
878 	}
879 	h->intrhandler = NULL;
880 	h->intrarg = NULL;
881 }
882 
883 const char *
884 stp4020_chip_intr_string(pch, ih)
885 	pcmcia_chipset_handle_t pch;
886 	void *ih;
887 {
888 	if (ih == NULL)
889 		return ("couldn't establish interrupt");
890 	else
891 		return ("");	/* nothing for now */
892 }
893 
894 /*
895  * Delay and possibly yield CPU.
896  * XXX - assumes a context
897  */
898 void
899 stp4020_delay(ms)
900 	unsigned int ms;
901 {
902 	unsigned int ticks;
903 
904 	/* Convert to ticks */
905 	ticks = (ms * hz) / 1000000;
906 
907 	if (cold || ticks == 0) {
908 		delay(ms);
909 		return;
910 	}
911 
912 #ifdef DEBUG
913 	if (ticks > 60 * hz)
914 		panic("stp4020: preposterous delay: %u", ticks);
915 #endif
916 	tsleep(&ticks, 0, "stp4020_delay", ticks);
917 }
918 
919 #ifdef STP4020_DEBUG
920 void
921 stp4020_dump_regs(h)
922 	struct stp4020_socket *h;
923 {
924 	/*
925 	 * Dump control and status registers.
926 	 */
927 	printf("socket[%d] registers:\n"
928 	    "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock,
929 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS,
930 	    stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS,
931 	    stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS,
932 	    stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
933 }
934 #endif /* STP4020_DEBUG */
935