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@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