i82365_isa.c revision 1.1.2.3 1 /* $NetBSD: i82365_isa.c,v 1.1.2.3 1997/10/16 02:57:10 thorpej Exp $ */
2
3 #define PCICISADEBUG
4
5 #include <sys/types.h>
6 #include <sys/param.h>
7 #include <sys/systm.h>
8 #include <sys/device.h>
9 #include <sys/extent.h>
10 #include <sys/malloc.h>
11
12 #include <vm/vm.h>
13
14 #include <machine/bus.h>
15 #include <machine/intr.h>
16
17 #include <dev/isa/isareg.h>
18 #include <dev/isa/isavar.h>
19
20 #include <dev/pcmcia/pcmciareg.h>
21 #include <dev/pcmcia/pcmciavar.h>
22 #include <dev/pcmcia/pcmciachip.h>
23
24 #include <dev/ic/i82365reg.h>
25 #include <dev/ic/i82365var.h>
26
27 #ifdef PCICISADEBUG
28 int pcicisa_debug = 0 /* XXX */ ;
29 #define DPRINTF(arg) if (pcicisa_debug) printf arg;
30 #else
31 #define DPRINTF(arg)
32 #endif
33
34 int pcic_isa_probe __P((struct device *, void *, void *));
35 void pcic_isa_attach __P((struct device *, struct device *, void *));
36
37 void *pcic_isa_chip_intr_establish __P((pcmcia_chipset_handle_t,
38 struct pcmcia_function *, int, int (*) (void *), void *));
39 void pcic_isa_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
40
41 struct cfattach pcic_isa_ca = {
42 sizeof(struct pcic_softc), pcic_isa_probe, pcic_isa_attach
43 };
44
45 static struct pcmcia_chip_functions pcic_isa_functions = {
46 pcic_chip_mem_alloc,
47 pcic_chip_mem_free,
48 pcic_chip_mem_map,
49 pcic_chip_mem_unmap,
50
51 pcic_chip_io_alloc,
52 pcic_chip_io_free,
53 pcic_chip_io_map,
54 pcic_chip_io_unmap,
55
56 pcic_isa_chip_intr_establish,
57 pcic_isa_chip_intr_disestablish,
58
59 pcic_chip_socket_enable,
60 pcic_chip_socket_disable,
61 };
62
63 int
64 pcic_isa_probe(parent, match, aux)
65 struct device *parent;
66 void *match, *aux;
67 {
68 struct isa_attach_args *ia = aux;
69 bus_space_tag_t iot = ia->ia_iot;
70 bus_space_handle_t ioh, memh;
71 int val, found;
72
73 if (bus_space_map(iot, ia->ia_iobase, PCIC_IOSIZE, 0, &ioh))
74 return (0);
75
76 if (ia->ia_msize == -1)
77 ia->ia_msize = PCIC_MEMSIZE;
78
79 if (bus_space_map(ia->ia_memt, ia->ia_maddr, ia->ia_msize, 0, &memh))
80 return (0);
81
82 found = 0;
83
84 /*
85 * this could be done with a loop, but it would violate the
86 * abstraction
87 */
88
89 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA + PCIC_IDENT);
90
91 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
92
93 if (pcic_ident_ok(val))
94 found++;
95
96
97 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB + PCIC_IDENT);
98
99 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
100
101 if (pcic_ident_ok(val))
102 found++;
103
104
105 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA + PCIC_IDENT);
106
107 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
108
109 if (pcic_ident_ok(val))
110 found++;
111
112
113 bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB + PCIC_IDENT);
114
115 val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
116
117 if (pcic_ident_ok(val))
118 found++;
119
120
121 bus_space_unmap(iot, ioh, PCIC_IOSIZE);
122 bus_space_unmap(ia->ia_memt, memh, ia->ia_msize);
123
124 if (!found)
125 return (0);
126
127 ia->ia_iosize = PCIC_IOSIZE;
128
129 return (1);
130 }
131
132 #ifndef PCIC_ISA_ALLOC_IOBASE
133 #define PCIC_ISA_ALLOC_IOBASE 0
134 #endif
135
136 #ifndef PCIC_ISA_ALLOC_IOSIZE
137 #define PCIC_ISA_ALLOC_IOSIZE 0
138 #endif
139
140 int pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE;
141 int pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE;
142
143 void
144 pcic_isa_attach(parent, self, aux)
145 struct device *parent, *self;
146 void *aux;
147 {
148 struct pcic_softc *sc = (void *) self;
149 struct isa_attach_args *ia = aux;
150 isa_chipset_tag_t ic = ia->ia_ic;
151 bus_space_tag_t iot = ia->ia_iot;
152 bus_space_tag_t memt = ia->ia_memt;
153 bus_space_handle_t ioh;
154 bus_space_handle_t memh;
155 bus_space_handle_t ioh_high;
156 int i, iobuswidth, tmp1, tmp2;
157
158 /* Map i/o space. */
159 if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh))
160 panic("pcic_isa_attach: can't map i/o space");
161
162 /* Map mem space. */
163 if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh))
164 panic("pcic_isa_attach: can't map i/o space");
165
166 sc->membase = ia->ia_maddr;
167 sc->subregionmask = (1 << (ia->ia_msize / PCIC_MEM_PAGESIZE)) - 1;
168
169 sc->intr_est = ic;
170 sc->pct = (pcmcia_chipset_tag_t) & pcic_isa_functions;
171
172 sc->iot = iot;
173 sc->ioh = ioh;
174 sc->memt = memt;
175 sc->memh = memh;
176
177 /*
178 * allocate an irq. it will be used by both controllers. I could
179 * use two different interrupts, but interrupts are relatively
180 * scarce, shareable, and for PCIC controllers, very infrequent.
181 */
182
183 if ((sc->irq = ia->ia_irq) == IRQUNK) {
184 /* XXX CHECK RETURN VALUE */
185 (void) isa_intr_alloc(ic, PCIC_CSC_INTR_IRQ_VALIDMASK,
186 IST_EDGE, &sc->irq);
187 printf(": using irq %d", sc->irq);
188 }
189 printf("\n");
190
191 pcic_attach(sc);
192
193 /*
194 * figure out how wide the isa bus is. Do this by checking if the
195 * pcic controller is mirrored 0x400 above where we expect it to be.
196 */
197
198 iobuswidth = 12;
199
200 /* Map i/o space. */
201 if (bus_space_map(iot, ia->ia_iobase + 0x400, ia->ia_iosize, 0,
202 &ioh_high))
203 panic("pcic_isa_attach: can't map high i/o space");
204
205 for (i = 0; i < PCIC_NSLOTS; i++) {
206 if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
207 /*
208 * read the ident flags from the normal space and
209 * from the mirror, and compare them
210 */
211
212 bus_space_write_1(iot, ioh, PCIC_REG_INDEX,
213 sc->handle[i].sock + PCIC_IDENT);
214 tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
215
216 bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX,
217 sc->handle[i].sock + PCIC_IDENT);
218 tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA);
219
220 if (tmp1 == tmp2)
221 iobuswidth = 10;
222 }
223 }
224
225 bus_space_free(iot, ioh_high, ia->ia_iosize);
226
227 /*
228 * XXX mycroft recommends I/O space range 0x400-0xfff . I should put
229 * this in a header somewhere
230 */
231
232 /*
233 * XXX some hardware doesn't seem to grok addresses in 0x400 range--
234 * apparently missing a bit or more of address lines. (e.g.
235 * CIRRUS_PD672X with Linksys EthernetCard ne2000 clone in TI
236 * TravelMate 5000--not clear which is at fault)
237 *
238 * Add a kludge to detect 10 bit wide buses and deal with them,
239 * and also a config file option to override the probe.
240 */
241
242 if (iobuswidth == 10) {
243 sc->iobase = 0x300;
244 sc->iosize = 0x0ff;
245 } else {
246 sc->iobase = 0x400;
247 sc->iosize = 0xbff;
248 }
249
250 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (probed)\n",
251 sc->dev.dv_xname, (long) sc->iobase,
252 (long) sc->iobase + sc->iosize));
253
254 if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) {
255 sc->iobase = pcic_isa_alloc_iobase;
256 sc->iosize = pcic_isa_alloc_iosize;
257
258 DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx "
259 "(config override)\n", sc->dev.dv_xname, (long) sc->iobase,
260 (long) sc->iobase + sc->iosize));
261 }
262 sc->ih = isa_intr_establish(ic, sc->irq, IST_EDGE, IPL_TTY,
263 pcic_intr, sc);
264
265 pcic_attach_sockets(sc);
266 }
267
268 /*
269 * allow patching or kernel option file override of available IRQs. Useful if
270 * order of probing would screw up other devices, or if PCIC hardware/cards
271 * have trouble with certain interrupt lines.
272 */
273
274 #ifndef PCIC_INTR_ALLOC_MASK
275 #define PCIC_INTR_ALLOC_MASK 0xffff
276 #endif
277
278 int pcic_intr_alloc_mask = PCIC_INTR_ALLOC_MASK;
279
280 void *
281 pcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg)
282 pcmcia_chipset_handle_t pch;
283 struct pcmcia_function *pf;
284 int ipl;
285 int (*fct) __P((void *));
286 void *arg;
287 {
288 struct pcic_handle *h = (struct pcic_handle *) pch;
289 int irq, ist;
290 void *ih;
291 int reg;
292
293 if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
294 ist = IST_LEVEL;
295 else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
296 ist = IST_PULSE;
297 else
298 ist = IST_LEVEL;
299
300 if (isa_intr_alloc(h->sc->intr_est,
301 PCIC_INTR_IRQ_VALIDMASK & pcic_intr_alloc_mask, ist, &irq))
302 return (NULL);
303 if ((ih = isa_intr_establish(h->sc->intr_est, irq, ist, ipl,
304 fct, arg)) == NULL)
305 return (NULL);
306
307 reg = pcic_read(h, PCIC_INTR);
308 reg &= ~PCIC_INTR_IRQ_MASK;
309 reg |= irq;
310 pcic_write(h, PCIC_INTR, reg);
311
312 h->ih_irq = irq;
313
314 printf("%s: card irq %d\n", h->pcmcia->dv_xname, irq);
315
316 return (ih);
317 }
318
319 void
320 pcic_isa_chip_intr_disestablish(pch, ih)
321 pcmcia_chipset_handle_t pch;
322 void *ih;
323 {
324 struct pcic_handle *h = (struct pcic_handle *) pch;
325 int reg;
326
327 h->ih_irq = 0;
328
329 reg = pcic_read(h, PCIC_INTR);
330 reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
331 pcic_write(h, PCIC_INTR, reg);
332
333 isa_intr_disestablish(h->sc->intr_est, ih);
334 }
335