#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gxio.c,v 1.29 2022/10/29 13:10:25 jmcneill Exp $");
#include "opt_cputypes.h"
#include "opt_gumstix.h"
#include "opt_gxio.h"
#include <sys/param.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <machine/bootconfig.h>
#if defined(CPU_XSCALE)
#include <arm/xscale/pxa2x0cpu.h>
#endif
#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0var.h>
#include <arm/xscale/pxa2x0_gpio.h>
#include <evbarm/gumstix/gumstixreg.h>
#include <evbarm/gumstix/gumstixvar.h>
#include "ioconf.h"
#include "locators.h"
struct gxioconf {
const char *name;
void (*config)(void);
};
#if defined(GUMSTIX)
static int gxiomatch(device_t, cfdata_t, void *);
static void gxioattach(device_t, device_t, void *);
static int gxiosearch(device_t, cfdata_t, const int *, void *);
static int gxioprint(void *, const char *);
CFATTACH_DECL_NEW(gxio, sizeof(struct gxio_softc),
gxiomatch, gxioattach, NULL, NULL);
#endif
void gxio_config(void);
void gxio_config_expansion(const char *);
#if defined(GUMSTIX)
static void basix_config(void);
static void cfstix_config(void);
static void etherstix_config(void);
static void netcf_config(void);
static void netcf_vx_config(void);
static void netduommc_config(void);
static void netduo_config(void);
static void netmicrosd_config(void);
static void netwifimicrosd_config(void);
static void netmmc_config(void);
static void wifistix_config(void);
static void wifistix_cf_config(void);
#endif
#if defined(CPU_XSCALE_PXA250)
static struct pxa2x0_gpioconf pxa255dep_gpioconf[] = {
{ 7, GPIO_OUT | GPIO_SET },
{ 12, GPIO_ALT_FN_1_OUT },
{ 29, GPIO_ALT_FN_1_IN },
{ 35, GPIO_ALT_FN_1_IN },
{ 41, GPIO_ALT_FN_2_OUT },
#ifndef GXIO_BLUETOOTH_ON_HWUART
{ 44, GPIO_ALT_FN_1_IN },
{ 45, GPIO_ALT_FN_2_OUT },
#else
{ 42, GPIO_ALT_FN_3_IN },
{ 43, GPIO_ALT_FN_3_OUT },
{ 44, GPIO_ALT_FN_3_IN },
{ 45, GPIO_ALT_FN_3_OUT },
#endif
#ifndef GXIO_BLUETOOTH_ON_HWUART
{ 48, GPIO_ALT_FN_1_OUT },
{ 49, GPIO_ALT_FN_1_IN },
{ 50, GPIO_ALT_FN_1_IN },
{ 51, GPIO_ALT_FN_1_OUT },
#endif
{ -1 }
};
#endif
#if defined(CPU_XSCALE_PXA270)
static struct pxa2x0_gpioconf verdexdep_gpioconf[] = {
{ 9, GPIO_ALT_FN_3_OUT },
{ 12, GPIO_OUT | GPIO_SET },
{ 17, GPIO_IN },
{ 34, GPIO_ALT_FN_1_IN },
{ 39, GPIO_ALT_FN_2_OUT },
{ 42, GPIO_ALT_FN_1_IN },
{ 43, GPIO_ALT_FN_2_OUT },
{ 44, GPIO_ALT_FN_1_IN },
{ 45, GPIO_ALT_FN_2_OUT },
{ 29, GPIO_ALT_FN_1_IN },
{ -1 }
};
#endif
static const struct gxioconf gxioconflist[] = {
#if defined(GUMSTIX)
{ "basix", basix_config },
{ "cfstix", cfstix_config },
{ "etherstix", etherstix_config },
{ "netcf", netcf_config },
{ "netcf-vx", netcf_vx_config },
{ "netduo-mmc", netduommc_config },
{ "netduo", netduo_config },
{ "netmicrosd", netmicrosd_config },
{ "netmicrosd-vx", netmicrosd_config },
{ "netwifimicrosd", netwifimicrosd_config },
{ "netmmc", netmmc_config },
{ "netpro-vx", netwifimicrosd_config },
{ "wifistix-cf", wifistix_cf_config },
{ "wifistix", wifistix_config },
#endif
{ NULL }
};
int gxpcic_gpio_reset;
struct gxpcic_slot_irqs gxpcic_slot_irqs[2] = { { 0, -1, -1 }, { 0, -1, -1 } };
#if defined(GUMSTIX)
static int
gxiomatch(device_t parent, cfdata_t match, void *aux)
{
struct pxaip_attach_args *pxa = aux;
bus_space_tag_t iot = &pxa2x0_bs_tag;
bus_space_handle_t ioh;
if (strcmp(pxa->pxa_name, match->cf_name) != 0 ||
pxa->pxa_addr != PXAIPCF_ADDR_DEFAULT)
return 0;
if (bus_space_map(iot,
PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE, 0, &ioh))
return 0;
bus_space_unmap(iot, ioh, PXA2X0_MEMCTL_SIZE);
return 1;
}
static void
gxioattach(device_t parent, device_t self, void *aux)
{
struct gxio_softc *sc = device_private(self);
aprint_normal("\n");
aprint_naive("\n");
sc->sc_dev = self;
sc->sc_iot = &pxa2x0_bs_tag;
if (bus_space_map(sc->sc_iot,
PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE, 0, &sc->sc_ioh))
return;
config_search(self, NULL,
CFARGS(.search = gxiosearch));
}
static int
gxiosearch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
{
struct gxio_softc *sc = device_private(parent);
struct gxio_attach_args gxa;
gxa.gxa_sc = sc;
gxa.gxa_iot = sc->sc_iot;
gxa.gxa_addr = cf->cf_loc[GXIOCF_ADDR];
gxa.gxa_gpirq = cf->cf_loc[GXIOCF_GPIRQ];
if (config_probe(parent, cf, &gxa))
config_attach(parent, cf, &gxa, gxioprint, CFARGS_NONE);
return 0;
}
static int
gxioprint(void *aux, const char *name)
{
struct gxio_attach_args *gxa = (struct gxio_attach_args *)aux;
if (gxa->gxa_addr != GXIOCF_ADDR_DEFAULT)
printf(" addr 0x%lx", gxa->gxa_addr);
if (gxa->gxa_gpirq > 0)
printf(" gpirq %d", gxa->gxa_gpirq);
return UNCONF;
}
#endif
#if defined(GUMSTIX)
void
gxio_config(void)
{
#if defined(CPU_XSCALE_PXA250)
struct pxa2x0_gpioconf *gumstix_gpioconf[] = {
pxa25x_com_ffuart_gpioconf,
pxa25x_com_stuart_gpioconf,
#ifndef GXIO_BLUETOOTH_ON_HWUART
pxa25x_com_btuart_gpioconf,
#endif
pxa25x_com_hwuart_gpioconf,
pxa25x_i2c_gpioconf,
pxa25x_pxaacu_gpioconf,
pxa255dep_gpioconf,
NULL
};
#endif
#if defined(CPU_XSCALE_PXA270)
struct pxa2x0_gpioconf *verdex_gpioconf[] = {
pxa27x_com_ffuart_gpioconf,
pxa27x_com_stuart_gpioconf,
pxa27x_com_btuart_gpioconf,
pxa27x_i2c_gpioconf,
pxa27x_pxaacu_gpioconf,
pxa27x_pxamci_gpioconf,
pxa27x_ohci_gpioconf,
verdexdep_gpioconf,
NULL
};
#endif
#if defined(CPU_XSCALE_PXA250)
pxa2x0_gpio_set_function(7, GPIO_OUT | GPIO_CLR);
#elif defined(CPU_XSCALE_PXA270)
pxa2x0_gpio_set_function(12, GPIO_OUT | GPIO_CLR);
#endif
delay(100);
#if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
pxa2x0_gpio_config(
(CPU_IS_PXA250) ? gumstix_gpioconf : verdex_gpioconf);
#elif defined(CPU_XSCALE_PXA270) || defined(CPU_XSCALE_PXA250)
#if defined(CPU_XSCALE_PXA270)
pxa2x0_gpio_config(verdex_gpioconf);
#else
pxa2x0_gpio_config(gumstix_gpioconf);
#endif
#endif
}
#endif
static int
gxio_find_default_expansion(void)
{
#ifdef GXIO_DEFAULT_EXPANSION
int i;
for (i = 0; gxioconflist[i].name != NULL; i++)
if (strncasecmp(gxioconflist[i].name, GXIO_DEFAULT_EXPANSION,
strlen(gxioconflist[i].name) + 1) == 0)
break;
return gxioconflist[i].name == NULL ? -1 : i;
#else
return -1;
#endif
}
void
gxio_config_expansion(const char *expansion)
{
int i, d;
d = gxio_find_default_expansion();
printf("supported expansions:\n");
for (i = 0; gxioconflist[i].name != NULL; i++)
printf(" %s%s\n", gxioconflist[i].name,
i == d ? " (DEFAULT)" : "");
if (expansion == NULL) {
printf("not specified 'expansion=' in the boot args.\n");
i = -1;
} else {
for (i = 0; gxioconflist[i].name != NULL; i++)
if (strncasecmp(gxioconflist[i].name, expansion,
strlen(gxioconflist[i].name) + 1) == 0)
break;
if (gxioconflist[i].name == NULL) {
printf("unknown expansion specified: %s\n", expansion);
i = -1;
}
}
const char *toconfigure;
if (i < 0) {
#ifdef GXIO_DEFAULT_EXPANSION
if (d == -1) {
printf("default expansion (%s) not found\n",
GXIO_DEFAULT_EXPANSION);
return;
}
expansion = GXIO_DEFAULT_EXPANSION;
i = d;
toconfigure = "default";
#else
return;
#endif
} else
toconfigure = "specified";
printf("configure %s expansion (%s)\n", toconfigure, expansion);
gxioconflist[i].config();
}
#if defined(GUMSTIX)
static void
basix_config(void)
{
pxa2x0_gpio_set_function(8, GPIO_ALT_FN_1_OUT);
pxa2x0_gpio_set_function(53, GPIO_ALT_FN_1_OUT);
#if 0
pxa2x0_gpio_set_function(11, GPIO_IN);
pxa2x0_gpio_set_function(22, GPIO_IN);
#endif
}
static void
cfstix_config(void)
{
u_int gpio, npoe_fn;
#if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
int bvd = (CPU_IS_PXA250) ? 4 : 111;
#else
#if defined(CPU_XSCALE_PXA270)
const int bvd = 111;
#else
const int bvd = 4;
#endif
#endif
if (CPU_IS_PXA250) {
gxpcic_slot_irqs[0].valid = 1;
gxpcic_slot_irqs[0].cd = 11;
gxpcic_slot_irqs[0].prdy = 26;
gxpcic_gpio_reset = 8;
} else {
gxpcic_slot_irqs[0].valid = 1;
gxpcic_slot_irqs[0].cd = 104;
gxpcic_slot_irqs[0].prdy = 96;
gxpcic_gpio_reset = 97;
}
#if 1
#else
pxa2x0_gpio_set_function(11, GPIO_IN);
pxa2x0_gpio_set_function(26, GPIO_IN);
#endif
pxa2x0_gpio_set_function(bvd, GPIO_IN);
for (gpio = 48, npoe_fn = 0; gpio <= 53 ; gpio++)
npoe_fn |= pxa2x0_gpio_get_function(gpio);
npoe_fn &= GPIO_SET;
pxa2x0_gpio_set_function(48, GPIO_ALT_FN_2_OUT | npoe_fn);
pxa2x0_gpio_set_function(49, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(50, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(51, GPIO_ALT_FN_2_OUT);
if (CPU_IS_PXA250) {
pxa2x0_gpio_set_function(52, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(53, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(54, GPIO_ALT_FN_2_OUT);
} else {
pxa2x0_gpio_set_function(102, GPIO_ALT_FN_1_OUT);
pxa2x0_gpio_set_function(105, GPIO_ALT_FN_1_OUT);
pxa2x0_gpio_set_function(79, GPIO_ALT_FN_1_OUT);
}
pxa2x0_gpio_set_function(55, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(56, GPIO_ALT_FN_1_IN);
pxa2x0_gpio_set_function(57, GPIO_ALT_FN_1_IN);
}
static void
etherstix_config(void)
{
extern struct cfdata cfdata[];
#if defined(CPU_XSCALE_PXA270) && defined(CPU_XSCALE_PXA250)
int rst = (CPU_IS_PXA250) ? 80 : 32;
int irq = (CPU_IS_PXA250) ? 36 : 99;
#else
#if defined(CPU_XSCALE_PXA270)
const int rst = 32, irq = 99;
#else
const int rst = 80, irq = 36;
#endif
#endif
int i;
pxa2x0_gpio_set_function(49, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(15, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(rst, GPIO_OUT | GPIO_SET);
delay(1);
pxa2x0_gpio_set_function(rst, GPIO_OUT | GPIO_CLR);
delay(50000);
for (i = 0; cfdata[i].cf_name != NULL; i++)
if (strcmp(cfdata[i].cf_name, "sm") == 0 &&
strcmp(cfdata[i].cf_atname, "sm_gxio") == 0 &&
cfdata[i].cf_loc[GXIOCF_ADDR] == 0x04000300 &&
cfdata[i].cf_loc[GXIOCF_GPIRQ] == GXIOCF_GPIRQ_DEFAULT)
cfdata[i].cf_loc[GXIOCF_GPIRQ] = irq;
}
static void
netcf_config(void)
{
etherstix_config();
cfstix_config();
}
static void
netcf_vx_config(void)
{
pxa2x0_gpio_set_function(27, GPIO_IN);
pxa2x0_gpio_set_function(107, GPIO_OUT | GPIO_CLR);
pxa2x0_gpio_set_function(118, GPIO_ALT_FN_1_IN | GPIO_CLR);
etherstix_config();
cfstix_config();
if (CPU_IS_PXA270) {
gxpcic_slot_irqs[0].cd = 104;
gxpcic_slot_irqs[0].prdy = 109;
gxpcic_gpio_reset = 110;
};
}
static void
netduommc_config(void)
{
netduo_config();
basix_config();
}
static void
netduo_config(void)
{
etherstix_config();
pxa2x0_gpio_set_function(78, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET);
delay(1);
pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR);
delay(50000);
}
static void
netmicrosd_config(void)
{
pxa2x0_gpio_set_function(49, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(15, GPIO_ALT_FN_2_OUT);
pxa2x0_gpio_set_function(107, GPIO_OUT | GPIO_CLR);
delay(hz / 2);
pxa2x0_gpio_set_function(107, GPIO_OUT | GPIO_SET);
delay(50000);
}
static void
netwifimicrosd_config(void)
{
netmicrosd_config();
cfstix_config();
pxa2x0_gpio_set_function(111, GPIO_CLR | GPIO_ALT_FN_1_IN);
pxa2x0_gpio_set_function(80, GPIO_OUT | GPIO_SET);
}
static void
netmmc_config(void)
{
etherstix_config();
basix_config();
}
static void
wifistix_config(void)
{
cfstix_config();
pxa2x0_gpio_set_function(80, GPIO_OUT | GPIO_SET);
}
static void
wifistix_cf_config(void)
{
gxpcic_slot_irqs[1].valid = 1;
gxpcic_slot_irqs[1].cd = 36;
gxpcic_slot_irqs[1].prdy = 27;
#if 1
#else
pxa2x0_gpio_set_function(36, GPIO_IN);
pxa2x0_gpio_set_function(27, GPIO_IN);
#endif
pxa2x0_gpio_set_function(18, GPIO_IN);
cfstix_config();
pxa2x0_gpio_set_function(80, GPIO_OUT | GPIO_SET);
}
#endif