Home | History | Annotate | Line # | Download | only in sa11x0
sa11xx_pcic.c revision 1.5
      1 /*	$NetBSD: sa11xx_pcic.c,v 1.5 2004/10/02 23:42:57 toshii Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 IWAMOTO Toshihiro.  All rights reserved.
      5  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Marc Horowitz.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Common code for SA11x0 based PCMCIA modules
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: sa11xx_pcic.c,v 1.5 2004/10/02 23:42:57 toshii Exp $");
     39 
     40 #include <sys/types.h>
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/device.h>
     44 #include <sys/callout.h>
     45 #include <sys/kernel.h>
     46 #include <sys/kthread.h>
     47 #include <sys/malloc.h>
     48 #include <uvm/uvm.h>
     49 
     50 #include <machine/bus.h>
     51 #include <machine/intr.h>
     52 
     53 #include <dev/pcmcia/pcmciareg.h>
     54 #include <dev/pcmcia/pcmciavar.h>
     55 #include <dev/pcmcia/pcmciachip.h>
     56 
     57 #include <arm/sa11x0/sa11x0_reg.h>
     58 #include <arm/sa11x0/sa11x0_var.h>
     59 #include <arm/sa11x0/sa11xx_pcicreg.h>
     60 #include <arm/sa11x0/sa11xx_pcicvar.h>
     61 
     62 static	int	sapcic_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
     63 					struct pcmcia_mem_handle *);
     64 static	void	sapcic_mem_free(pcmcia_chipset_handle_t,
     65 				       struct pcmcia_mem_handle *);
     66 static	int	sapcic_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
     67 				      bus_size_t, struct pcmcia_mem_handle *,
     68 				      bus_addr_t *, int *);
     69 static	void	sapcic_mem_unmap(pcmcia_chipset_handle_t, int);
     70 static	int	sapcic_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
     71 				       bus_size_t, bus_size_t,
     72 				       struct pcmcia_io_handle *);
     73 static	void	sapcic_io_free(pcmcia_chipset_handle_t,
     74 				      struct pcmcia_io_handle *);
     75 static	int	sapcic_io_map(pcmcia_chipset_handle_t, int,
     76 				     bus_addr_t, bus_size_t,
     77 				     struct pcmcia_io_handle *, int *);
     78 static	void	sapcic_io_unmap(pcmcia_chipset_handle_t, int);
     79 static	void	*sapcic_intr_establish(pcmcia_chipset_handle_t,
     80 					      struct pcmcia_function *, int,
     81 					      int (*)(void *), void *);
     82 static	void	sapcic_intr_disestablish(pcmcia_chipset_handle_t,
     83 						void *);
     84 static	void	sapcic_socket_enable(pcmcia_chipset_handle_t);
     85 static	void	sapcic_socket_disable(pcmcia_chipset_handle_t);
     86 static	void	sapcic_socket_settype(pcmcia_chipset_handle_t, int);
     87 
     88 static	void	sapcic_event_thread(void *);
     89 
     90 static	void	sapcic_delay(int, const char *);
     91 
     92 #ifdef DEBUG
     93 #define DPRINTF(arg)	printf arg
     94 #else
     95 #define DPRINTF(arg)
     96 #endif
     97 
     98 struct pcmcia_chip_functions sa11x0_pcmcia_functions = {
     99 	sapcic_mem_alloc,
    100 	sapcic_mem_free,
    101 	sapcic_mem_map,
    102 	sapcic_mem_unmap,
    103 
    104 	sapcic_io_alloc,
    105 	sapcic_io_free,
    106 	sapcic_io_map,
    107 	sapcic_io_unmap,
    108 
    109 	sapcic_intr_establish,
    110 	sapcic_intr_disestablish,
    111 
    112 	sapcic_socket_enable,
    113 	sapcic_socket_disable,
    114 	sapcic_socket_settype,
    115 };
    116 
    117 
    118 void
    119 sapcic_kthread_create(arg)
    120 	void *arg;
    121 {
    122 	struct sapcic_socket *so = arg;
    123 
    124 	/* XXX attach card if already present */
    125 
    126 	so->laststatus =(so->pcictag->read)(so, SAPCIC_STATUS_CARD);
    127 	if (so->laststatus == SAPCIC_CARD_VALID) {
    128 		printf("%s: card present\n",
    129 		       so->sc->sc_dev.dv_xname);
    130 
    131 		pcmcia_card_attach(so->pcmcia);
    132 	}
    133 
    134 	if (kthread_create1(sapcic_event_thread, so, &so->event_thread,
    135 			    "%s,%d", so->sc->sc_dev.dv_xname, so->socket)) {
    136 		printf("%s: unable to create event thread for socket %d\n",
    137 		       so->sc->sc_dev.dv_xname, so->socket);
    138 		panic("sapcic_kthread_create");
    139 	}
    140 }
    141 
    142 static void
    143 sapcic_event_thread(arg)
    144 	void *arg;
    145 {
    146 	struct sapcic_socket *so = arg;
    147 	int newstatus, s;
    148 
    149 	while (so->shutdown == 0) {
    150 		/*
    151 		 * Serialize event processing on the PCIC.  We may
    152 		 * sleep while we hold this lock.
    153 		 */
    154 		(void) lockmgr(&so->sc->sc_lock, LK_EXCLUSIVE, NULL);
    155 
    156 		/* sleep .25s to be enqueued chatterling interrupts */
    157 		(void) tsleep((caddr_t)sapcic_event_thread, PWAIT,
    158 			      "pcicss", hz/4);
    159 
    160 		s = splhigh();
    161 		so->event = 0;
    162 
    163 		/* we don't rely on interrupt type */
    164 		newstatus = (so->pcictag->read)(so, SAPCIC_STATUS_CARD);
    165 		splx(s);
    166 
    167 		if (so->laststatus == newstatus) {
    168 			/*
    169 			 * No events to process; release the PCIC lock.
    170 			 */
    171 			(void) lockmgr(&so->sc->sc_lock, LK_RELEASE, NULL);
    172 			(void) tsleep(&so->event, PWAIT, "pcicev", hz);
    173 			continue;
    174 		}
    175 
    176 		so->laststatus = newstatus;
    177 		switch (newstatus) {
    178 		case SAPCIC_CARD_VALID:
    179 			printf("%s: insertion event\n",
    180 			       so->sc->sc_dev.dv_xname);
    181 
    182 			pcmcia_card_attach(so->pcmcia);
    183 			break;
    184 
    185 		case SAPCIC_CARD_INVALID:
    186 			printf("%s: removal event\n",
    187 			       so->sc->sc_dev.dv_xname);
    188 
    189 			pcmcia_card_detach(so->pcmcia, DETACH_FORCE);
    190 			break;
    191 
    192 		default:
    193 			panic("sapcic_event_thread: unknown status %d",
    194 			    newstatus);
    195 		}
    196 
    197 		(void) lockmgr(&so->sc->sc_lock, LK_RELEASE, NULL);
    198 	}
    199 
    200 	so->event_thread = NULL;
    201 
    202 	/* In case parent is waiting for us to exit. */
    203 	wakeup(so->sc);
    204 
    205 	kthread_exit(0);
    206 }
    207 
    208 static void
    209 sapcic_delay(timo, wmesg)
    210 	int timo;		/* in milliseconds */
    211 	const char *wmesg;
    212 {
    213 #ifdef DIAGNOSTIC
    214 	if (curlwp == NULL)
    215 		panic("sapcic_delay: called in interrupt context");
    216 #endif
    217 
    218 	tsleep(sapcic_delay, PWAIT, wmesg, roundup(timo * hz, 1000) / 1000);
    219 }
    220 
    221 int
    222 sapcic_intr(arg)
    223 	void *arg;
    224 {
    225 	struct sapcic_socket *so = arg;
    226 
    227 	so->event++;
    228 	(so->pcictag->clear_intr)(so->socket);
    229 	wakeup(&so->event);
    230 	return 1;
    231 }
    232 
    233 static int
    234 sapcic_mem_alloc(pch, size, pmh)
    235 	pcmcia_chipset_handle_t pch;
    236 	bus_size_t size;
    237 	struct pcmcia_mem_handle *pmh;
    238 {
    239 	struct sapcic_socket *so = pch;
    240 
    241 	/* All we need is bus space tag */
    242 	memset(pmh, 0, sizeof(*pmh));
    243 	pmh->memt = so->sc->sc_iot;
    244 	return (0);
    245 }
    246 
    247 
    248 static void
    249 sapcic_mem_free(pch, pmh)
    250 	pcmcia_chipset_handle_t pch;
    251 	struct pcmcia_mem_handle *pmh;
    252 {
    253 }
    254 
    255 static int
    256 sapcic_mem_map(pch, kind, card_addr, size, pmh, offsetp, windowp)
    257 	pcmcia_chipset_handle_t pch;
    258 	int kind;
    259 	bus_addr_t card_addr;
    260 	bus_size_t size;
    261 	struct pcmcia_mem_handle *pmh;
    262 	bus_addr_t *offsetp;
    263 	int *windowp;
    264 {
    265 	struct sapcic_socket *so = pch;
    266 	int error;
    267 	bus_addr_t pa;
    268 
    269 	pa = trunc_page(card_addr);
    270 	*offsetp = card_addr - pa;
    271 	size = round_page(card_addr + size) - pa;
    272 	pmh->realsize = size;
    273 
    274 	pa += SAPCIC_BASE_OFFSET;
    275 	pa += SAPCIC_SOCKET_OFFSET * so->socket;
    276 
    277 	switch (kind & ~PCMCIA_WIDTH_MEM_MASK) {
    278 	case PCMCIA_MEM_ATTR:
    279 		pa += SAPCIC_ATTR_OFFSET;
    280 		break;
    281 	case PCMCIA_MEM_COMMON:
    282 		pa += SAPCIC_COMMON_OFFSET;
    283 		break;
    284 	default:
    285 		panic("sapcic_mem_map: bogus kind");
    286 	}
    287 
    288 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pmh->memh);
    289 	if (! error)
    290 		*windowp = (int)pmh->memh;
    291 	return (error);
    292 }
    293 
    294 static void
    295 sapcic_mem_unmap(pch, window)
    296 	pcmcia_chipset_handle_t pch;
    297 	int window;
    298 {
    299 	struct sapcic_socket *so = pch;
    300 
    301 	bus_space_unmap(so->sc->sc_iot, (bus_addr_t)window, 4096); /* XXX */
    302 }
    303 
    304 static int
    305 sapcic_io_alloc(pch, start, size, align, pih)
    306 	pcmcia_chipset_handle_t pch;
    307 	bus_addr_t start;
    308 	bus_size_t size;
    309 	bus_size_t align;
    310 	struct pcmcia_io_handle *pih;
    311 {
    312 	struct sapcic_socket *so = pch;
    313 	int error;
    314 	bus_addr_t pa;
    315 
    316 	memset(pih, 0, sizeof(*pih));
    317 	pih->iot = so->sc->sc_iot;
    318 	pih->addr = start;
    319 	pih->size = size;
    320 
    321 	pa = pih->addr;
    322 	pa += SAPCIC_BASE_OFFSET;
    323 	pa += SAPCIC_SOCKET_OFFSET * so->socket;
    324 
    325 	DPRINTF(("sapcic_io_alloc: %x %x\n", (unsigned int)pa,
    326 		 (unsigned int)size));
    327 	/* XXX Are we ignoring alignment constraints? */
    328 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pih->ioh);
    329 
    330 	return (error);
    331 }
    332 
    333 static void
    334 sapcic_io_free(pch, pih)
    335 	pcmcia_chipset_handle_t pch;
    336 	struct pcmcia_io_handle *pih;
    337 {
    338 	struct sapcic_socket *so = pch;
    339 
    340 	bus_space_unmap(so->sc->sc_iot, pih->ioh, pih->size);
    341 }
    342 
    343 static int
    344 sapcic_io_map(pch, width, offset, size, pih, windowp)
    345 	pcmcia_chipset_handle_t pch;
    346 	int width;
    347 	bus_addr_t offset;
    348 	bus_size_t size;
    349 	struct pcmcia_io_handle *pih;
    350 	int *windowp;
    351 {
    352 	return (0);
    353 }
    354 
    355 static void sapcic_io_unmap(pch, window)
    356 	pcmcia_chipset_handle_t pch;
    357 	int window;
    358 {
    359 }
    360 
    361 static void *
    362 sapcic_intr_establish(pch, pf, ipl, fct, arg)
    363 	pcmcia_chipset_handle_t pch;
    364 	struct pcmcia_function *pf;
    365 	int ipl;
    366 	int (*fct)(void *);
    367 	void *arg;
    368 {
    369 	struct sapcic_socket *so = pch;
    370 
    371 	/* XXX need to check if something should be done here */
    372 
    373 	return ((so->pcictag->intr_establish)(so, ipl, fct, arg));
    374 }
    375 
    376 static void
    377 sapcic_intr_disestablish(pch, ih)
    378 	pcmcia_chipset_handle_t pch;
    379 	void *ih;
    380 {
    381 	struct sapcic_socket *so = pch;
    382 
    383 	((so->pcictag->intr_disestablish)(so, ih));
    384 }
    385 
    386 static void
    387 sapcic_socket_enable(pch)
    388 	pcmcia_chipset_handle_t pch;
    389 {
    390 	struct sapcic_socket *so = pch;
    391 	int i;
    392 
    393 #if defined(DIAGNOSTIC) && defined(notyet)
    394 	if (so->flags & PCIC_FLAG_ENABLED)
    395 		printf("sapcic_socket_enable: enabling twice\n");
    396 #endif
    397 
    398 	/* disable interrupts */
    399 
    400 	/* power down the socket to reset it, clear the card reset pin */
    401 	(so->pcictag->set_power)(so, SAPCIC_POWER_OFF);
    402 
    403 	/*
    404 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
    405 	 * we are changing Vcc (Toff).
    406 	 */
    407 	sapcic_delay(300 + 100, "pccen0");
    408 
    409 	/* power up the socket */
    410 	/* XXX voltage selection should be done in PCMCIA code */
    411 	if (so->power_capability & SAPCIC_POWER_5V) {
    412 		(so->pcictag->set_power)(so, SAPCIC_POWER_5V);
    413 		(so->pcictag->write)(so, SAPCIC_CONTROL_POWERSELECT,
    414 				     SAPCIC_POWER_5V);
    415 	} else {
    416 		(so->pcictag->set_power)(so, SAPCIC_POWER_3V);
    417 		(so->pcictag->write)(so, SAPCIC_CONTROL_POWERSELECT,
    418 				     SAPCIC_POWER_3V);
    419 	}
    420 
    421 	/* enable PCMCIA control lines */
    422 	(so->pcictag->write)(so, SAPCIC_CONTROL_LINEENABLE, 1);
    423 
    424 	/*
    425 	 * wait 100ms until power raise (Tpr) and 20ms to become
    426 	 * stable (Tsu(Vcc)).
    427 	 *
    428 	 * some machines require some more time to be settled
    429 	 * (300ms is added here).
    430 	 */
    431 	sapcic_delay(100 + 20 + 300, "pccen1");
    432 
    433 	/* honor nWAIT signal */
    434 	(so->pcictag->write)(so, SAPCIC_CONTROL_WAITENABLE, 1);
    435 	/* now make sure we have reset# active */
    436 	(so->pcictag->write)(so, SAPCIC_CONTROL_RESET, 1);
    437 
    438 	/*
    439 	 * hold RESET at least 10us, this is a min allow for slop in
    440 	 * delay routine.
    441 	 */
    442 	delay(20);
    443 
    444 	/* clear the reset flag */
    445 	(so->pcictag->write)(so, SAPCIC_CONTROL_RESET, 0);
    446 
    447 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
    448 	sapcic_delay(20, "pccen2");
    449 
    450 	/* wait for the chip to finish initializing */
    451 	sapcic_delay(10, "pccen3");
    452 	for(i = 100; i; i--) {
    453 		if ((so->pcictag->read)(so, SAPCIC_STATUS_READY))
    454 			break;
    455 		sapcic_delay(100, "pccen4");
    456 	}
    457 	DPRINTF(("sapcic_socket_enable: wait ready %d\n", 100 - i));
    458 
    459 	/* finally enable the interrupt */
    460 
    461 }
    462 
    463 static void
    464 sapcic_socket_disable(pch)
    465 	pcmcia_chipset_handle_t pch;
    466 {
    467 	struct sapcic_socket *so = pch;
    468 
    469 	/* XXX mask card interrupts */
    470 
    471 	/* power down the card */
    472 	(so->pcictag->set_power)(so, SAPCIC_POWER_OFF);
    473 
    474 	/* float controller lines */
    475 	(so->pcictag->write)(so, SAPCIC_CONTROL_LINEENABLE, 0);
    476 }
    477 
    478 static void
    479 sapcic_socket_settype(pch, type)
    480 	pcmcia_chipset_handle_t pch;
    481 	int type;
    482 {
    483 
    484 	/* XXX nothing to do */
    485 }
    486