xref: /netbsd-src/sys/dev/isa/i82365_isasubr.c (revision 4e6df137e8e14049b5a701d249962c480449c141)
1 /*	$NetBSD: i82365_isasubr.c,v 1.45 2009/09/17 18:14:41 tsutsui Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 Christian E. Hopps.  All rights reserved.
5  * Copyright (c) 1998 Bill Sommerfeld.  All rights reserved.
6  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by Marc Horowitz.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: i82365_isasubr.c,v 1.45 2009/09/17 18:14:41 tsutsui Exp $");
36 
37 #define	PCICISADEBUG
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/extent.h>
43 #include <sys/malloc.h>
44 
45 #include <sys/bus.h>
46 #include <sys/intr.h>
47 
48 #include <dev/isa/isareg.h>
49 #include <dev/isa/isavar.h>
50 
51 #include <dev/pcmcia/pcmciareg.h>
52 #include <dev/pcmcia/pcmciavar.h>
53 #include <dev/pcmcia/pcmciachip.h>
54 
55 #include <dev/ic/i82365reg.h>
56 #include <dev/ic/i82365var.h>
57 #include <dev/isa/i82365_isavar.h>
58 
59 /*****************************************************************************
60  * Configurable parameters.
61  *****************************************************************************/
62 
63 #include "opt_pcic_isa_alloc_iobase.h"
64 #include "opt_pcic_isa_alloc_iosize.h"
65 #include "opt_pcic_isa_intr_alloc_mask.h"
66 
67 /*
68  * Default I/O allocation range.  If both are set to non-zero, these
69  * values will be used instead.  Otherwise, the code attempts to probe
70  * the bus width.  Systems with 10 address bits should use 0x300 and 0xff.
71  * Systems with 12 address bits (most) should use 0x400 and 0xbff.
72  */
73 
74 #ifndef PCIC_ISA_ALLOC_IOBASE
75 #define	PCIC_ISA_ALLOC_IOBASE		0
76 #endif
77 
78 #ifndef PCIC_ISA_ALLOC_IOSIZE
79 #define	PCIC_ISA_ALLOC_IOSIZE		0
80 #endif
81 
82 int	pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE;
83 int	pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE;
84 
85 
86 /*
87  * Default IRQ allocation bitmask.  This defines the range of allowable
88  * IRQs for PCMCIA slots.  Useful if order of probing would screw up other
89  * devices, or if PCIC hardware/cards have trouble with certain interrupt
90  * lines.
91  */
92 
93 #ifndef PCIC_ISA_INTR_ALLOC_MASK
94 #define	PCIC_ISA_INTR_ALLOC_MASK	0xffff
95 #endif
96 
97 int	pcic_isa_intr_alloc_mask = PCIC_ISA_INTR_ALLOC_MASK;
98 
99 #ifndef	PCIC_IRQ_PROBE
100 #ifdef hpcmips
101 /*
102  * The irq probing doesn't work with current vrisab implementation.
103  * The irq is just an key to find matching GPIO port to use and is fixed.
104  */
105 #define	PCIC_IRQ_PROBE	0
106 #else
107 #define	PCIC_IRQ_PROBE	1
108 #endif
109 #endif
110 
111 int	pcic_irq_probe = PCIC_IRQ_PROBE;
112 
113 /*****************************************************************************
114  * End of configurable parameters.
115  *****************************************************************************/
116 
117 #ifdef PCICISADEBUG
118 int	pcicsubr_debug = 0;
119 #define	DPRINTF(arg) do { if (pcicsubr_debug) printf arg ; } while (0)
120 #else
121 #define	DPRINTF(arg)
122 #endif
123 
124 /*
125  * count the interrupt if we have a status set
126  * just use socket 0
127  */
128 
129 void pcic_isa_probe_interrupts(struct pcic_isa_softc *, struct pcic_handle *);
130 static int pcic_isa_count_intr(void *);
131 
132 static int
133 pcic_isa_count_intr(void *arg)
134 {
135 	struct pcic_softc *sc;
136 	struct pcic_isa_softc *isc;
137 	struct pcic_handle *h;
138 	int cscreg;
139 
140 	h = arg;
141 	isc = device_private(h->ph_parent);
142 	sc = &isc->sc_pcic;
143 
144 	cscreg = pcic_read(h, PCIC_CSC);
145 	if (cscreg & PCIC_CSC_CD) {
146 		if ((++sc->intr_detect % 20) == 0)
147 			printf(".");
148 		else
149 			DPRINTF(("."));
150 		return 1;
151 	}
152 
153 	/*
154 	 * make sure we don't get stuck in a loop due to
155 	 * unhandled level interrupts
156 	 */
157 	if (++sc->intr_false > 40) {
158 		isa_intr_disestablish(isc->sc_ic, sc->ih);
159 		sc->ih = 0;
160 
161 		pcic_write(h, PCIC_CSC_INTR, 0);
162 		delay(10);
163 	}
164 
165 #ifdef PCICISADEBUG
166 	if (cscreg)
167 		DPRINTF(("o"));
168 	else
169 		DPRINTF(("X"));
170 #endif
171 	return cscreg ? 1 : 0;
172 }
173 
174 /*
175  * use soft interrupt card detect to find out which irqs are available
176  * for this controller
177  */
178 void
179 pcic_isa_probe_interrupts(struct pcic_isa_softc *isc, struct pcic_handle *h)
180 {
181 	struct pcic_softc *sc = &isc->sc_pcic;
182 	isa_chipset_tag_t ic;
183 	int i, j, mask, irq;
184 	int cd, cscintr, intr, csc;
185 
186 	ic = isc->sc_ic;
187 
188 	printf("%s: controller %d detecting irqs with mask 0x%04x:",
189 	    device_xname(&sc->dev), h->chip, sc->intr_mask[h->chip]);
190 	DPRINTF(("\n"));
191 
192 	/* clear any current interrupt */
193 	pcic_read(h, PCIC_CSC);
194 
195 	/* first disable the status irq, card detect is enabled later */
196 	pcic_write(h, PCIC_CSC_INTR, 0);
197 
198 	/* steer the interrupt to isa and disable ring and interrupt */
199 	intr = pcic_read(h, PCIC_INTR);
200 	DPRINTF(("pcic: old intr 0x%x\n", intr));
201 	intr &= ~(PCIC_INTR_RI_ENABLE | PCIC_INTR_ENABLE | PCIC_INTR_IRQ_MASK);
202 	pcic_write(h, PCIC_INTR, intr);
203 
204 
205 	/* clear any current interrupt */
206 	pcic_read(h, PCIC_CSC);
207 
208 	cd = pcic_read(h, PCIC_CARD_DETECT);
209 	cd |= PCIC_CARD_DETECT_SW_INTR;
210 
211 	mask = 0;
212 	for (i = 0; i < 16; i++) {
213 		/* honor configured limitations */
214 		if ((sc->intr_mask[h->chip] & (1 << i)) == 0)
215 			continue;
216 
217 		DPRINTF(("probing irq %d: ", i));
218 
219 		/* ask for a pulse interrupt so we don't share */
220 		if (isa_intr_alloc(ic, (1 << i), IST_PULSE, &irq)) {
221 			DPRINTF(("currently allocated\n"));
222 			continue;
223 		}
224 
225 		cscintr = PCIC_CSC_INTR_CD_ENABLE;
226 		cscintr |= (irq << PCIC_CSC_INTR_IRQ_SHIFT);
227 		pcic_write(h, PCIC_CSC_INTR, cscintr);
228 		delay(10);
229 
230 		/* Clear any pending interrupt. */
231 		(void) pcic_read(h, PCIC_CSC);
232 
233 		if ((sc->ih = isa_intr_establish(ic, irq, IST_EDGE, IPL_TTY,
234 		    pcic_isa_count_intr, h)) == NULL)
235 			panic("cant get interrupt");
236 
237 		/* interrupt 40 times */
238 		sc->intr_detect = 0;
239 		for (j = 0; j < 40 && sc->ih; j++) {
240 			sc->intr_false = 0;
241 			pcic_write(h, PCIC_CARD_DETECT, cd);
242 			delay(100);
243 			csc = pcic_read(h, PCIC_CSC);
244 			DPRINTF(("%s", csc ? "-" : ""));
245 		}
246 		DPRINTF((" total %d\n", sc->intr_detect));
247 		/* allow for misses */
248 		if (sc->intr_detect > 37 && sc->intr_detect <= 40) {
249 			printf("%d", i);
250 			DPRINTF((" succeded\n"));
251 			mask |= (1 << i);
252 		}
253 
254 		if (sc->ih) {
255 			isa_intr_disestablish(ic, sc->ih);
256 			sc->ih = 0;
257 
258 			pcic_write(h, PCIC_CSC_INTR, 0);
259 			delay(10);
260 		}
261 	}
262 	sc->intr_mask[h->chip] = mask;
263 
264 	printf("%s\n", sc->intr_mask[h->chip] ? "" : " none");
265 }
266 
267 /*
268  * called with interrupts enabled, light up the irqs to find out
269  * which irq lines are actually hooked up to our pcic
270  */
271 void
272 pcic_isa_config_interrupts(device_t self)
273 {
274 	struct pcic_softc *sc;
275 	struct pcic_isa_softc *isc;
276 	struct pcic_handle *h;
277 	isa_chipset_tag_t ic;
278 	int s, i, chipmask, chipuniq;
279 
280 	isc = device_private(self);
281 	sc = &isc->sc_pcic;
282 	ic = isc->sc_ic;
283 
284 	/* probe each controller */
285 	chipmask = 0xffff;
286 	for (i = 0; i < PCIC_NSLOTS; i += 2) {
287 		if (sc->handle[i].flags & PCIC_FLAG_SOCKETP)
288 			h = &sc->handle[i];
289 		else if (sc->handle[i + 1].flags & PCIC_FLAG_SOCKETP)
290 			h = &sc->handle[i + 1];
291 		else
292 			continue;
293 
294 		sc->intr_mask[h->chip] =
295 		    PCIC_INTR_IRQ_VALIDMASK & pcic_isa_intr_alloc_mask;
296 
297 		/* the cirrus chips lack support for the soft interrupt */
298 		if (pcic_irq_probe != 0 &&
299 		    h->vendor != PCIC_VENDOR_CIRRUS_PD67XX)
300 			pcic_isa_probe_interrupts(isc, h);
301 
302 		chipmask &= sc->intr_mask[h->chip];
303 	}
304 	/* now see if there is at least one irq per chip not shared by all */
305 	chipuniq = 1;
306 	for (i = 0; i < PCIC_NSLOTS; i += 2) {
307 		if ((sc->handle[i].flags & PCIC_FLAG_SOCKETP) == 0 &&
308 		    (sc->handle[i + 1].flags & PCIC_FLAG_SOCKETP) == 0)
309 			continue;
310 		if ((sc->intr_mask[i / 2] & ~chipmask) == 0) {
311 			chipuniq = 0;
312 			break;
313 		}
314 	}
315 	/*
316 	 * the rest of the following code used to run at config time with
317 	 * no interrupts and gets unhappy if this is violated so...
318 	 */
319 	s = splhigh();
320 
321 	/*
322 	 * allocate our irq.  it will be used by both controllers.  I could
323 	 * use two different interrupts, but interrupts are relatively
324 	 * scarce, shareable, and for PCIC controllers, very infrequent.
325 	 */
326 	if ((device_cfdata(self)->cf_flags & 1) == 0) {
327 		if (sc->irq != ISA_UNKNOWN_IRQ) {
328 			if ((chipmask & (1 << sc->irq)) == 0)
329 				printf("%s: warning: configured irq %d not "
330 				    "detected as available\n",
331 				    device_xname(self), sc->irq);
332 		} else if (chipmask == 0 ||
333 		    isa_intr_alloc(ic, chipmask, IST_EDGE, &sc->irq)) {
334 			aprint_error_dev(self, "no available irq; ");
335 			sc->irq = ISA_UNKNOWN_IRQ;
336 		} else if ((chipmask & ~(1 << sc->irq)) == 0 && chipuniq == 0) {
337 			aprint_error_dev(self, "can't share irq with cards; ");
338 			sc->irq = ISA_UNKNOWN_IRQ;
339 		}
340 	} else {
341 		printf("%s: ", device_xname(self));
342 		sc->irq = ISA_UNKNOWN_IRQ;
343 	}
344 
345 	if (sc->irq != ISA_UNKNOWN_IRQ) {
346 		sc->ih = isa_intr_establish(ic, sc->irq, IST_EDGE, IPL_TTY,
347 		    pcic_intr, sc);
348 		if (sc->ih == NULL) {
349 			aprint_error_dev(self, "can't establish interrupt");
350 			sc->irq = ISA_UNKNOWN_IRQ;
351 		}
352 	}
353 	if (sc->irq == ISA_UNKNOWN_IRQ)
354 		printf("polling for socket events\n");
355 	else
356 		printf("%s: using irq %d for socket events\n",
357 		    device_xname(self), sc->irq);
358 
359 	pcic_attach_sockets_finish(sc);
360 
361 	splx(s);
362 }
363 
364 /*
365  * XXX This routine does not deal with the aliasing issue that its
366  * trying to.
367  *
368  * Any isa device may be decoding only 10 bits of address including
369  * the pcic.  This routine only detects if the pcic is doing 10 bits.
370  *
371  * What should be done is detect the pcic's idea of the bus width,
372  * and then within those limits allocate a sparse map, where the
373  * each sub region is offset by 0x400.
374  */
375 void pcic_isa_bus_width_probe(struct pcic_softc *sc, bus_space_tag_t iot,
376     bus_space_handle_t ioh, bus_addr_t base, uint32_t length)
377 {
378 	bus_space_handle_t ioh_high;
379 	int i, iobuswidth, tmp1, tmp2;
380 
381 	/*
382 	 * figure out how wide the isa bus is.  Do this by checking if the
383 	 * pcic controller is mirrored 0x400 above where we expect it to be.
384 	 */
385 
386 	iobuswidth = 12;
387 
388 	/* Map i/o space. */
389 	if (bus_space_map(iot, base + 0x400, length, 0, &ioh_high)) {
390 		aprint_error_dev(&sc->dev, "can't map high i/o space\n");
391 		return;
392 	}
393 
394 	for (i = 0; i < PCIC_NSLOTS; i++) {
395 		if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
396 			/*
397 			 * read the ident flags from the normal space and
398 			 * from the mirror, and compare them
399 			 */
400 
401 			bus_space_write_1(iot, ioh, PCIC_REG_INDEX,
402 			    sc->handle[i].sock + PCIC_IDENT);
403 			tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
404 
405 			bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX,
406 			    sc->handle[i].sock + PCIC_IDENT);
407 			tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA);
408 
409 			if (tmp1 == tmp2)
410 				iobuswidth = 10;
411 		}
412 	}
413 
414 	bus_space_free(iot, ioh_high, length);
415 
416 	/*
417 	 * XXX some hardware doesn't seem to grok addresses in 0x400 range--
418 	 * apparently missing a bit or more of address lines. (e.g.
419 	 * CIRRUS_PD672X with Linksys EthernetCard ne2000 clone in TI
420 	 * TravelMate 5000--not clear which is at fault)
421 	 *
422 	 * Add a kludge to detect 10 bit wide buses and deal with them,
423 	 * and also a config file option to override the probe.
424 	 */
425 
426 	if (iobuswidth == 10) {
427 		sc->iobase = 0x300;
428 		sc->iosize = 0x0ff;
429 	} else {
430 		sc->iobase = 0x400;
431 		sc->iosize = 0xbff;
432 	}
433 
434 	DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (probed)\n",
435 	    device_xname(&sc->dev), (long) sc->iobase,
436 	    (long) sc->iobase + sc->iosize));
437 
438 	if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) {
439 		sc->iobase = pcic_isa_alloc_iobase;
440 		sc->iosize = pcic_isa_alloc_iosize;
441 
442 		DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx "
443 		    "(config override)\n", device_xname(&sc->dev),
444 		    (long) sc->iobase, (long) sc->iobase + sc->iosize));
445 	}
446 }
447 
448 void *
449 pcic_isa_chip_intr_establish(pcmcia_chipset_handle_t pch,
450     struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg)
451 {
452 	struct pcic_handle *h = (struct pcic_handle *) pch;
453 	struct pcic_isa_softc *isc = device_private(h->ph_parent);
454 	struct pcic_softc *sc = &isc->sc_pcic;
455 	isa_chipset_tag_t ic = isc->sc_ic;
456 	int irq, ist;
457 	void *ih;
458 	int reg;
459 
460 	/*
461 	 * PLEASE NOTE:
462 	 * The IRQLEVEL bit has no bearing on what happens on the host side of
463 	 * the PCMCIA controller.  ISA interrupts are defined to be edge-
464 	 * triggered, and as this attachment is for ISA devices, the interrupt
465 	 * *must* be configured for edge-trigger.  If you think you should
466 	 * change this to use IST_LEVEL, you are *wrong*.  You should figure
467 	 * out what your real problem is and leave this code alone rather than
468 	 * breaking everyone else's systems.  - mycroft
469 	 */
470 	if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
471 		ist = IST_EDGE;		/* SEE COMMENT ABOVE */
472 	else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
473 		ist = IST_PULSE;	/* SEE COMMENT ABOVE */
474 	else
475 		ist = IST_EDGE;		/* SEE COMMENT ABOVE */
476 
477 	if (isa_intr_alloc(ic, sc->intr_mask[h->chip], ist, &irq))
478 		return NULL;
479 
480 	h->ih_irq = irq;
481 	if (h->flags & PCIC_FLAG_ENABLED) {
482 		reg = pcic_read(h, PCIC_INTR);
483 		reg &= ~PCIC_INTR_IRQ_MASK;
484 		pcic_write(h, PCIC_INTR, reg | irq);
485 	}
486 
487 	if ((ih = isa_intr_establish(ic, irq, ist, ipl, fct, arg)) == NULL)
488 		return NULL;
489 
490 	printf("%s: card irq %d\n", device_xname(h->pcmcia), irq);
491 
492 	return ih;
493 }
494 
495 void
496 pcic_isa_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
497 {
498 	struct pcic_handle *h = (struct pcic_handle *) pch;
499 	struct pcic_isa_softc *isc = device_private(h->ph_parent);
500 	isa_chipset_tag_t ic = isc->sc_ic;
501 	int reg;
502 
503 	isa_intr_disestablish(ic, ih);
504 
505 	h->ih_irq = 0;
506 	if (h->flags & PCIC_FLAG_ENABLED) {
507 		reg = pcic_read(h, PCIC_INTR);
508 		reg &= ~PCIC_INTR_IRQ_MASK;
509 		pcic_write(h, PCIC_INTR, reg);
510 	}
511 }
512