1 /* $Id: imx_pcic.c,v 1.3 2008/06/30 00:46:41 perry Exp $ */
4 * IMX CF interface to pcic/pcmcia
5 * derived from pxa2x0_pcic
6 * Sun Apr 1 21:42:37 PDT 2007
9 /* $NetBSD: imx_pcic.c,v 1.2 2008/04/27 18:58:44 matt Exp $ */
10 /* $OpenBSD: pxa2x0_pcic.c,v 1.17 2005/12/14 15:08:51 uwe Exp $ */
13 * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
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.
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.
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$Id: imx_pcic.c,v 1.3 2008/06/30 00:46:41 perry Exp $");
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 #include <sys/malloc.h>
40 #include <machine/bus.h>
41 #include <machine/intr.h>
43 #include <dev/pcmcia/pcmciareg.h>
44 #include <dev/pcmcia/pcmciavar.h>
45 #include <dev/pcmcia/pcmciachip.h>
48 #include <arm/imx/imx_gpio.h>
50 #include <arm/imx/imx_pcic.h>
52 static int imx_pcic_print(void *, const char *);
54 static void imx_pcic_event_thread(void *);
56 static void imx_pcic_event_process(struct imx_pcic_socket
*);
57 static void imx_pcic_attach_card(struct imx_pcic_socket
*);
60 static void imx_pcic_detach_card(struct imx_pcic_socket
*, int);
63 static int imx_pcic_mem_alloc(pcmcia_chipset_handle_t
, bus_size_t
,
64 struct pcmcia_mem_handle
*);
65 static void imx_pcic_mem_free(pcmcia_chipset_handle_t
,
66 struct pcmcia_mem_handle
*);
67 static int imx_pcic_mem_map(pcmcia_chipset_handle_t
, int, bus_addr_t
,
68 bus_size_t
, struct pcmcia_mem_handle
*, bus_size_t
*, int *);
69 static void imx_pcic_mem_unmap(pcmcia_chipset_handle_t
, int);
71 static int imx_pcic_io_alloc(pcmcia_chipset_handle_t
, bus_addr_t
,
72 bus_size_t
, bus_size_t
, struct pcmcia_io_handle
*);
73 static void imx_pcic_io_free(pcmcia_chipset_handle_t
,
74 struct pcmcia_io_handle
*);
75 static int imx_pcic_io_map(pcmcia_chipset_handle_t
, int,
76 bus_addr_t
, bus_size_t
, struct pcmcia_io_handle
*, int *);
77 static void imx_pcic_io_unmap(pcmcia_chipset_handle_t
, int);
79 static void *imx_pcic_intr_establish(pcmcia_chipset_handle_t
,
80 struct pcmcia_function
*, int, int (*)(void *), void *);
81 static void imx_pcic_intr_disestablish(pcmcia_chipset_handle_t
, void *);
83 static void imx_pcic_socket_enable(pcmcia_chipset_handle_t
);
84 static void imx_pcic_socket_disable(pcmcia_chipset_handle_t
);
85 static void imx_pcic_socket_settype(pcmcia_chipset_handle_t
, int);
88 * PCMCIA chipset methods
90 static struct pcmcia_chip_functions imx_pcic_pcmcia_functions
= {
101 imx_pcic_intr_establish
,
102 imx_pcic_intr_disestablish
,
104 imx_pcic_socket_enable
,
105 imx_pcic_socket_disable
,
106 imx_pcic_socket_settype
,
109 #define IMX_MEMCTL_BASE 0x08000000 /* XXX */
110 #define IMX_MEMCTL_SIZE 0x00000010 /* XXX */
111 #define IMX_PCIC_SOCKET_BASE 0x08009000 /* XXX */
112 #define IMX_PCIC_SOCKET_OFFSET 0x00000000 /* XXX */
113 #define IMX_PCIC_ATTR_OFFSET 0x00000800 /* XXX 5912 */
114 #define IMX_PCIC_COMMON_OFFSET 0x00000000 /* XXX 5912 */
122 imx_pcic_mem_alloc(pcmcia_chipset_handle_t pch
, bus_size_t size
,
123 struct pcmcia_mem_handle
*pmh
)
125 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
127 /* All we need is the bus space tag */
128 memset(pmh
, 0, sizeof(*pmh
));
129 pmh
->memt
= so
->sc
->sc_iot
;
135 imx_pcic_mem_free(pcmcia_chipset_handle_t pch
, struct pcmcia_mem_handle
*pmh
)
142 imx_pcic_mem_map(pcmcia_chipset_handle_t pch
, int kind
, bus_addr_t card_addr
,
143 bus_size_t size
, struct pcmcia_mem_handle
*pmh
, bus_size_t
*offsetp
,
146 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
150 printf("%s: card_addr %lx\n", __func__
, card_addr
);
151 pa
= trunc_page(card_addr
);
152 *offsetp
= card_addr
- pa
;
153 printf("%s: offset %lx\n", __func__
, *offsetp
);
154 size
= round_page(card_addr
+ size
) - pa
;
155 pmh
->realsize
= size
;
157 pa
+= IMX_PCIC_SOCKET_BASE
;
158 pa
+= IMX_PCIC_SOCKET_OFFSET
* so
->socket
;
159 printf("%s: pa %lx\n", __func__
, pa
);
160 printf("%s: kind %x\n", __func__
, kind
);
162 switch (kind
& ~PCMCIA_WIDTH_MEM_MASK
) {
163 case PCMCIA_MEM_ATTR
:
164 pa
+= IMX_PCIC_ATTR_OFFSET
;
166 case PCMCIA_MEM_COMMON
:
167 pa
+= IMX_PCIC_COMMON_OFFSET
;
170 panic("imx_pcic_mem_map: bogus kind");
173 printf("%s: pa %lx\n", __func__
, pa
);
175 error
= bus_space_map(so
->sc
->sc_iot
, pa
, size
, 0, &pmh
->memh
);
179 *windowp
= (int)pmh
->memh
;
184 imx_pcic_mem_unmap(pcmcia_chipset_handle_t pch
, int window
)
186 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
188 bus_space_unmap(so
->sc
->sc_iot
, (bus_addr_t
)window
, 4096); /* XXX */
192 imx_pcic_io_alloc(pcmcia_chipset_handle_t pch
, bus_addr_t start
,
193 bus_size_t size
, bus_size_t align
, struct pcmcia_io_handle
*pih
)
195 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
199 memset(pih
, 0, sizeof(*pih
));
200 pih
->iot
= so
->sc
->sc_iot
;
205 pa
+= IMX_PCIC_SOCKET_BASE
;
206 pa
+= IMX_PCIC_SOCKET_OFFSET
* so
->socket
;
208 /* XXX Are we ignoring alignment constraints? */
209 error
= bus_space_map(so
->sc
->sc_iot
, pa
, size
, 0, &pih
->ioh
);
215 imx_pcic_io_free(pcmcia_chipset_handle_t pch
, struct pcmcia_io_handle
*pih
)
217 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
219 bus_space_unmap(so
->sc
->sc_iot
, pih
->ioh
, pih
->size
);
223 imx_pcic_io_map(pcmcia_chipset_handle_t pch
, int width
, bus_addr_t offset
,
224 bus_size_t size
, struct pcmcia_io_handle
*pih
, int *windowp
)
231 imx_pcic_io_unmap(pcmcia_chipset_handle_t pch
, int window
)
238 imx_pcic_intr_establish(pcmcia_chipset_handle_t pch
,
239 struct pcmcia_function
*pf
, int ipl
, int (*fct
)(void *), void *arg
)
241 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
242 /* XXX need to check if something should be done here */
244 return (*so
->pcictag
->intr_establish
)(so
, ipl
, fct
, arg
);
248 imx_pcic_intr_disestablish(pcmcia_chipset_handle_t pch
, void *ih
)
250 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
252 (*so
->pcictag
->intr_disestablish
)(so
, ih
);
256 imx_pcic_socket_enable(pcmcia_chipset_handle_t pch
)
259 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
262 /* Power down the card and socket before setting the voltage. */
263 (*so
->pcictag
->write
)(so
, IMX_PCIC_CARD_POWER
, IMX_PCIC_POWER_OFF
);
264 (*so
->pcictag
->set_power
)(so
, IMX_PCIC_POWER_OFF
);
267 * Wait 300ms until power fails (Tpf). Then, wait 100ms since
268 * we are changing Vcc (Toff).
270 delay((300 + 100) * 1000);
272 /* Power up the socket and card at appropriate voltage. */
273 if (so
->power_capability
& IMX_PCIC_POWER_5V
) {
274 (*so
->pcictag
->set_power
)(so
, IMX_PCIC_POWER_5V
);
275 (*so
->pcictag
->write
)(so
, IMX_PCIC_CARD_POWER
,
278 (*so
->pcictag
->set_power
)(so
, IMX_PCIC_POWER_3V
);
279 (*so
->pcictag
->write
)(so
, IMX_PCIC_CARD_POWER
,
284 * Wait 100ms until power raise (Tpr) and 20ms to become
287 * Some machines require some more time to be settled
288 * (another 200ms is added here).
290 delay((100 + 20 + 200) * 1000);
292 /* Hold RESET at least 10us. */
293 (*so
->pcictag
->write
)(so
, IMX_PCIC_CARD_RESET
, 1);
295 /* XXX wrong, but lets TE-CF100 cards work for some reason. */
297 (*so
->pcictag
->write
)(so
, IMX_PCIC_CARD_RESET
, 0);
299 /* Wait 20ms as per PC Card standard (r2.01) section 4.3.6. */
302 /* Wait for the card to become ready. */
303 for (i
= 0; i
< 10000; i
++) {
304 if ((*so
->pcictag
->read
)(so
, IMX_PCIC_CARD_READY
))
309 printf("%s: (stubbed)\n", __func__
);
314 imx_pcic_socket_disable(pcmcia_chipset_handle_t pch
)
317 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)pch
;
320 printf("imx_pcic_socket_disable: socket %d\n", so
->socket
);
323 /* Power down the card and socket. */
324 (*so
->pcictag
->write
)(so
, IMX_PCIC_CARD_POWER
, IMX_PCIC_POWER_OFF
);
325 (*so
->pcictag
->set_power
)(so
, IMX_PCIC_POWER_OFF
);
330 imx_pcic_socket_settype(pcmcia_chipset_handle_t pch
, int type
)
334 printf("imx_pcic_socket_settype: type=%d",type
);
337 case PCMCIA_IFTYPE_MEMORY
:
338 printf("(Memory)\n");
340 case PCMCIA_IFTYPE_IO
:
344 printf("(unknown)\n");
351 * Attachment and initialization
354 imx_pcic_print(void *aux
, const char *name
)
361 imx_pcic_attach_common(struct imx_pcic_softc
*sc
,
362 void (*socket_setup_hook
)(struct imx_pcic_socket
*))
364 struct pcmciabus_attach_args paa
;
365 struct imx_pcic_socket
*so
;
366 int s
[IMX_PCIC_NSLOT
];
369 printf(": %d slot%s\n", sc
->sc_nslots
, sc
->sc_nslots
< 2 ? "" : "s");
371 if (sc
->sc_nslots
== 0) {
372 aprint_error("%s: can't attach\n", sc
->sc_dev
.dv_xname
);
376 if (bus_space_map(sc
->sc_iot
, IMX_MEMCTL_BASE
, IMX_MEMCTL_SIZE
,
377 0, &sc
->sc_memctl_ioh
)) {
378 aprint_error("%s: failed to map MEMCTL\n", sc
->sc_dev
.dv_xname
);
383 /* Clear CIT (card present) and set NOS correctly. */
384 bus_space_write_4(sc
->sc_iot
, sc
->sc_memctl_ioh
, MEMCTL_MECR
,
385 (sc
->sc_nslots
== 2) ? MECR_NOS
: 0);
388 if (sc
->sc_flags
& PPF_REVERSE_ORDER
) {
389 for (i
= 0; i
< sc
->sc_nslots
; i
++) {
390 s
[i
] = sc
->sc_nslots
- 1 - i
;
393 for (i
= 0; i
< sc
->sc_nslots
; i
++) {
398 for (i
= 0; i
< sc
->sc_nslots
; i
++) {
399 so
= &sc
->sc_socket
[s
[i
]];
404 (*socket_setup_hook
)(so
);
406 paa
.paa_busname
= "pcmcia";
407 paa
.pct
= (pcmcia_chipset_tag_t
)&imx_pcic_pcmcia_functions
;
408 paa
.pch
= (pcmcia_chipset_handle_t
)so
;
409 printf("%s: sc_pa %lx\n", __func__
, sc
->sc_pa
);
410 paa
.iobase
= sc
->sc_pa
;
413 so
->pcmcia
= config_found_ia(&sc
->sc_dev
, "pcmciabus", &paa
,
417 imx_gpio_set_direction(sc
->sc_irqpin
[s
[i
]], GPIO_IN
);
418 imx_gpio_set_direction(sc
->sc_irqcfpin
[s
[i
]], GPIO_IN
);
420 /* Card slot interrupt */
421 so
->irq
= imx_gpio_intr_establish(sc
->sc_irqcfpin
[s
[i
]],
422 IST_EDGE_BOTH
, IPL_BIO
/* XXX */, "pcic",
425 /* GPIO pin for interrupt */
426 so
->irqpin
= sc
->sc_irqpin
[s
[i
]];
428 so
->irqpin
= sc
->sc_irqpin
[s
[i
]];
429 printf("%s: slot %d, irqpin %d\n", __func__
, s
[i
], sc
->sc_irqpin
[s
[i
]]);
432 if (kthread_create(PRI_NONE
, 0, NULL
,
433 imx_pcic_event_thread
, so
, &so
->event_thread
,
434 "%s,%d", sc
->sc_dev
.dv_xname
, so
->socket
) != 0) {
435 printf("%s: unable to create event thread for %d\n",
436 sc
->sc_dev
.dv_xname
, so
->socket
);
442 * Card slot interrupt handling
445 imx_pcic_intr(void *arg
)
447 struct imx_pcic_socket
*so
= (struct imx_pcic_socket
*)arg
;
449 (*so
->pcictag
->clear_intr
)(so
);
456 imx_pcic_event_thread(void *arg
)
459 struct imx_pcic_socket
*sock
= (struct imx_pcic_socket
*)arg
;
463 while (sock
->sc
->sc_shutdown
== 0) {
464 (void) tsleep(sock
, PWAIT
, "imx_pcicev", 0);
466 /* sleep .25s to avoid chattering interrupts */
467 (void) tsleep((void *)sock
, PWAIT
, "imx_pcicss", hz
/4);
469 cs
= (*sock
->pcictag
->read
)(sock
, IMX_PCIC_CARD_STATUS
);
470 present
= sock
->flags
& IMX_PCIC_FLAG_CARDP
;
471 if ((cs
== IMX_PCIC_CARD_VALID
) == (present
== 1)) {
472 continue; /* state unchanged */
476 imx_pcic_event_process(sock
);
478 sock
->event_thread
= NULL
;
480 /* In case parent is waiting for us to exit. */
488 imx_pcic_event_process(struct imx_pcic_socket
*sock
)
492 cs
= (*sock
->pcictag
->read
)(sock
, IMX_PCIC_CARD_STATUS
);
493 if (cs
== IMX_PCIC_CARD_VALID
) {
494 if (!(sock
->flags
& IMX_PCIC_FLAG_CARDP
)) {
495 imx_pcic_attach_card(sock
);
498 if ((sock
->flags
& IMX_PCIC_FLAG_CARDP
)) {
499 imx_pcic_detach_card(sock
, DETACH_FORCE
);
505 imx_pcic_attach_card(struct imx_pcic_socket
*h
)
508 if (h
->flags
& IMX_PCIC_FLAG_CARDP
)
509 panic("pcic_attach_card: already attached");
510 h
->flags
|= IMX_PCIC_FLAG_CARDP
;
513 /* call the MI attach function */
514 pcmcia_card_attach(h
->pcmcia
);
520 imx_pcic_detach_card(struct imx_pcic_socket
*h
, int flags
)
522 struct imx_pcic_softc
*sc
= h
->sc
;
525 if (h
->flags
& IMX_PCIC_FLAG_CARDP
) {
526 h
->flags
&= ~IMX_PCIC_FLAG_CARDP
;
528 /* call the MI detach function */
529 pcmcia_card_detach(h
->pcmcia
, flags
);
532 /* Clear CIT if no other card is present. */
533 for (i
= 0; i
< sc
->sc_nslots
; i
++) {
534 if (sc
->sc_socket
[i
].flags
& IMX_PCIC_FLAG_CARDP
) {