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