1 /* $NetBSD: i82365_isasubr.c,v 1.44 2009/09/14 13:41:15 tsutsui Exp $ */
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.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: i82365_isasubr.c,v 1.44 2009/09/14 13:41:15 tsutsui Exp $");
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>
48 #include <dev/isa/isareg.h>
49 #include <dev/isa/isavar.h>
51 #include <dev/pcmcia/pcmciareg.h>
52 #include <dev/pcmcia/pcmciavar.h>
53 #include <dev/pcmcia/pcmciachip.h>
55 #include <dev/ic/i82365reg.h>
56 #include <dev/ic/i82365var.h>
57 #include <dev/isa/i82365_isavar.h>
59 /*****************************************************************************
60 * Configurable parameters.
61 *****************************************************************************/
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"
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.
74 #ifndef PCIC_ISA_ALLOC_IOBASE
75 #define PCIC_ISA_ALLOC_IOBASE 0
78 #ifndef PCIC_ISA_ALLOC_IOSIZE
79 #define PCIC_ISA_ALLOC_IOSIZE 0
82 int pcic_isa_alloc_iobase
= PCIC_ISA_ALLOC_IOBASE
;
83 int pcic_isa_alloc_iosize
= PCIC_ISA_ALLOC_IOSIZE
;
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
93 #ifndef PCIC_ISA_INTR_ALLOC_MASK
94 #define PCIC_ISA_INTR_ALLOC_MASK 0xffff
97 int pcic_isa_intr_alloc_mask
= PCIC_ISA_INTR_ALLOC_MASK
;
99 #ifndef PCIC_IRQ_PROBE
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.
105 #define PCIC_IRQ_PROBE 0
107 #define PCIC_IRQ_PROBE 1
111 int pcic_irq_probe
= PCIC_IRQ_PROBE
;
113 /*****************************************************************************
114 * End of configurable parameters.
115 *****************************************************************************/
118 int pcicsubr_debug
= 0;
119 #define DPRINTF(arg) do { if (pcicsubr_debug) printf arg ; } while (0)
125 * count the interrupt if we have a status set
129 void pcic_isa_probe_interrupts(struct pcic_isa_softc
*, struct pcic_handle
*);
130 static int pcic_isa_count_intr(void *);
133 pcic_isa_count_intr(void *arg
)
135 struct pcic_softc
*sc
;
136 struct pcic_isa_softc
*isc
;
137 struct pcic_handle
*h
;
141 isc
= device_private(h
->ph_parent
);
144 cscreg
= pcic_read(h
, PCIC_CSC
);
145 if (cscreg
& PCIC_CSC_CD
) {
146 if ((++sc
->intr_detect
% 20) == 0)
154 * make sure we don't get stuck in a loop due to
155 * unhandled level interrupts
157 if (++sc
->intr_false
> 40) {
158 isa_intr_disestablish(isc
->sc_ic
, sc
->ih
);
161 pcic_write(h
, PCIC_CSC_INTR
, 0);
171 return cscreg
? 1 : 0;
175 * use soft interrupt card detect to find out which irqs are available
176 * for this controller
179 pcic_isa_probe_interrupts(struct pcic_isa_softc
*isc
, struct pcic_handle
*h
)
181 struct pcic_softc
*sc
= &isc
->sc_pcic
;
182 isa_chipset_tag_t ic
;
184 int cd
, cscintr
, intr
, csc
;
188 printf("%s: controller %d detecting irqs with mask 0x%04x:",
189 device_xname(&sc
->dev
), h
->chip
, sc
->intr_mask
[h
->chip
]);
192 /* clear any current interrupt */
193 pcic_read(h
, PCIC_CSC
);
195 /* first disable the status irq, card detect is enabled later */
196 pcic_write(h
, PCIC_CSC_INTR
, 0);
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
);
205 /* clear any current interrupt */
206 pcic_read(h
, PCIC_CSC
);
208 cd
= pcic_read(h
, PCIC_CARD_DETECT
);
209 cd
|= PCIC_CARD_DETECT_SW_INTR
;
212 for (i
= 0; i
< 16; i
++) {
213 /* honor configured limitations */
214 if ((sc
->intr_mask
[h
->chip
] & (1 << i
)) == 0)
217 DPRINTF(("probing irq %d: ", i
));
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"));
225 cscintr
= PCIC_CSC_INTR_CD_ENABLE
;
226 cscintr
|= (irq
<< PCIC_CSC_INTR_IRQ_SHIFT
);
227 pcic_write(h
, PCIC_CSC_INTR
, cscintr
);
230 /* Clear any pending interrupt. */
231 (void) pcic_read(h
, PCIC_CSC
);
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");
237 /* interrupt 40 times */
239 for (j
= 0; j
< 40 && sc
->ih
; j
++) {
241 pcic_write(h
, PCIC_CARD_DETECT
, cd
);
243 csc
= pcic_read(h
, PCIC_CSC
);
244 DPRINTF(("%s", csc
? "-" : ""));
246 DPRINTF((" total %d\n", sc
->intr_detect
));
247 /* allow for misses */
248 if (sc
->intr_detect
> 37 && sc
->intr_detect
<= 40) {
250 DPRINTF((" succeded\n"));
255 isa_intr_disestablish(ic
, sc
->ih
);
258 pcic_write(h
, PCIC_CSC_INTR
, 0);
262 sc
->intr_mask
[h
->chip
] = mask
;
264 printf("%s\n", sc
->intr_mask
[h
->chip
] ? "" : " none");
268 * called with interrupts enabled, light up the irqs to find out
269 * which irq lines are actually hooked up to our pcic
272 pcic_isa_config_interrupts(device_t self
)
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
;
280 isc
= device_private(self
);
284 /* probe each controller */
286 for (i
= 0; i
< PCIC_NSLOTS
; i
+= 2) {
287 if (sc
->handle
[i
].flags
& PCIC_FLAG_SOCKETP
)
289 else if (sc
->handle
[i
+ 1].flags
& PCIC_FLAG_SOCKETP
)
290 h
= &sc
->handle
[i
+ 1];
294 sc
->intr_mask
[h
->chip
] =
295 PCIC_INTR_IRQ_VALIDMASK
& pcic_isa_intr_alloc_mask
;
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
);
302 chipmask
&= sc
->intr_mask
[h
->chip
];
304 /* now see if there is at least one irq per chip not shared by all */
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)
310 if ((sc
->intr_mask
[i
/ 2] & ~chipmask
) == 0) {
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...
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.
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
;
341 printf("%s: ", device_xname(self
));
342 sc
->irq
= ISA_UNKNOWN_IRQ
;
345 if (sc
->irq
!= ISA_UNKNOWN_IRQ
) {
346 sc
->ih
= isa_intr_establish(ic
, sc
->irq
, IST_EDGE
, IPL_TTY
,
348 if (sc
->ih
== NULL
) {
349 aprint_error_dev(self
, "can't establish interrupt");
350 sc
->irq
= ISA_UNKNOWN_IRQ
;
353 if (sc
->irq
== ISA_UNKNOWN_IRQ
)
354 printf("polling for socket events\n");
356 printf("%s: using irq %d for socket events\n",
357 device_xname(self
), sc
->irq
);
359 pcic_attach_sockets_finish(sc
);
365 * XXX This routine does not deal with the aliasing issue that its
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.
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.
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
)
378 bus_space_handle_t ioh_high
;
379 int i
, iobuswidth
, tmp1
, tmp2
;
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.
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");
394 for (i
= 0; i
< PCIC_NSLOTS
; i
++) {
395 if (sc
->handle
[i
].flags
& PCIC_FLAG_SOCKETP
) {
397 * read the ident flags from the normal space and
398 * from the mirror, and compare them
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
);
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
);
414 bus_space_free(iot
, ioh_high
, length
);
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)
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.
426 if (iobuswidth
== 10) {
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
));
438 if (pcic_isa_alloc_iobase
&& pcic_isa_alloc_iosize
) {
439 sc
->iobase
= pcic_isa_alloc_iobase
;
440 sc
->iosize
= pcic_isa_alloc_iosize
;
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
));
449 pcic_isa_chip_intr_establish(pcmcia_chipset_handle_t pch
,
450 struct pcmcia_function
*pf
, int ipl
, int (*fct
)(void *), void *arg
)
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
;
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
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 */
475 ist
= IST_EDGE
; /* SEE COMMENT ABOVE */
477 if (isa_intr_alloc(ic
, sc
->intr_mask
[h
->chip
], ist
, &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
);
487 if ((ih
= isa_intr_establish(ic
, irq
, ist
, ipl
, fct
, arg
)) == NULL
)
490 printf("%s: card irq %d\n", device_xname(h
->pcmcia
), irq
);
496 pcic_isa_chip_intr_disestablish(pcmcia_chipset_handle_t pch
, void *ih
)
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
;
503 isa_intr_disestablish(ic
, ih
);
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
);