Home | History | Annotate | Line # | Download | only in sa11x0
sa11xx_pcic.c revision 1.4
      1 /*	$NetBSD: sa11xx_pcic.c,v 1.4 2003/07/15 00:24:51 lukem 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.4 2003/07/15 00:24:51 lukem 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 
     87 static	void	sapcic_event_thread(void *);
     88 
     89 static	void	sapcic_delay(int, const char *);
     90 
     91 #ifdef DEBUG
     92 #define DPRINTF(arg)	printf arg
     93 #else
     94 #define DPRINTF(arg)
     95 #endif
     96 
     97 struct pcmcia_chip_functions sa11x0_pcmcia_functions = {
     98 	sapcic_mem_alloc,
     99 	sapcic_mem_free,
    100 	sapcic_mem_map,
    101 	sapcic_mem_unmap,
    102 
    103 	sapcic_io_alloc,
    104 	sapcic_io_free,
    105 	sapcic_io_map,
    106 	sapcic_io_unmap,
    107 
    108 	sapcic_intr_establish,
    109 	sapcic_intr_disestablish,
    110 
    111 	sapcic_socket_enable,
    112 	sapcic_socket_disable,
    113 };
    114 
    115 
    116 void
    117 sapcic_kthread_create(arg)
    118 	void *arg;
    119 {
    120 	struct sapcic_socket *so = arg;
    121 
    122 	/* XXX attach card if already present */
    123 
    124 	so->laststatus =(so->pcictag->read)(so, SAPCIC_STATUS_CARD);
    125 	if (so->laststatus == SAPCIC_CARD_VALID) {
    126 		printf("%s: card present\n",
    127 		       so->sc->sc_dev.dv_xname);
    128 
    129 		pcmcia_card_attach(so->pcmcia);
    130 	}
    131 
    132 	if (kthread_create1(sapcic_event_thread, so, &so->event_thread,
    133 			    "%s,%d", so->sc->sc_dev.dv_xname, so->socket)) {
    134 		printf("%s: unable to create event thread for socket %d\n",
    135 		       so->sc->sc_dev.dv_xname, so->socket);
    136 		panic("sapcic_kthread_create");
    137 	}
    138 }
    139 
    140 static void
    141 sapcic_event_thread(arg)
    142 	void *arg;
    143 {
    144 	struct sapcic_socket *so = arg;
    145 	int newstatus, s;
    146 
    147 	while (so->shutdown == 0) {
    148 		/*
    149 		 * Serialize event processing on the PCIC.  We may
    150 		 * sleep while we hold this lock.
    151 		 */
    152 		(void) lockmgr(&so->sc->sc_lock, LK_EXCLUSIVE, NULL);
    153 
    154 		/* sleep .25s to be enqueued chatterling interrupts */
    155 		(void) tsleep((caddr_t)sapcic_event_thread, PWAIT,
    156 			      "pcicss", hz/4);
    157 
    158 		s = splhigh();
    159 		so->event = 0;
    160 
    161 		/* we don't rely on interrupt type */
    162 		newstatus = (so->pcictag->read)(so, SAPCIC_STATUS_CARD);
    163 		splx(s);
    164 
    165 		if (so->laststatus == newstatus) {
    166 			/*
    167 			 * No events to process; release the PCIC lock.
    168 			 */
    169 			(void) lockmgr(&so->sc->sc_lock, LK_RELEASE, NULL);
    170 			(void) tsleep(&so->event, PWAIT, "pcicev", hz);
    171 			continue;
    172 		}
    173 
    174 		so->laststatus = newstatus;
    175 		switch (newstatus) {
    176 		case SAPCIC_CARD_VALID:
    177 			printf("%s: insertion event\n",
    178 			       so->sc->sc_dev.dv_xname);
    179 
    180 			pcmcia_card_attach(so->pcmcia);
    181 			break;
    182 
    183 		case SAPCIC_CARD_INVALID:
    184 			printf("%s: removal event\n",
    185 			       so->sc->sc_dev.dv_xname);
    186 
    187 			pcmcia_card_detach(so->pcmcia, DETACH_FORCE);
    188 			break;
    189 
    190 		default:
    191 			panic("sapcic_event_thread: unknown status %d",
    192 			    newstatus);
    193 		}
    194 
    195 		(void) lockmgr(&so->sc->sc_lock, LK_RELEASE, NULL);
    196 	}
    197 
    198 	so->event_thread = NULL;
    199 
    200 	/* In case parent is waiting for us to exit. */
    201 	wakeup(so->sc);
    202 
    203 	kthread_exit(0);
    204 }
    205 
    206 static void
    207 sapcic_delay(timo, wmesg)
    208 	int timo;		/* in milliseconds */
    209 	const char *wmesg;
    210 {
    211 #ifdef DIAGNOSTIC
    212 	if (curlwp == NULL)
    213 		panic("sapcic_delay: called in interrupt context");
    214 #endif
    215 
    216 	tsleep(sapcic_delay, PWAIT, wmesg, roundup(timo * hz, 1000) / 1000);
    217 }
    218 
    219 int
    220 sapcic_intr(arg)
    221 	void *arg;
    222 {
    223 	struct sapcic_socket *so = arg;
    224 
    225 	so->event++;
    226 	(so->pcictag->clear_intr)(so->socket);
    227 	wakeup(&so->event);
    228 	return 1;
    229 }
    230 
    231 static int
    232 sapcic_mem_alloc(pch, size, pmh)
    233 	pcmcia_chipset_handle_t pch;
    234 	bus_size_t size;
    235 	struct pcmcia_mem_handle *pmh;
    236 {
    237 	struct sapcic_socket *so = pch;
    238 
    239 	/* All we need is bus space tag */
    240 	memset(pmh, 0, sizeof(*pmh));
    241 	pmh->memt = so->sc->sc_iot;
    242 	return (0);
    243 }
    244 
    245 
    246 static void
    247 sapcic_mem_free(pch, pmh)
    248 	pcmcia_chipset_handle_t pch;
    249 	struct pcmcia_mem_handle *pmh;
    250 {
    251 }
    252 
    253 static int
    254 sapcic_mem_map(pch, kind, card_addr, size, pmh, offsetp, windowp)
    255 	pcmcia_chipset_handle_t pch;
    256 	int kind;
    257 	bus_addr_t card_addr;
    258 	bus_size_t size;
    259 	struct pcmcia_mem_handle *pmh;
    260 	bus_addr_t *offsetp;
    261 	int *windowp;
    262 {
    263 	struct sapcic_socket *so = pch;
    264 	int error;
    265 	bus_addr_t pa;
    266 
    267 	pa = trunc_page(card_addr);
    268 	*offsetp = card_addr - pa;
    269 	size = round_page(card_addr + size) - pa;
    270 	pmh->realsize = size;
    271 
    272 	pa += SAPCIC_BASE_OFFSET;
    273 	pa += SAPCIC_SOCKET_OFFSET * so->socket;
    274 
    275 	switch (kind & ~PCMCIA_WIDTH_MEM_MASK) {
    276 	case PCMCIA_MEM_ATTR:
    277 		pa += SAPCIC_ATTR_OFFSET;
    278 		break;
    279 	case PCMCIA_MEM_COMMON:
    280 		pa += SAPCIC_COMMON_OFFSET;
    281 		break;
    282 	default:
    283 		panic("sapcic_mem_map: bogus kind");
    284 	}
    285 
    286 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pmh->memh);
    287 	if (! error)
    288 		*windowp = (int)pmh->memh;
    289 	return (error);
    290 }
    291 
    292 static void
    293 sapcic_mem_unmap(pch, window)
    294 	pcmcia_chipset_handle_t pch;
    295 	int window;
    296 {
    297 	struct sapcic_socket *so = pch;
    298 
    299 	bus_space_unmap(so->sc->sc_iot, (bus_addr_t)window, 4096); /* XXX */
    300 }
    301 
    302 static int
    303 sapcic_io_alloc(pch, start, size, align, pih)
    304 	pcmcia_chipset_handle_t pch;
    305 	bus_addr_t start;
    306 	bus_size_t size;
    307 	bus_size_t align;
    308 	struct pcmcia_io_handle *pih;
    309 {
    310 	struct sapcic_socket *so = pch;
    311 	int error;
    312 	bus_addr_t pa;
    313 
    314 	memset(pih, 0, sizeof(*pih));
    315 	pih->iot = so->sc->sc_iot;
    316 	pih->addr = start;
    317 	pih->size = size;
    318 
    319 	pa = pih->addr;
    320 	pa += SAPCIC_BASE_OFFSET;
    321 	pa += SAPCIC_SOCKET_OFFSET * so->socket;
    322 
    323 	DPRINTF(("sapcic_io_alloc: %x %x\n", (unsigned int)pa,
    324 		 (unsigned int)size));
    325 	/* XXX Are we ignoring alignment constraints? */
    326 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pih->ioh);
    327 
    328 	return (error);
    329 }
    330 
    331 static void
    332 sapcic_io_free(pch, pih)
    333 	pcmcia_chipset_handle_t pch;
    334 	struct pcmcia_io_handle *pih;
    335 {
    336 	struct sapcic_socket *so = pch;
    337 
    338 	bus_space_unmap(so->sc->sc_iot, pih->ioh, pih->size);
    339 }
    340 
    341 static int
    342 sapcic_io_map(pch, width, offset, size, pih, windowp)
    343 	pcmcia_chipset_handle_t pch;
    344 	int width;
    345 	bus_addr_t offset;
    346 	bus_size_t size;
    347 	struct pcmcia_io_handle *pih;
    348 	int *windowp;
    349 {
    350 	return (0);
    351 }
    352 
    353 static void sapcic_io_unmap(pch, window)
    354 	pcmcia_chipset_handle_t pch;
    355 	int window;
    356 {
    357 }
    358 
    359 static void *
    360 sapcic_intr_establish(pch, pf, ipl, fct, arg)
    361 	pcmcia_chipset_handle_t pch;
    362 	struct pcmcia_function *pf;
    363 	int ipl;
    364 	int (*fct)(void *);
    365 	void *arg;
    366 {
    367 	struct sapcic_socket *so = pch;
    368 
    369 	/* XXX need to check if something should be done here */
    370 
    371 	return ((so->pcictag->intr_establish)(so, ipl, fct, arg));
    372 }
    373 
    374 static void
    375 sapcic_intr_disestablish(pch, ih)
    376 	pcmcia_chipset_handle_t pch;
    377 	void *ih;
    378 {
    379 	struct sapcic_socket *so = pch;
    380 
    381 	((so->pcictag->intr_disestablish)(so, ih));
    382 }
    383 
    384 static void
    385 sapcic_socket_enable(pch)
    386 	pcmcia_chipset_handle_t pch;
    387 {
    388 	struct sapcic_socket *so = pch;
    389 	int i;
    390 
    391 #if defined(DIAGNOSTIC) && defined(notyet)
    392 	if (so->flags & PCIC_FLAG_ENABLED)
    393 		printf("sapcic_socket_enable: enabling twice\n");
    394 #endif
    395 
    396 	/* disable interrupts */
    397 
    398 	/* power down the socket to reset it, clear the card reset pin */
    399 	(so->pcictag->set_power)(so, SAPCIC_POWER_OFF);
    400 
    401 	/*
    402 	 * wait 300ms until power fails (Tpf).  Then, wait 100ms since
    403 	 * we are changing Vcc (Toff).
    404 	 */
    405 	sapcic_delay(300 + 100, "pccen0");
    406 
    407 	/* power up the socket */
    408 	/* XXX voltage selection should be done in PCMCIA code */
    409 	if (so->power_capability & SAPCIC_POWER_5V) {
    410 		(so->pcictag->set_power)(so, SAPCIC_POWER_5V);
    411 		(so->pcictag->write)(so, SAPCIC_CONTROL_POWERSELECT,
    412 				     SAPCIC_POWER_5V);
    413 	} else {
    414 		(so->pcictag->set_power)(so, SAPCIC_POWER_3V);
    415 		(so->pcictag->write)(so, SAPCIC_CONTROL_POWERSELECT,
    416 				     SAPCIC_POWER_3V);
    417 	}
    418 
    419 	/* enable PCMCIA control lines */
    420 	(so->pcictag->write)(so, SAPCIC_CONTROL_LINEENABLE, 1);
    421 
    422 	/*
    423 	 * wait 100ms until power raise (Tpr) and 20ms to become
    424 	 * stable (Tsu(Vcc)).
    425 	 *
    426 	 * some machines require some more time to be settled
    427 	 * (300ms is added here).
    428 	 */
    429 	sapcic_delay(100 + 20 + 300, "pccen1");
    430 
    431 	/* honor nWAIT signal */
    432 	(so->pcictag->write)(so, SAPCIC_CONTROL_WAITENABLE, 1);
    433 	/* now make sure we have reset# active */
    434 	(so->pcictag->write)(so, SAPCIC_CONTROL_RESET, 1);
    435 
    436 	/*
    437 	 * hold RESET at least 10us, this is a min allow for slop in
    438 	 * delay routine.
    439 	 */
    440 	delay(20);
    441 
    442 	/* clear the reset flag */
    443 	(so->pcictag->write)(so, SAPCIC_CONTROL_RESET, 0);
    444 
    445 	/* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
    446 	sapcic_delay(20, "pccen2");
    447 
    448 	/* wait for the chip to finish initializing */
    449 	sapcic_delay(10, "pccen3");
    450 	for(i = 100; i; i--) {
    451 		if ((so->pcictag->read)(so, SAPCIC_STATUS_READY))
    452 			break;
    453 		sapcic_delay(100, "pccen4");
    454 	}
    455 	DPRINTF(("sapcic_socket_enable: wait ready %d\n", 100 - i));
    456 
    457 	/* finally enable the interrupt */
    458 
    459 }
    460 
    461 static void
    462 sapcic_socket_disable(pch)
    463 	pcmcia_chipset_handle_t pch;
    464 {
    465 	struct sapcic_socket *so = pch;
    466 
    467 	/* XXX mask card interrupts */
    468 
    469 	/* power down the card */
    470 	(so->pcictag->set_power)(so, SAPCIC_POWER_OFF);
    471 
    472 	/* float controller lines */
    473 	(so->pcictag->write)(so, SAPCIC_CONTROL_LINEENABLE, 0);
    474 }
    475