gxio.c revision 1.7.20.3 1 /* $NetBSD: gxio.c,v 1.7.20.3 2009/08/19 18:46:06 yamt Exp $ */
2 /*
3 * Copyright (C) 2005, 2006, 2007 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 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: gxio.c,v 1.7.20.3 2009/08/19 18:46:06 yamt Exp $");
35
36 #include "opt_gxio.h"
37
38 #include <sys/param.h>
39 #include <sys/device.h>
40 #include <sys/errno.h>
41 #include <sys/kernel.h>
42
43 #include <sys/systm.h>
44
45 #include <machine/bootconfig.h>
46
47 #include <arm/xscale/pxa2x0cpu.h>
48 #include <arm/xscale/pxa2x0reg.h>
49 #include <arm/xscale/pxa2x0var.h>
50 #include <arm/xscale/pxa2x0_gpio.h>
51 #include <evbarm/gumstix/gumstixvar.h>
52
53 #include "locators.h"
54
55
56 struct gxioconf {
57 const char *name;
58 void (*config)(void);
59 };
60
61 static int gxiomatch(device_t, cfdata_t, void *);
62 static void gxioattach(device_t, device_t, void *);
63 static int gxiosearch(device_t, cfdata_t, const int *, void *);
64 static int gxioprint(void *, const char *);
65
66 void gxio_config_pin(void);
67 void gxio_config_expansion(char *);
68 static void gxio_config_gpio(const struct gxioconf *, char *);
69 static void basix_config(void);
70 static void cfstix_config(void);
71 static void etherstix_config(void);
72 static void netcf_config(void);
73 static void netduommc_config(void);
74 static void netduo_config(void);
75 static void netmicrosd_config(void);
76 static void netwifimicrosd_config(void);
77 static void netmmc_config(void);
78 static void wifistix_config(void);
79 static void wifistix_cf_config(void);
80
81 CFATTACH_DECL_NEW(
82 gxio, sizeof(struct gxio_softc), gxiomatch, gxioattach, NULL, NULL);
83
84 char busheader[MAX_BOOT_STRING];
85
86 #if defined(CPU_XSCALE_PXA250)
87 static struct pxa2x0_gpioconf pxa255dep_gpioconf[] = {
88 /* Bluetooth module configuration */
89 { 7, GPIO_OUT | GPIO_SET }, /* power on */
90 { 12, GPIO_ALT_FN_1_OUT }, /* 32kHz out. required by SingleStone */
91
92 /* AC97 configuration */
93 { 29, GPIO_ALT_FN_1_IN }, /* SDATA_IN0 */
94
95 /* FFUART configuration */
96 { 35, GPIO_ALT_FN_1_IN }, /* CTS */
97 { 41, GPIO_ALT_FN_2_OUT }, /* RTS */
98
99 #ifndef GXIO_BLUETOOTH_ON_HWUART
100 /* BTUART configuration */
101 { 44, GPIO_ALT_FN_1_IN }, /* BTCTS */
102 { 45, GPIO_ALT_FN_2_OUT }, /* BTRTS */
103 #else
104 /* HWUART configuration */
105 { 42, GPIO_ALT_FN_3_IN }, /* HWRXD */
106 { 43, GPIO_ALT_FN_3_OUT }, /* HWTXD */
107 { 44, GPIO_ALT_FN_3_IN }, /* HWCTS */
108 { 45, GPIO_ALT_FN_3_OUT }, /* HWRTS */
109 #endif
110
111 #ifndef GXIO_BLUETOOTH_ON_HWUART
112 /* HWUART configuration */
113 { 48, GPIO_ALT_FN_1_OUT }, /* HWTXD */
114 { 49, GPIO_ALT_FN_1_IN }, /* HWRXD */
115 { 50, GPIO_ALT_FN_1_IN }, /* HWCTS */
116 { 51, GPIO_ALT_FN_1_OUT }, /* HWRTS */
117 #endif
118
119 { -1 }
120 };
121 #endif
122 #if defined(CPU_XSCALE_PXA270)
123 static struct pxa2x0_gpioconf verdexdep_gpioconf[] = {
124 /* Bluetooth module configuration */
125 { 9, GPIO_ALT_FN_3_OUT }, /* CHOUT<0> */
126
127 /* FFUART configuration */
128 { 27, GPIO_ALT_FN_3_OUT }, /* FFRTS */
129 { 34, GPIO_ALT_FN_1_IN }, /* FFRXD */
130 { 39, GPIO_ALT_FN_2_OUT }, /* FFTXD */
131 { 100, GPIO_ALT_FN_3_IN }, /* FFCTS */
132
133 /* BTUART configuration */
134 { 42, GPIO_ALT_FN_1_IN }, /* BTRXD */
135 { 43, GPIO_ALT_FN_2_OUT }, /* BTTXD */
136 { 44, GPIO_ALT_FN_1_IN }, /* BTCTS */
137 { 45, GPIO_ALT_FN_2_OUT }, /* BTRTS */
138
139 /* AC97 configuration */
140 { 29, GPIO_ALT_FN_1_IN }, /* SDATA_IN0 */
141
142 { -1 }
143 };
144 #endif
145
146 static const struct gxioconf busheader_conf[] = {
147 { "basix", basix_config },
148 { "cfstix", cfstix_config },
149 { "etherstix", etherstix_config },
150 { "netcf", netcf_config },
151 { "netcf-vx", netcf_config },
152 { "netduo-mmc", netduommc_config },
153 { "netduo", netduo_config },
154 { "netmicrosd", netmicrosd_config },
155 { "netmicrosd-vx", netmicrosd_config },
156 { "netwifimicrosd", netwifimicrosd_config },
157 { "netmmc", netmmc_config },
158 { "netpro-vx", netwifimicrosd_config },
159 { "wifistix-cf", wifistix_cf_config },
160 { "wifistix", wifistix_config },
161 { NULL }
162 };
163
164 int gxpcic_gpio_reset;
165 struct gxpcic_slot_irqs gxpcic_slot_irqs[2] = { { 0, -1, -1 }, { 0, -1, -1 } };
166
167
168 /* ARGSUSED */
169 static int
170 gxiomatch(device_t parent, cfdata_t match, void *aux)
171 {
172 struct pxaip_attach_args *pxa = aux;
173 bus_space_tag_t iot = &pxa2x0_bs_tag;
174 bus_space_handle_t ioh;
175
176 if (strcmp(pxa->pxa_name, match->cf_name) != 0 ||
177 pxa->pxa_addr != PXAIPCF_ADDR_DEFAULT)
178 return 0;
179
180 if (bus_space_map(iot,
181 PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE, 0, &ioh))
182 return (0);
183 bus_space_unmap(iot, ioh, PXA2X0_MEMCTL_SIZE);
184
185 /* nothing */
186 return (1);
187 }
188
189 /* ARGSUSED */
190 static void
191 gxioattach(device_t parent, device_t self, void *aux)
192 {
193 struct gxio_softc *sc = device_private(self);
194
195 aprint_normal("\n");
196 aprint_naive("\n");
197
198 sc->sc_dev = self;
199 sc->sc_iot = &pxa2x0_bs_tag;
200
201 if (bus_space_map(sc->sc_iot,
202 PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE, 0, &sc->sc_ioh))
203 return;
204
205 /*
206 * Attach each gumstix expansion of busheader side devices
207 */
208 config_search_ia(gxiosearch, self, "gxio", NULL);
209 }
210
211 /* ARGSUSED */
212 static int
213 gxiosearch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
214 {
215 struct gxio_softc *sc = device_private(parent);
216 struct gxio_attach_args gxa;
217
218 gxa.gxa_sc = sc;
219 gxa.gxa_iot = sc->sc_iot;
220 gxa.gxa_addr = cf->cf_loc[GXIOCF_ADDR];
221 gxa.gxa_gpirq = cf->cf_loc[GXIOCF_GPIRQ];
222
223 if (config_match(parent, cf, &gxa))
224 config_attach(parent, cf, &gxa, gxioprint);
225
226 return (0);
227 }
228
229 /* ARGSUSED */
230 static int
231 gxioprint(void *aux, const char *name)
232 {
233 struct gxio_attach_args *gxa = (struct gxio_attach_args *)aux;
234
235 if (gxa->gxa_addr != GXIOCF_ADDR_DEFAULT)
236 printf(" addr 0x%lx", gxa->gxa_addr);
237 if (gxa->gxa_gpirq > 0)
238 printf(" gpirq %d", gxa->gxa_gpirq);
239 return (UNCONF);
240 }
241
242
243 /*
244 * configure for GPIO pin and expansion boards.
245 */
246 void
247 gxio_config_pin(void)
248 {
249 #if defined(CPU_XSCALE_PXA250)
250 struct pxa2x0_gpioconf *gumstix_gpioconf[] = {
251 pxa25x_com_ffuart_gpioconf,
252 pxa25x_com_stuart_gpioconf,
253 #ifndef GXIO_BLUETOOTH_ON_HWUART
254 pxa25x_com_btuart_gpioconf,
255 #endif
256 pxa25x_com_hwuart_gpioconf,
257 pxa25x_i2c_gpioconf,
258 pxa25x_pxaacu_gpioconf,
259 pxa255dep_gpioconf,
260 NULL
261 };
262 #endif
263 #if defined(CPU_XSCALE_PXA270)
264 struct pxa2x0_gpioconf *verdex_gpioconf[] = {
265 pxa27x_com_ffuart_gpioconf,
266 pxa27x_com_stuart_gpioconf,
267 pxa27x_com_btuart_gpioconf,
268 pxa27x_i2c_gpioconf,
269 pxa27x_pxaacu_gpioconf,
270 pxa27x_pxamci_gpioconf,
271 pxa27x_ohci_gpioconf,
272 verdexdep_gpioconf,
273 NULL
274 };
275 #endif
276
277 /* XXX: turn off for power of bluetooth module */
278 pxa2x0_gpio_set_function(7, GPIO_OUT | GPIO_CLR);
279 delay(100);
280
281 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
282 pxa2x0_gpio_config(
283 (CPU_IS_PXA250) ? gumstix_gpioconf : verdex_gpioconf);
284 #else
285 #if defined(CPU_XSCALE_PXA270)
286 pxa2x0_gpio_config(verdex_gpioconf);
287 #else
288 pxa2x0_gpio_config(gumstix_gpioconf);
289 #endif
290 #endif
291 }
292
293 void
294 gxio_config_expansion(char *expansion)
295 {
296
297 if (expansion == NULL) {
298 printf("not specified 'busheader=' in the boot args.\n");
299 #ifdef GXIO_DEFAULT_EXPANSION
300 printf("configure default expansion (%s)\n",
301 GXIO_DEFAULT_EXPANSION);
302 expansion = __UNCONST(GXIO_DEFAULT_EXPANSION);
303 #else
304 return;
305 #endif
306 }
307 gxio_config_gpio(busheader_conf, expansion);
308 }
309
310 static void
311 gxio_config_gpio(const struct gxioconf *gxioconflist, char *expansion)
312 {
313 int i, rv;
314
315 for (i = 0; i < strlen(expansion); i++)
316 expansion[i] = tolower(expansion[i]);
317 for (i = 0; gxioconflist[i].name != NULL; i++) {
318 rv = strncmp(expansion, gxioconflist[i].name,
319 strlen(gxioconflist[i].name) + 1);
320 if (rv == 0) {
321 gxioconflist[i].config();
322 break;
323 }
324 }
325 }
326
327
328 static void
329 basix_config(void)
330 {
331
332 pxa2x0_gpio_set_function(8, GPIO_ALT_FN_1_OUT); /* MMCCS0 */
333 pxa2x0_gpio_set_function(53, GPIO_ALT_FN_1_OUT); /* MMCCLK */
334 #if 0
335 /* this configuration set by gxmci.c::pxamci_attach() */
336 pxa2x0_gpio_set_function(11, GPIO_IN); /* nSD_DETECT */
337 pxa2x0_gpio_set_function(22, GPIO_IN); /* nSD_WP */
338 #endif
339 }
340
341 static void
342 cfstix_config(void)
343 {
344 u_int gpio, npoe_fn;
345 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
346 int bvd = (CPU_IS_PXA250) ? 4 : 111;
347 #else
348 #if defined(CPU_XSCALE_PXA270)
349 const int bvd = 111;
350 #else
351 const int bvd = 4;
352 #endif
353 #endif
354
355 if (CPU_IS_PXA250) {
356 gxpcic_slot_irqs[0].valid = 1;
357 gxpcic_slot_irqs[0].cd = 11;
358 gxpcic_slot_irqs[0].prdy = 26;
359 gxpcic_gpio_reset = 8;
360 } else {
361 gxpcic_slot_irqs[0].valid = 1;
362 gxpcic_slot_irqs[0].cd = 104;
363 gxpcic_slot_irqs[0].prdy = 96;
364 gxpcic_gpio_reset = 97;
365 }
366
367 #if 1
368 /* PCD/PRDY set by pxa2x0_pcic.c::pxapcic_attach_common() */
369 #else
370 pxa2x0_gpio_set_function(11, GPIO_IN); /* PCD1 */
371 pxa2x0_gpio_set_function(26, GPIO_IN); /* PRDY1/~IRQ1 */
372 #endif
373 pxa2x0_gpio_set_function(bvd, GPIO_IN); /* BVD1/~STSCHG1 */
374
375 for (gpio = 48, npoe_fn = 0; gpio <= 53 ; gpio++)
376 npoe_fn |= pxa2x0_gpio_get_function(gpio);
377 npoe_fn &= GPIO_SET;
378
379 pxa2x0_gpio_set_function(48, GPIO_ALT_FN_2_OUT | npoe_fn); /* nPOE */
380 pxa2x0_gpio_set_function(49, GPIO_ALT_FN_2_OUT); /* nPWE */
381 pxa2x0_gpio_set_function(50, GPIO_ALT_FN_2_OUT); /* nPIOR */
382 pxa2x0_gpio_set_function(51, GPIO_ALT_FN_2_OUT); /* nPIOW */
383 if (CPU_IS_PXA250) {
384 pxa2x0_gpio_set_function(52, GPIO_ALT_FN_2_OUT); /* nPCE1 */
385 pxa2x0_gpio_set_function(53, GPIO_ALT_FN_2_OUT); /* nPCE2 */
386 pxa2x0_gpio_set_function(54, GPIO_ALT_FN_2_OUT); /* pSKTSEL */
387 } else {
388 pxa2x0_gpio_set_function(102, GPIO_ALT_FN_1_OUT); /* nPCE1 */
389 pxa2x0_gpio_set_function(105, GPIO_ALT_FN_1_OUT); /* nPCE2 */
390 pxa2x0_gpio_set_function(79, GPIO_ALT_FN_1_OUT); /* pSKTSEL */
391 }
392 pxa2x0_gpio_set_function(55, GPIO_ALT_FN_2_OUT); /* nPREG */
393 pxa2x0_gpio_set_function(56, GPIO_ALT_FN_1_IN); /* nPWAIT */
394 pxa2x0_gpio_set_function(57, GPIO_ALT_FN_1_IN); /* nIOIS16 */
395 }
396
397 static void
398 etherstix_config(void)
399 {
400 extern struct cfdata cfdata[];
401 #if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
402 int rst = (CPU_IS_PXA250) ? 80 : 32;
403 int irq = (CPU_IS_PXA250) ? 36 : 99;
404 #else
405 #if defined(CPU_XSCALE_PXA270)
406 const int rst = 32, irq = 99;
407 #else
408 const int rst = 80, irq = 36;
409 #endif
410 #endif
411 int i;
412
413 pxa2x0_gpio_set_function(49, GPIO_ALT_FN_2_OUT); /* nPWE */
414 pxa2x0_gpio_set_function(15, GPIO_ALT_FN_2_OUT); /* nCS 1 */
415 pxa2x0_gpio_set_function(rst, GPIO_OUT | GPIO_SET); /* RESET 1 */
416 delay(1);
417 pxa2x0_gpio_set_function(rst, GPIO_OUT | GPIO_CLR);
418 delay(50000);
419
420 for (i = 0; cfdata[i].cf_name != NULL; i++)
421 if (strcmp(cfdata[i].cf_name, "sm") == 0 &&
422 strcmp(cfdata[i].cf_atname, "sm_gxio") == 0 &&
423 cfdata[i].cf_loc[GXIOCF_ADDR] == 0x04000300 &&
424 cfdata[i].cf_loc[GXIOCF_GPIRQ] == GXIOCF_GPIRQ_DEFAULT)
425 cfdata[i].cf_loc[GXIOCF_GPIRQ] = irq;
426 }
427
428 static void
429 netcf_config(void)
430 {
431
432 etherstix_config();
433 cfstix_config();
434 if (CPU_IS_PXA270) {
435 /* Overwrite */
436 gxpcic_slot_irqs[0].cd = 104;
437 gxpcic_slot_irqs[0].prdy = 109;
438 gxpcic_gpio_reset = 110;
439 };
440 }
441
442 static void
443 netduommc_config(void)
444 {
445
446 netduo_config();
447 basix_config();
448 }
449
450 static void
451 netduo_config(void)
452 {
453
454 etherstix_config();
455
456 pxa2x0_gpio_set_function(78, GPIO_ALT_FN_2_OUT); /* nCS 2 */
457 pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET); /* RESET 2 */
458 delay(1);
459 pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR);
460 delay(50000);
461 }
462
463 static void
464 netmicrosd_config(void)
465 {
466
467 /* MicroSD(mci) always configure on PXA270 */
468
469 pxa2x0_gpio_set_function(49, GPIO_ALT_FN_2_OUT); /* nPWE */
470 pxa2x0_gpio_set_function(15, GPIO_ALT_FN_2_OUT); /* nCS 1 */
471 pxa2x0_gpio_set_function(107, GPIO_OUT | GPIO_CLR); /* RESET 1 */
472 delay(hz / 2);
473 pxa2x0_gpio_set_function(107, GPIO_OUT | GPIO_SET);
474 delay(50000);
475 }
476
477 static void
478 netwifimicrosd_config(void)
479 {
480
481 netmicrosd_config();
482
483 cfstix_config();
484 /* However use pxamci. */
485 pxa2x0_gpio_set_function(111, GPIO_CLR | GPIO_ALT_FN_1_IN);
486 /* XXXX: Power to Marvell 88W8385??? */
487 pxa2x0_gpio_set_function(80, GPIO_OUT | GPIO_SET);
488 }
489
490 static void
491 netmmc_config(void)
492 {
493
494 etherstix_config();
495 basix_config();
496 }
497
498 static void
499 wifistix_config(void)
500 {
501
502 cfstix_config();
503
504 /* XXXX: Power to Marvell 88W8385??? */
505 pxa2x0_gpio_set_function(80, GPIO_OUT | GPIO_SET);
506 }
507
508 static void
509 wifistix_cf_config(void)
510 {
511
512 gxpcic_slot_irqs[1].valid = 1;
513 gxpcic_slot_irqs[1].cd = 36;
514 gxpcic_slot_irqs[1].prdy = 27;
515
516 #if 1
517 /* this configuration set by pxa2x0_pcic.c::pxapcic_attach_common() */
518 #else
519 pxa2x0_gpio_set_function(36, GPIO_IN); /* PCD2 */
520 pxa2x0_gpio_set_function(27, GPIO_IN); /* PRDY2/~IRQ2 */
521 #endif
522 pxa2x0_gpio_set_function(18, GPIO_IN); /* BVD2/~STSCHG2 */
523
524 cfstix_config();
525
526 /* XXXX: Power to Marvell 88W8385??? */
527 pxa2x0_gpio_set_function(80, GPIO_OUT | GPIO_SET);
528 }
529