aupcmcia.c revision 1.3 1 /* $NetBSD: aupcmcia.c,v 1.3 2007/07/09 20:52:22 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
6 *
7 * Written by Garrett D'Amore for Itronix Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Itronix Inc. may not be used to endorse
18 * or promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /* #include "opt_pci.h" */
35 /* #include "pci.h" */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: aupcmcia.c,v 1.3 2007/07/09 20:52:22 ad Exp $");
39
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/errno.h>
44 #include <sys/kernel.h>
45 #include <sys/kthread.h>
46
47 #include <dev/pcmcia/pcmciareg.h>
48 #include <dev/pcmcia/pcmciavar.h>
49 #include <dev/pcmcia/pcmciachip.h>
50
51 #include <mips/alchemy/include/au_himem_space.h>
52 #include <mips/alchemy/include/aubusvar.h>
53 #include <mips/alchemy/include/aureg.h>
54 #include <mips/alchemy/include/auvar.h>
55
56 #include <mips/alchemy/dev/aupcmciareg.h>
57 #include <mips/alchemy/dev/aupcmciavar.h>
58
59 /*
60 * Borrow PCMCIADEBUG for now. Generally aupcmcia is the only PCMCIA
61 * host on these machines anyway.
62 */
63 #ifdef PCMCIADEBUG
64 int aupcm_debug = 1;
65 #define DPRINTF(arg) if (aupcm_debug) printf arg
66 #else
67 #define DPRINTF(arg)
68 #endif
69
70 /*
71 * And for information about mappings, etc. use this one.
72 */
73 #ifdef AUPCMCIANOISY
74 #define NOISY(arg) printf arg
75 #else
76 #define NOISY(arg)
77 #endif
78
79 /*
80 * Note, we use prefix "aupcm" instead of "aupcmcia", even though our
81 * driver is the latter, mostly because my fingers have trouble typing
82 * the former. "aupcm" should be sufficiently unique to avoid
83 * confusion.
84 */
85
86 static int aupcm_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
87 struct pcmcia_mem_handle *);
88 static void aupcm_mem_free(pcmcia_chipset_handle_t,
89 struct pcmcia_mem_handle *);
90 static int aupcm_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
91 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
92 static void aupcm_mem_unmap(pcmcia_chipset_handle_t, int);
93
94 static int aupcm_io_alloc(pcmcia_chipset_handle_t, bus_addr_t, bus_size_t,
95 bus_size_t, struct pcmcia_io_handle *);
96 static void aupcm_io_free(pcmcia_chipset_handle_t, struct pcmcia_io_handle *);
97 static int aupcm_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
98 bus_size_t, struct pcmcia_io_handle *, int *);
99 static void aupcm_io_unmap(pcmcia_chipset_handle_t, int);
100 static void *aupcm_intr_establish(pcmcia_chipset_handle_t,
101 struct pcmcia_function *, int, int (*)(void *), void *);
102 static void aupcm_intr_disestablish(pcmcia_chipset_handle_t, void *);
103
104 static void aupcm_slot_enable(pcmcia_chipset_handle_t);
105 static void aupcm_slot_disable(pcmcia_chipset_handle_t);
106 static void aupcm_slot_settype(pcmcia_chipset_handle_t, int);
107
108 static int aupcm_match(struct device *, struct cfdata *, void *);
109 static void aupcm_attach(struct device *, struct device *, void *);
110
111 static void aupcm_event_thread(void *);
112 static int aupcm_card_intr(void *);
113 static void aupcm_softintr(void *);
114 static int aupcm_print(void *, const char *);
115
116 struct aupcm_slot {
117 struct aupcm_softc *as_softc;
118 int as_slot;
119 int as_status;
120 int as_enabled;
121 int (*as_intr)(void *);
122 int as_card_irq;
123 int as_status_irq;
124 void *as_intrarg;
125 void *as_softint;
126 void *as_hardint;
127 const char *as_name;
128 bus_addr_t as_offset;
129 struct mips_bus_space as_iot;
130 struct mips_bus_space as_attrt;
131 struct mips_bus_space as_memt;
132 void *as_wins[AUPCMCIA_NWINS];
133
134 struct device *as_pcmcia;
135 };
136
137 /* this structure needs to be exposed... */
138 struct aupcm_softc {
139 struct device sc_dev;
140 pcmcia_chipset_tag_t sc_pct;
141
142 void (*sc_slot_enable)(int);
143 void (*sc_slot_disable)(int);
144 int (*sc_slot_status)(int);
145
146 paddr_t sc_base;
147
148 int sc_wake;
149 lwp_t *sc_thread;
150
151 int sc_nslots;
152 struct aupcm_slot sc_slots[AUPCMCIA_NSLOTS];
153 };
154
155 static struct pcmcia_chip_functions aupcm_functions = {
156 aupcm_mem_alloc,
157 aupcm_mem_free,
158 aupcm_mem_map,
159 aupcm_mem_unmap,
160
161 aupcm_io_alloc,
162 aupcm_io_free,
163 aupcm_io_map,
164 aupcm_io_unmap,
165
166 aupcm_intr_establish,
167 aupcm_intr_disestablish,
168
169 aupcm_slot_enable,
170 aupcm_slot_disable,
171 aupcm_slot_settype,
172 };
173
174 static struct mips_bus_space aupcm_memt;
175
176 CFATTACH_DECL(aupcmcia, sizeof (struct aupcm_softc),
177 aupcm_match, aupcm_attach, NULL, NULL);
178
179 int
180 aupcm_match(struct device *parent, struct cfdata *cf, void *aux)
181 {
182 struct aubus_attach_args *aa = aux;
183 static int found = 0;
184
185 if (found)
186 return 0;
187
188 if (strcmp(aa->aa_name, "aupcmcia") != 0)
189 return 0;
190
191 found = 1;
192
193 return 1;
194 }
195
196 void
197 aupcm_attach(struct device *parent, struct device *self, void *aux)
198 {
199 /* struct aubus_attach_args *aa = aux; */
200 struct aupcm_softc *sc = (struct aupcm_softc *)self;
201 static int done = 0;
202 int slot;
203 struct aupcmcia_machdep *md;
204
205 /* initialize bus space */
206 if (done) {
207 /* there can be only one. */
208 return;
209 }
210
211 done = 1;
212 /*
213 * PCMCIA memory can live within pretty much the entire 32-bit
214 * space, modulo 64 MB wraps. We don't have to support coexisting
215 * DMA.
216 */
217 au_himem_space_init(&aupcm_memt, "pcmciamem",
218 PCMCIA_BASE, AUPCMCIA_ATTR_OFFSET, 0xffffffff,
219 AU_HIMEM_SPACE_LITTLE_ENDIAN);
220
221 if ((md = aupcmcia_machdep()) == NULL) {
222 printf("\n%s:unable to get machdep structure\n",
223 sc->sc_dev.dv_xname);
224 return;
225 }
226
227 sc->sc_nslots = md->am_nslots;
228 sc->sc_slot_enable = md->am_slot_enable;
229 sc->sc_slot_disable = md->am_slot_disable;
230 sc->sc_slot_status = md->am_slot_status;
231
232 printf(": Alchemy PCMCIA, %d slots\n", sc->sc_nslots);
233
234 sc->sc_pct = (pcmcia_chipset_tag_t)&aupcm_functions;
235
236 for (slot = 0; slot < sc->sc_nslots; slot++) {
237 struct aupcm_slot *sp;
238 struct pcmciabus_attach_args paa;
239
240 sp = &sc->sc_slots[slot];
241 sp->as_softc = sc;
242
243 sp->as_slot = slot;
244 sp->as_name = md->am_slot_name(slot);
245 sp->as_offset = md->am_slot_offset(slot);
246 sp->as_card_irq = md->am_slot_irq(slot, AUPCMCIA_IRQ_CARD);
247 sp->as_status_irq = md->am_slot_irq(slot,
248 AUPCMCIA_IRQ_INSERT);
249
250 au_himem_space_init(&sp->as_attrt, "pcmciaattr",
251 PCMCIA_BASE + sp->as_offset + AUPCMCIA_ATTR_OFFSET,
252 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN);
253
254 au_himem_space_init(&sp->as_memt, "pcmciamem",
255 PCMCIA_BASE + sp->as_offset + AUPCMCIA_MEM_OFFSET,
256 0, AUPCMCIA_MAP_SIZE, AU_HIMEM_SPACE_LITTLE_ENDIAN);
257
258 au_himem_space_init(&sp->as_iot, "pcmciaio",
259 PCMCIA_BASE + sp->as_offset + AUPCMCIA_IO_OFFSET,
260 0, AUPCMCIA_MAP_SIZE,
261 AU_HIMEM_SPACE_LITTLE_ENDIAN | AU_HIMEM_SPACE_IO);
262
263 sp->as_status = 0;
264
265 paa.paa_busname = "pcmcia";
266 paa.pct = sc->sc_pct;
267 paa.pch = (pcmcia_chipset_handle_t)sp;
268
269 paa.iobase = 0;
270 paa.iosize = AUPCMCIA_MAP_SIZE;
271
272 sp->as_pcmcia = config_found(&sc->sc_dev, &paa, aupcm_print);
273
274 /* if no pcmcia, make sure slot is powered down */
275 if (sp->as_pcmcia == NULL) {
276 aupcm_slot_disable(sp);
277 continue;
278 }
279
280 /* this makes sure we probe the slot */
281 sc->sc_wake |= (1 << slot);
282 }
283
284 /*
285 * XXX: this would be an excellent time time to establish a handler
286 * for the card insertion interrupt, but that's edge triggered, and
287 * au_icu.c won't support it right now. We poll in the event thread
288 * for now. Start by initializing it now.
289 */
290 if (kthread_create(PRI_NONE, 0, NULL, aupcm_event_thread, sc,
291 &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0)
292 panic("%s: unable to create event kthread",
293 sc->sc_dev.dv_xname);
294 }
295
296 int
297 aupcm_print(void *aux, const char *pnp)
298 {
299 struct pcmciabus_attach_args *paa = aux;
300 struct aupcm_slot *sp = paa->pch;
301
302 printf(" socket %d irq %d, %s", sp->as_slot, sp->as_card_irq,
303 sp->as_name);
304
305 return (UNCONF);
306 }
307
308 void *
309 aupcm_intr_establish(pcmcia_chipset_handle_t pch,
310 struct pcmcia_function *pf, int level, int (*handler)(void *), void *arg)
311 {
312 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
313 int s;
314
315 /*
316 * Hmm. perhaps this intr should be a list. well, PCMCIA
317 * devices generally only have one interrupt, and so should
318 * generally have only one handler. So we leave it for now.
319 * (Other PCMCIA bus drivers do it this way.)
320 */
321 sp->as_intr = handler;
322 sp->as_intrarg = arg;
323
324 /*
325 * XXX: pil must be a software interrupt level. That
326 * automatically implies that it is lower than any other
327 * hardware interrupts. So trying to figure out which level
328 * (IPL_SOFTNET, IPL_SOFTSERIAL, etc.) doesn't really do
329 * anything for us.
330 */
331 sp->as_softint = softintr_establish(IPL_SOFT, aupcm_softintr, sp);
332
333 /* set up hard interrupt handler for the card IRQs */
334 s = splhigh();
335 sp->as_hardint = au_intr_establish(sp->as_card_irq, 0,
336 IPL_TTY, IST_LEVEL_LOW, aupcm_card_intr, sp);
337 /* if card is not powered up, then leave the IRQ masked */
338 if (!sp->as_enabled) {
339 au_intr_disable(sp->as_card_irq);
340 }
341 splx(s);
342
343 return (sp->as_softint);
344 }
345
346 void
347 aupcm_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
348 {
349 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
350
351 KASSERT(sp->as_softint == ih);
352 /* KASSERT(sp->as_hardint); */
353 /* set up hard interrupt handler for the card IRQs */
354
355 au_intr_disestablish(sp->as_hardint);
356 sp->as_hardint = 0;
357
358 softintr_disestablish(ih);
359 sp->as_softint = 0;
360 sp->as_intr = NULL;
361 sp->as_intrarg = NULL;
362 }
363
364 /*
365 * FYI: Hot detach of PCMCIA is supposedly safe because H/W doesn't
366 * fault on accesses to missing hardware.
367 */
368 void
369 aupcm_event_thread(void *arg)
370 {
371 struct aupcm_softc *sc = arg;
372 struct aupcm_slot *sp;
373 int s, i, attach, detach;
374
375 for (;;) {
376 s = splhigh();
377 if (sc->sc_wake == 0) {
378 splx(s);
379 /*
380 * XXX: Currently, the au_icu.c lacks support
381 * for edge-triggered interrupts. So we
382 * cannot really use the status change
383 * inerrupts. For now we poll (once per sec).
384 * FYI, Linux does it this way, and they *do*
385 * have support for edge triggered interrupts.
386 * Go figure.
387 */
388 tsleep(&sc->sc_wake, PWAIT, "aupcm_event", hz);
389 }
390 sc->sc_wake = 0;
391
392 attach = detach = 0;
393 for (i = 0; i < sc->sc_nslots; i++) {
394 sp = &sc->sc_slots[i];
395
396 if (sc->sc_slot_status(sp->as_slot) != 0) {
397 if (!sp->as_status) {
398 DPRINTF(("%s: card %d insertion\n",
399 sc->sc_dev.dv_xname, i));
400 attach |= (1 << i);
401 sp->as_status = 1;
402 }
403 } else {
404 if (sp->as_status) {
405 DPRINTF(("%s: card %d removal\n",
406 sc->sc_dev.dv_xname, i));
407 detach |= (1 << i);
408 sp->as_status = 0;
409 }
410 }
411 }
412 splx(s);
413
414 for (i = 0; i < sc->sc_nslots; i++) {
415 sp = &sc->sc_slots[i];
416
417 if (detach & (1 << i)) {
418 aupcm_slot_disable(sp);
419 pcmcia_card_detach(sp->as_pcmcia,
420 DETACH_FORCE);
421 } else if (attach & (1 << i)) {
422 /*
423 * until the function is enabled, don't
424 * honor interrupts
425 */
426 sp->as_enabled = 0;
427 au_intr_disable(sp->as_card_irq);
428 pcmcia_card_attach(sp->as_pcmcia);
429 }
430 }
431 }
432 }
433
434 #if 0
435 void
436 aupcm_status_intr(void *arg)
437 {
438 int s;
439 struct aupcm_softc *sc = arg;
440
441 s = splhigh();
442
443 /* kick the status thread so it does its bit */
444 sc->sc_wake = 1;
445 wakeup(&sc->sc_wake);
446
447 splx(s);
448 }
449 #endif
450
451 int
452 aupcm_card_intr(void *arg)
453 {
454 struct aupcm_slot *sp = arg;
455
456 /* disable the hard interrupt for now */
457 au_intr_disable(sp->as_card_irq);
458
459 if (sp->as_intr != NULL) {
460 softintr_schedule(sp->as_softint);
461 }
462
463 return 1;
464 }
465
466 void
467 aupcm_softintr(void *arg)
468 {
469 struct aupcm_slot *sp = arg;
470 int s;
471
472 sp->as_intr(sp->as_intrarg);
473
474 s = splhigh();
475
476 if (sp->as_intr && sp->as_enabled) {
477 au_intr_enable(sp->as_card_irq);
478 }
479
480 splx(s);
481 }
482
483 void
484 aupcm_slot_enable(pcmcia_chipset_handle_t pch)
485 {
486 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
487 int s;
488
489 /* no interrupts while we reset the card, please */
490 if (sp->as_intr)
491 au_intr_disable(sp->as_card_irq);
492
493 /*
494 * XXX: should probably lock to make sure slot_disable and
495 * enable not called together. However, i believe that the
496 * event thread basically serializes them anyway.
497 */
498
499 sp->as_softc->sc_slot_enable(sp->as_slot);
500 /* card is powered up now, honor device interrupts */
501
502 s = splhigh();
503 sp->as_enabled = 1;
504 if (sp->as_intr)
505 au_intr_enable(sp->as_card_irq);
506 splx(s);
507 }
508
509 void
510 aupcm_slot_disable(pcmcia_chipset_handle_t pch)
511 {
512 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
513 int s;
514
515 s = splhigh();
516 au_intr_disable(sp->as_card_irq);
517 sp->as_enabled = 0;
518 splx(s);
519
520 sp->as_softc->sc_slot_disable(sp->as_slot);
521 }
522
523 void
524 aupcm_slot_settype(pcmcia_chipset_handle_t pch, int type)
525 {
526 /* we do nothing now : type == PCMCIA_IFTYPE_IO */
527 }
528
529 int
530 aupcm_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
531 struct pcmcia_mem_handle *pcmh)
532 {
533 pcmh->memt = NULL;
534 pcmh->size = pcmh->realsize = size;
535 pcmh->addr = 0;
536 pcmh->mhandle = 0;
537
538 return 0;
539 }
540
541 void
542 aupcm_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pcmh)
543 {
544 /* nothing to do */
545 }
546
547 int
548 aupcm_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t addr,
549 bus_size_t size, struct pcmcia_mem_handle *pcmh, bus_size_t *offsetp,
550 int *windowp)
551 {
552 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
553 int win, err;
554 int s;
555
556 s = splhigh();
557 for (win = 0; win < AUPCMCIA_NWINS; win++) {
558 if (sp->as_wins[win] == NULL) {
559 sp->as_wins[win] = pcmh;
560 break;
561 }
562 }
563 splx(s);
564
565 if (win >= AUPCMCIA_NWINS) {
566 return ENOMEM;
567 }
568
569 if (kind & PCMCIA_MEM_ATTR) {
570 pcmh->memt = &sp->as_attrt;
571 NOISY(("mapping ATTR addr %x size %x\n", (uint32_t)addr,
572 (uint32_t)size));
573 } else {
574 pcmh->memt = &sp->as_memt;
575 NOISY(("mapping MEMORY addr %x size %x\n", (uint32_t)addr,
576 (uint32_t)size));
577 }
578
579 if ((size + addr) > (64 * 1024 * 1024))
580 return EINVAL;
581
582 pcmh->size = size;
583
584 err = bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh);
585 if (err != 0) {
586 sp->as_wins[win] = NULL;
587 return err;
588 }
589 *offsetp = 0;
590 *windowp = win;
591
592 return 0;
593 }
594
595 void
596 aupcm_mem_unmap(pcmcia_chipset_handle_t pch, int win)
597 {
598 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
599 struct pcmcia_mem_handle *pcmh;
600
601 pcmh = (struct pcmcia_mem_handle *)sp->as_wins[win];
602 sp->as_wins[win] = NULL;
603
604 NOISY(("memory umap virtual %x\n", (uint32_t)pcmh->memh));
605 bus_space_unmap(pcmh->memt, pcmh->memh, pcmh->size);
606 pcmh->memt = NULL;
607 }
608
609 int
610 aupcm_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
611 bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pih)
612 {
613 struct aupcm_slot *sp = (struct aupcm_slot *)pch;
614 bus_space_handle_t bush;
615 int err;
616
617 pih->iot = &sp->as_iot;
618 pih->size = size;
619 pih->flags = 0;
620
621 /*
622 * start from the initial offset - this gets us a slot
623 * specific address, while still leaving the addresses more or
624 * less zero-based which is required for x86-style device
625 * drivers.
626 */
627 err = bus_space_alloc(pih->iot, start, 0x100000,
628 size, align, 0, 0, &pih->addr, &bush);
629 NOISY(("start = %x, addr = %x, size = %x, bush = %x\n",
630 (uint32_t)start, (uint32_t)pih->addr, (uint32_t)size,
631 (uint32_t)bush));
632
633 /* and we convert it back */
634 if (err == 0) {
635 pih->ihandle = (void *)bush;
636 }
637
638 return (err);
639 }
640
641 void
642 aupcm_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
643 {
644 bus_space_free(pih->iot, (bus_space_handle_t)pih->ihandle,
645 pih->size);
646 }
647
648 int
649 aupcm_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
650 bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
651 {
652 int err;
653
654 err = bus_space_subregion(pih->iot, (bus_space_handle_t)pih->ihandle,
655 offset, size, &pih->ioh);
656 NOISY(("io map offset = %x, size = %x, ih = %x, hdl=%x\n",
657 (uint32_t)offset, (uint32_t)size,
658 (uint32_t)pih->ihandle, (uint32_t)pih->ioh));
659
660 return err;
661 }
662
663 void
664 aupcm_io_unmap(pcmcia_chipset_handle_t pch, int win)
665 {
666 /* We mustn't unmap/free subregion bus space! */
667 NOISY(("io unmap\n"));
668 }
669