1 /*	$OpenBSD: stp4020.c,v 1.13 2005/01/27 17:03:24 millert Exp $	*/
2 /*	$NetBSD: stp4020.c,v 1.23 2002/06/01 23:51:03 lukem Exp $	*/
3 
4 /*-
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Paul Kranenburg.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * STP4020: SBus/PCMCIA bridge supporting one Type-3 PCMCIA card, or up to
42  * two Type-1 and Type-2 PCMCIA cards..
43  */
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/errno.h>
48 #include <sys/extent.h>
49 #include <sys/proc.h>
50 #include <sys/kernel.h>
51 #include <sys/kthread.h>
52 #include <sys/device.h>
53 
54 #include <dev/pcmcia/pcmciareg.h>
55 #include <dev/pcmcia/pcmciavar.h>
56 #include <dev/pcmcia/pcmciachip.h>
57 
58 #include <machine/bus.h>
59 
60 #include <dev/sbus/stp4020reg.h>
61 #include <dev/sbus/stp4020var.h>
62 
63 /*
64  * We use the three available windows per socket in a simple, fixed
65  * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
66  * spaces into sbus space.
67  */
68 #define STP_WIN_ATTR	0	/* index of the attribute memory space window */
69 #define	STP_WIN_MEM	1	/* index of the common memory space window */
70 #define	STP_WIN_IO	2	/* index of the io space window */
71 
72 #ifdef STP4020_DEBUG
73 int stp4020_debug = 0;
74 #define DPRINTF(x)	do { if (stp4020_debug) printf x; } while(0)
75 #else
76 #define DPRINTF(x)
77 #endif
78 
79 int	stp4020print(void *, const char *);
80 void	stp4020_map_window(struct stp4020_socket *, int, int);
81 void	stp4020_calc_speed(int, int, int *, int *);
82 
83 struct	cfdriver stp_cd = {
84 	NULL, "stp", DV_DULL
85 };
86 
87 #ifdef STP4020_DEBUG
88 static void	stp4020_dump_regs(struct stp4020_socket *);
89 #endif
90 
91 static u_int16_t stp4020_rd_sockctl(struct stp4020_socket *, int);
92 static void	stp4020_wr_sockctl(struct stp4020_socket *, int, u_int16_t);
93 static u_int16_t stp4020_rd_winctl(struct stp4020_socket *, int, int);
94 static void	stp4020_wr_winctl(struct stp4020_socket *, int, int, u_int16_t);
95 
96 void	stp4020_delay(unsigned int);
97 void	stp4020_attach_socket(struct stp4020_socket *, int);
98 void	stp4020_create_event_thread(void *);
99 void	stp4020_event_thread(void *);
100 void	stp4020_queue_event(struct stp4020_softc *, int);
101 
102 int	stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
103 	    struct pcmcia_mem_handle *);
104 void	stp4020_chip_mem_free(pcmcia_chipset_handle_t,
105 	    struct pcmcia_mem_handle *);
106 int	stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
107 	    bus_size_t, struct pcmcia_mem_handle *, bus_addr_t *, int *);
108 void	stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int);
109 
110 int	stp4020_chip_io_alloc(pcmcia_chipset_handle_t,
111 	    bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle *);
112 void	stp4020_chip_io_free(pcmcia_chipset_handle_t,
113 	    struct pcmcia_io_handle *);
114 int	stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
115 	    bus_size_t, struct pcmcia_io_handle *, int *);
116 void	stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int);
117 
118 void	stp4020_chip_socket_enable(pcmcia_chipset_handle_t);
119 void	stp4020_chip_socket_disable(pcmcia_chipset_handle_t);
120 void	*stp4020_chip_intr_establish(pcmcia_chipset_handle_t,
121 	    struct pcmcia_function *, int, int (*) (void *), void *, char *);
122 void	stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
123 const char *stp4020_chip_intr_string(pcmcia_chipset_handle_t, void *);
124 
125 /* Our PCMCIA chipset methods */
126 static struct pcmcia_chip_functions stp4020_functions = {
127 	stp4020_chip_mem_alloc,
128 	stp4020_chip_mem_free,
129 	stp4020_chip_mem_map,
130 	stp4020_chip_mem_unmap,
131 
132 	stp4020_chip_io_alloc,
133 	stp4020_chip_io_free,
134 	stp4020_chip_io_map,
135 	stp4020_chip_io_unmap,
136 
137 	stp4020_chip_intr_establish,
138 	stp4020_chip_intr_disestablish,
139 	stp4020_chip_intr_string,
140 
141 	stp4020_chip_socket_enable,
142 	stp4020_chip_socket_disable
143 };
144 
145 
146 static __inline__ u_int16_t
stp4020_rd_sockctl(h,idx)147 stp4020_rd_sockctl(h, idx)
148 	struct stp4020_socket *h;
149 	int idx;
150 {
151 	int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
152 	return (bus_space_read_2(h->tag, h->regs, o));
153 }
154 
155 static __inline__ void
stp4020_wr_sockctl(h,idx,v)156 stp4020_wr_sockctl(h, idx, v)
157 	struct stp4020_socket *h;
158 	int idx;
159 	u_int16_t v;
160 {
161 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
162 	bus_space_write_2(h->tag, h->regs, o, v);
163 }
164 
165 static __inline__ u_int16_t
stp4020_rd_winctl(h,win,idx)166 stp4020_rd_winctl(h, win, idx)
167 	struct stp4020_socket *h;
168 	int win;
169 	int idx;
170 {
171 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
172 	    (STP4020_WINREGS_SIZE * win) + idx;
173 	return (bus_space_read_2(h->tag, h->regs, o));
174 }
175 
176 static __inline__ void
stp4020_wr_winctl(h,win,idx,v)177 stp4020_wr_winctl(h, win, idx, v)
178 	struct stp4020_socket *h;
179 	int win;
180 	int idx;
181 	u_int16_t v;
182 {
183 	int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
184 	    (STP4020_WINREGS_SIZE * win) + idx;
185 	bus_space_write_2(h->tag, h->regs, o, v);
186 }
187 
188 
189 int
stp4020print(aux,busname)190 stp4020print(aux, busname)
191 	void *aux;
192 	const char *busname;
193 {
194 	struct pcmciabus_attach_args *paa = aux;
195 	struct stp4020_socket *h = paa->pch;
196 
197 	printf(" socket %d", h->sock);
198 	return (UNCONF);
199 }
200 
201 /*
202  * Attach all the sub-devices we can find
203  */
204 void
stpattach_common(struct stp4020_softc * sc,int clockfreq)205 stpattach_common(struct stp4020_softc *sc, int clockfreq)
206 {
207 	int i, rev;
208 
209 	rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
210 	    STP4020_ISR1_REV_M;
211 	printf(": rev %x\n", rev);
212 
213 	sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
214 
215 	/*
216 	 * Arrange that a kernel thread be created to handle
217 	 * insert/removal events.
218 	 */
219 	sc->events = 0;
220 	kthread_create_deferred(stp4020_create_event_thread, sc);
221 
222 	for (i = 0; i < STP4020_NSOCK; i++) {
223 		struct stp4020_socket *h = &sc->sc_socks[i];
224 		h->sock = i;
225 		h->sc = sc;
226 #ifdef STP4020_DEBUG
227 		if (stp4020_debug)
228 			stp4020_dump_regs(h);
229 #endif
230 		stp4020_attach_socket(h, clockfreq);
231 	}
232 }
233 
234 void
stp4020_attach_socket(h,speed)235 stp4020_attach_socket(h, speed)
236 	struct stp4020_socket *h;
237 	int speed;
238 {
239 	struct pcmciabus_attach_args paa;
240 	int v;
241 
242 	/* Map all three windows */
243 	stp4020_map_window(h, STP_WIN_ATTR, speed);
244 	stp4020_map_window(h, STP_WIN_MEM, speed);
245 	stp4020_map_window(h, STP_WIN_IO, speed);
246 
247 	/* Configure one pcmcia device per socket */
248 	paa.paa_busname = "pcmcia";
249 	paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
250 	paa.pch = (pcmcia_chipset_handle_t)h;
251 	paa.iobase = 0;
252 	paa.iosize = STP4020_WINDOW_SIZE;
253 
254 	h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
255 
256 	if (h->pcmcia == NULL)
257 		return;
258 
259 	/*
260 	 * There's actually a pcmcia bus attached; initialize the slot.
261 	 */
262 
263 	/*
264 	 * Clear things up before we enable status change interrupts.
265 	 * This seems to not be fully initialized by the PROM.
266 	 */
267 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
268 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
269 	stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
270 	stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
271 
272 	/*
273 	 * Enable socket status change interrupts.
274 	 * We use SB_INT[1] for status change interrupts.
275 	 */
276 	v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
277 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
278 
279 	/* Get live status bits from ISR0 */
280 	v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
281 	h->sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
282 	if (h->sense != 0) {
283 		h->flags |= STP4020_SOCKET_BUSY;
284 		pcmcia_card_attach(h->pcmcia);
285 	}
286 }
287 
288 
289 /*
290  * Deferred thread creation callback.
291  */
292 void
stp4020_create_event_thread(arg)293 stp4020_create_event_thread(arg)
294 	void *arg;
295 {
296 	struct stp4020_softc *sc = arg;
297 	const char *name = sc->sc_dev.dv_xname;
298 
299 	if (kthread_create(stp4020_event_thread, sc, &sc->event_thread,
300 	    "%s", name)) {
301 		panic("%s: unable to create event thread", name);
302 	}
303 }
304 
305 /*
306  * The actual event handling thread.
307  */
308 void
stp4020_event_thread(arg)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
stp4020_queue_event(sc,sock)368 stp4020_queue_event(sc, sock)
369 	struct stp4020_softc *sc;
370 	int sock;
371 {
372 	int s;
373 
374 	s = splhigh();
375 	sc->events |= (1 << sock);
376 	splx(s);
377 	wakeup(&sc->events);
378 }
379 
380 int
stp4020_statintr(arg)381 stp4020_statintr(arg)
382 	void *arg;
383 {
384 	struct stp4020_softc *sc = arg;
385 	int i, sense, r = 0;
386 
387 	/*
388 	 * Check each socket for pending requests.
389 	 */
390 	for (i = 0 ; i < STP4020_NSOCK; i++) {
391 		struct stp4020_socket *h;
392 		int v;
393 
394 		h = &sc->sc_socks[i];
395 
396 		/* Read socket's ISR0 for the interrupt status bits */
397 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
398 		sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
399 
400 #ifdef STP4020_DEBUG
401 		if (stp4020_debug != 0)
402 			printf("stp4020_statintr: ISR0=%b\n",
403 			    v, STP4020_ISR0_IOBITS);
404 #endif
405 
406 		/* Ack all interrupts at once */
407 		stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
408 		    STP4020_ISR0_ALL_STATUS_IRQ);
409 
410 		if ((v & STP4020_ISR0_CDCHG) != 0) {
411 			r = 1;
412 
413 			/*
414 			 * Card detect status changed. In an ideal world,
415 			 * both card detect sensors should be set if a card
416 			 * is in the slot, and clear if it is not.
417 			 *
418 			 * Unfortunately, it turns out that we can get the
419 			 * notification before both sensors are set (or
420 			 * clear).
421 			 *
422 			 * This can be very funny if only one sensor is set.
423 			 * Is this a removal or an insertion operation?
424 			 * Defer appropriate action to the worker thread.
425 			 */
426 			if (sense != h->sense)
427 				stp4020_queue_event(sc, i);
428 
429 		}
430 
431 		/* informational messages */
432 		if ((v & STP4020_ISR0_BVD1CHG) != 0) {
433 			DPRINTF(("stp4020[%d]: Battery change 1\n",
434 			    h->sock));
435 			r = 1;
436 		}
437 
438 		if ((v & STP4020_ISR0_BVD2CHG) != 0) {
439 			DPRINTF(("stp4020[%d]: Battery change 2\n",
440 			    h->sock));
441 			r = 1;
442 		}
443 
444 		if ((v & STP4020_ISR0_RDYCHG) != 0) {
445 			DPRINTF(("stp4020[%d]: Ready/Busy change\n",
446 			    h->sock));
447 			r = 1;
448 		}
449 
450 		if ((v & STP4020_ISR0_WPCHG) != 0) {
451 			DPRINTF(("stp4020[%d]: Write protect change\n",
452 			    h->sock));
453 			r = 1;
454 		}
455 
456 		if ((v & STP4020_ISR0_PCTO) != 0) {
457 			DPRINTF(("stp4020[%d]: Card access timeout\n",
458 			    h->sock));
459 			r = 1;
460 		}
461 
462 		if ((v & STP4020_ISR0_SCINT) != 0) {
463 			DPRINTF(("stp4020[%d]: Status change\n",
464 			    h->sock));
465 			r = 1;
466 		}
467 
468 		/*
469 		 * Not interrupts flag per se, but interrupts can occur when
470 		 * they are asserted, at least during our slot enable routine.
471 		 */
472 		if ((h->flags & STP4020_SOCKET_ENABLING) &&
473 		    (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON)))
474 			r = 1;
475 	}
476 
477 	return (r);
478 }
479 
480 int
stp4020_iointr(arg)481 stp4020_iointr(arg)
482 	void *arg;
483 {
484 	struct stp4020_softc *sc = arg;
485 	int i, r = 0;
486 
487 	/*
488 	 * Check each socket for pending requests.
489 	 */
490 	for (i = 0 ; i < STP4020_NSOCK; i++) {
491 		struct stp4020_socket *h;
492 		int v;
493 
494 		h = &sc->sc_socks[i];
495 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
496 
497 		if ((v & STP4020_ISR0_IOINT) != 0) {
498 			/* we can not deny this is ours, no matter what the
499 			   card driver says. */
500 			r = 1;
501 
502 			/* ack interrupt */
503 			stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
504 
505 			/* It's a card interrupt */
506 			if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
507 				printf("stp4020[%d]: spurious interrupt?\n",
508 				    h->sock);
509 				continue;
510 			}
511 			/* Call card handler, if any */
512 			if (h->intrhandler != NULL) {
513 				/*
514 				 * We ought to be at an higher ipl level
515 				 * than the callback, since the first
516 				 * interrupt of this device is usually
517 				 * higher than IPL_CLOCK.
518 				 */
519 				splassert(h->ipl);
520 				(*h->intrhandler)(h->intrarg);
521 			}
522 		}
523 
524 	}
525 
526 	return (r);
527 }
528 
529 /*
530  * The function gets the sbus speed and a access time and calculates
531  * values for the CMDLNG and CMDDLAY registers.
532  */
533 void
stp4020_calc_speed(int bus_speed,int ns,int * length,int * delay)534 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
535 {
536 	int result;
537 
538 	if (ns < STP4020_MEM_SPEED_MIN)
539 		ns = STP4020_MEM_SPEED_MIN;
540 	else if (ns > STP4020_MEM_SPEED_MAX)
541 		ns = STP4020_MEM_SPEED_MAX;
542 	result = ns * (bus_speed / 1000);
543 	if (result % 1000000)
544 		result = result / 1000000 + 1;
545 	else
546 		result /= 1000000;
547 	*length = result;
548 
549 	/* the sbus frequency range is limited, so we can keep this simple */
550 	*delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2;
551 }
552 
553 void
stp4020_map_window(struct stp4020_socket * h,int win,int speed)554 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
555 {
556 	int v, length, delay;
557 
558 	/*
559 	 * According to the PC Card standard 300ns access timing should be
560 	 * used for attribute memory access. Our pcmcia framework does not
561 	 * seem to propagate timing information, so we use that
562 	 * everywhere.
563 	 */
564 	stp4020_calc_speed(speed, 300, &length, &delay);
565 
566 	/*
567 	 * Fill in the Address Space Select and Base Address
568 	 * fields of this windows control register 0.
569 	 */
570 	v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) |
571 	    ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M);
572 	switch (win) {
573 	case STP_WIN_ATTR:
574 		v |= STP4020_WCR0_ASPSEL_AM;
575 		break;
576 	case STP_WIN_MEM:
577 		v |= STP4020_WCR0_ASPSEL_CM;
578 		break;
579 	case STP_WIN_IO:
580 		v |= STP4020_WCR0_ASPSEL_IO;
581 		break;
582 	}
583 	v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
584 	stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
585 	stp4020_wr_winctl(h, win, STP4020_WCR1_IDX,
586 	    1 << STP4020_WCR1_WAITREQ_S);
587 }
588 
589 int
stp4020_chip_mem_alloc(pch,size,pcmhp)590 stp4020_chip_mem_alloc(pch, size, pcmhp)
591 	pcmcia_chipset_handle_t pch;
592 	bus_size_t size;
593 	struct pcmcia_mem_handle *pcmhp;
594 {
595 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
596 
597 	/* we can not do much here, defere work to _mem_map */
598 	pcmhp->memt = h->wintag;
599 	pcmhp->size = size;
600 	pcmhp->addr = 0;
601 	pcmhp->mhandle = 0;
602 	pcmhp->realsize = size;
603 
604 	return (0);
605 }
606 
607 void
stp4020_chip_mem_free(pch,pcmhp)608 stp4020_chip_mem_free(pch, pcmhp)
609 	pcmcia_chipset_handle_t pch;
610 	struct pcmcia_mem_handle *pcmhp;
611 {
612 }
613 
614 int
stp4020_chip_mem_map(pch,kind,card_addr,size,pcmhp,offsetp,windowp)615 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
616 	pcmcia_chipset_handle_t pch;
617 	int kind;
618 	bus_addr_t card_addr;
619 	bus_size_t size;
620 	struct pcmcia_mem_handle *pcmhp;
621 	bus_addr_t *offsetp;
622 	int *windowp;
623 {
624 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
625 	int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM;
626 
627 	pcmhp->memt = h->wintag;
628 	bus_space_subregion(h->wintag, h->windows[win].winaddr,
629 	    card_addr, size, &pcmhp->memh);
630 	pcmhp->size = size;
631 	pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
632 	*offsetp = 0;
633 	*windowp = win;
634 
635 	return (0);
636 }
637 
638 void
stp4020_chip_mem_unmap(pch,win)639 stp4020_chip_mem_unmap(pch, win)
640 	pcmcia_chipset_handle_t pch;
641 	int win;
642 {
643 }
644 
645 int
stp4020_chip_io_alloc(pch,start,size,align,pcihp)646 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
647 	pcmcia_chipset_handle_t pch;
648 	bus_addr_t start;
649 	bus_size_t size;
650 	bus_size_t align;
651 	struct pcmcia_io_handle *pcihp;
652 {
653 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
654 
655 	pcihp->iot = h->wintag;
656 	pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
657 	pcihp->size = size;
658 	return (0);
659 }
660 
661 void
stp4020_chip_io_free(pch,pcihp)662 stp4020_chip_io_free(pch, pcihp)
663 	pcmcia_chipset_handle_t pch;
664 	struct pcmcia_io_handle *pcihp;
665 {
666 }
667 
668 int
stp4020_chip_io_map(pch,width,offset,size,pcihp,windowp)669 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
670 	pcmcia_chipset_handle_t pch;
671 	int width;
672 	bus_addr_t offset;
673 	bus_size_t size;
674 	struct pcmcia_io_handle *pcihp;
675 	int *windowp;
676 {
677 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
678 
679 	pcihp->iot = h->wintag;
680 	bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr,
681 	    offset, size, &pcihp->ioh);
682 	*windowp = 0;
683 	return (0);
684 }
685 
686 void
stp4020_chip_io_unmap(pch,win)687 stp4020_chip_io_unmap(pch, win)
688 	pcmcia_chipset_handle_t pch;
689 	int win;
690 {
691 }
692 
693 void
stp4020_chip_socket_enable(pch)694 stp4020_chip_socket_enable(pch)
695 	pcmcia_chipset_handle_t pch;
696 {
697 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
698 	int i, v;
699 
700 	h->flags |= STP4020_SOCKET_ENABLING;
701 
702 	/* this bit is mostly stolen from pcic_attach_card */
703 
704 	/* Power down the socket to reset it, clear the card reset pin */
705 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
706 
707 	/*
708 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
709 	 * we are changing Vcc (Toff).
710 	 */
711 	stp4020_delay((300 + 100) * 1000);
712 
713 	/* Power up the socket */
714 	v = STP4020_ICR1_MSTPWR;
715 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
716 
717 	/*
718 	 * wait 100ms until power raise (Tpr) and 20ms to become
719 	 * stable (Tsu(Vcc)).
720 	 *
721 	 * some machines require some more time to be settled
722 	 * (another 200ms is added here).
723 	 */
724 	stp4020_delay((100 + 20 + 200) * 1000);
725 
726 	v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC;
727 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
728 
729 	/*
730 	 * hold RESET at least 20us.
731 	 */
732 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
733 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET);
734 	delay(20);
735 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
736 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET);
737 
738 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
739 	stp4020_delay(20000);
740 
741 	/* Wait for the chip to finish initializing (5 seconds max) */
742 	for (i = 10000; i > 0; i--) {
743 		v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
744 		/* If the card has been removed, abort */
745 		if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) {
746 			h->flags &= ~STP4020_SOCKET_ENABLING;
747 			return;
748 		}
749 		if ((v & STP4020_ISR0_RDYST) != 0)
750 			break;
751 		delay(500);
752 	}
753 	if (i <= 0) {
754 #ifdef STP4020_DEBUG
755 		printf("stp4020_chip_socket_enable: not ready: status %b\n",
756 		    v, STP4020_ISR0_IOBITS);
757 #endif
758 		h->flags &= ~STP4020_SOCKET_ENABLING;
759 		return;
760 	}
761 
762 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
763 
764 	/*
765 	 * Check the card type.
766 	 * Enable socket I/O interrupts for IO cards.
767 	 * We use level SB_INT[0] for I/O interrupts.
768 	 */
769 	if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
770 		v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE);
771 		v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE |
772 		    STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN;
773 		DPRINTF(("%s: configuring card for IO usage\n",
774 		    h->sc->sc_dev.dv_xname));
775 	} else {
776 		v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
777 		    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
778 		v |= STP4020_ICR0_IFTYPE_MEM;
779 		DPRINTF(("%s: configuring card for MEM ONLY usage\n",
780 		    h->sc->sc_dev.dv_xname));
781 	}
782 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
783 
784 	h->flags &= ~STP4020_SOCKET_ENABLING;
785 }
786 
787 void
stp4020_chip_socket_disable(pch)788 stp4020_chip_socket_disable(pch)
789 	pcmcia_chipset_handle_t pch;
790 {
791 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
792 	int v;
793 
794 	/*
795 	 * Disable socket I/O interrupts.
796 	 */
797 	v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
798 	v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
799 	    STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
800 	stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
801 
802 	/* Power down the socket */
803 	stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
804 
805 	/*
806 	 * wait 300ms until power fails (Tpf).
807 	 */
808 	stp4020_delay(300 * 1000);
809 }
810 
811 void *
stp4020_chip_intr_establish(pch,pf,ipl,handler,arg,xname)812 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname)
813 	pcmcia_chipset_handle_t pch;
814 	struct pcmcia_function *pf;
815 	int ipl;
816 	int (*handler) (void *);
817 	void *arg;
818 	char *xname;
819 {
820 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
821 
822 	h->intrhandler = handler;
823 	h->intrarg = arg;
824 	h->ipl = ipl;
825 	return (h);
826 }
827 
828 void
stp4020_chip_intr_disestablish(pch,ih)829 stp4020_chip_intr_disestablish(pch, ih)
830 	pcmcia_chipset_handle_t pch;
831 	void *ih;
832 {
833 	struct stp4020_socket *h = (struct stp4020_socket *)pch;
834 
835 	h->intrhandler = NULL;
836 	h->intrarg = NULL;
837 }
838 
839 const char *
stp4020_chip_intr_string(pch,ih)840 stp4020_chip_intr_string(pch, ih)
841 	pcmcia_chipset_handle_t pch;
842 	void *ih;
843 {
844 	if (ih == NULL)
845 		return ("couldn't establish interrupt");
846 	else
847 		return ("");	/* nothing for now */
848 }
849 
850 /*
851  * Delay and possibly yield CPU.
852  * XXX - assumes a context
853  */
854 void
stp4020_delay(ms)855 stp4020_delay(ms)
856 	unsigned int ms;
857 {
858 	unsigned int ticks;
859 
860 	/* Convert to ticks */
861 	ticks = (ms * hz) / 1000000;
862 
863 	if (cold || ticks == 0) {
864 		delay(ms);
865 		return;
866 	}
867 
868 #ifdef DEBUG
869 	if (ticks > 60 * hz)
870 		panic("stp4020: preposterous delay: %u", ticks);
871 #endif
872 	tsleep(&ticks, 0, "stp4020_delay", ticks);
873 }
874 
875 #ifdef STP4020_DEBUG
876 void
stp4020_dump_regs(h)877 stp4020_dump_regs(h)
878 	struct stp4020_socket *h;
879 {
880 	/*
881 	 * Dump control and status registers.
882 	 */
883 	printf("socket[%d] registers:\n"
884 	    "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock,
885 	    stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS,
886 	    stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS,
887 	    stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS,
888 	    stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
889 }
890 #endif /* STP4020_DEBUG */
891