xref: /netbsd/sys/arch/arm/imx/imx_pcic.c (revision 6550d01e)
1 /*	$Id: imx_pcic.c,v 1.3 2008/06/30 00:46:41 perry 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.3 2008/06/30 00:46:41 perry 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.3 2008/06/30 00:46:41 perry 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 #include <sys/malloc.h>
37 
38 #include <uvm/uvm.h>
39 
40 #include <machine/bus.h>
41 #include <machine/intr.h>
42 
43 #include <dev/pcmcia/pcmciareg.h>
44 #include <dev/pcmcia/pcmciavar.h>
45 #include <dev/pcmcia/pcmciachip.h>
46 
47 #ifdef NOTYET
48 #include <arm/imx/imx_gpio.h>
49 #endif
50 #include <arm/imx/imx_pcic.h>
51 
52 static int	imx_pcic_print(void *, const char *);
53 
54 static void	imx_pcic_event_thread(void *);
55 #ifdef NOTYET
56 static void	imx_pcic_event_process(struct imx_pcic_socket *);
57 static void	imx_pcic_attach_card(struct imx_pcic_socket *);
58 #endif
59 #ifdef NOTYET
60 static void	imx_pcic_detach_card(struct imx_pcic_socket *, int);
61 #endif
62 
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);
70 
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);
78 
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 *);
82 
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);
86 
87 /*
88  * PCMCIA chipset methods
89  */
90 static struct pcmcia_chip_functions imx_pcic_pcmcia_functions = {
91 	imx_pcic_mem_alloc,
92 	imx_pcic_mem_free,
93 	imx_pcic_mem_map,
94 	imx_pcic_mem_unmap,
95 
96 	imx_pcic_io_alloc,
97 	imx_pcic_io_free,
98 	imx_pcic_io_map,
99 	imx_pcic_io_unmap,
100 
101 	imx_pcic_intr_establish,
102 	imx_pcic_intr_disestablish,
103 
104 	imx_pcic_socket_enable,
105 	imx_pcic_socket_disable,
106 	imx_pcic_socket_settype,
107 };
108 
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 */
115 
116 
117 
118 /*
119  * PCMCIA Helpers
120  */
121 static int
122 imx_pcic_mem_alloc(pcmcia_chipset_handle_t pch, bus_size_t size,
123     struct pcmcia_mem_handle *pmh)
124 {
125 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
126 
127 	/* All we need is the bus space tag */
128 	memset(pmh, 0, sizeof(*pmh));
129 	pmh->memt = so->sc->sc_iot;
130 
131 	return 0;
132 }
133 
134 static void
135 imx_pcic_mem_free(pcmcia_chipset_handle_t pch, struct pcmcia_mem_handle *pmh)
136 {
137 
138 	/* Nothing to do */
139 }
140 
141 static int
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,
144     int *windowp)
145 {
146 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
147 	int error;
148 	bus_addr_t pa;
149 
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;
156 
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);
161 
162 	switch (kind & ~PCMCIA_WIDTH_MEM_MASK) {
163 	case PCMCIA_MEM_ATTR:
164 		pa += IMX_PCIC_ATTR_OFFSET;
165 		break;
166 	case PCMCIA_MEM_COMMON:
167 		pa += IMX_PCIC_COMMON_OFFSET;
168 		break;
169 	default:
170 		panic("imx_pcic_mem_map: bogus kind");
171 	}
172 
173 printf("%s: pa %lx\n", __func__, pa);
174 Debugger();
175 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pmh->memh);
176 	if (error)
177 		return error;
178 
179 	*windowp = (int)pmh->memh;
180 	return 0;
181 }
182 
183 static void
184 imx_pcic_mem_unmap(pcmcia_chipset_handle_t pch, int window)
185 {
186 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
187 
188 	bus_space_unmap(so->sc->sc_iot, (bus_addr_t)window, 4096); /* XXX */
189 }
190 
191 static int
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)
194 {
195 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
196 	bus_addr_t pa;
197 	int error;
198 
199 	memset(pih, 0, sizeof(*pih));
200 	pih->iot = so->sc->sc_iot;
201 	pih->addr = start;
202 	pih->size = size;
203 
204 	pa = pih->addr;
205 	pa += IMX_PCIC_SOCKET_BASE;
206 	pa += IMX_PCIC_SOCKET_OFFSET * so->socket;
207 
208 	/* XXX Are we ignoring alignment constraints? */
209 	error = bus_space_map(so->sc->sc_iot, pa, size, 0, &pih->ioh);
210 
211 	return error;
212 }
213 
214 static void
215 imx_pcic_io_free(pcmcia_chipset_handle_t pch, struct pcmcia_io_handle *pih)
216 {
217 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
218 
219 	bus_space_unmap(so->sc->sc_iot, pih->ioh, pih->size);
220 }
221 
222 static int
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)
225 {
226 
227 	return 0;
228 }
229 
230 static void
231 imx_pcic_io_unmap(pcmcia_chipset_handle_t pch, int window)
232 {
233 
234 	/* Nothing to do */
235 }
236 
237 static void *
238 imx_pcic_intr_establish(pcmcia_chipset_handle_t pch,
239     struct pcmcia_function *pf, int ipl, int (*fct)(void *), void *arg)
240 {
241 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
242 	/* XXX need to check if something should be done here */
243 
244 	return (*so->pcictag->intr_establish)(so, ipl, fct, arg);
245 }
246 
247 static void
248 imx_pcic_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
249 {
250 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
251 
252 	(*so->pcictag->intr_disestablish)(so, ih);
253 }
254 
255 static void
256 imx_pcic_socket_enable(pcmcia_chipset_handle_t pch)
257 {
258 #ifdef NOTYET
259 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
260 	int i;
261 
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);
265 
266 	/*
267 	 * Wait 300ms until power fails (Tpf).  Then, wait 100ms since
268 	 * we are changing Vcc (Toff).
269 	 */
270 	delay((300 + 100) * 1000);
271 
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,
276 		    IMX_PCIC_POWER_5V);
277 	} else {
278 		(*so->pcictag->set_power)(so, IMX_PCIC_POWER_3V);
279 		(*so->pcictag->write)(so, IMX_PCIC_CARD_POWER,
280 		    IMX_PCIC_POWER_3V);
281 	}
282 
283 	/*
284 	 * Wait 100ms until power raise (Tpr) and 20ms to become
285 	 * stable (Tsu(Vcc)).
286 	 *
287 	 * Some machines require some more time to be settled
288 	 * (another 200ms is added here).
289 	 */
290 	delay((100 + 20 + 200) * 1000);
291 
292 	/* Hold RESET at least 10us. */
293 	(*so->pcictag->write)(so, IMX_PCIC_CARD_RESET, 1);
294 	delay(10);
295 	/* XXX wrong, but lets TE-CF100 cards work for some reason. */
296 	delay(3000);
297 	(*so->pcictag->write)(so, IMX_PCIC_CARD_RESET, 0);
298 
299 	/* Wait 20ms as per PC Card standard (r2.01) section 4.3.6. */
300 	delay(20 * 1000);
301 
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))
305 			break;
306 		delay(500);
307 	}
308 #else
309 printf("%s: (stubbed)\n", __func__);
310 #endif	/* NOTYET */
311 }
312 
313 static void
314 imx_pcic_socket_disable(pcmcia_chipset_handle_t pch)
315 {
316 #ifdef NOTYET
317 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)pch;
318 
319 #ifdef PCICDEBUG
320 	printf("imx_pcic_socket_disable: socket %d\n", so->socket);
321 #endif
322 
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);
326 #endif	/* NOTYET */
327 }
328 
329 static void
330 imx_pcic_socket_settype(pcmcia_chipset_handle_t pch, int type)
331 {
332 
333 #ifdef PCICDEBUG
334 	printf("imx_pcic_socket_settype: type=%d",type);
335 
336 	switch (type) {
337 	case PCMCIA_IFTYPE_MEMORY:
338 		printf("(Memory)\n");
339 		break;
340 	case PCMCIA_IFTYPE_IO:
341 		printf("(I/O)\n");
342 		break;
343 	default:
344 		printf("(unknown)\n");
345 		break;
346 	}
347 #endif
348 }
349 
350 /*
351  * Attachment and initialization
352  */
353 static int
354 imx_pcic_print(void *aux, const char *name)
355 {
356 
357 	return UNCONF;
358 }
359 
360 void
361 imx_pcic_attach_common(struct imx_pcic_softc *sc,
362     void (*socket_setup_hook)(struct imx_pcic_socket *))
363 {
364 	struct pcmciabus_attach_args paa;
365 	struct imx_pcic_socket *so;
366 	int s[IMX_PCIC_NSLOT];
367 	int i;
368 
369 	printf(": %d slot%s\n", sc->sc_nslots, sc->sc_nslots < 2 ? "" : "s");
370 
371 	if (sc->sc_nslots == 0) {
372 		aprint_error("%s: can't attach\n", sc->sc_dev.dv_xname);
373 		return;
374 	}
375 
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);
379 		return;
380 	}
381 
382 #if 0
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);
386 #endif
387 
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;
391 		}
392 	} else {
393 		for (i = 0; i < sc->sc_nslots; i++) {
394 			s[i] = i;
395 		}
396 	}
397 
398 	for (i = 0; i < sc->sc_nslots; i++) {
399 		so = &sc->sc_socket[s[i]];
400 		so->sc = sc;
401 		so->socket = s[i];
402 		so->flags = 0;
403 
404 		(*socket_setup_hook)(so);
405 
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;
411 		paa.iosize = 0x2000;
412 
413 		so->pcmcia = config_found_ia(&sc->sc_dev, "pcmciabus", &paa,
414 		    imx_pcic_print);
415 
416 #ifdef NOTYET
417 		imx_gpio_set_direction(sc->sc_irqpin[s[i]], GPIO_IN);
418 		imx_gpio_set_direction(sc->sc_irqcfpin[s[i]], GPIO_IN);
419 
420 		/* Card slot interrupt */
421 		so->irq = imx_gpio_intr_establish(sc->sc_irqcfpin[s[i]],
422 		    IST_EDGE_BOTH, IPL_BIO /* XXX */, "pcic",
423 		    imx_pcic_intr, so);
424 
425 		/* GPIO pin for interrupt */
426 		so->irqpin = sc->sc_irqpin[s[i]];
427 #else
428 		so->irqpin = sc->sc_irqpin[s[i]];
429 printf("%s: slot %d, irqpin %d\n",  __func__, s[i], sc->sc_irqpin[s[i]]);
430 #endif	/* NOTYET */
431 
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);
437 		}
438 	}
439 }
440 
441 /*
442  * Card slot interrupt handling
443  */
444 int
445 imx_pcic_intr(void *arg)
446 {
447 	struct imx_pcic_socket *so = (struct imx_pcic_socket *)arg;
448 
449 	(*so->pcictag->clear_intr)(so);
450         wakeup(so);
451 
452         return 1;
453 }
454 
455 static void
456 imx_pcic_event_thread(void *arg)
457 {
458 #ifdef NOTYET
459 	struct imx_pcic_socket *sock = (struct imx_pcic_socket *)arg;
460 	u_int cs;
461 	int present;
462 
463 	while (sock->sc->sc_shutdown == 0) {
464 		(void) tsleep(sock, PWAIT, "imx_pcicev", 0);
465 
466 		/* sleep .25s to avoid chattering interrupts */
467 		(void) tsleep((void *)sock, PWAIT, "imx_pcicss", hz/4);
468 
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 */
473 		}
474 
475 		/* XXX Do both? */
476 		imx_pcic_event_process(sock);
477 	}
478 	sock->event_thread = NULL;
479 
480 	/* In case parent is waiting for us to exit. */
481 	wakeup(sock->sc);
482 	kthread_exit(0);
483 #endif	/* NOTYET */
484 }
485 
486 #ifdef NOTYET
487 static void
488 imx_pcic_event_process(struct imx_pcic_socket *sock)
489 {
490 	u_int cs;
491 
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);
496 		}
497 	} else {
498 		if ((sock->flags & IMX_PCIC_FLAG_CARDP)) {
499 			imx_pcic_detach_card(sock, DETACH_FORCE);
500 		}
501 	}
502 }
503 
504 static void
505 imx_pcic_attach_card(struct imx_pcic_socket *h)
506 {
507 
508 	if (h->flags & IMX_PCIC_FLAG_CARDP)
509 		panic("pcic_attach_card: already attached");
510 	h->flags |= IMX_PCIC_FLAG_CARDP;
511 
512 
513 	/* call the MI attach function */
514 	pcmcia_card_attach(h->pcmcia);
515 }
516 #endif	/* NOTYET */
517 
518 #ifdef NOTYET
519 static void
520 imx_pcic_detach_card(struct imx_pcic_socket *h, int flags)
521 {
522 	struct imx_pcic_softc *sc = h->sc;
523 	int i;
524 
525 	if (h->flags & IMX_PCIC_FLAG_CARDP) {
526 		h->flags &= ~IMX_PCIC_FLAG_CARDP;
527 
528 		/* call the MI detach function */
529 		pcmcia_card_detach(h->pcmcia, flags);
530 	}
531 
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) {
535 			return;
536 		}
537 	}
538 }
539 #endif	/* NOTYET */
540