Home | History | Annotate | Line # | Download | only in dev
gayle_pcmcia.c revision 1.1
      1 /*	$NetBSD: gayle_pcmcia.c,v 1.1 2000/01/23 20:57:27 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_IREQ;
    238 		self->devs[0].flags |= SLOT_NEW_CARD_EVENT;
    239 		return 1;
    240 	}
    241 	return 0;
    242 }
    243 
    244 static int
    245 pccard_intr2(arg)
    246 	void *arg;
    247 {
    248 	struct pccard_softc *self = arg;
    249 	struct pccard_slot *slot = &self->devs[0];
    250 
    251 	if (slot->flags & SLOT_NEW_CARD_EVENT) {
    252 		slot->flags &= ~SLOT_NEW_CARD_EVENT;
    253 
    254 		/* reset the registers */
    255 		gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_DETECT;
    256 		gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
    257 		gayle.pcc_config = 0;
    258 		pccard_attach_slot(&self->devs[0]);
    259 	} else {
    260 		int intreq = gayle.intreq;
    261 		if (intreq & GAYLE_INT_IREQ) {
    262 			gayle.intreq = (intreq ^ GAYLE_INT_IREQ) |
    263 				GAYLE_INT_IDE | GAYLE_INT_DETECT;
    264 
    265 			if (slot->flags & SLOT_OCCUPIED &&
    266 		   	    slot->intr_func != NULL)
    267 				slot->intr_func(slot->intr_arg);
    268 
    269 			return 1;
    270 		}
    271 	}
    272 	return 0;
    273 }
    274 
    275 static void
    276 pccard_kthread(arg)
    277 	void *arg;
    278 {
    279 	struct pccard_softc *self = arg;
    280 	struct pccard_slot *slot = &self->devs[0];
    281 
    282 	for (;;) {
    283 		int s = spl2();
    284 
    285 		if (slot->flags & SLOT_NEW_CARD_EVENT) {
    286 			slot->flags &= ~SLOT_NEW_CARD_EVENT;
    287 			gayle.intreq = 0xc0;
    288 
    289 			/* reset the registers */
    290 			gayle.intreq = GAYLE_INT_IDE | GAYLE_INT_DETECT;
    291 			gayle.pcc_status = GAYLE_CCMEM_WP | GAYLE_CCIO_SPKR;
    292 			gayle.pcc_config = 0;
    293 			pccard_attach_slot(&self->devs[0]);
    294 		}
    295 		splx(s);
    296 
    297 		tsleep(slot, PWAIT, "pccthread", hz);
    298 	}
    299 }
    300 
    301 static void
    302 pccard_attach_slot(slot)
    303 	struct pccard_slot *slot;
    304 {
    305 	if (!(slot->flags & SLOT_OCCUPIED) &&
    306 			gayle.pcc_status & GAYLE_CCMEM_DETECT) {
    307 		if (pcmcia_card_attach(slot->card) == 0)
    308 			slot->flags |= SLOT_OCCUPIED;
    309 	}
    310 }
    311 
    312 static int
    313 pcf_mem_alloc(pch, bsz, pcmh)
    314 	pcmcia_chipset_handle_t pch;
    315 	bus_size_t bsz;
    316 	struct pcmcia_mem_handle *pcmh;
    317 {
    318 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    319 	pcmh->memt = &slot->sc->attr_space;
    320 	pcmh->memh = pcmh->memt->base;
    321 	return 0;
    322 }
    323 
    324 static void
    325 pcf_mem_free(pch, memh)
    326 	pcmcia_chipset_handle_t pch;
    327 	struct pcmcia_mem_handle *memh;
    328 {
    329 }
    330 
    331 static int
    332 pcf_mem_map(pch, kind, addr, size, pcmh, offsetp, windowp)
    333 	pcmcia_chipset_handle_t pch;
    334 	int kind;
    335 	bus_addr_t addr;
    336 	bus_size_t size;
    337 	struct pcmcia_mem_handle *pcmh;
    338 	bus_addr_t *offsetp;
    339 	int *windowp;
    340 {
    341 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    342 
    343 	switch (kind) {
    344 	case PCMCIA_MEM_ATTR:
    345 		pcmh->memt = &slot->sc->attr_space;
    346 		break;
    347 	case PCMCIA_MEM_COMMON:
    348 		pcmh->memt = &slot->sc->mem_space;
    349 		break;
    350 	default:
    351 		/* This means that this code needs an update/a bugfix */
    352 		printf("Unknown kind of PCMCIA memory (amiga/dev/pccard.c)\n");
    353 		return 1;
    354 	}
    355 
    356 	bus_space_map(pcmh->memt, addr, size, 0, &pcmh->memh);
    357 	*offsetp = 0;
    358 	*windowp = 0;			/* unused */
    359 
    360 	return 0;
    361 }
    362 
    363 static void
    364 pcf_mem_unmap(pch, win)
    365 	pcmcia_chipset_handle_t pch;
    366 	int win;
    367 {
    368 }
    369 
    370 static int
    371 pcf_io_alloc(pch, start, size, align, pcihp)
    372 	pcmcia_chipset_handle_t pch;
    373 	bus_addr_t start;
    374 	bus_size_t size;
    375 	bus_size_t align;
    376 	struct pcmcia_io_handle *pcihp;
    377 {
    378 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    379 
    380 	pcihp->iot = &slot->sc->io_space;
    381 	pcihp->ioh = pcihp->iot->base;
    382 	return 0;
    383 }
    384 
    385 static void
    386 pcf_io_free(pch, pcihp)
    387 	pcmcia_chipset_handle_t pch;
    388 	struct pcmcia_io_handle *pcihp;
    389 {
    390 }
    391 
    392 static int
    393 pcf_io_map(pch, width, offset, size, pcihp, windowp)
    394 	pcmcia_chipset_handle_t pch;
    395 	int width;
    396 	bus_addr_t offset;
    397 	bus_size_t size;
    398 	struct pcmcia_io_handle *pcihp;
    399 	int *windowp;
    400 {
    401 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    402 
    403 	pcihp->iot = &slot->sc->io_space;
    404 	pcihp->ioh = offset;
    405 
    406 	*windowp = 0;		/* unused */
    407 	return 0;
    408 }
    409 
    410 static void
    411 pcf_io_unmap(pch, win)
    412 	pcmcia_chipset_handle_t pch;
    413 	int win;
    414 {
    415 }
    416 
    417 static void *
    418 pcf_intr_establish(pch, pf, ipl, func, arg)
    419 	pcmcia_chipset_handle_t pch;
    420 	struct pcmcia_function *pf;
    421 	int ipl;
    422 	int (*func)(void *);
    423 	void *arg;
    424 {
    425 	struct pccard_slot *slot = (struct pccard_slot *) pch;
    426 	int s;
    427 
    428 	s = splhigh();
    429 	if (slot->intr_func == NULL) {
    430 		slot->intr_func = func;
    431 		slot->intr_arg = arg;
    432 	} else {
    433 		/* if we are here, we need to put intrs into a list */
    434 		printf("ARGH! see arch/amiga/dev/pccard.c\n");
    435 		slot = NULL;
    436 	}
    437 	splx(s);
    438 
    439 	return slot;
    440 }
    441 
    442 static void
    443 pcf_intr_disestablish(pch, intr_handler)
    444 	pcmcia_chipset_handle_t pch;
    445 	void *intr_handler;
    446 {
    447 	struct pccard_slot *slot = (struct pccard_slot *) intr_handler;
    448 
    449 	if (slot != NULL) {
    450 		slot->intr_func = NULL;
    451 		slot->intr_arg = NULL;
    452 	}
    453 }
    454 
    455 static void
    456 pcf_socket_enable(pch)
    457 	pcmcia_chipset_handle_t pch;
    458 {
    459 }
    460 
    461 static void
    462 pcf_socket_disable(pch)
    463 	pcmcia_chipset_handle_t pch;
    464 {
    465 }
    466 
    467 
    468 static u_int8_t
    469 pcmio_bsr1(h, o)
    470 	bus_space_handle_t h;
    471 	bus_size_t o;
    472 {
    473 	return *((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0));
    474 }
    475 
    476 static void
    477 pcmio_bsw1(h, o, v)
    478 	bus_space_handle_t h;
    479 	bus_size_t o;
    480 	unsigned v;
    481 {
    482 	*((volatile u_int8_t *) h + o + (o & 1 ? 0xffff : 0)) = v;
    483 }
    484 
    485 static void
    486 pcmio_bsrm1(h, o, p, c)
    487 	bus_space_handle_t h;
    488 	bus_size_t o;
    489 	u_int8_t *p;
    490 	bus_size_t c;
    491 {
    492 	volatile u_int8_t *src = (volatile u_int8_t *) (h + o +
    493 							(o & 1 ? 0xffff : 0));
    494 
    495 
    496 	/* XXX we can (should, must) optimize this if c >= 4 */
    497 	for (; c > 0; c--)
    498 		*p++ = *src;
    499 }
    500 
    501 
    502 static void
    503 pcmio_bswm1(h, o, p, c)
    504 	bus_space_handle_t h;
    505 	bus_size_t o;
    506 	const u_int8_t *p;
    507 	bus_size_t c;
    508 {
    509 	volatile u_int8_t *dst = (volatile u_int8_t *) (h + o +
    510 							(o & 1 ? 0xffff : 0));
    511 
    512 
    513 	/* XXX we can (should, must) optimize this if c >= 4 */
    514 	for (; c > 0; c--)
    515 		*dst = *p++;
    516 }
    517 
    518 static void
    519 pcmio_bsrr1(h, o, p, c)
    520 	bus_space_handle_t h;
    521 	bus_size_t o;
    522 	u_int8_t *p;
    523 	bus_size_t c;
    524 {
    525 	volatile u_int8_t *cp1;
    526 	volatile u_int8_t *cp2;
    527 	volatile u_int8_t *temp;
    528 
    529 	if (o & 1) {
    530 		cp1 = (volatile u_int8_t *) h + o + 0x10000;
    531 		cp2 = (volatile u_int8_t *) h + o;
    532 	} else {
    533 		cp1 = (volatile u_int8_t *) h + o;
    534 		cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2;
    535 	}
    536 
    537 	/* XXX we can (should, must) optimize this if c >= 4 */
    538 	for (; c > 0; c--) {
    539 		*p++ = *cp1;
    540 		cp1 += 2;
    541 
    542 		/* swap pointers - hope gcc generates exg for this ;) */
    543 		temp = cp1;
    544 		cp1 = cp2;
    545 		cp2 = temp;
    546 	}
    547 }
    548 
    549 
    550 static void
    551 pcmio_bswr1(h, o, p, c)
    552 	bus_space_handle_t h;
    553 	bus_size_t o;
    554 	const u_int8_t *p;
    555 	bus_size_t c;
    556 {
    557 	volatile u_int8_t *cp1;
    558 	volatile u_int8_t *cp2;
    559 	volatile u_int8_t *temp;
    560 
    561 	if (o & 1) {
    562 		cp1 = (volatile u_int8_t *) h + o + 0x10000;
    563 		cp2 = (volatile u_int8_t *) h + o;
    564 	} else {
    565 		cp1 = (volatile u_int8_t *) h + o;
    566 		cp2 = (volatile u_int8_t *) h + o + 0x10000 + 2;
    567 	}
    568 
    569 	/* XXX we can (should, must) optimize this if c >= 4 */
    570 	for (; c > 0; c--) {
    571 		*cp1 = *p++;
    572 		cp1 += 2;
    573 
    574 		/* swap pointers - hope gcc generates exg for this ;) */
    575 		temp = cp1;
    576 		cp1 = cp2;
    577 		cp2 = temp;
    578 	}
    579 }
    580 
    581 void
    582 pcmio_bssr1(h, o, v, c)
    583 	bus_space_handle_t h;
    584 	bus_size_t o;
    585 	unsigned v;
    586 	bus_size_t c;
    587 {
    588 	panic("pcmio_bssr1 is not defined (" __FILE__ ")");
    589 }
    590 
    591 void
    592 pcmio_bscr1(h, o, g, q, c)
    593 	bus_space_handle_t h;
    594 	bus_size_t o;
    595 	bus_space_handle_t g;
    596 	bus_size_t q;
    597 	bus_size_t c;
    598 {
    599 	panic("pcmio_bscr1 is not defined (" __FILE__ ")");
    600 }
    601