gayle_pcmcia.c revision 1.11 1 /* $NetBSD: gayle_pcmcia.c,v 1.11 2002/01/26 13:40:54 aymeric Exp $ */
2
3 /* public domain */
4
5 /* PCMCIA front-end driver for A1200's and A600's. */
6
7 #include <sys/param.h>
8 #include <sys/cdefs.h>
9 #include <sys/device.h>
10 #include <sys/kernel.h>
11 #include <sys/kthread.h>
12 #include <sys/systm.h>
13
14 #include <uvm/uvm.h>
15
16 #include <dev/pcmcia/pcmciareg.h>
17 #include <dev/pcmcia/pcmciavar.h>
18
19 #include <machine/cpu.h>
20 #include <amiga/amiga/custom.h>
21 #include <amiga/amiga/device.h>
22 #include <amiga/amiga/gayle.h>
23 #include <amiga/amiga/isr.h>
24
25
26 /* There is one of these for each slot. And yes, there is only one slot. */
27 struct pccard_slot {
28 struct pccard_softc *sc; /* refer to `parent' */
29 int (*intr_func)(void *);
30 void * intr_arg;
31 struct device *card;
32 int flags;
33 #define SLOT_OCCUPIED 0x01
34 #define SLOT_NEW_CARD_EVENT 0x02
35 };
36
37 struct pccard_softc {
38 struct device sc_dev;
39 struct bus_space_tag io_space;
40 struct bus_space_tag attr_space;
41 struct bus_space_tag mem_space;
42 struct pccard_slot devs[1];
43 struct isr intr6;
44 struct isr intr2;
45 };
46
47 static int pccard_probe(struct device *, struct cfdata *, void *);
48 static void pccard_attach(struct device *, struct device *, void *);
49 static void pccard_attach_slot(struct pccard_slot *);
50 static int pccard_intr6(void *);
51 static int pccard_intr2(void *);
52 static void pccard_create_kthread(void *);
53 static void pccard_kthread(void *);
54
55 static int pcf_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
56 struct pcmcia_mem_handle *);
57 static void pcf_mem_free(pcmcia_chipset_handle_t, struct pcmcia_mem_handle *);
58 static int pcf_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
59 struct pcmcia_mem_handle *, bus_addr_t *, int *);
60 static void pcf_mem_unmap(pcmcia_chipset_handle_t, int);
61 static int pcf_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t,
62 bus_size_t, struct pcmcia_io_handle *);
63 static void pcf_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *);
64 static int pcf_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, bus_size_t,
65 struct pcmcia_io_handle *, int *);
66 static void pcf_io_unmap(pcmcia_chipset_handle_t, int);
67 static void *pcf_intr_establish(pcmcia_chipset_handle_t,
68 struct pcmcia_function *, int, int (*)(void *), void *);
69 static void pcf_intr_disestablish(pcmcia_chipset_handle_t, void *);
70 static void pcf_socket_enable(pcmcia_chipset_handle_t);
71 static void pcf_socket_disable(pcmcia_chipset_handle_t);
72
73 static bsr(pcmio_bsr1, u_int8_t);
74 static bsw(pcmio_bsw1, u_int8_t);
75 static bsrm(pcmio_bsrm1, u_int8_t);
76 static bswm(pcmio_bswm1, u_int8_t);
77 static bsrm(pcmio_bsrr1, u_int8_t);
78 static bswm(pcmio_bswr1, u_int8_t);
79 static bssr(pcmio_bssr1, u_int8_t);
80 static bscr(pcmio_bscr1, u_int8_t);
81
82 struct cfattach pccard_ca = {
83 sizeof(struct pccard_softc), pccard_probe, pccard_attach
84 };
85
86 struct pcmcia_chip_functions chip_functions = {
87 pcf_mem_alloc, pcf_mem_free,
88 pcf_mem_map, pcf_mem_unmap,
89 pcf_io_alloc, pcf_io_free,
90 pcf_io_map, pcf_io_unmap,
91 pcf_intr_establish, pcf_intr_disestablish,
92 pcf_socket_enable, pcf_socket_disable
93 };
94
95 struct amiga_bus_space_methods pcmio_bs_methods;
96
97 static u_int8_t *reset_card_reg;
98
99 static int
100 pccard_probe(struct device *dev, struct cfdata *cfd, void *aux)
101 {
102
103 return (/*is_a600() || */is_a1200()) && matchname(aux, "pccard");
104 }
105
106 static void
107 pccard_attach(struct device *parent, struct device *myself, void *aux)
108 {
109 struct pccard_softc *self = (struct pccard_softc *) myself;
110 struct pcmciabus_attach_args paa;
111 vaddr_t pcmcia_base = GAYLE_PCMCIA_START;
112 vaddr_t i;
113 int ret;
114
115 printf("\n");
116
117 gayle_init();
118
119 ret = uvm_map(kernel_map, &pcmcia_base,
120 GAYLE_PCMCIA_END - GAYLE_PCMCIA_START, NULL,
121 UVM_UNKNOWN_OFFSET, 0,
122 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE,
123 UVM_INH_NONE, UVM_ADV_RANDOM, 0));
124 if (ret != 0) {
125 printf("attach failed (no virtual memory)\n");
126 return;
127 }
128
129 for (i = GAYLE_PCMCIA_START; i < GAYLE_PCMCIA_END; i += PAGE_SIZE)
130 pmap_enter(kernel_map->pmap,
131 i - GAYLE_PCMCIA_START + pcmcia_base, i,
132 VM_PROT_READ | VM_PROT_WRITE, TRUE);
133 pmap_update(kernel_map->pmap);
134
135 /* override the one-byte access methods for I/O space */
136 pcmio_bs_methods = amiga_bus_stride_1;
137 pcmio_bs_methods.bsr1 = pcmio_bsr1;
138 pcmio_bs_methods.bsw1 = pcmio_bsw1;
139 pcmio_bs_methods.bsrm1 = pcmio_bsrm1;
140 pcmio_bs_methods.bswm1 = pcmio_bswm1;
141 pcmio_bs_methods.bsrr1 = pcmio_bsrr1;
142 pcmio_bs_methods.bswr1 = pcmio_bswr1;
143 pcmio_bs_methods.bssr1 = pcmio_bssr1;
144 pcmio_bs_methods.bscr1 = pcmio_bscr1;
145
146 reset_card_reg = (u_int8_t *) pcmcia_base - GAYLE_PCMCIA_START +
147 GAYLE_PCMCIA_RESET;
148
149 self->io_space.base = (u_int) pcmcia_base - GAYLE_PCMCIA_START +
150 GAYLE_PCMCIA_IO_START;
151 self->io_space.absm = &pcmio_bs_methods;
152
153 self->attr_space.base = (u_int) pcmcia_base - GAYLE_PCMCIA_START +
154 GAYLE_PCMCIA_ATTR_START;
155 self->attr_space.absm = &amiga_bus_stride_1;
156
157 /* XXX we should check if the 4M of common memory are actually
158 * RAM or PCMCIA usable.
159 * For now, we just do as if the 4M were RAM and make common memory
160 * point to attribute memory, which is OK for some I/O cards.
161 */
162 self->mem_space.base = (u_int) pcmcia_base;
163 self->mem_space.absm = &amiga_bus_stride_1;
164
165 self->devs[0].sc = self;
166 self->devs[0].intr_func = NULL;
167 self->devs[0].intr_arg = NULL;
168 self->devs[0].flags = 0;
169
170 gayle.pcc_status = 0;
171 gayle.intreq = 0;
172 gayle.pcc_config = 0;
173 gayle.intena &= GAYLE_INT_IDE;
174
175 paa.paa_busname = "pcmcia";
176 paa.pct = &chip_functions;
177 paa.pch = &self->devs[0];
178 paa.iobase = 0;
179 paa.iosize = 0;
180 self->devs[0].card =
181 config_found_sm(myself, &paa, simple_devprint, NULL);
182 if (self->devs[0].card == NULL) {
183 printf("attach failed, config_found_sm() returned NULL\n");
184 return;
185 }
186
187 self->intr6.isr_intr = pccard_intr6;
188 self->intr6.isr_arg = self;
189 self->intr6.isr_ipl = 6;
190 add_isr(&self->intr6);
191
192 self->intr2.isr_intr = pccard_intr2;
193 self->intr2.isr_arg = self;
194 self->intr2.isr_ipl = 2;
195 add_isr(&self->intr2);
196
197 kthread_create(pccard_create_kthread, self);
198
199 gayle.intena |= GAYLE_INT_DETECT | GAYLE_INT_IREQ;
200
201 /* reset the card if it's already there */
202 if (gayle.pcc_status & GAYLE_CCMEM_DETECT) {
203 volatile u_int8_t x;
204 *reset_card_reg = 0x0;
205 delay(1000);
206 x = *reset_card_reg;
207 gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
208 }
209
210 pccard_attach_slot(&self->devs[0]);
211 }
212
213 /* This is called as soon as it is possible to create a kernel thread */
214 static void
215 pccard_create_kthread(void *arg)
216 {
217 struct pccard_softc *self = arg;
218
219 if (kthread_create1(pccard_kthread, self, NULL, "pccard thread")) {
220 printf("%s: can't create kernel thread\n",
221 self->sc_dev.dv_xname);
222 panic("pccard kthread_create() failed");
223 }
224 }
225
226 static int
227 pccard_intr6(void *arg)
228 {
229 struct pccard_softc *self = arg;
230
231 if (gayle.intreq & GAYLE_INT_DETECT) {
232 gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_STSCHG |
233 GAYLE_INT_SPKR | GAYLE_INT_WP | GAYLE_INT_IREQ;
234 self->devs[0].flags |= SLOT_NEW_CARD_EVENT;
235 return 1;
236 }
237 return 0;
238 }
239
240 static int
241 pccard_intr2(void *arg)
242 {
243 struct pccard_softc *self = arg;
244 struct pccard_slot *slot = &self->devs[0];
245
246 if (slot->flags & SLOT_NEW_CARD_EVENT) {
247 slot->flags &= ~SLOT_NEW_CARD_EVENT;
248
249 /* reset the registers */
250 gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_DETECT;
251 gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
252 gayle.pcc_config = 0;
253 pccard_attach_slot(&self->devs[0]);
254 } else {
255 int intreq = gayle.intreq &
256 (GAYLE_INT_STSCHG | GAYLE_INT_WP | GAYLE_INT_IREQ);
257 if (intreq) {
258 gayle.intreq = (intreq ^ 0x2c) | 0xc0;
259
260 return slot->flags & SLOT_OCCUPIED &&
261 slot->intr_func != NULL &&
262 slot->intr_func(slot->intr_arg);
263 }
264 }
265 return 0;
266 }
267
268 static void
269 pccard_kthread(void *arg)
270 {
271 struct pccard_softc *self = arg;
272 struct pccard_slot *slot = &self->devs[0];
273
274 for (;;) {
275 int s = spl2();
276
277 if (slot->flags & SLOT_NEW_CARD_EVENT) {
278 slot->flags &= ~SLOT_NEW_CARD_EVENT;
279 gayle.intreq = 0xc0;
280
281 /* reset the registers */
282 gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_DETECT;
283 gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
284 gayle.pcc_config = 0;
285 pccard_attach_slot(&self->devs[0]);
286 }
287 splx(s);
288
289 tsleep(slot, PWAIT, "pccthread", hz);
290 }
291 }
292
293 static void
294 pccard_attach_slot(struct pccard_slot *slot)
295 {
296
297 if (!(slot->flags & SLOT_OCCUPIED) &&
298 gayle.pcc_status & GAYLE_CCMEM_DETECT) {
299 if (pcmcia_card_attach(slot->card) == 0)
300 slot->flags |= SLOT_OCCUPIED;
301 }
302 }
303
304 static int
305 pcf_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t bsz,
306 struct pcmcia_mem_handle *pcmh)
307 {
308 struct pccard_slot *slot = (struct pccard_slot *) pch;
309
310 pcmh->memt = &slot->sc->attr_space;
311 pcmh->memh = pcmh->memt->base;
312 return 0;
313 }
314
315 static void
316 pcf_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *memh)
317 {
318 }
319
320 static int
321 pcf_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr,
322 bus_size_t size, struct pcmcia_mem_handle *pcmh,
323 bus_addr_t *offsetp, int *windowp)
324 {
325 struct pccard_slot *slot = (struct pccard_slot *) pch;
326
327 /* Ignore width requirements */
328 kind &= ~PCMCIA_WIDTH_MEM_MASK;
329
330 switch (kind) {
331 case PCMCIA_MEM_ATTR:
332 pcmh->memt = &slot->sc->attr_space;
333 break;
334 case PCMCIA_MEM_COMMON:
335 pcmh->memt = &slot->sc->mem_space;
336 break;
337 default:
338 /* This means that this code needs an update/a bugfix */
339 printf(__FILE__ ": unknown kind %d of PCMCIA memory\n", kind);
340 return 1;
341 }
342
343 bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh);
344 *offsetp = 0;
345 *windowp = 0; /* unused */
346
347 return 0;
348 }
349
350 static void
351 pcf_mem_unmap(pcmcia_chipset_handle_t pch, int win)
352 {
353 }
354
355 static int
356 pcf_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start, bus_size_t size,
357 bus_size_t align, struct pcmcia_io_handle *pcihp)
358 {
359 struct pccard_slot *slot = (struct pccard_slot *) pch;
360
361 pcihp->iot = &slot->sc->io_space;
362 pcihp->ioh = pcihp->iot->base;
363 return 0;
364 }
365
366 static void
367 pcf_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pcihp)
368 {
369 }
370
371 static int
372 pcf_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
373 bus_size_t size, struct pcmcia_io_handle *pcihp, int *windowp)
374 {
375 struct pccard_slot *slot = (struct pccard_slot *) pch;
376
377 pcihp->iot = &slot->sc->io_space;
378 pcihp->ioh = offset;
379
380 *windowp = 0; /* unused */
381 return 0;
382 }
383
384 static void
385 pcf_io_unmap(pcmcia_chipset_handle_t pch, int win)
386 {
387 }
388
389 static void *
390 pcf_intr_establish(pcmcia_chipset_handle_t pch, struct pcmcia_function *pf,
391 int ipl, int (*func)(void *), void *arg)
392 {
393 struct pccard_slot *slot = (struct pccard_slot *) pch;
394 int s;
395
396 s = splhigh();
397 if (slot->intr_func == NULL) {
398 slot->intr_func = func;
399 slot->intr_arg = arg;
400 } else {
401 /* if we are here, we need to put intrs into a list */
402 printf("ARGH! see " __FILE__ "\n");
403 slot = NULL;
404 }
405 splx(s);
406
407 return slot;
408 }
409
410 static void
411 pcf_intr_disestablish(pcmcia_chipset_handle_t pch, void *intr_handler)
412 {
413 struct pccard_slot *slot = (struct pccard_slot *) intr_handler;
414
415 if (slot != NULL) {
416 slot->intr_func = NULL;
417 slot->intr_arg = NULL;
418 }
419 }
420
421 static void
422 pcf_socket_enable(pcmcia_chipset_handle_t pch)
423 {
424 }
425
426 static void
427 pcf_socket_disable(pcmcia_chipset_handle_t pch)
428 {
429 }
430
431
432 static u_int8_t
433 pcmio_bsr1(bus_space_handle_t h, bus_size_t o)
434 {
435
436 return *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0));
437 }
438
439 static void
440 pcmio_bsw1(bus_space_handle_t h, bus_size_t o, unsigned v)
441 {
442
443 *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)) = v;
444 }
445
446 static void
447 pcmio_bsrm1(bus_space_handle_t h, bus_size_t o, u_int8_t *p, bus_size_t c)
448 {
449 volatile u_int8_t *src = (volatile u_int8_t *)
450 (h + o + (o & 1 ? 0xffff : 0));
451
452
453 /* XXX we can (should, must) optimize this if c >= 4 */
454 for (; c > 0; c--)
455 *p++ = *src;
456 }
457
458
459 static void
460 pcmio_bswm1(bus_space_handle_t h, bus_size_t o, const u_int8_t *p, bus_size_t c)
461 {
462 volatile u_int8_t *dst = (volatile u_int8_t *)
463 (h + o + (o & 1 ? 0xffff : 0));
464
465
466 /* XXX we can (should, must) optimize this if c >= 4 */
467 for (; c > 0; c--)
468 *dst = *p++;
469 }
470
471 static void
472 pcmio_bsrr1(bus_space_handle_t h, bus_size_t o, u_int8_t *p, bus_size_t c)
473 {
474 volatile u_int8_t *cp1;
475 volatile u_int8_t *cp2;
476 volatile u_int8_t *temp;
477
478 if (o & 1) {
479 cp1 = (volatile u_int8_t *) h + o + 0x10000;
480 cp2 = (volatile u_int8_t *) h + o;
481 } else {
482 cp1 = (volatile u_int8_t *) h + o;
483 cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2;
484 }
485
486 /* XXX we can (should, must) optimize this if c >= 4 */
487 for (; c > 0; c--) {
488 *p++ = *cp1;
489 cp1 += 2;
490
491 /* swap pointers - hope gcc generates exg for this ;) */
492 temp = cp1;
493 cp1 = cp2;
494 cp2 = temp;
495 }
496 }
497
498
499 static void
500 pcmio_bswr1(bus_space_handle_t h, bus_size_t o, const u_int8_t *p, bus_size_t c)
501 {
502 volatile u_int8_t *cp1;
503 volatile u_int8_t *cp2;
504 volatile u_int8_t *temp;
505
506 if (o & 1) {
507 cp1 = (volatile u_int8_t *) h + o + 0x10000;
508 cp2 = (volatile u_int8_t *) h + o;
509 } else {
510 cp1 = (volatile u_int8_t *) h + o;
511 cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2;
512 }
513
514 /* XXX we can (should, must) optimize this if c >= 4 */
515 for (; c > 0; c--) {
516 *cp1 = *p++;
517 cp1 += 2;
518
519 /* swap pointers - hope gcc generates exg for this ;) */
520 temp = cp1;
521 cp1 = cp2;
522 cp2 = temp;
523 }
524 }
525
526 void
527 pcmio_bssr1(bus_space_handle_t h, bus_size_t o, unsigned v, bus_size_t c)
528 {
529
530 panic("pcmio_bssr1 is not defined (" __FILE__ ")");
531 }
532
533 void
534 pcmio_bscr1(bus_space_handle_t h, bus_size_t o, bus_space_handle_t g,
535 bus_size_t q, bus_size_t c)
536 {
537
538 panic("pcmio_bscr1 is not defined (" __FILE__ ")");
539 }
540