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