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