Home | History | Annotate | Line # | Download | only in imx
      1 /*	$Id: imx_pcic.c,v 1.9 2022/09/27 06:36:42 skrll Exp $	*/
      2 
      3 /*
      4  * IMX CF interface to pcic/pcmcia
      5  * derived from pxa2x0_pcic
      6  * Sun Apr  1 21:42:37 PDT 2007
      7  */
      8 
      9 /*	$NetBSD: imx_pcic.c,v 1.9 2022/09/27 06:36:42 skrll Exp $	*/
     10 /*	$OpenBSD: pxa2x0_pcic.c,v 1.17 2005/12/14 15:08:51 uwe Exp $	*/
     11 
     12 /*
     13  * Copyright (c) 2005 Dale Rahn <drahn (at) openbsd.org>
     14  *
     15  * Permission to use, copy, modify, and distribute this software for any
     16  * purpose with or without fee is hereby granted, provided that the above
     17  * copyright notice and this permission notice appear in all copies.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     20  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     21  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     22  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     23  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     24  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     25  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$Id: imx_pcic.c,v 1.9 2022/09/27 06:36:42 skrll Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/systm.h>
     33 #include <sys/device.h>
     34 #include <sys/kernel.h>
     35 #include <sys/kthread.h>
     36 
     37 #include <uvm/uvm.h>
     38 
     39 #include <sys/bus.h>
     40 #include <machine/intr.h>
     41 
     42 #include <dev/pcmcia/pcmciareg.h>
     43 #include <dev/pcmcia/pcmciavar.h>
     44 #include <dev/pcmcia/pcmciachip.h>
     45 
     46 #ifdef NOTYET
     47 #include <arm/imx/imx_gpio.h>
     48 #endif
     49 #include <arm/imx/imx_pcic.h>
     50 
     51 static int	imx_pcic_print(void *, const char *);
     52 
     53 static void	imx_pcic_event_thread(void *);
     54 #ifdef NOTYET
     55 static void	imx_pcic_event_process(struct imx_pcic_socket *);
     56 static void	imx_pcic_attach_card(struct imx_pcic_socket *);
     57 #endif
     58 #ifdef NOTYET
     59 static void	imx_pcic_detach_card(struct imx_pcic_socket *, int);
     60 #endif
     61 
     62 static int	imx_pcic_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
     63 		    struct pcmcia_mem_handle *);
     64 static void	imx_pcic_mem_free(pcmcia_chipset_handle_t,
     65 		    struct pcmcia_mem_handle *);
     66 static int	imx_pcic_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
     67 		   bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
     68 static void	imx_pcic_mem_unmap(pcmcia_chipset_handle_t, int);
     69 
     70 static int	imx_pcic_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
     71 		    bus_size_t, bus_size_t, struct pcmcia_io_handle *);
     72 static void	imx_pcic_io_free(pcmcia_chipset_handle_t,
     73 		    struct pcmcia_io_handle *);
     74 static int	imx_pcic_io_map(pcmcia_chipset_handle_t, int,
     75 		    bus_addr_t, bus_size_t, struct pcmcia_io_handle *, int *);
     76 static void	imx_pcic_io_unmap(pcmcia_chipset_handle_t, int);
     77 
     78 static void	*imx_pcic_intr_establish(pcmcia_chipset_handle_t,
     79 		    struct pcmcia_function *, int, int (*)(void *), void *);
     80 static void	imx_pcic_intr_disestablish(pcmcia_chipset_handle_t, void *);
     81 
     82 static void	imx_pcic_socket_enable(pcmcia_chipset_handle_t);
     83 static void	imx_pcic_socket_disable(pcmcia_chipset_handle_t);
     84 static void	imx_pcic_socket_settype(pcmcia_chipset_handle_t, int);
     85 
     86 /*
     87  * PCMCIA chipset methods
     88  */
     89 static struct pcmcia_chip_functions imx_pcic_pcmcia_functions = {
     90 	imx_pcic_mem_alloc,
     91 	imx_pcic_mem_free,
     92 	imx_pcic_mem_map,
     93 	imx_pcic_mem_unmap,
     94 
     95 	imx_pcic_io_alloc,
     96 	imx_pcic_io_free,
     97 	imx_pcic_io_map,
     98 	imx_pcic_io_unmap,
     99 
    100 	imx_pcic_intr_establish,
    101 	imx_pcic_intr_disestablish,
    102 
    103 	imx_pcic_socket_enable,
    104 	imx_pcic_socket_disable,
    105 	imx_pcic_socket_settype,
    106 };
    107 
    108 #define IMX_MEMCTL_BASE	0x08000000		/* XXX */
    109 #define IMX_MEMCTL_SIZE	0x00000010		/* XXX */
    110 #define IMX_PCIC_SOCKET_BASE	0x08009000		/* XXX */
    111 #define IMX_PCIC_SOCKET_OFFSET	0x00000000		/* XXX */
    112 #define	IMX_PCIC_ATTR_OFFSET	0x00000800		/* XXX 5912 */
    113 #define	IMX_PCIC_COMMON_OFFSET	0x00000000		/* XXX 5912 */
    114 
    115 
    116 
    117 /*
    118  * PCMCIA Helpers
    119  */
    120 static int
    121 imx_pcic_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
    122     struct pcmcia_mem_handle *pmh)
    123 {
    124 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    125 
    126 	/* All we need is the bus space tag */
    127 	memset(pmh, 0, sizeof(*pmh));
    128 	pmh->memt = so->sc->sc_iot;
    129 
    130 	return 0;
    131 }
    132 
    133 static void
    134 imx_pcic_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
    135 {
    136 
    137 	/* Nothing to do */
    138 }
    139 
    140 static int
    141 imx_pcic_mem_map(pcmcia_chipset_handle_t pch, int kind, bus_addr_t card_addr,
    142     bus_size_t size, struct pcmcia_mem_handle *pmh, bus_size_t *offsetp,
    143     int *windowp)
    144 {
    145 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    146 	int error;
    147 	bus_addr_t pa;
    148 
    149 printf("%s: card_addr %lx\n", __func__, card_addr);
    150 	pa = trunc_page(card_addr);
    151 	*offsetp = card_addr - pa;
    152 printf("%s: offset %lx\n", __func__, *offsetp);
    153 	size = round_page(card_addr + size) - pa;
    154 	pmh->realsize = size;
    155 
    156 	pa += IMX_PCIC_SOCKET_BASE;
    157 	pa += IMX_PCIC_SOCKET_OFFSET * so->socket;
    158 printf("%s: pa %lx\n", __func__, pa);
    159 printf("%s: kind %x\n", __func__, kind);
    160 
    161 	switch (kind & ~PCMCIA_WIDTH_MEM_MASK) {
    162 	case PCMCIA_MEM_ATTR:
    163 		pa += IMX_PCIC_ATTR_OFFSET;
    164 		break;
    165 	case PCMCIA_MEM_COMMON:
    166 		pa += IMX_PCIC_COMMON_OFFSET;
    167 		break;
    168 	default:
    169 		panic("imx_pcic_mem_map: bogus kind");
    170 	}
    171 
    172 printf("%s: pa %lx\n", __func__, pa);
    173 Debugger();
    174 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pmh->memh);
    175 	if (error)
    176 		return error;
    177 
    178 	*windowp = (int)pmh->memh;
    179 	return 0;
    180 }
    181 
    182 static void
    183 imx_pcic_mem_unmap(pcmcia_chipset_handle_t pch, int window)
    184 {
    185 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    186 
    187 	bus_space_unmap(so->sc->sc_iot, (bus_addr_t)window, 4096); /* XXX */
    188 }
    189 
    190 static int
    191 imx_pcic_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
    192     bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pih)
    193 {
    194 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    195 	bus_addr_t pa;
    196 	int error;
    197 
    198 	memset(pih, 0, sizeof(*pih));
    199 	pih->iot = so->sc->sc_iot;
    200 	pih->addr = start;
    201 	pih->size = size;
    202 
    203 	pa = pih->addr;
    204 	pa += IMX_PCIC_SOCKET_BASE;
    205 	pa += IMX_PCIC_SOCKET_OFFSET * so->socket;
    206 
    207 	/* XXX Are we ignoring alignment constraints? */
    208 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pih->ioh);
    209 
    210 	return error;
    211 }
    212 
    213 static void
    214 imx_pcic_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
    215 {
    216 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    217 
    218 	bus_space_unmap(so->sc->sc_iot, pih->ioh, pih->size);
    219 }
    220 
    221 static int
    222 imx_pcic_io_map(pcmcia_chipset_handle_t pch, int width, bus_addr_t offset,
    223     bus_size_t size, struct pcmcia_io_handle *pih, int *windowp)
    224 {
    225 
    226 	return 0;
    227 }
    228 
    229 static void
    230 imx_pcic_io_unmap(pcmcia_chipset_handle_t pch, int window)
    231 {
    232 
    233 	/* Nothing to do */
    234 }
    235 
    236 static void *
    237 imx_pcic_intr_establish(pcmcia_chipset_handle_t pch,
    238     struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg)
    239 {
    240 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    241 	/* XXX need to check if something should be done here */
    242 
    243 	return (*so->pcictag->intr_establish)(so, ipl, fct, arg);
    244 }
    245 
    246 static void
    247 imx_pcic_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
    248 {
    249 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    250 
    251 	(*so->pcictag->intr_disestablish)(so, ih);
    252 }
    253 
    254 static void
    255 imx_pcic_socket_enable(pcmcia_chipset_handle_t pch)
    256 {
    257 #ifdef NOTYET
    258 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    259 	int i;
    260 
    261 	/* Power down the card and socket before setting the voltage. */
    262 	(*so->pcictag->write)(so, IMX_PCIC_CARD_POWER, IMX_PCIC_POWER_OFF);
    263 	(*so->pcictag->set_power)(so, IMX_PCIC_POWER_OFF);
    264 
    265 	/*
    266 	 * Wait 300ms until power fails (Tpf).  Then, wait 100ms since
    267 	 * we are changing Vcc (Toff).
    268 	 */
    269 	delay((300 + 100) * 1000);
    270 
    271 	/* Power up the socket and card at appropriate voltage. */
    272 	if (so->power_capability & IMX_PCIC_POWER_5V) {
    273 		(*so->pcictag->set_power)(so, IMX_PCIC_POWER_5V);
    274 		(*so->pcictag->write)(so, IMX_PCIC_CARD_POWER,
    275 		    IMX_PCIC_POWER_5V);
    276 	} else {
    277 		(*so->pcictag->set_power)(so, IMX_PCIC_POWER_3V);
    278 		(*so->pcictag->write)(so, IMX_PCIC_CARD_POWER,
    279 		    IMX_PCIC_POWER_3V);
    280 	}
    281 
    282 	/*
    283 	 * Wait 100ms until power raise (Tpr) and 20ms to become
    284 	 * stable (Tsu(Vcc)).
    285 	 *
    286 	 * Some machines require some more time to be settled
    287 	 * (another 200ms is added here).
    288 	 */
    289 	delay((100 + 20 + 200) * 1000);
    290 
    291 	/* Hold RESET at least 10us. */
    292 	(*so->pcictag->write)(so, IMX_PCIC_CARD_RESET, 1);
    293 	delay(10);
    294 	/* XXX wrong, but lets TE-CF100 cards work for some reason. */
    295 	delay(3000);
    296 	(*so->pcictag->write)(so, IMX_PCIC_CARD_RESET, 0);
    297 
    298 	/* Wait 20ms as per PC Card standard (r2.01) section 4.3.6. */
    299 	delay(20 * 1000);
    300 
    301 	/* Wait for the card to become ready. */
    302 	for (i = 0; i < 10000; i++) {
    303 		if ((*so->pcictag->read)(so, IMX_PCIC_CARD_READY))
    304 			break;
    305 		delay(500);
    306 	}
    307 #else
    308 printf("%s: (stubbed)\n", __func__);
    309 #endif	/* NOTYET */
    310 }
    311 
    312 static void
    313 imx_pcic_socket_disable(pcmcia_chipset_handle_t pch)
    314 {
    315 #ifdef NOTYET
    316 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
    317 
    318 #ifdef PCICDEBUG
    319 	printf("imx_pcic_socket_disable: socket %d\n", so->socket);
    320 #endif
    321 
    322 	/* Power down the card and socket. */
    323 	(*so->pcictag->write)(so, IMX_PCIC_CARD_POWER, IMX_PCIC_POWER_OFF);
    324 	(*so->pcictag->set_power)(so, IMX_PCIC_POWER_OFF);
    325 #endif	/* NOTYET */
    326 }
    327 
    328 static void
    329 imx_pcic_socket_settype(pcmcia_chipset_handle_t pch, int type)
    330 {
    331 
    332 #ifdef PCICDEBUG
    333 	printf("imx_pcic_socket_settype: type=%d",type);
    334 
    335 	switch (type) {
    336 	case PCMCIA_IFTYPE_MEMORY:
    337 		printf("(Memory)\n");
    338 		break;
    339 	case PCMCIA_IFTYPE_IO:
    340 		printf("(I/O)\n");
    341 		break;
    342 	default:
    343 		printf("(unknown)\n");
    344 		break;
    345 	}
    346 #endif
    347 }
    348 
    349 /*
    350  * Attachment and initialization
    351  */
    352 static int
    353 imx_pcic_print(void *aux, const char *name)
    354 {
    355 
    356 	return UNCONF;
    357 }
    358 
    359 void
    360 imx_pcic_attach_common(struct imx_pcic_softc *sc,
    361     void (*socket_setup_hook)(struct imx_pcic_socket *))
    362 {
    363 	struct pcmciabus_attach_args paa;
    364 	struct imx_pcic_socket *so;
    365 	int s[IMX_PCIC_NSLOT];
    366 	int i;
    367 
    368 	printf(": %d slot%s\n", sc->sc_nslots, sc->sc_nslots < 2 ? "" : "s");
    369 
    370 	if (sc->sc_nslots == 0) {
    371 		aprint_error("%s: can't attach\n", device_xname(sc->sc_dev));
    372 		return;
    373 	}
    374 
    375 	if (bus_space_map(sc->sc_iot, IMX_MEMCTL_BASE, IMX_MEMCTL_SIZE,
    376 	    0, &sc->sc_memctl_ioh)) {
    377 		aprint_error("%s: failed to map MEMCTL\n", device_xname(sc->sc_dev));
    378 		return;
    379 	}
    380 
    381 #if 0
    382 	/* Clear CIT (card present) and set NOS correctly. */
    383 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MECR,
    384 	    (sc->sc_nslots == 2) ? MECR_NOS : 0);
    385 #endif
    386 
    387 	if (sc->sc_flags & PPF_REVERSE_ORDER) {
    388 		for (i = 0; i < sc->sc_nslots; i++) {
    389 			s[i] = sc->sc_nslots - 1 - i;
    390 		}
    391 	} else {
    392 		for (i = 0; i < sc->sc_nslots; i++) {
    393 			s[i] = i;
    394 		}
    395 	}
    396 
    397 	for (i = 0; i < sc->sc_nslots; i++) {
    398 		so = &sc->sc_socket[s[i]];
    399 		so->sc = sc;
    400 		so->socket = s[i];
    401 		so->flags = 0;
    402 
    403 		(*socket_setup_hook)(so);
    404 
    405 		paa.paa_busname = "pcmcia";
    406 		paa.pct = (pcmcia_chipset_tag_t)&imx_pcic_pcmcia_functions;
    407 		paa.pch = (pcmcia_chipset_handle_t)so;
    408 printf("%s: sc_pa %lx\n", __func__, sc->sc_pa);
    409 
    410 		so->pcmcia =
    411 		    config_found(sc->sc_dev, &paa, imx_pcic_print, CFARGS_NONE);
    412 
    413 #ifdef NOTYET
    414 		imx_gpio_set_direction(sc->sc_irqpin[s[i]], GPIO_IN);
    415 		imx_gpio_set_direction(sc->sc_irqcfpin[s[i]], GPIO_IN);
    416 
    417 		/* Card slot interrupt */
    418 		so->irq = imx_gpio_intr_establish(sc->sc_irqcfpin[s[i]],
    419 		    IST_EDGE_BOTH, IPL_BIO /* XXX */, "pcic",
    420 		    imx_pcic_intr, so);
    421 
    422 		/* GPIO pin for interrupt */
    423 		so->irqpin = sc->sc_irqpin[s[i]];
    424 #else
    425 		so->irqpin = sc->sc_irqpin[s[i]];
    426 printf("%s: slot %d, irqpin %d\n",  __func__, s[i], sc->sc_irqpin[s[i]]);
    427 #endif	/* NOTYET */
    428 
    429 		if (kthread_create(PRI_NONE, 0, NULL,
    430 		    imx_pcic_event_thread, so, &so->event_thread,
    431 		    "%s,%d", device_xname(sc->sc_dev), so->socket) != 0) {
    432 			printf("%s: unable to create event thread for %d\n",
    433 				device_xname(sc->sc_dev), so->socket);
    434 		}
    435 	}
    436 }
    437 
    438 /*
    439  * Card slot interrupt handling
    440  */
    441 int
    442 imx_pcic_intr(void *arg)
    443 {
    444 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)arg;
    445 
    446 	(*so->pcictag->clear_intr)(so);
    447         wakeup(so);
    448 
    449         return 1;
    450 }
    451 
    452 static void
    453 imx_pcic_event_thread(void *arg)
    454 {
    455 #ifdef NOTYET
    456 	struct imx_pcic_socket *sock = (struct imx_pcic_socket *)arg;
    457 	u_int cs;
    458 	int present;
    459 
    460 	while (sock->sc->sc_shutdown == 0) {
    461 		(void) tsleep(sock, PWAIT, "imx_pcicev", 0);
    462 
    463 		/* sleep .25s to avoid chattering interrupts */
    464 		(void) tsleep((void *)sock, PWAIT, "imx_pcicss", hz/4);
    465 
    466 		cs = (*sock->pcictag->read)(sock, IMX_PCIC_CARD_STATUS);
    467 		present = sock->flags & IMX_PCIC_FLAG_CARDP;
    468 		if ((cs == IMX_PCIC_CARD_VALID) == (present == 1)) {
    469 			continue;	/* state unchanged */
    470 		}
    471 
    472 		/* XXX Do both? */
    473 		imx_pcic_event_process(sock);
    474 	}
    475 	sock->event_thread = NULL;
    476 
    477 	/* In case parent is waiting for us to exit. */
    478 	wakeup(sock->sc);
    479 	kthread_exit(0);
    480 #endif	/* NOTYET */
    481 }
    482 
    483 #ifdef NOTYET
    484 static void
    485 imx_pcic_event_process(struct imx_pcic_socket *sock)
    486 {
    487 	u_int cs;
    488 
    489 	cs = (*sock->pcictag->read)(sock, IMX_PCIC_CARD_STATUS);
    490 	if (cs == IMX_PCIC_CARD_VALID) {
    491 		if (!(sock->flags & IMX_PCIC_FLAG_CARDP)) {
    492 			imx_pcic_attach_card(sock);
    493 		}
    494 	} else {
    495 		if ((sock->flags & IMX_PCIC_FLAG_CARDP)) {
    496 			imx_pcic_detach_card(sock, DETACH_FORCE);
    497 		}
    498 	}
    499 }
    500 
    501 static void
    502 imx_pcic_attach_card(struct imx_pcic_socket *h)
    503 {
    504 
    505 	if (h->flags & IMX_PCIC_FLAG_CARDP)
    506 		panic("pcic_attach_card: already attached");
    507 	h->flags |= IMX_PCIC_FLAG_CARDP;
    508 
    509 
    510 	/* call the MI attach function */
    511 	pcmcia_card_attach(h->pcmcia);
    512 }
    513 #endif	/* NOTYET */
    514 
    515 #ifdef NOTYET
    516 static void
    517 imx_pcic_detach_card(struct imx_pcic_socket *h, int flags)
    518 {
    519 	struct imx_pcic_softc *sc = h->sc;
    520 	int i;
    521 
    522 	if (h->flags & IMX_PCIC_FLAG_CARDP) {
    523 		h->flags &= ~IMX_PCIC_FLAG_CARDP;
    524 
    525 		/* call the MI detach function */
    526 		pcmcia_card_detach(h->pcmcia, flags);
    527 	}
    528 
    529 	/* Clear CIT if no other card is present. */
    530 	for (i = 0; i < sc->sc_nslots; i++) {
    531 		if (sc->sc_socket[i].flags & IMX_PCIC_FLAG_CARDP) {
    532 			return;
    533 		}
    534 	}
    535 }
    536 #endif	/* NOTYET */
    537