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