xref: /netbsd-src/sys/arch/evbarm/gumstix/gxpcic.c (revision 2980e352a13e8f0b545a366830c411e7a542ada8)
1 /*	$NetBSD: gxpcic.c,v 1.8 2008/05/11 08:23:17 kiyohara Exp $ */
2 /*
3  * Copyright (C) 2005, 2006 WIDE Project and SOUM Corporation.
4  * All rights reserved.
5  *
6  * Written by Takashi Kiyohara and Susumu Miki for WIDE Project and SOUM
7  * Corporation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the name of SOUM Corporation
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT and SOUM CORPORATION ``AS IS''
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT AND SOUM CORPORATION
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * Copyright (c) 2002, 2003, 2005  Genetec corp.  All rights reserved.
35  *
36  * PCMCIA/CF support for TWINTAIL (G4255EB)
37  * Written by Hiroyuki Bessho for Genetec corp.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. The name of Genetec corp. may not be used to endorse
48  *    or promote products derived from this software without specific prior
49  *    written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORP.
55  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61  * POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/types.h>
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/device.h>
68 #include <sys/callout.h>
69 #include <sys/kernel.h>
70 #include <sys/kthread.h>
71 #include <sys/malloc.h>
72 #include <uvm/uvm.h>
73 
74 #include <machine/bus.h>
75 #include <machine/intr.h>
76 
77 #include <dev/pcmcia/pcmciareg.h>
78 #include <dev/pcmcia/pcmciavar.h>
79 #include <dev/pcmcia/pcmciachip.h>
80 
81 #include <arch/arm/xscale/pxa2x0cpu.h>
82 #include <arch/arm/xscale/pxa2x0var.h>
83 #include <arch/arm/xscale/pxa2x0reg.h>
84 #include <arch/arm/xscale/pxa2x0_gpio.h>
85 #include <arch/arm/xscale/pxa2x0_pcic.h>
86 #include <arch/evbarm/gumstix/gumstixvar.h>
87 
88 
89 #ifdef DEBUG
90 #define DPRINTF(arg)	printf arg
91 #else
92 #define DPRINTF(arg)
93 #endif
94 
95 #define HAVE_CARD(r)	(!((r) & GPIO_SET))
96 
97 #define GXIO_GPIRQ11_CD1	11
98 #define GXIO_GPIRQ26_PRDY1	26
99 #define GXIO_GPIRQ27_PRDY2	27
100 #define GXIO_GPIRQ36_CD2	36
101 
102 
103 static	int  	gxpcic_match(device_t, struct cfdata *, void *);
104 static	void  	gxpcic_attach(device_t, device_t, void *);
105 static	void	gxpcic_pcic_socket_setup(struct pxapcic_socket *);
106 
107 static	u_int	gxpcic_read(struct pxapcic_socket *, int);
108 static	void	gxpcic_write(struct pxapcic_socket *, int, u_int);
109 static	void	gxpcic_set_power(struct pxapcic_socket *, int);
110 static	void	gxpcic_clear_intr(struct pxapcic_socket *);
111 static	void	*gxpcic_intr_establish(struct pxapcic_socket *, int,
112 				       int (*)(void *), void *);
113 static	void	gxpcic_intr_disestablish(struct pxapcic_socket *, void *);
114 __inline void gxpcic_cpld_clk(void);
115 __inline u_char gxpcic_cpld_read_bits(int bits);
116 static	int	gxpcic_count_slot(struct pxapcic_softc *);
117 
118 CFATTACH_DECL(pxapcic_gxpcic, sizeof(struct pxapcic_softc),
119     gxpcic_match, gxpcic_attach, NULL, NULL);
120 
121 static struct pxapcic_tag gxpcic_pcic_functions = {
122 	gxpcic_read,
123 	gxpcic_write,
124 	gxpcic_set_power,
125 	gxpcic_clear_intr,
126 	gxpcic_intr_establish,
127 	gxpcic_intr_disestablish,
128 };
129 
130 static struct {
131 	int cd;
132 	int prdy;
133 } gxpcic_slot_irqs[] = {
134 	{ GXIO_GPIRQ11_CD1, GXIO_GPIRQ26_PRDY1 },
135 	{ GXIO_GPIRQ36_CD2, GXIO_GPIRQ27_PRDY2 }
136 };
137 
138 
139 static int
140 gxpcic_match(device_t parent, struct cfdata *cf, void *aux)
141 {
142 	struct pxa2x0_gpioconf *gpioconf;
143 	u_int reg;
144 	int i;
145 
146 	/*
147 	 * Check GPIO configuration.  If you use these, it is sure already
148 	 * to have been set by gxio.
149 	 */
150 	gpioconf = CPU_IS_PXA250 ? pxa25x_pcic_gpioconf :
151 	    pxa27x_pcic_gpioconf;
152 	for (i = 0; gpioconf[i].pin != -1; i++) {
153 		reg = pxa2x0_gpio_get_function(gpioconf[i].pin);
154 		if (GPIO_FN(reg) != GPIO_FN(gpioconf[i].value) ||
155 		    GPIO_FN_IS_OUT(reg) != GPIO_FN_IS_OUT(gpioconf[i].value))
156 			return (0);
157 	}
158 
159 	return	1;	/* match */
160 }
161 
162 static void
163 gxpcic_attach(device_t parent, device_t self, void *aux)
164 {
165 	struct pxapcic_softc *sc = device_private(self);
166 	struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux;
167 	int nslot, i;
168 
169 	sc->sc_iot = pxa->pxa_iot;
170 
171 	nslot = gxpcic_count_slot(sc);
172 
173 	for (i = 0; i < nslot; i++) {
174 		sc->sc_irqpin[i] = gxpcic_slot_irqs[i].prdy;
175 		sc->sc_irqcfpin[i] = gxpcic_slot_irqs[i].cd;
176 	}
177 	sc->sc_nslots = nslot;
178 
179 	pxapcic_attach_common(sc, &gxpcic_pcic_socket_setup);
180 }
181 
182 static void
183 gxpcic_pcic_socket_setup(struct pxapcic_socket *so)
184 {
185 	struct pxapcic_softc *sc = so->sc;
186 
187 	/* 3.3V only? */
188 	so->power_capability = PXAPCIC_POWER_3V;
189 	so->pcictag_cookie = NULL;
190 	so->pcictag = &gxpcic_pcic_functions;
191 
192 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
193 	    MEMCTL_MCMEM(so->socket), MC_TIMING_VAL(9 ,9, 29));
194 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
195 	    MEMCTL_MCATT(so->socket), MC_TIMING_VAL(9 ,9, 29));
196 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
197 	    MEMCTL_MCIO(so->socket), MC_TIMING_VAL(5 ,5, 16));
198 }
199 
200 static u_int
201 gxpcic_read(struct pxapcic_socket *so, int which)
202 {
203 	int reg;
204 
205 	switch (which) {
206 	case PXAPCIC_CARD_STATUS:
207 		reg = pxa2x0_gpio_get_function(gxpcic_slot_irqs[so->socket].cd);
208 		return (HAVE_CARD(reg) ?
209 		    PXAPCIC_CARD_VALID : PXAPCIC_CARD_INVALID);
210 
211 	case PXAPCIC_CARD_READY:
212 		reg = pxa2x0_gpio_get_function(
213 		    gxpcic_slot_irqs[so->socket].prdy);
214 		return (reg & GPIO_SET ? 1 : 0);
215 
216 	default:
217 		panic("%s: bogus register", __func__);
218 	}
219 	/* NOTREACHED */
220 }
221 
222 /* ARGSUSED */
223 static void
224 gxpcic_write(struct pxapcic_socket *so, int which, u_int arg)
225 {
226 
227 	switch (which) {
228 	case PXAPCIC_CARD_POWER:
229 	case PXAPCIC_CARD_RESET:
230 		/* We can't */
231 		break;
232 
233 	default:
234 		panic("%s: bogus register", __func__);
235 	}
236 	/* NOTREACHED */
237 }
238 
239 static void
240 gxpcic_set_power(struct pxapcic_socket *__so, int arg)
241 {
242 
243 	if(arg != PXAPCIC_POWER_OFF && arg != PXAPCIC_POWER_3V)
244 		panic("%s: bogus arg\n", __func__);
245 
246 	/* 3.3V only? */
247 }
248 
249 /* ARGSUSED */
250 static void
251 gxpcic_clear_intr(struct pxapcic_socket *so)
252 {
253 
254 	/* nothing to do */
255 }
256 
257 static void *
258 gxpcic_intr_establish(struct pxapcic_socket *so, int level,
259     int (* ih_fun)(void *), void *ih_arg)
260 {
261 
262 	return pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING,
263 	    level, ih_fun, ih_arg);
264 }
265 
266 /* ARGSUSED */
267 static void
268 gxpcic_intr_disestablish(struct pxapcic_socket *so, void *ih)
269 {
270 
271 	pxa2x0_gpio_intr_disestablish(ih);
272 }
273 
274 
275 /*
276  * XXXXX: slot count functions from Linux
277  */
278 __inline void
279 gxpcic_cpld_clk()
280 {
281 
282 	pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_CLR);
283 	pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_SET);
284 }
285 
286 __inline u_char
287 gxpcic_cpld_read_bits(int bits)
288 {
289 	u_int shift = 0, gpio;
290 	u_char result = 0;
291 
292 	while (bits--) {
293 		gpio = pxa2x0_gpio_get_function(11);
294 		result |= ((gpio & GPIO_SET) == GPIO_SET) << shift;
295 		shift++;
296 		gxpcic_cpld_clk();
297 	}
298 	return result;
299 }
300 
301 /*
302  * We use the CPLD on the CF-CF card to read a value from a shift register.
303  * If we can read that magic sequence, then we have 2 CF cards; otherwise
304  * we assume just one.  The CPLD will send the value of the shift register
305  * on GPIO11 (the CD line for slot 0) when RESET is held in reset.  We use
306  * GPIO48 (nPWE) as a clock signal, GPIO52/53 (card enable for both cards)
307  * to control read/write to the shift register.
308  */
309 static int
310 gxpcic_count_slot(struct pxapcic_softc *sc)
311 {
312 	u_int poe, pce1, pce2;
313 	int nslot;
314 
315 	poe = pxa2x0_gpio_get_function(48);
316 	pce1 = pxa2x0_gpio_get_function(52);
317 	pce2 = pxa2x0_gpio_get_function(53);
318 
319 	/* Reset */
320 	pxa2x0_gpio_set_function(8, GPIO_OUT | GPIO_SET);
321 
322 	/* Setup the shift register */
323 	pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET);
324 	pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_CLR);
325 
326 	/* Tick the clock to program the shift register */
327 	gxpcic_cpld_clk();
328 
329 	/* Now set shift register into read mode */
330 	pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR);
331 	pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_SET);
332 
333 	/* We can read the bits now -- 0xc2 means "Dual compact flash" */
334 	if (gxpcic_cpld_read_bits(8) != 0xc2)
335 		/* We do not have 2 CF slots */
336 		nslot = 1;
337 	else
338 		/* We have 2 CF slots */
339 		nslot = 2;
340 
341 	delay(50);
342 	pxa2x0_gpio_set_function(8, GPIO_OUT | GPIO_CLR);	/* clr RESET */
343 
344 	pxa2x0_gpio_set_function(48, poe);
345 	pxa2x0_gpio_set_function(52, pce1);
346 	pxa2x0_gpio_set_function(53, pce2);
347 
348 	return nslot;
349 }
350