i82365_isa.c revision 1.4.2.3 1 /* $NetBSD: i82365_isa.c,v 1.4.2.3 1997/11/05 21:45:17 thorpej Exp $ */
2
3 #define PCICISADEBUG
4
5 /*
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/types.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/extent.h>
39 #include <sys/malloc.h>
40
41 #include <vm/vm.h>
42
43 #include <machine/bus.h>
44 #include <machine/intr.h>
45
46 #include <dev/isa/isareg.h>
47 #include <dev/isa/isavar.h>
48
49 #include <dev/pcmcia/pcmciareg.h>
50 #include <dev/pcmcia/pcmciavar.h>
51 #include <dev/pcmcia/pcmciachip.h>
52
53 #include <dev/ic/i82365reg.h>
54 #include <dev/ic/i82365var.h>
55
56 /*****************************************************************************
57 * Configurable parameters.
58 *****************************************************************************/
59
60 #include "opt_pcic_isa_alloc_iobase.h"
61 #include "opt_pcic_isa_alloc_iosize.h"
62 #include "opt_pcic_isa_intr_alloc_mask.h"
63
64 /*
65 * Default I/O allocation range. If both are set to non-zero, these
66 * values will be used instead. Otherwise, the code attempts to probe
67 * the bus width. Systems with 10 address bits should use 0x300 and 0xff.
68 * Systems with 12 address bits (most) should use 0x400 and 0xbff.
69 */
70
71 #ifndef PCIC_ISA_ALLOC_IOBASE
72 #define PCIC_ISA_ALLOC_IOBASE 0
73 #endif
74
75 #ifndef PCIC_ISA_ALLOC_IOSIZE
76 #define PCIC_ISA_ALLOC_IOSIZE 0
77 #endif
78
79 int pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE;
80 int pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE;
81
82 /*
83 * Default IRQ allocation bitmask. This defines the range of allowable
84 * IRQs for PCMCIA slots. Useful if order of probing would screw up other
85 * devices, or if PCIC hardware/cards have trouble with certain interrupt
86 * lines.
87 *
88 * We disable IRQ 10 by default, since some common laptops (namely, the
89 * NEC Versa series) reserve IRQ 10 for the docking station SCSI interface.
90 */
91
92 #ifndef PCIC_ISA_INTR_ALLOC_MASK
93 #define PCIC_ISA_INTR_ALLOC_MASK 0xfbff
94 #endif
95
96 int pcic_isa_intr_alloc_mask = PCIC_ISA_INTR_ALLOC_MASK;
97
98 /*****************************************************************************
99 * End of configurable parameters.
100 *****************************************************************************/
101
102 #ifdef PCICISADEBUG
103 int pcicisa_debug = 0 /* XXX */ ;
104 #define DPRINTF(arg) if (pcicisa_debug) printf arg;
105 #else
106 #define DPRINTF(arg)
107 #endif
108
109 int pcic_isa_probe __P((struct device *, void *, void *));
110 void pcic_isa_attach __P((struct device *, struct device *, void *));
111
112 void *pcic_isa_chip_intr_establish __P((pcmcia_chipset_handle_t,
113 struct pcmcia_function *, int, int (*) (void *), void *));
114 void pcic_isa_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
115
116 struct cfattach pcic_isa_ca = {
117 sizeof(struct pcic_softc), pcic_isa_probe, pcic_isa_attach
118 };
119
120 static struct pcmcia_chip_functions pcic_isa_functions = {
121 pcic_chip_mem_alloc,
122 pcic_chip_mem_free,
123 pcic_chip_mem_map,
124 pcic_chip_mem_unmap,
125
126 pcic_chip_io_alloc,
127 pcic_chip_io_free,
128 pcic_chip_io_map,
129 pcic_chip_io_unmap,
130
131 pcic_isa_chip_intr_establish,
132 pcic_isa_chip_intr_disestablish,
133
134 pcic_chip_socket_enable,
135 pcic_chip_socket_disable,
136 };
137
138 int
139 pcic_isa_probe(parent, match, aux)
140 struct device *parent;
141 void *match, *aux;
142 {
143 struct isa_attach_args *ia = aux;
144 bus_space_tag_t iot = ia->ia_iot;
145 bus_space_handle_t ioh, memh;
146 int val, found;
147
148 /* Disallow wildcarded i/o address. */
149 if (ia->ia_iobase == ISACF_PORT_DEFAULT)
150 return (0);
151
152 if (bus_space_map(iot, ia->ia_iobase, PCIC_IOSIZE, 0, &ioh))
153 return (0);
154
155 if (ia->ia_msize == -1)
156 ia->ia_msize = PCIC_MEMSIZE;
157
158 if (bus_space_map(ia->ia_memt, ia->ia_maddr, ia->ia_msize, 0, &memh))
159 return (0);
160
161 found = 0;
162
163 /*
164 * this could be done with a loop, but it would violate the
165 * abstraction
166 */
167
168 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA + PCIC_IDENT);
169
170 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
171
172 if (pcic_ident_ok(val))
173 found++;
174
175
176 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB + PCIC_IDENT);
177
178 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
179
180 if (pcic_ident_ok(val))
181 found++;
182
183
184 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA + PCIC_IDENT);
185
186 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
187
188 if (pcic_ident_ok(val))
189 found++;
190
191
192 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB + PCIC_IDENT);
193
194 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
195
196 if (pcic_ident_ok(val))
197 found++;
198
199
200 bus_space_unmap(iot, ioh, PCIC_IOSIZE);
201 bus_space_unmap(ia->ia_memt, memh, ia->ia_msize);
202
203 if (!found)
204 return (0);
205
206 ia->ia_iosize = PCIC_IOSIZE;
207
208 return (1);
209 }
210
211 void
212 pcic_isa_attach(parent, self, aux)
213 struct device *parent, *self;
214 void *aux;
215 {
216 struct pcic_softc *sc = (void *) self;
217 struct isa_attach_args *ia = aux;
218 isa_chipset_tag_t ic = ia->ia_ic;
219 bus_space_tag_t iot = ia->ia_iot;
220 bus_space_tag_t memt = ia->ia_memt;
221 bus_space_handle_t ioh;
222 bus_space_handle_t memh;
223 bus_space_handle_t ioh_high;
224 int i, iobuswidth, tmp1, tmp2;
225
226 /* Map i/o space. */
227 if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) {
228 printf(": can't map i/o space\n");
229 return;
230 }
231
232 /* Map mem space. */
233 if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh)) {
234 printf(": can't map mem space\n");
235 return;
236 }
237
238 sc->membase = ia->ia_maddr;
239 sc->subregionmask = (1 << (ia->ia_msize / PCIC_MEM_PAGESIZE)) - 1;
240
241 sc->intr_est = ic;
242 sc->pct = (pcmcia_chipset_tag_t) & pcic_isa_functions;
243
244 sc->iot = iot;
245 sc->ioh = ioh;
246 sc->memt = memt;
247 sc->memh = memh;
248
249 /*
250 * allocate an irq. it will be used by both controllers. I could
251 * use two different interrupts, but interrupts are relatively
252 * scarce, shareable, and for PCIC controllers, very infrequent.
253 */
254
255 if ((sc->irq = ia->ia_irq) == IRQUNK) {
256 if (isa_intr_alloc(ic,
257 PCIC_CSC_INTR_IRQ_VALIDMASK & pcic_isa_intr_alloc_mask,
258 IST_EDGE, &sc->irq)) {
259 printf("\n%s: can't allocate interrupt\n",
260 sc->dev.dv_xname);
261 return;
262 }
263 printf(": using irq %d", sc->irq);
264 }
265 printf("\n");
266
267 pcic_attach(sc);
268
269 /*
270 * figure out how wide the isa bus is. Do this by checking if the
271 * pcic controller is mirrored 0x400 above where we expect it to be.
272 */
273
274 iobuswidth = 12;
275
276 /* Map i/o space. */
277 if (bus_space_map(iot, ia->ia_iobase + 0x400, ia->ia_iosize, 0,
278 &ioh_high)) {
279 printf("%s: can't map high i/o space\n", sc->dev.dv_xname);
280 return;
281 }
282
283 for (i = 0; i < PCIC_NSLOTS; i++) {
284 if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
285 /*
286 * read the ident flags from the normal space and
287 * from the mirror, and compare them
288 */
289
290 bus_space_write_1(iot, ioh, PCIC_REG_INDEX,
291 sc->handle[i].sock + PCIC_IDENT);
292 tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
293
294 bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX,
295 sc->handle[i].sock + PCIC_IDENT);
296 tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA);
297
298 if (tmp1 == tmp2)
299 iobuswidth = 10;
300 }
301 }
302
303 bus_space_free(iot, ioh_high, ia->ia_iosize);
304
305 /*
306 * XXX mycroft recommends I/O space range 0x400-0xfff . I should put
307 * this in a header somewhere
308 */
309
310 /*
311 * XXX some hardware doesn't seem to grok addresses in 0x400 range--
312 * apparently missing a bit or more of address lines. (e.g.
313 * CIRRUS_PD672X with Linksys EthernetCard ne2000 clone in TI
314 * TravelMate 5000--not clear which is at fault)
315 *
316 * Add a kludge to detect 10 bit wide buses and deal with them,
317 * and also a config file option to override the probe.
318 */
319
320 if (iobuswidth == 10) {
321 sc->iobase = 0x300;
322 sc->iosize = 0x0ff;
323 } else {
324 #if 0
325 /*
326 * This is what we'd like to use, but...
327 */
328 sc->iobase = 0x400;
329 sc->iosize = 0xbff;
330 #else
331 /*
332 * ...the above bus width probe doesn't always work.
333 * So, experimentation has shown the following range
334 * to not lose on systems that 0x300-0x3ff loses on
335 * (e.g. the NEC Versa 6030X).
336 */
337 sc->iobase = 0x330;
338 sc->iosize = 0x0cf;
339 #endif
340 }
341
342 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (probed)\n",
343 sc->dev.dv_xname, (long) sc->iobase,
344 (long) sc->iobase + sc->iosize));
345
346 if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) {
347 sc->iobase = pcic_isa_alloc_iobase;
348 sc->iosize = pcic_isa_alloc_iosize;
349
350 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx "
351 "(config override)\n", sc->dev.dv_xname, (long) sc->iobase,
352 (long) sc->iobase + sc->iosize));
353 }
354 sc->ih = isa_intr_establish(ic, sc->irq, IST_EDGE, IPL_TTY,
355 pcic_intr, sc);
356 if (sc->ih == NULL) {
357 printf("%s: can't establish interrupt\n", sc->dev.dv_xname);
358 return;
359 }
360
361 pcic_attach_sockets(sc);
362 }
363
364 void *
365 pcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg)
366 pcmcia_chipset_handle_t pch;
367 struct pcmcia_function *pf;
368 int ipl;
369 int (*fct) __P((void *));
370 void *arg;
371 {
372 struct pcic_handle *h = (struct pcic_handle *) pch;
373 int irq, ist;
374 void *ih;
375 int reg;
376
377 if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
378 ist = IST_LEVEL;
379 else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
380 ist = IST_PULSE;
381 else
382 ist = IST_LEVEL;
383
384 if (isa_intr_alloc(h->sc->intr_est,
385 PCIC_INTR_IRQ_VALIDMASK & pcic_isa_intr_alloc_mask, ist, &irq))
386 return (NULL);
387 if ((ih = isa_intr_establish(h->sc->intr_est, irq, ist, ipl,
388 fct, arg)) == NULL)
389 return (NULL);
390
391 reg = pcic_read(h, PCIC_INTR);
392 reg &= ~PCIC_INTR_IRQ_MASK;
393 reg |= irq;
394 pcic_write(h, PCIC_INTR, reg);
395
396 h->ih_irq = irq;
397
398 printf("%s: card irq %d\n", h->pcmcia->dv_xname, irq);
399
400 return (ih);
401 }
402
403 void
404 pcic_isa_chip_intr_disestablish(pch, ih)
405 pcmcia_chipset_handle_t pch;
406 void *ih;
407 {
408 struct pcic_handle *h = (struct pcic_handle *) pch;
409 int reg;
410
411 h->ih_irq = 0;
412
413 reg = pcic_read(h, PCIC_INTR);
414 reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
415 pcic_write(h, PCIC_INTR, reg);
416
417 isa_intr_disestablish(h->sc->intr_est, ih);
418 }
419