Home | History | Annotate | Line # | Download | only in dev
gayle_pcmcia.c revision 1.6
      1 /*	$NetBSD: gayle_pcmcia.c,v 1.6 2000/09/27 08:24:02 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 /*
     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, 0,
    132 		UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE,
    133 		UVM_INH_NONE, UVM_ADV_RANDOM, 0));
    134 	if (ret != KERN_SUCCESS) {
    135 		printf("attach failed (no virtual memory)\n");
    136 		return;
    137 	}
    138 
    139 	for (i = GAYLE_PCMCIA_START; i < GAYLE_PCMCIA_END; i += PAGE_SIZE)
    140 		pmap_enter(kernel_map->pmap,
    141 		    i - GAYLE_PCMCIA_START + pcmcia_base, i,
    142 		    VM_PROT_READ | VM_PROT_WRITE, TRUE);
    143 
    144 	/* override the one-byte access methods for I/O space */
    145 	pcmio_bs_methods = amiga_bus_stride_1;
    146 	pcmio_bs_methods.bsr1 = pcmio_bsr1;
    147 	pcmio_bs_methods.bsw1 = pcmio_bsw1;
    148 	pcmio_bs_methods.bsrm1 = pcmio_bsrm1;
    149 	pcmio_bs_methods.bswm1 = pcmio_bswm1;
    150 	pcmio_bs_methods.bsrr1 = pcmio_bsrr1;
    151 	pcmio_bs_methods.bswr1 = pcmio_bswr1;
    152 	pcmio_bs_methods.bssr1 = pcmio_bssr1;
    153 	pcmio_bs_methods.bscr1 = pcmio_bscr1;
    154 
    155 	reset_card_reg = (u_int8_t *) pcmcia_base - GAYLE_PCMCIA_START +
    156 	    GAYLE_PCMCIA_RESET;
    157 
    158 	self->io_space.base = (u_int) pcmcia_base - GAYLE_PCMCIA_START +
    159 	    GAYLE_PCMCIA_IO_START;
    160 	self->io_space.absm = &pcmio_bs_methods;
    161 
    162 	self->attr_space.base = (u_int) pcmcia_base - GAYLE_PCMCIA_START +
    163 	    GAYLE_PCMCIA_ATTR_START;
    164 	self->attr_space.absm = &amiga_bus_stride_1;
    165 
    166 	/* XXX we should check if the 4M of common memory are actually
    167 	 *	RAM or PCMCIA usable.
    168 	 * For now, we just do as if the 4M were RAM and make common memory
    169 	 * point to attribute memory, which is OK for some I/O cards.
    170 	 */
    171 	self->mem_space.base = (u_int) pcmcia_base;
    172 	self->mem_space.absm = &amiga_bus_stride_1;
    173 
    174 	self->devs[0].sc = self;
    175 	self->devs[0].intr_func = NULL;
    176 	self->devs[0].intr_arg = NULL;
    177 	self->devs[0].flags = 0;
    178 
    179 	gayle.pcc_status = 0;
    180 	gayle.intreq = 0;
    181 	gayle.pcc_config = 0;
    182 	gayle.intena &= GAYLE_INT_IDE;
    183 
    184 	paa.paa_busname = "pcmcia";
    185 	paa.pct = &chip_functions;
    186 	paa.pch = &self->devs[0];
    187 	paa.iobase = 0;
    188 	paa.iosize = 0;
    189 	self->devs[0].card =
    190 		config_found_sm(myself, &paa, simple_devprint, NULL);
    191 	if (self->devs[0].card == NULL) {
    192 		printf("attach failed, config_found_sm() returned NULL\n");
    193 		return;
    194 	}
    195 
    196 	self->intr6.isr_intr = pccard_intr6;
    197 	self->intr6.isr_arg = self;
    198 	self->intr6.isr_ipl = 6;
    199 	add_isr(&self->intr6);
    200 
    201 	self->intr2.isr_intr = pccard_intr2;
    202 	self->intr2.isr_arg = self;
    203 	self->intr2.isr_ipl = 2;
    204 	add_isr(&self->intr2);
    205 
    206 	kthread_create(pccard_create_kthread, self);
    207 
    208 	gayle.intena |= GAYLE_INT_DETECT | GAYLE_INT_IREQ;
    209 
    210 	/* reset the card if it's already there */
    211 	if (gayle.pcc_status & GAYLE_CCMEM_DETECT) {
    212 		volatile u_int8_t x;
    213 		*reset_card_reg = 0x0;
    214 		delay(1000);
    215 		x = *reset_card_reg;
    216 		gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
    217 	}
    218 
    219 	pccard_attach_slot(&self->devs[0]);
    220 }
    221 
    222 /* This is called as soon as it is possible to create a kernel thread */
    223 static void
    224 pccard_create_kthread(arg)
    225 	void *arg;
    226 {
    227 	struct pccard_softc *self = arg;
    228 
    229 	if (kthread_create1(pccard_kthread, self, NULL, "pccard thread")) {
    230 		printf("%s: can't create kernel thread\n",
    231 			self->sc_dev.dv_xname);
    232 		panic("pccard kthread_create() failed");
    233 	}
    234 }
    235 
    236 static int
    237 pccard_intr6(arg)
    238 	void *arg;
    239 {
    240 	struct pccard_softc *self = arg;
    241 
    242 	if (gayle.intreq & GAYLE_INT_DETECT) {
    243 		gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_STSCHG |
    244 		    GAYLE_INT_SPKR | GAYLE_INT_WP | GAYLE_INT_IREQ;
    245 		self->devs[0].flags |= SLOT_NEW_CARD_EVENT;
    246 		return 1;
    247 	}
    248 	return 0;
    249 }
    250 
    251 static int
    252 pccard_intr2(arg)
    253 	void *arg;
    254 {
    255 	struct pccard_softc *self = arg;
    256 	struct pccard_slot *slot = &self->devs[0];
    257 
    258 	if (slot->flags & SLOT_NEW_CARD_EVENT) {
    259 		slot->flags &= ~SLOT_NEW_CARD_EVENT;
    260 
    261 		/* reset the registers */
    262 		gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_DETECT;
    263 		gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
    264 		gayle.pcc_config = 0;
    265 		pccard_attach_slot(&self->devs[0]);
    266 	} else {
    267 		int intreq = gayle.intreq &
    268 		    (GAYLE_INT_STSCHG | GAYLE_INT_WP | GAYLE_INT_IREQ);
    269 		if (intreq) {
    270 			gayle.intreq = (intreq ^ 0x2c) | 0xc0;
    271 
    272 			return slot->flags & SLOT_OCCUPIED &&
    273 		   		slot->intr_func != NULL &&
    274 				slot->intr_func(slot->intr_arg);
    275 		}
    276 	}
    277 	return 0;
    278 }
    279 
    280 static void
    281 pccard_kthread(arg)
    282 	void *arg;
    283 {
    284 	struct pccard_softc *self = arg;
    285 	struct pccard_slot *slot = &self->devs[0];
    286 
    287 	for (;;) {
    288 		int s = spl2();
    289 
    290 		if (slot->flags & SLOT_NEW_CARD_EVENT) {
    291 			slot->flags &= ~SLOT_NEW_CARD_EVENT;
    292 			gayle.intreq = 0xc0;
    293 
    294 			/* reset the registers */
    295 			gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_DETECT;
    296 			gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
    297 			gayle.pcc_config = 0;
    298 			pccard_attach_slot(&self->devs[0]);
    299 		}
    300 		splx(s);
    301 
    302 		tsleep(slot, PWAIT, "pccthread", hz);
    303 	}
    304 }
    305 
    306 static void
    307 pccard_attach_slot(slot)
    308 	struct pccard_slot *slot;
    309 {
    310 	if (!(slot->flags & SLOT_OCCUPIED) &&
    311 			gayle.pcc_status & GAYLE_CCMEM_DETECT) {
    312 		if (pcmcia_card_attach(slot->card) == 0)
    313 			slot->flags |= SLOT_OCCUPIED;
    314 	}
    315 }
    316 
    317 static int
    318 pcf_mem_alloc(pch, bsz, pcmh)
    319 	pcmcia_chipset_handle_t pch;
    320 	bus_size_t bsz;
    321 	struct pcmcia_mem_handle *pcmh;
    322 {
    323 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    324 	pcmh->memt = &slot->sc->attr_space;
    325 	pcmh->memh = pcmh->memt->base;
    326 	return 0;
    327 }
    328 
    329 static void
    330 pcf_mem_free(pch, memh)
    331 	pcmcia_chipset_handle_t pch;
    332 	struct pcmcia_mem_handle *memh;
    333 {
    334 }
    335 
    336 static int
    337 pcf_mem_map(pch, kind, addr, size, pcmh, offsetp, windowp)
    338 	pcmcia_chipset_handle_t pch;
    339 	int kind;
    340 	bus_addr_t addr;
    341 	bus_size_t size;
    342 	struct pcmcia_mem_handle *pcmh;
    343 	bus_addr_t *offsetp;
    344 	int *windowp;
    345 {
    346 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    347 
    348 	/* Ignore width requirements */
    349 	kind &= ~PCMCIA_WIDTH_MEM_MASK;
    350 
    351 	switch (kind) {
    352 	case PCMCIA_MEM_ATTR:
    353 		pcmh->memt = &slot->sc->attr_space;
    354 		break;
    355 	case PCMCIA_MEM_COMMON:
    356 		pcmh->memt = &slot->sc->mem_space;
    357 		break;
    358 	default:
    359 		/* This means that this code needs an update/a bugfix */
    360 		printf(__FILE__ ": Unknown kind of PCMCIA memory\n");
    361 		return 1;
    362 	}
    363 
    364 	bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh);
    365 	*offsetp = 0;
    366 	*windowp = 0;			/* unused */
    367 
    368 	return 0;
    369 }
    370 
    371 static void
    372 pcf_mem_unmap(pch, win)
    373 	pcmcia_chipset_handle_t pch;
    374 	int win;
    375 {
    376 }
    377 
    378 static int
    379 pcf_io_alloc(pch, start, size, align, pcihp)
    380 	pcmcia_chipset_handle_t pch;
    381 	bus_addr_t start;
    382 	bus_size_t size;
    383 	bus_size_t align;
    384 	struct pcmcia_io_handle *pcihp;
    385 {
    386 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    387 
    388 	pcihp->iot = &slot->sc->io_space;
    389 	pcihp->ioh = pcihp->iot->base;
    390 	return 0;
    391 }
    392 
    393 static void
    394 pcf_io_free(pch, pcihp)
    395 	pcmcia_chipset_handle_t pch;
    396 	struct pcmcia_io_handle *pcihp;
    397 {
    398 }
    399 
    400 static int
    401 pcf_io_map(pch, width, offset, size, pcihp, windowp)
    402 	pcmcia_chipset_handle_t pch;
    403 	int width;
    404 	bus_addr_t offset;
    405 	bus_size_t size;
    406 	struct pcmcia_io_handle *pcihp;
    407 	int *windowp;
    408 {
    409 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    410 
    411 	pcihp->iot = &slot->sc->io_space;
    412 	pcihp->ioh = offset;
    413 
    414 	*windowp = 0;		/* unused */
    415 	return 0;
    416 }
    417 
    418 static void
    419 pcf_io_unmap(pch, win)
    420 	pcmcia_chipset_handle_t pch;
    421 	int win;
    422 {
    423 }
    424 
    425 static void *
    426 pcf_intr_establish(pch, pf, ipl, func, arg)
    427 	pcmcia_chipset_handle_t pch;
    428 	struct pcmcia_function *pf;
    429 	int ipl;
    430 	int (*func)(void *);
    431 	void *arg;
    432 {
    433 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    434 	int s;
    435 
    436 	s = splhigh();
    437 	if (slot->intr_func == NULL) {
    438 		slot->intr_func = func;
    439 		slot->intr_arg = arg;
    440 	} else {
    441 		/* if we are here, we need to put intrs into a list */
    442 		printf("ARGH! see " __FILE__ "\n");
    443 		slot = NULL;
    444 	}
    445 	splx(s);
    446 
    447 	return slot;
    448 }
    449 
    450 static void
    451 pcf_intr_disestablish(pch, intr_handler)
    452 	pcmcia_chipset_handle_t pch;
    453 	void *intr_handler;
    454 {
    455 	struct pccard_slot *slot = (struct pccard_slot *) intr_handler;
    456 
    457 	if (slot != NULL) {
    458 		slot->intr_func = NULL;
    459 		slot->intr_arg = NULL;
    460 	}
    461 }
    462 
    463 static void
    464 pcf_socket_enable(pch)
    465 	pcmcia_chipset_handle_t pch;
    466 {
    467 }
    468 
    469 static void
    470 pcf_socket_disable(pch)
    471 	pcmcia_chipset_handle_t pch;
    472 {
    473 }
    474 
    475 
    476 static u_int8_t
    477 pcmio_bsr1(h, o)
    478 	bus_space_handle_t h;
    479 	bus_size_t o;
    480 {
    481 	return *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0));
    482 }
    483 
    484 static void
    485 pcmio_bsw1(h, o, v)
    486 	bus_space_handle_t h;
    487 	bus_size_t o;
    488 	unsigned v;
    489 {
    490 	*((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)) = v;
    491 }
    492 
    493 static void
    494 pcmio_bsrm1(h, o, p, c)
    495 	bus_space_handle_t h;
    496 	bus_size_t o;
    497 	u_int8_t *p;
    498 	bus_size_t c;
    499 {
    500 	volatile u_int8_t *src = (volatile u_int8_t *) (h + o +
    501 							(o & 1 ? 0xffff : 0));
    502 
    503 
    504 	/* XXX we can (should, must) optimize this if c >= 4 */
    505 	for (; c > 0; c--)
    506 		*p++ = *src;
    507 }
    508 
    509 
    510 static void
    511 pcmio_bswm1(h, o, p, c)
    512 	bus_space_handle_t h;
    513 	bus_size_t o;
    514 	const u_int8_t *p;
    515 	bus_size_t c;
    516 {
    517 	volatile u_int8_t *dst = (volatile u_int8_t *) (h + o +
    518 							(o & 1 ? 0xffff : 0));
    519 
    520 
    521 	/* XXX we can (should, must) optimize this if c >= 4 */
    522 	for (; c > 0; c--)
    523 		*dst = *p++;
    524 }
    525 
    526 static void
    527 pcmio_bsrr1(h, o, p, c)
    528 	bus_space_handle_t h;
    529 	bus_size_t o;
    530 	u_int8_t *p;
    531 	bus_size_t c;
    532 {
    533 	volatile u_int8_t *cp1;
    534 	volatile u_int8_t *cp2;
    535 	volatile u_int8_t *temp;
    536 
    537 	if (o & 1) {
    538 		cp1 = (volatile u_int8_t *) h + o + 0x10000;
    539 		cp2 = (volatile u_int8_t *) h + o;
    540 	} else {
    541 		cp1 = (volatile u_int8_t *) h + o;
    542 		cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2;
    543 	}
    544 
    545 	/* XXX we can (should, must) optimize this if c >= 4 */
    546 	for (; c > 0; c--) {
    547 		*p++ = *cp1;
    548 		cp1 += 2;
    549 
    550 		/* swap pointers - hope gcc generates exg for this ;) */
    551 		temp = cp1;
    552 		cp1 = cp2;
    553 		cp2 = temp;
    554 	}
    555 }
    556 
    557 
    558 static void
    559 pcmio_bswr1(h, o, p, c)
    560 	bus_space_handle_t h;
    561 	bus_size_t o;
    562 	const u_int8_t *p;
    563 	bus_size_t c;
    564 {
    565 	volatile u_int8_t *cp1;
    566 	volatile u_int8_t *cp2;
    567 	volatile u_int8_t *temp;
    568 
    569 	if (o & 1) {
    570 		cp1 = (volatile u_int8_t *) h + o + 0x10000;
    571 		cp2 = (volatile u_int8_t *) h + o;
    572 	} else {
    573 		cp1 = (volatile u_int8_t *) h + o;
    574 		cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2;
    575 	}
    576 
    577 	/* XXX we can (should, must) optimize this if c >= 4 */
    578 	for (; c > 0; c--) {
    579 		*cp1 = *p++;
    580 		cp1 += 2;
    581 
    582 		/* swap pointers - hope gcc generates exg for this ;) */
    583 		temp = cp1;
    584 		cp1 = cp2;
    585 		cp2 = temp;
    586 	}
    587 }
    588 
    589 void
    590 pcmio_bssr1(h, o, v, c)
    591 	bus_space_handle_t h;
    592 	bus_size_t o;
    593 	unsigned v;
    594 	bus_size_t c;
    595 {
    596 	panic("pcmio_bssr1 is not defined (" __FILE__ ")");
    597 }
    598 
    599 void
    600 pcmio_bscr1(h, o, g, q, c)
    601 	bus_space_handle_t h;
    602 	bus_size_t o;
    603 	bus_space_handle_t g;
    604 	bus_size_t q;
    605 	bus_size_t c;
    606 {
    607 	panic("pcmio_bscr1 is not defined (" __FILE__ ")");
    608 }
    609