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