1 /* $NetBSD: gxpcic.c,v 1.15 2023/12/20 13:55:17 thorpej 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 <uvm/uvm.h>
72
73 #include <sys/bus.h>
74 #include <machine/intr.h>
75
76 #include <dev/pcmcia/pcmciareg.h>
77 #include <dev/pcmcia/pcmciavar.h>
78 #include <dev/pcmcia/pcmciachip.h>
79
80 #include <arch/arm/xscale/pxa2x0cpu.h>
81 #include <arch/arm/xscale/pxa2x0var.h>
82 #include <arch/arm/xscale/pxa2x0reg.h>
83 #include <arch/arm/xscale/pxa2x0_gpio.h>
84 #include <arch/arm/xscale/pxa2x0_pcic.h>
85 #include <arch/evbarm/gumstix/gumstixvar.h>
86
87
88 #ifdef DEBUG
89 #define DPRINTF(arg) printf arg
90 #else
91 #define DPRINTF(arg)
92 #endif
93
94 #define HAVE_CARD(r) (!((r) & GPIO_SET))
95
96
97 static int gxpcic_match(device_t, cfdata_t, void *);
98 static void gxpcic_attach(device_t, device_t, void *);
99 static void gxpcic_socket_setup(struct pxapcic_socket *);
100
101 static u_int gxpcic_read(struct pxapcic_socket *, int);
102 static void gxpcic_write(struct pxapcic_socket *, int, u_int);
103 static void gxpcic_set_power(struct pxapcic_socket *, int);
104 static void gxpcic_clear_intr(struct pxapcic_socket *);
105 static void *gxpcic_intr_establish(struct pxapcic_socket *, int,
106 int (*)(void *), void *);
107 static void gxpcic_intr_disestablish(struct pxapcic_socket *, void *);
108 static __inline void gxpcic_cpld_clk(void);
109 static __inline u_char gxpcic_cpld_read_bits(int bits);
110 static int gxpcic_count_slot(struct pxapcic_softc *);
111
112 CFATTACH_DECL_NEW(gxpcic, sizeof(struct pxapcic_softc),
113 gxpcic_match, gxpcic_attach, NULL, NULL);
114
115 static struct pxapcic_tag gxpcic_functions = {
116 gxpcic_read,
117 gxpcic_write,
118 gxpcic_set_power,
119 gxpcic_clear_intr,
120 gxpcic_intr_establish,
121 gxpcic_intr_disestablish,
122 };
123
124
125 static int
gxpcic_match(device_t parent,cfdata_t match,void * aux)126 gxpcic_match(device_t parent, cfdata_t match, void *aux)
127 {
128 struct pxaip_attach_args *pxa = aux;
129 struct pxa2x0_gpioconf *gpioconf;
130 u_int reg;
131 int i;
132
133 if (strcmp(pxa->pxa_name, match->cf_name) != 0)
134 return 0;
135
136 /*
137 * Check GPIO configuration. If you use these, it is sure already
138 * to have been set by gxio.
139 */
140 gpioconf = CPU_IS_PXA250 ? pxa25x_pcic_gpioconf :
141 pxa27x_pcic_gpioconf;
142 for (i = 0; gpioconf[i].pin != -1; i++) {
143 reg = pxa2x0_gpio_get_function(gpioconf[i].pin);
144 if (GPIO_FN(reg) != GPIO_FN(gpioconf[i].value) ||
145 GPIO_FN_IS_OUT(reg) != GPIO_FN_IS_OUT(gpioconf[i].value)) {
146 if (!CPU_IS_PXA250 && gpioconf[i].pin == 111)
147 continue;
148 return 0;
149 }
150 }
151
152 return 1; /* match */
153 }
154
155 static void
gxpcic_attach(device_t parent,device_t self,void * aux)156 gxpcic_attach(device_t parent, device_t self, void *aux)
157 {
158 struct pxapcic_softc *sc = device_private(self);
159 struct pxaip_attach_args *pxa = aux;
160 int nslot, i, j;
161
162 sc->sc_dev = self;
163 sc->sc_iot = pxa->pxa_iot;
164
165 nslot = gxpcic_count_slot(sc);
166
167 for (i = 0, j = 0; i < nslot; i++) {
168 if (!gxpcic_slot_irqs[i].valid) {
169 j++;
170 continue;
171 }
172 sc->sc_irqpin[i - j] = gxpcic_slot_irqs[i].prdy;
173 sc->sc_irqcfpin[i - j] = gxpcic_slot_irqs[i].cd;
174 }
175 sc->sc_nslots = i - j;
176
177 pxapcic_attach_common(sc, &gxpcic_socket_setup);
178 }
179
180 static void
gxpcic_socket_setup(struct pxapcic_socket * so)181 gxpcic_socket_setup(struct pxapcic_socket *so)
182 {
183 #if 0
184 struct pxapcic_softc *sc = so->sc;
185 #endif
186
187 /* 3.3V only? */
188 so->power_capability = PXAPCIC_POWER_3V;
189 so->pcictag_cookie = NULL;
190 so->pcictag = &gxpcic_functions;
191
192 #if 0 /* We use already set values by u-boot. */
193 bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
194 MEMCTL_MCMEM(so->socket), MC_TIMING_VAL(9 ,9, 29));
195 bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
196 MEMCTL_MCATT(so->socket), MC_TIMING_VAL(9 ,9, 29));
197 bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
198 MEMCTL_MCIO(so->socket), MC_TIMING_VAL(5 ,5, 16));
199 #endif
200 }
201
202 static u_int
gxpcic_read(struct pxapcic_socket * so,int which)203 gxpcic_read(struct pxapcic_socket *so, int which)
204 {
205 int reg;
206
207 switch (which) {
208 case PXAPCIC_CARD_STATUS:
209 reg = pxa2x0_gpio_get_function(so->sc->sc_irqcfpin[so->socket]);
210 return (HAVE_CARD(reg) ?
211 PXAPCIC_CARD_VALID : PXAPCIC_CARD_INVALID);
212
213 case PXAPCIC_CARD_READY:
214 reg = pxa2x0_gpio_get_function(so->sc->sc_irqpin[so->socket]);
215 return (reg & GPIO_SET ? 1 : 0);
216
217 default:
218 panic("%s: bogus register", __func__);
219 }
220 /* NOTREACHED */
221 }
222
223 /* ARGSUSED */
224 static void
gxpcic_write(struct pxapcic_socket * so,int which,u_int arg)225 gxpcic_write(struct pxapcic_socket *so, int which, u_int arg)
226 {
227
228 switch (which) {
229 case PXAPCIC_CARD_POWER:
230 case PXAPCIC_CARD_RESET:
231 /* We can't */
232 break;
233
234 default:
235 panic("%s: bogus register", __func__);
236 }
237 /* NOTREACHED */
238 }
239
240 static void
gxpcic_set_power(struct pxapcic_socket * __so,int arg)241 gxpcic_set_power(struct pxapcic_socket *__so, int arg)
242 {
243
244 if(arg != PXAPCIC_POWER_OFF && arg != PXAPCIC_POWER_3V)
245 panic("%s: bogus arg\n", __func__);
246
247 /* 3.3V only? */
248 }
249
250 /* ARGSUSED */
251 static void
gxpcic_clear_intr(struct pxapcic_socket * so)252 gxpcic_clear_intr(struct pxapcic_socket *so)
253 {
254
255 /* nothing to do */
256 }
257
258 static void *
gxpcic_intr_establish(struct pxapcic_socket * so,int level,int (* ih_fun)(void *),void * ih_arg)259 gxpcic_intr_establish(struct pxapcic_socket *so, int level,
260 int (* ih_fun)(void *), void *ih_arg)
261 {
262
263 return pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING,
264 level, ih_fun, ih_arg);
265 }
266
267 /* ARGSUSED */
268 static void
gxpcic_intr_disestablish(struct pxapcic_socket * so,void * ih)269 gxpcic_intr_disestablish(struct pxapcic_socket *so, void *ih)
270 {
271
272 pxa2x0_gpio_intr_disestablish(ih);
273 }
274
275
276 /*
277 * XXXXX: slot count functions from Linux
278 */
279 static __inline void
gxpcic_cpld_clk(void)280 gxpcic_cpld_clk(void)
281 {
282
283 pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_CLR);
284 pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_SET);
285 }
286
287 static inline u_char
gxpcic_cpld_read_bits(int bits)288 gxpcic_cpld_read_bits(int bits)
289 {
290 u_int shift = 0, gpio;
291 u_char result = 0;
292
293 while (bits--) {
294 gpio = pxa2x0_gpio_get_function(11);
295 result |= ((gpio & GPIO_SET) == GPIO_SET) << shift;
296 shift++;
297 gxpcic_cpld_clk();
298 }
299 return result;
300 }
301
302 /*
303 * We use the CPLD on the CF-CF card to read a value from a shift register.
304 * If we can read that magic sequence, then we have 2 CF cards; otherwise
305 * we assume just one. The CPLD will send the value of the shift register
306 * on GPIO11 (the CD line for slot 0) when RESET is held in reset. We use
307 * GPIO48 (nPWE) as a clock signal, GPIO52/53 (card enable for both cards)
308 * to control read/write to the shift register.
309 */
310 static int
gxpcic_count_slot(struct pxapcic_softc * sc)311 gxpcic_count_slot(struct pxapcic_softc *sc)
312 {
313 u_int poe, pce1, pce2;
314 int nslot;
315
316 poe = pxa2x0_gpio_get_function(48);
317 pce1 = pxa2x0_gpio_get_function(52);
318 pce2 = pxa2x0_gpio_get_function(53);
319
320 /* RESET */
321 pxa2x0_gpio_set_function(gxpcic_gpio_reset, GPIO_OUT | GPIO_CLR);
322
323 /* Setup the shift register */
324 pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET);
325 pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_CLR);
326
327 /* Tick the clock to program the shift register */
328 gxpcic_cpld_clk();
329
330 /* Now set shift register into read mode */
331 pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR);
332 pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_SET);
333
334 /* We can read the bits now -- 0xc2 means "Dual compact flash" */
335 if (gxpcic_cpld_read_bits(8) != 0xc2)
336 /* We do not have 2 CF slots */
337 nslot = 1;
338 else
339 /* We have 2 CF slots */
340 nslot = 2;
341
342 delay(50);
343 /* clear RESET */
344 pxa2x0_gpio_set_function(gxpcic_gpio_reset, GPIO_OUT | GPIO_CLR);
345
346 pxa2x0_gpio_set_function(48, poe);
347 pxa2x0_gpio_set_function(52, pce1);
348 pxa2x0_gpio_set_function(53, pce2);
349
350 return nslot;
351 }
352