xref: /netbsd-src/sys/dev/sbus/stp4020.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: stp4020.c,v 1.11 2000/07/09 20:57:44 pk Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards.
41  */
42 
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/errno.h>
47 #include <sys/malloc.h>
48 #include <sys/proc.h>
49 #include <sys/kernel.h>
50 #include <sys/kthread.h>
51 #include <sys/device.h>
52 
53 #include <dev/pcmcia/pcmciareg.h>
54 #include <dev/pcmcia/pcmciavar.h>
55 #include <dev/pcmcia/pcmciachip.h>
56 
57 #include <machine/bus.h>
58 #include <machine/intr.h>
59 
60 #include <dev/sbus/sbusvar.h>
61 #include <dev/sbus/stp4020reg.h>
62 
63 #define STP4020_DEBUG 1	/* XXX-temp */
64 
65 #if defined(STP4020_DEBUG)
66 int stp4020_debug = 0;
67 #define DPRINTF(x)	do { if (stp4020_debug) printf x; } while(0)
68 #else
69 #define DPRINTF(x)
70 #endif
71 
72 /*
73  * Event queue; events detected in an interrupt context go here
74  * awaiting attention from our event handling thread.
75  */
76 struct stp4020_event {
77 	SIMPLEQ_ENTRY(stp4020_event) se_q;
78 	int	se_type;
79 	int	se_sock;
80 };
81 /* Defined event types */
82 #define STP4020_EVENT_INSERTION	0
83 #define STP4020_EVENT_REMOVAL	1
84 
85 /*
86  * Per socket data.
87  */
88 struct stp4020_socket {
89 	struct stp4020_softc	*sc;	/* Back link */
90 	int		flags;
91 #define STP4020_SOCKET_BUSY	0x0001
92 #define STP4020_SOCKET_SHUTDOWN	0x0002
93 	int		sock;		/* Socket number (0 or 1) */
94 	bus_space_tag_t	tag;		/* socket control space */
95 	bus_space_handle_t	regs;	/* 			*/
96 	struct device	*pcmcia;	/* Associated PCMCIA device */
97 	int		(*intrhandler)	/* Card driver interrupt handler */
98 			    __P((void *));
99 	void		*intrarg;	/* Card interrupt handler argument */
100 	int		ipl;		/* Interrupt level suggested by card */
101 	int		winalloc;	/* Windows allocated (bitmask) */
102 	struct {
103 		bus_space_handle_t	winaddr;/* this window's address */
104 	} windows[STP4020_NWIN];
105 
106 };
107 
108 struct stp4020_softc {
109 	struct device	sc_dev;		/* Base device */
110 	struct sbusdev	sc_sd;		/* SBus device */
111 	bus_space_tag_t	sc_bustag;
112 	bus_dma_tag_t	sc_dmatag;
113 	pcmcia_chipset_tag_t	sc_pct;	/* Chipset methods */
114 
115 	struct proc	*event_thread;		/* event handling thread */
116 	SIMPLEQ_HEAD(, stp4020_event)	events;	/* Pending events for thread */
117 
118 	struct stp4020_socket sc_socks[STP4020_NSOCK];
119 };
120 
121 
122 static int	stp4020print	__P((void *, const char *));
123 static int	stp4020match	__P((struct device *, struct cfdata *, void *));
124 static void	stp4020attach	__P((struct device *, struct device *, void *));
125 static int	stp4020_iointr	__P((void *));
126 static int	stp4020_statintr __P((void *));
127 
128 struct cfattach nell_ca = {
129 	sizeof(struct stp4020_softc), stp4020match, stp4020attach
130 };
131 
132 #ifdef STP4020_DEBUG
133 static void	stp4020_dump_regs __P((struct stp4020_socket *));
134 #endif
135 
136 static int	stp4020_rd_sockctl __P((struct stp4020_socket *, int));
137 static void	stp4020_wr_sockctl __P((struct stp4020_socket *, int, int));
138 static int	stp4020_rd_winctl __P((struct stp4020_socket *, int, int));
139 static void	stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int));
140 
141 void	stp4020_delay __P((unsigned int));
142 void	stp4020_attach_socket __P((struct stp4020_socket *));
143 void	stp4020_create_event_thread __P((void *));
144 void	stp4020_event_thread __P((void *));
145 void	stp4020_queue_event __P((struct stp4020_softc *, int, int));
146 
147 int	stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
148 				    struct pcmcia_mem_handle *));
149 void	stp4020_chip_mem_free __P((pcmcia_chipset_handle_t,
150 				   struct pcmcia_mem_handle *));
151 int	stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
152 				  bus_size_t, struct pcmcia_mem_handle *,
153 				  bus_addr_t *, int *));
154 void	stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int));
155 
156 int	stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t,
157 				   bus_addr_t, bus_size_t, bus_size_t,
158 				   struct pcmcia_io_handle *));
159 void	stp4020_chip_io_free __P((pcmcia_chipset_handle_t,
160 				  struct pcmcia_io_handle *));
161 int	stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
162 				 bus_size_t, struct pcmcia_io_handle *, int *));
163 void	stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
164 
165 void	stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t));
166 void	stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t));
167 void	*stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t,
168 					  struct pcmcia_function *, int,
169 					  int (*) __P((void *)), void *));
170 void	stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
171 
172 
173 /* Our PCMCIA chipset methods */
174 static struct pcmcia_chip_functions stp4020_functions = {
175 	stp4020_chip_mem_alloc,
176 	stp4020_chip_mem_free,
177 	stp4020_chip_mem_map,
178 	stp4020_chip_mem_unmap,
179 
180 	stp4020_chip_io_alloc,
181 	stp4020_chip_io_free,
182 	stp4020_chip_io_map,
183 	stp4020_chip_io_unmap,
184 
185 	stp4020_chip_intr_establish,
186 	stp4020_chip_intr_disestablish,
187 
188 	stp4020_chip_socket_enable,
189 	stp4020_chip_socket_disable
190 };
191 
192 
193 static __inline__ int
194 stp4020_rd_sockctl(h, idx)
195 	struct stp4020_socket *h;
196 	int idx;
197 {
198 	int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
199 	return (bus_space_read_2(h->tag, h->regs, o));
200 }
201 
202 static __inline__ void
203 stp4020_wr_sockctl(h, idx, v)
204 	struct stp4020_socket *h;
205 	int idx;
206 	int v;
207 {
208 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
209 	bus_space_write_2(h->tag, h->regs, o, v);
210 }
211 
212 static __inline__ int
213 stp4020_rd_winctl(h, win, idx)
214 	struct stp4020_socket *h;
215 	int win;
216 	int idx;
217 {
218 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
219 		(STP4020_WINREGS_SIZE * win) + idx;
220 	return (bus_space_read_2(h->tag, h->regs, o));
221 }
222 
223 static __inline__ void
224 stp4020_wr_winctl(h, win, idx, v)
225 	struct stp4020_socket *h;
226 	int win;
227 	int idx;
228 	int v;
229 {
230 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
231 		(STP4020_WINREGS_SIZE * win) + idx;
232 
233 	bus_space_write_2(h->tag, h->regs, o, v);
234 }
235 
236 
237 int
238 stp4020print(aux, busname)
239 	void *aux;
240 	const char *busname;
241 {
242 	struct pcmciabus_attach_args *paa = aux;
243 	struct stp4020_socket *h = paa->pch;
244 
245 	printf(" socket %d", h->sock);
246 	return (UNCONF);
247 }
248 
249 int
250 stp4020match(parent, cf, aux)
251 	struct device *parent;
252 	struct cfdata *cf;
253 	void *aux;
254 {
255 	struct sbus_attach_args *sa = aux;
256 
257 	return (strcmp("SUNW,pcmcia", sa->sa_name) == 0);
258 }
259 
260 /*
261  * Attach all the sub-devices we can find
262  */
263 void
264 stp4020attach(parent, self, aux)
265 	struct device *parent, *self;
266 	void *aux;
267 {
268 	struct sbus_attach_args *sa = aux;
269 	struct stp4020_softc *sc = (void *)self;
270 	int node, rev;
271 	int i;
272 	bus_space_handle_t bh;
273 
274 	node = sa->sa_node;
275 
276 	/* Transfer bus tags */
277 	sc->sc_bustag = sa->sa_bustag;
278 	sc->sc_dmatag = sa->sa_dmatag;
279 
280 	/* Set up per-socket static initialization */
281 	sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
282 	sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag;
283 
284 	if (sa->sa_nreg < 8) {
285 		printf("%s: only %d register sets\n",
286 			self->dv_xname, sa->sa_nreg);
287 		return;
288 	}
289 
290 	if (sa->sa_nintr != 2) {
291 		printf("%s: expect 2 interrupt Sbus levels; got %d\n",
292 			self->dv_xname, sa->sa_nintr);
293 		return;
294 	}
295 
296 #define STP4020_BANK_PROM	0
297 #define STP4020_BANK_CTRL	4
298 	for (i = 0; i < 8; i++) {
299 
300 		/*
301 		 * STP4020 Register address map:
302 		 *	bank  0:   Forth PROM
303 		 *	banks 1-3: socket 0, windows 0-2
304 		 *	bank  4:   control registers
305 		 *	banks 5-7: socket 1, windows 0-2
306 		 */
307 
308 		if (i == STP4020_BANK_PROM)
309 			/* Skip the PROM */
310 			continue;
311 
312 		if (sbus_bus_map(sa->sa_bustag,
313 				 sa->sa_reg[i].sbr_slot,
314 				 sa->sa_reg[i].sbr_offset,
315 				 sa->sa_reg[i].sbr_size,
316 				 BUS_SPACE_MAP_LINEAR, 0,
317 				 &bh) != 0) {
318 			printf("%s: attach: cannot map registers\n",
319 				self->dv_xname);
320 			return;
321 		}
322 
323 		if (i == STP4020_BANK_CTRL) {
324 			/*
325 			 * Copy tag and handle to both socket structures
326 			 * for easy access in control/status IO functions.
327 			 */
328 			sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
329 		} else if (i < STP4020_BANK_CTRL) {
330 			/* banks 1-3 */
331 			sc->sc_socks[0].windows[i-1].winaddr = bh;
332 		} else {
333 			/* banks 5-7 */
334 			sc->sc_socks[1].windows[i-5].winaddr = bh;
335 		}
336 	}
337 
338 	sbus_establish(&sc->sc_sd, &sc->sc_dev);
339 
340 	/*
341 	 * We get to use two SBus interrupt levels.
342 	 * The higher level we use for status change interrupts;
343 	 * the lower level for PC card I/O.
344 	 */
345 	if (sa->sa_nintr != 0) {
346 		bus_intr_establish(sa->sa_bustag, sa->sa_intr[1].sbi_pri,
347 				   IPL_NONE, 0, stp4020_statintr, sc);
348 
349 		bus_intr_establish(sa->sa_bustag, sa->sa_intr[0].sbi_pri,
350 				   IPL_NONE, 0, stp4020_iointr, sc);
351 	}
352 
353 	rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
354 		STP4020_ISR1_REV_M;
355 	printf(": rev %x\n", rev);
356 
357 	sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
358 
359 	/*
360 	 * Arrange that a kernel thread be created to handle
361 	 * insert/removal events.
362 	 */
363 	SIMPLEQ_INIT(&sc->events);
364 	kthread_create(stp4020_create_event_thread, sc);
365 
366 	for (i = 0; i < STP4020_NSOCK; i++) {
367 		struct stp4020_socket *h = &sc->sc_socks[i];
368 		h->sock = i;
369 		h->sc = sc;
370 #ifdef STP4020_DEBUG
371 		stp4020_dump_regs(h);
372 #endif
373 		stp4020_attach_socket(h);
374 	}
375 }
376 
377 void
378 stp4020_attach_socket(h)
379 	struct stp4020_socket *h;
380 {
381 	struct pcmciabus_attach_args paa;
382 	int v;
383 
384 	/* Initialize the rest of the handle */
385 	h->winalloc = 0;
386 
387 	/* Configure one pcmcia device per socket */
388 	paa.paa_busname = "pcmcia";
389 	paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
390 	paa.pch = (pcmcia_chipset_handle_t)h;
391 	paa.iobase = 0;
392 	paa.iosize = 0;
393 
394 	h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
395 
396 	if (h->pcmcia == NULL)
397 		return;
398 
399 	/*
400 	 * There's actually a pcmcia bus attached; initialize the slot.
401 	 */
402 
403 	/*
404 	 * Enable socket status change interrupts.
405 	 * We use SB_INT[1] for status change interrupts.
406 	 */
407 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
408 	v |= STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
409 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
410 
411 	/* Get live status bits from ISR0 */
412 	v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
413 	if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
414 		return;
415 
416 	pcmcia_card_attach(h->pcmcia);
417 	h->flags |= STP4020_SOCKET_BUSY;
418 }
419 
420 
421 /*
422  * Deferred thread creation callback.
423  */
424 void
425 stp4020_create_event_thread(arg)
426 	void *arg;
427 {
428 	struct stp4020_softc *sc = arg;
429 	const char *name = sc->sc_dev.dv_xname;
430 
431 	if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread,
432 			   "%s", name)) {
433 		panic("%s: unable to create event thread", name);
434 	}
435 }
436 
437 /*
438  * The actual event handling thread.
439  */
440 void
441 stp4020_event_thread(arg)
442 	void *arg;
443 {
444 	struct stp4020_softc *sc = arg;
445 	struct stp4020_event *e;
446 	int s;
447 
448 	while (1) {
449 		struct stp4020_socket *h;
450 		int n;
451 
452 		s = splhigh();
453 		if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
454 			splx(s);
455 			(void)tsleep(&sc->events, PWAIT, "pcicev", 0);
456 			continue;
457 		}
458 		SIMPLEQ_REMOVE_HEAD(&sc->events, e, se_q);
459 		splx(s);
460 
461 		n = e->se_sock;
462 		if (n < 0 || n >= STP4020_NSOCK)
463 			panic("stp4020_event_thread: wayward socket number %d",
464 			      n);
465 
466 		h = &sc->sc_socks[n];
467 		switch (e->se_type) {
468 		case STP4020_EVENT_INSERTION:
469 			pcmcia_card_attach(h->pcmcia);
470 			break;
471 		case STP4020_EVENT_REMOVAL:
472 			pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
473 			break;
474 		default:
475 			panic("stp4020_event_thread: unknown event type %d",
476 			      e->se_type);
477 		}
478 		free(e, M_TEMP);
479 	}
480 }
481 
482 void
483 stp4020_queue_event(sc, sock, event)
484 	struct stp4020_softc *sc;
485 	int sock, event;
486 {
487 	struct stp4020_event *e;
488 	int s;
489 
490 	e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
491 	if (e == NULL)
492 		panic("stp4020_queue_event: can't allocate event");
493 
494 	e->se_type = event;
495 	e->se_sock = sock;
496 	s = splhigh();
497 	SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
498 	splx(s);
499 	wakeup(&sc->events);
500 }
501 
502 int
503 stp4020_statintr(arg)
504 	void *arg;
505 {
506 	struct stp4020_softc *sc = arg;
507 	int i, r = 0;
508 
509 	/*
510 	 * Check each socket for pending requests.
511 	 */
512 	for (i = 0 ; i < STP4020_NSOCK; i++) {
513 		struct stp4020_socket *h;
514 		int v;
515 
516 		h = &sc->sc_socks[i];
517 
518 		/* Read socket's ISR0 for the interrupt status bits */
519 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
520 
521 #ifdef STP4020_DEBUG
522 		if (stp4020_debug != 0) {
523 			char bits[64];
524 			bitmask_snprintf(v, STP4020_ISR0_IOBITS,
525 					 bits, sizeof(bits));
526 			printf("stp4020_statintr: ISR0=%s\n", bits);
527 		}
528 #endif
529 
530 		/* Ack all interrupts at once */
531 		stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
532 				   STP4020_ISR0_ALL_STATUS_IRQ);
533 
534 		if ((v & STP4020_ISR0_CDCHG) != 0) {
535 			/*
536 			 * Card status change detect
537 			 */
538 			if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) != 0){
539 				if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
540 					stp4020_queue_event(sc, i,
541 						STP4020_EVENT_INSERTION);
542 					h->flags |= STP4020_SOCKET_BUSY;
543 				}
544 			}
545 			if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
546 				if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
547 					stp4020_queue_event(sc, i,
548 						STP4020_EVENT_REMOVAL);
549 					h->flags &= ~STP4020_SOCKET_BUSY;
550 				}
551 			}
552 		}
553 
554 		/* XXX - a bunch of unhandled conditions */
555 		if ((v & STP4020_ISR0_BVD1CHG) != 0) {
556 			printf("stp4020[%d]: Battery change 1\n", h->sock);
557 		}
558 
559 		if ((v & STP4020_ISR0_BVD2CHG) != 0) {
560 			printf("stp4020[%d]: Battery change 2\n", h->sock);
561 		}
562 
563 		if ((v & STP4020_ISR0_RDYCHG) != 0) {
564 			printf("stp4020[%d]: Ready/Busy change\n", h->sock);
565 		}
566 
567 		if ((v & STP4020_ISR0_WPCHG) != 0) {
568 			printf("stp4020[%d]: Write protect change\n", h->sock);
569 		}
570 
571 		if ((v & STP4020_ISR0_PCTO) != 0) {
572 			printf("stp4020[%d]: Card access timeout\n", h->sock);
573 		}
574 	}
575 
576 	return (r);
577 }
578 
579 int
580 stp4020_iointr(arg)
581 	void *arg;
582 {
583 	struct stp4020_softc *sc = arg;
584 	int i, r = 0;
585 
586 	/*
587 	 * Check each socket for pending requests.
588 	 */
589 	for (i = 0 ; i < STP4020_NSOCK; i++) {
590 		struct stp4020_socket *h;
591 		int v;
592 
593 		h = &sc->sc_socks[i];
594 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
595 
596 		if ((v & STP4020_ISR0_IOINT) != 0) {
597 			/* It's a card interrupt */
598 			if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
599 				printf("stp4020[%d]: spurious interrupt?\n",
600 					h->sock);
601 				continue;
602 			}
603 			/* Call card handler, if any */
604 			if (h->intrhandler != NULL)
605 				r |= (*h->intrhandler)(h->intrarg);
606 		}
607 
608 	}
609 
610 	return (r);
611 }
612 
613 int
614 stp4020_chip_mem_alloc(pch, size, pcmhp)
615 	pcmcia_chipset_handle_t pch;
616 	bus_size_t size;
617 	struct pcmcia_mem_handle *pcmhp;
618 {
619 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
620 	int i, win;
621 
622 	/*
623 	 * Allocate a window.
624 	 */
625 	if (size > STP4020_WINDOW_SIZE)
626 		return (1);
627 
628 	for (win = -1, i = 0; i < STP4020_NWIN; i++) {
629 		if ((h->winalloc & (1 << i)) == 0) {
630 			win = i;
631 			h->winalloc |= (1 << i);
632 			break;
633 		}
634 	}
635 
636 	if (win == -1)
637 		return (1);
638 
639 	pcmhp->memt = 0;
640 	pcmhp->memh = h->windows[win].winaddr;
641 	pcmhp->addr = 0;	/* What is it used for? */
642 	pcmhp->size = size;
643 	pcmhp->mhandle = win;	/* Use our window number as a handle */
644 	pcmhp->realsize = STP4020_WINDOW_SIZE;
645 
646 	return (0);
647 }
648 
649 void
650 stp4020_chip_mem_free(pch, pcmhp)
651 	pcmcia_chipset_handle_t pch;
652 	struct pcmcia_mem_handle *pcmhp;
653 {
654 
655 	return;
656 }
657 
658 int
659 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
660 	pcmcia_chipset_handle_t pch;
661 	int kind;
662 	bus_addr_t card_addr;
663 	bus_size_t size;
664 	struct pcmcia_mem_handle *pcmhp;
665 	bus_addr_t *offsetp;
666 	int *windowp;
667 {
668 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
669 	bus_addr_t offset;
670 	int win, v;
671 
672 	int mem8 = (kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8;
673 	kind &= ~PCMCIA_WIDTH_MEM_MASK;
674 
675 	if(mem8) {
676 	    /* XXX Fix 8-bit memory accesses (can this be done at all?) */
677 #ifdef DIAGNOSTIC
678 	    printf("stp4020_chip_mem_map: can't handle 8-bit memory\n");
679 #endif
680 	    return (-1);
681 	}
682 
683 	win = pcmhp->mhandle;
684 	*windowp = win;
685 
686 	/*
687 	 * Compute the address offset to the pcmcia address space
688 	 * for the window.
689 	 */
690 	offset = card_addr & -STP4020_WINDOW_SIZE;
691 	card_addr -= offset;
692 	*offsetp = offset;
693 
694 	/*
695 	 * Fill in the Address Space Select and Base Address
696 	 * fields of this windows control register 0.
697 	 */
698 	v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX);
699 	v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M);
700 	v |= (kind == PCMCIA_MEM_ATTR)
701 		? STP4020_WCR0_ASPSEL_AM
702 		: STP4020_WCR0_ASPSEL_CM;
703 	v |= (STP4020_ADDR2PAGE(card_addr) & STP4020_WCR0_BASE_M);
704 	stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
705 
706 	return (0);
707 }
708 
709 void
710 stp4020_chip_mem_unmap(pch, win)
711 	pcmcia_chipset_handle_t pch;
712 	int win;
713 {
714 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
715 
716 #ifdef DIAGNOSTIC
717 	if (win < 0 || win > 2)
718 		panic("stp4020_chip_mem_unmap: window (%d) out of range", win);
719 #endif
720 	h->winalloc &= ~(1 << win);
721 	/*
722 	 * If possible, invalidate hardware mapping here; but
723 	 * I don't think the stp4020 has provided for that.
724 	 */
725 }
726 
727 int
728 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
729 	pcmcia_chipset_handle_t pch;
730 	bus_addr_t start;
731 	bus_size_t size;
732 	bus_size_t align;
733 	struct pcmcia_io_handle *pcihp;
734 {
735 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
736 
737 	if (start) {
738 		/* How on earth can `start' be interpreted??
739 		   WHERE DOES THE CARD DRIVER GET IT FROM?
740 		 */
741 	}
742 
743 	pcihp->iot = h->tag;
744 	pcihp->ioh = 0;
745 	pcihp->addr = 0;
746 	pcihp->size = size;
747 	pcihp->flags = 0;
748 
749 	return (0);
750 }
751 
752 void
753 stp4020_chip_io_free(pch, pcihp)
754 	pcmcia_chipset_handle_t pch;
755 	struct pcmcia_io_handle *pcihp;
756 {
757 
758 	return;
759 }
760 
761 int
762 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
763 	pcmcia_chipset_handle_t pch;
764 	int width;
765 	bus_addr_t offset;
766 	bus_size_t size;
767 	struct pcmcia_io_handle *pcihp;
768 	int *windowp;
769 {
770 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
771 	int i, win, v;
772 
773 	/*
774 	 * Allocate a window.
775 	 */
776 	if (size > STP4020_WINDOW_SIZE)
777 		return (1);
778 
779 	for (win = -1, i = 0; i < STP4020_NWIN; i++) {
780 		if ((h->winalloc & (1 << i)) == 0) {
781 			win = i;
782 			h->winalloc |= (1 << i);
783 			break;
784 		}
785 	}
786 
787 	if (win == -1)
788 		return (1);
789 
790 	*windowp = win;
791 
792 	/*
793 	 * Fill in the Address Space Select and Base Address
794 	 * fields of this windows control register 0.
795 	 */
796 	v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX);
797 	v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M);
798 	v |= STP4020_WCR0_ASPSEL_IO;
799 	v |= (STP4020_ADDR2PAGE(pcihp->addr+offset) & STP4020_WCR0_BASE_M);
800 	stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
801 
802 	return (0);
803 }
804 
805 void
806 stp4020_chip_io_unmap(pch, win)
807 	pcmcia_chipset_handle_t pch;
808 	int win;
809 {
810 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
811 
812 #ifdef DIAGNOSTIC
813 	if (win < 0 || win > 2)
814 		panic("stp4020_chip_io_unmap: window (%d) out of range", win);
815 #endif
816 
817 	h->winalloc &= ~(1 << win);
818 }
819 
820 void
821 stp4020_chip_socket_enable(pch)
822 	pcmcia_chipset_handle_t pch;
823 {
824 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
825 	int i, v, cardtype;
826 
827 	/* this bit is mostly stolen from pcic_attach_card */
828 
829 	/* Power down the socket to reset it, clear the card reset pin */
830 	v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
831 	v &= ~STP4020_ICR1_MSTPWR;
832 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
833 
834 	/*
835 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
836 	 * we are changing Vcc (Toff).
837 	 */
838 	stp4020_delay((300 + 100) * 1000);
839 
840 	/* Power up the socket */
841 	v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
842 	v |= STP4020_ICR1_MSTPWR;
843 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
844 
845 	/*
846 	 * wait 100ms until power raise (Tpr) and 20ms to become
847 	 * stable (Tsu(Vcc)).
848 	 */
849 	stp4020_delay((100 + 20) * 1000);
850 
851 	v |= STP4020_ICR1_PCIFOE;
852 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
853 
854 	/*
855 	 * hold RESET at least 10us.
856 	 */
857 	delay(10);
858 
859 	/* Clear reset flag */
860 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
861 	v &= ~STP4020_ICR0_RESET;
862 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
863 
864 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
865 	stp4020_delay(20000);
866 
867 	/* Wait for the chip to finish initializing (5 seconds max) */
868 	for (i = 10000; i > 0; i--) {
869 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
870 		if ((v & STP4020_ISR0_RDYST) != 0)
871 			break;
872 		delay(500);
873 	}
874 	if (i <= 0) {
875 		char bits[64];
876 		bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
877 				 STP4020_ISR0_IOBITS, bits, sizeof(bits));
878 		printf("stp4020_chip_socket_enable: not ready: status %s\n",
879 			bits);
880 		return;
881 	}
882 
883 	/* Set the card type */
884 	cardtype = pcmcia_card_gettype(h->pcmcia);
885 
886 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
887 	v &= ~STP4020_ICR0_IFTYPE;
888 	v |= (cardtype == PCMCIA_IFTYPE_IO)
889 			? STP4020_ICR0_IFTYPE_IO
890 			: STP4020_ICR0_IFTYPE_MEM;
891 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
892 
893 	DPRINTF(("%s: stp4020_chip_socket_enable %02x cardtype %s\n",
894 		h->sc->sc_dev.dv_xname, h->sock,
895 		((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem")));
896 
897 	/*
898 	 * Enable socket I/O interrupts.
899 	 * We use level SB_INT[0] for I/O interrupts.
900 	 */
901 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
902 	v &= ~STP4020_ICR0_IOILVL;
903 	v |= STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL_SB0;
904 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
905 
906 #if 0
907 	/* Reinstall all the memory and io mappings */
908 	for (win = 0; win < STP4020_NWIN; win++)
909 		if (h->winalloc & (1 << win))
910 			___chip_mem_map(h, win);
911 
912 #endif
913 }
914 
915 void
916 stp4020_chip_socket_disable(pch)
917 	pcmcia_chipset_handle_t pch;
918 {
919 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
920 	int v;
921 
922 	DPRINTF(("stp4020_chip_socket_disable\n"));
923 
924 	/*
925 	 * Disable socket I/O interrupts.
926 	 */
927 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
928 	v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL);
929 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
930 
931 	/* Power down the socket */
932 	v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX);
933 	v &= ~STP4020_ICR1_MSTPWR;
934 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
935 
936 	/*
937 	 * wait 300ms until power fails (Tpf).
938 	 */
939 	stp4020_delay(300 * 1000);
940 }
941 
942 void *
943 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
944 	pcmcia_chipset_handle_t pch;
945 	struct pcmcia_function *pf;
946 	int ipl;
947 	int (*handler) __P((void *));
948 	void *arg;
949 {
950 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
951 
952 	h->intrhandler = handler;
953 	h->intrarg = arg;
954 	h->ipl = ipl;
955 	return (NULL);
956 }
957 
958 void
959 stp4020_chip_intr_disestablish(pch, ih)
960 	pcmcia_chipset_handle_t pch;
961 	void *ih;
962 {
963 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
964 
965 	h->intrhandler = NULL;
966 	h->intrarg = NULL;
967 }
968 
969 /*
970  * Delay and possibly yield CPU.
971  * XXX - assumes a context
972  */
973 void
974 stp4020_delay(ms)
975 	unsigned int ms;
976 {
977 	unsigned int ticks;
978 extern	int cold;
979 
980 	/* Convert to ticks */
981 	ticks = (ms * hz ) / 1000000;
982 
983 	if (cold || ticks == 0) {
984 		delay(ms);
985 		return;
986 	}
987 
988 #ifdef DIAGNOSTIC
989 	if (ticks > 60*hz)
990 		panic("stp4020: preposterous delay: %u", ticks);
991 #endif
992 	tsleep(&ticks, 0, "stp4020_delay", ticks);
993 }
994 
995 #ifdef STP4020_DEBUG
996 void
997 stp4020_dump_regs(h)
998 	struct stp4020_socket *h;
999 {
1000 	char bits[64];
1001 	/*
1002 	 * Dump control and status registers.
1003 	 */
1004 	printf("socket[%d] registers:\n", h->sock);
1005 	bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX),
1006 			 STP4020_ICR0_BITS, bits, sizeof(bits));
1007 	printf("\tICR0=%s\n", bits);
1008 
1009 	bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX),
1010 			 STP4020_ICR1_BITS, bits, sizeof(bits));
1011 	printf("\tICR1=%s\n", bits);
1012 
1013 	bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
1014 			 STP4020_ISR0_IOBITS, bits, sizeof(bits));
1015 	printf("\tISR0=%s\n", bits);
1016 
1017 	bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX),
1018 			 STP4020_ISR1_BITS, bits, sizeof(bits));
1019 	printf("\tISR1=%s\n", bits);
1020 }
1021 #endif /* STP4020_DEBUG */
1022