version 1.2, 2006/10/17 17:06:22 |
version 1.2.8.4, 2007/09/03 14:24:04 |
|
|
#include <dev/pcmcia/pcmciavar.h> |
#include <dev/pcmcia/pcmciavar.h> |
#include <dev/pcmcia/pcmciachip.h> |
#include <dev/pcmcia/pcmciachip.h> |
|
|
|
#include <arch/arm/xscale/pxa2x0cpu.h> |
#include <arch/arm/xscale/pxa2x0var.h> |
#include <arch/arm/xscale/pxa2x0var.h> |
#include <arch/arm/xscale/pxa2x0reg.h> |
#include <arch/arm/xscale/pxa2x0reg.h> |
#include <arch/arm/sa11x0/sa11xx_pcicvar.h> |
#include <arch/arm/xscale/pxa2x0_gpio.h> |
|
#include <arch/arm/xscale/pxa2x0_pcic.h> |
#include <arch/evbarm/gumstix/gumstixvar.h> |
#include <arch/evbarm/gumstix/gumstixvar.h> |
|
|
|
|
|
|
|
|
#define HAVE_CARD(r) (!((r) & GPIO_SET)) |
#define HAVE_CARD(r) (!((r) & GPIO_SET)) |
|
|
#define GXIO_GPIO8_RESET 8 |
#define GXIO_GPIRQ11_CD1 11 |
#define GXIO_GPIRQ11_nCD 11 |
#define GXIO_GPIRQ26_PRDY1 26 |
#define GXIO_GPIO26_READY 26 |
#define GXIO_GPIRQ27_PRDY2 27 |
|
#define GXIO_GPIRQ36_CD2 36 |
|
|
struct gxpcic_softc; |
|
|
|
struct gxpcic_socket { |
static int gxpcic_match(struct device *, struct cfdata *, void *); |
struct sapcic_socket ss; /* inherit socket for sa11x0 pcic */ |
static void gxpcic_attach(struct device *, struct device *, void *); |
}; |
static void gxpcic_pcic_socket_setup(struct pxapcic_socket *); |
|
|
struct gxpcic_softc { |
static u_int gxpcic_read(struct pxapcic_socket *, int); |
struct sapcic_softc sc_pc; /* inherit SA11xx pcic */ |
static void gxpcic_write(struct pxapcic_socket *, int, u_int); |
|
static void gxpcic_set_power(struct pxapcic_socket *, int); |
bus_space_tag_t sc_iot; |
static void gxpcic_clear_intr(struct pxapcic_socket *); |
bus_space_handle_t sc_ioh; |
static void *gxpcic_intr_establish(struct pxapcic_socket *, int, |
int sc_gpirq; |
|
|
|
struct gxpcic_socket sc_socket[2]; |
|
int sc_cards; |
|
}; |
|
|
|
static int gxpcic_match(struct device *, struct cfdata *, void *); |
|
static void gxpcic_attach(struct device *, struct device *, void *); |
|
|
|
static int gxpcic_card_detect(void *); |
|
static int gxpcic_read(struct sapcic_socket *, int); |
|
static void gxpcic_write(struct sapcic_socket *, int, int); |
|
static void gxpcic_set_power(struct sapcic_socket *, int); |
|
static void gxpcic_clear_intr(int); |
|
static void *gxpcic_intr_establish(struct sapcic_socket *, int, |
|
int (*)(void *), void *); |
int (*)(void *), void *); |
static void gxpcic_intr_disestablish(struct sapcic_socket *, void *); |
static void gxpcic_intr_disestablish(struct pxapcic_socket *, void *); |
|
__inline void gxpcic_cpld_clk(void); |
|
__inline u_char gxpcic_cpld_read_bits(int bits); |
|
static int gxpcic_count_slot(struct pxapcic_softc *); |
|
|
CFATTACH_DECL(gxpcic, sizeof(struct gxpcic_softc), |
CFATTACH_DECL(pxapcic_gxpcic, sizeof(struct pxapcic_softc), |
gxpcic_match, gxpcic_attach, NULL, NULL); |
gxpcic_match, gxpcic_attach, NULL, NULL); |
|
|
static struct sapcic_tag gxpcic_tag = { |
static struct pxapcic_tag gxpcic_pcic_functions = { |
gxpcic_read, |
gxpcic_read, |
gxpcic_write, |
gxpcic_write, |
gxpcic_set_power, |
gxpcic_set_power, |
Line 137 static struct sapcic_tag gxpcic_tag = { |
|
Line 127 static struct sapcic_tag gxpcic_tag = { |
|
gxpcic_intr_disestablish, |
gxpcic_intr_disestablish, |
}; |
}; |
|
|
|
static struct { |
|
int cd; |
|
int prdy; |
|
} gxpcic_slot_irqs[] = { |
|
{ GXIO_GPIRQ11_CD1, GXIO_GPIRQ26_PRDY1 }, |
|
{ GXIO_GPIRQ36_CD2, GXIO_GPIRQ27_PRDY2 } |
|
}; |
|
|
|
|
static int |
static int |
gxpcic_match(struct device *parent, struct cfdata *cf, void *aux) |
gxpcic_match(struct device *parent, struct cfdata *cf, void *aux) |
{ |
{ |
struct { |
struct pxa2x0_gpioconf *gpioconf; |
int gpio; |
|
u_int fn; |
|
} gpiomodes[] = { |
|
{ 48, GPIO_ALT_FN_2_OUT }, /* nPOE */ |
|
{ 49, GPIO_ALT_FN_2_OUT }, /* nPWE */ |
|
{ 50, GPIO_ALT_FN_2_OUT }, /* nPIOR */ |
|
{ 51, GPIO_ALT_FN_2_OUT }, /* nPIOW */ |
|
{ 54, GPIO_ALT_FN_2_OUT }, /* pSKTSEL */ |
|
{ 55, GPIO_ALT_FN_2_OUT }, /* nPREG */ |
|
{ 56, GPIO_ALT_FN_1_IN }, /* nPWAIT */ |
|
{ 57, GPIO_ALT_FN_1_IN }, /* nIOIS16 */ |
|
{ -1 } |
|
}; |
|
u_int reg; |
u_int reg; |
int i; |
int i; |
|
|
for (i = 0; gpiomodes[i].gpio != -1; i++) { |
/* |
reg = pxa2x0_gpio_get_function(gpiomodes[i].gpio); |
* Check GPIO configuration. If you use these, it is sure already |
if (GPIO_FN(reg) != GPIO_FN(gpiomodes[i].fn) || |
* to have been set by gxio. |
GPIO_FN_IS_OUT(reg) != GPIO_FN_IS_OUT(gpiomodes[i].fn)) |
*/ |
break; |
gpioconf = CPU_IS_PXA250 ? pxa25x_pcic_gpioconf : |
|
pxa27x_pcic_gpioconf; |
|
for (i = 0; gpioconf[i].pin != -1; i++) { |
|
reg = pxa2x0_gpio_get_function(gpioconf[i].pin); |
|
if (GPIO_FN(reg) != GPIO_FN(gpioconf[i].value) || |
|
GPIO_FN_IS_OUT(reg) != GPIO_FN_IS_OUT(gpioconf[i].value)) |
|
return (0); |
} |
} |
if (gpiomodes[i].gpio != -1) |
|
return 0; |
|
|
|
return 1; /* match */ |
return 1; /* match */ |
} |
} |
Line 173 gxpcic_match(struct device *parent, stru |
|
Line 162 gxpcic_match(struct device *parent, stru |
|
static void |
static void |
gxpcic_attach(struct device *parent, struct device *self, void *aux) |
gxpcic_attach(struct device *parent, struct device *self, void *aux) |
{ |
{ |
struct gxio_softc *gxsc = (struct gxio_softc *)parent; |
struct pxapcic_softc *sc = (struct pxapcic_softc *)self; |
struct gxpcic_softc *sc = (struct gxpcic_softc *)self; |
struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux; |
struct gxio_attach_args *gxa = aux; |
int nslot, i; |
struct pcmciabus_attach_args paa; |
|
int mecr, val, i, n; |
|
|
|
printf("\n"); |
|
|
|
sc->sc_iot = sc->sc_pc.sc_iot = gxa->gxa_iot; |
|
sc->sc_ioh = gxsc->sc_ioh; |
|
sc->sc_gpirq = gxa->gxa_gpirq; |
|
sc->sc_cards = 0; |
|
|
|
n = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MEMCTL_MECR) & MECR_NOS ? |
|
2 : 1; |
|
for (i = 0; i < n; i++) { |
|
sc->sc_socket[i].ss.sc = &sc->sc_pc; |
|
sc->sc_socket[i].ss.socket = 0; |
|
sc->sc_socket[i].ss.pcictag_cookie = NULL; |
|
sc->sc_socket[i].ss.pcictag = &gxpcic_tag; |
|
sc->sc_socket[i].ss.event_thread = NULL; |
|
sc->sc_socket[i].ss.event = 0; |
|
sc->sc_socket[i].ss.laststatus = SAPCIC_CARD_INVALID; |
|
sc->sc_socket[i].ss.shutdown = 0; |
|
|
|
/* 3.3V only? */ |
|
sc->sc_socket[i].ss.power_capability = SAPCIC_POWER_3V; |
|
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, MEMCTL_MCMEM(i), |
|
MC_TIMING_VAL(10,10,30)); |
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, MEMCTL_MCATT(i), |
|
MC_TIMING_VAL(10,10,30)); |
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, MEMCTL_MCIO(i), |
|
MC_TIMING_VAL(6,6,17)); |
|
|
|
paa.paa_busname = "pcmcia"; |
|
paa.pct = (pcmcia_chipset_tag_t)&sa11x0_pcmcia_functions; |
|
paa.pch = (pcmcia_chipset_handle_t)&sc->sc_socket[i].ss; |
|
paa.iobase = 0; |
|
paa.iosize = 0x4000000; |
|
|
|
sc->sc_socket[i].ss.pcmcia = |
|
(struct device *)config_found_ia(&sc->sc_pc.sc_dev, |
|
"pcmciabus", &paa, NULL); |
|
|
|
/* interrupt for card insertion/removal */ |
|
gxio_intr_establish(sc, GXIO_GPIRQ11_nCD, IST_EDGE_BOTH, |
|
IPL_BIO, gxpcic_card_detect, &sc->sc_socket[i]); |
|
|
|
/* if card was insert then set CIT */ |
|
val = pxa2x0_gpio_get_function(GXIO_GPIRQ11_nCD); |
|
if (HAVE_CARD(val)) { |
|
mecr = bus_space_read_4( |
|
sc->sc_iot, sc->sc_ioh, MEMCTL_MECR); |
|
bus_space_write_4(sc->sc_iot, |
|
sc->sc_ioh, MEMCTL_MECR, mecr | MECR_CIT); |
|
} |
|
|
|
/* schedule kthread creation */ |
sc->sc_iot = pxa->pxa_iot; |
kthread_create(sapcic_kthread_create, &sc->sc_socket[i].ss); |
|
} |
|
|
|
} |
nslot = gxpcic_count_slot(sc); |
|
|
static int |
for (i = 0; i < nslot; i++) { |
gxpcic_card_detect(void *arg) |
sc->sc_irqpin[i] = gxpcic_slot_irqs[i].prdy; |
{ |
sc->sc_irqcfpin[i] = gxpcic_slot_irqs[i].cd; |
struct gxpcic_socket *socket = arg; |
|
struct gxpcic_softc *sc = (struct gxpcic_softc *)socket->ss.sc; |
|
int sock_no = socket->ss.socket; |
|
int mecr, last, val, s; |
|
|
|
s = splbio(); |
|
last = sc->sc_cards; |
|
val = pxa2x0_gpio_get_function(GXIO_GPIRQ11_nCD); |
|
if (HAVE_CARD(val)) { |
|
sc->sc_cards |= 1<<sock_no; |
|
/* if it is the first card, turn on expansion memory control. */ |
|
if (last == 0) { |
|
mecr = bus_space_read_4( |
|
sc->sc_iot, sc->sc_ioh, MEMCTL_MECR); |
|
bus_space_write_4(sc->sc_iot, |
|
sc->sc_ioh, MEMCTL_MECR, mecr | MECR_CIT); |
|
} |
|
} else { |
|
sc->sc_cards &= ~(1<<sock_no); |
|
/* if we loast all cards, turn off expansion memory control. */ |
|
if (sc->sc_cards == 0) { |
|
mecr = bus_space_read_4( |
|
sc->sc_iot, sc->sc_ioh, MEMCTL_MECR); |
|
bus_space_write_4(sc->sc_iot, |
|
sc->sc_ioh, MEMCTL_MECR, mecr & ~MECR_CIT); |
|
} |
|
} |
} |
splx(s); |
sc->sc_nslots = nslot; |
|
|
DPRINTF(("%s: card %d %s\n", sc->sc_pc.sc_dev.dv_xname, sock_no, |
pxapcic_attach_common(sc, &gxpcic_pcic_socket_setup); |
HAVE_CARD(val) ? "inserted" : "removed")); |
} |
|
|
sapcic_intr(arg); |
static void |
|
gxpcic_pcic_socket_setup(struct pxapcic_socket *so) |
|
{ |
|
struct pxapcic_softc *sc = so->sc; |
|
|
return 1; |
/* 3.3V only? */ |
|
so->power_capability = PXAPCIC_POWER_3V; |
|
so->pcictag_cookie = NULL; |
|
so->pcictag = &gxpcic_pcic_functions; |
|
|
|
bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, |
|
MEMCTL_MCMEM(so->socket), MC_TIMING_VAL(9 ,9, 29)); |
|
bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, |
|
MEMCTL_MCATT(so->socket), MC_TIMING_VAL(9 ,9, 29)); |
|
bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh, |
|
MEMCTL_MCIO(so->socket), MC_TIMING_VAL(5 ,5, 16)); |
} |
} |
|
|
/* ARGSUSED */ |
static u_int |
static int |
gxpcic_read(struct pxapcic_socket *so, int which) |
gxpcic_read(struct sapcic_socket *so, int which) |
|
{ |
{ |
int reg; |
int reg; |
|
|
switch (which) { |
switch (which) { |
case SAPCIC_STATUS_CARD: |
case PXAPCIC_CARD_STATUS: |
reg = pxa2x0_gpio_get_function(GXIO_GPIRQ11_nCD); |
reg = pxa2x0_gpio_get_function(gxpcic_slot_irqs[so->socket].cd); |
return (HAVE_CARD(reg) ? |
return (HAVE_CARD(reg) ? |
SAPCIC_CARD_VALID : SAPCIC_CARD_INVALID); |
PXAPCIC_CARD_VALID : PXAPCIC_CARD_INVALID); |
|
|
case SAPCIC_STATUS_READY: |
case PXAPCIC_CARD_READY: |
reg = pxa2x0_gpio_get_function(GXIO_GPIO26_READY); |
reg = pxa2x0_gpio_get_function( |
|
gxpcic_slot_irqs[so->socket].prdy); |
return (reg & GPIO_SET ? 1 : 0); |
return (reg & GPIO_SET ? 1 : 0); |
|
|
default: |
default: |
panic("%s: bogus register", __FUNCTION__); |
panic("%s: bogus register", __FUNCTION__); |
} |
} |
|
/* NOTREACHED */ |
} |
} |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static void |
static void |
gxpcic_write(struct sapcic_socket *so, int which, int arg) |
gxpcic_write(struct pxapcic_socket *so, int which, u_int arg) |
{ |
{ |
|
|
switch (which) { |
switch (which) { |
case SAPCIC_CONTROL_RESET: |
case PXAPCIC_CARD_POWER: |
#if 0 /* XXXX: Our PXA2x0 no necessary ??? */ |
case PXAPCIC_CARD_RESET: |
if (arg) |
/* We can't */ |
pxa2x0_gpio_set_function(GXIO_GPIO8_RESET, GPIO_SET); |
|
else |
|
pxa2x0_gpio_set_function(GXIO_GPIO8_RESET, GPIO_CLR); |
|
#endif |
|
break; |
|
|
|
case SAPCIC_CONTROL_LINEENABLE: |
|
break; |
|
|
|
case SAPCIC_CONTROL_WAITENABLE: |
|
break; |
|
|
|
case SAPCIC_CONTROL_POWERSELECT: |
|
break; |
break; |
|
|
default: |
default: |
panic("%s: bogus register", __FUNCTION__); |
panic("%s: bogus register", __FUNCTION__); |
} |
} |
|
/* NOTREACHED */ |
} |
} |
|
|
static void |
static void |
gxpcic_set_power(struct sapcic_socket *__so, int arg) |
gxpcic_set_power(struct pxapcic_socket *__so, int arg) |
{ |
{ |
|
|
if(arg != SAPCIC_POWER_OFF && arg != SAPCIC_POWER_3V) |
if(arg != PXAPCIC_POWER_OFF && arg != PXAPCIC_POWER_3V) |
panic("%s: bogus arg\n", __FUNCTION__); |
panic("%s: bogus arg\n", __FUNCTION__); |
|
|
/* 3.3V only? */ |
/* 3.3V only? */ |
Line 339 gxpcic_set_power(struct sapcic_socket *_ |
|
Line 248 gxpcic_set_power(struct sapcic_socket *_ |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static void |
static void |
gxpcic_clear_intr(int arg) |
gxpcic_clear_intr(struct pxapcic_socket *so) |
{ |
{ |
|
|
/* nothing to do */ |
/* nothing to do */ |
} |
} |
|
|
static void * |
static void * |
gxpcic_intr_establish(struct sapcic_socket *so, int level, |
gxpcic_intr_establish(struct pxapcic_socket *so, int level, |
int (* ih_fun)(void *), void *ih_arg) |
int (* ih_fun)(void *), void *ih_arg) |
{ |
{ |
__attribute__((unused))struct gxpcic_softc *sc = |
|
(struct gxpcic_softc *)so->sc; |
|
int gpirq; |
|
|
|
gpirq = GXIO_GPIO26_READY; |
return pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING, |
|
level, ih_fun, ih_arg); |
|
} |
|
|
DPRINTF(("%s: card %d gpio %d\n", |
/* ARGSUSED */ |
sc->sc_pc.sc_dev.dv_xname, so->socket, gpirq)); |
static void |
|
gxpcic_intr_disestablish(struct pxapcic_socket *so, void *ih) |
|
{ |
|
|
return gxio_intr_establish(sc, gpirq, IST_EDGE_FALLING, level, |
pxa2x0_gpio_intr_disestablish(ih); |
ih_fun, ih_arg); |
|
} |
} |
|
|
static void |
|
gxpcic_intr_disestablish(struct sapcic_socket *so, void *ih) |
/* |
|
* XXXXX: slot count functions from Linux |
|
*/ |
|
__inline void |
|
gxpcic_cpld_clk() |
{ |
{ |
__attribute__((unused))struct gxpcic_softc *sc = |
|
(struct gxpcic_softc *)so->sc; |
|
|
|
gxio_intr_disestablish(sc, ih); |
pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_CLR); |
|
pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_SET); |
|
} |
|
|
|
__inline u_char |
|
gxpcic_cpld_read_bits(int bits) |
|
{ |
|
u_int shift = 0, gpio; |
|
u_char result = 0; |
|
|
|
while (bits--) { |
|
gpio = pxa2x0_gpio_get_function(11); |
|
result |= ((gpio & GPIO_SET) == GPIO_SET) << shift; |
|
shift++; |
|
gxpcic_cpld_clk(); |
|
} |
|
return result; |
|
} |
|
|
|
/* |
|
* We use the CPLD on the CF-CF card to read a value from a shift register. |
|
* If we can read that magic sequence, then we have 2 CF cards; otherwise |
|
* we assume just one. The CPLD will send the value of the shift register |
|
* on GPIO11 (the CD line for slot 0) when RESET is held in reset. We use |
|
* GPIO48 (nPWE) as a clock signal, GPIO52/53 (card enable for both cards) |
|
* to control read/write to the shift register. |
|
*/ |
|
static int |
|
gxpcic_count_slot(struct pxapcic_softc *sc) |
|
{ |
|
u_int poe, pce1, pce2; |
|
int nslot; |
|
|
|
poe = pxa2x0_gpio_get_function(48); |
|
pce1 = pxa2x0_gpio_get_function(52); |
|
pce2 = pxa2x0_gpio_get_function(53); |
|
|
|
/* Reset */ |
|
pxa2x0_gpio_set_function(8, GPIO_OUT | GPIO_SET); |
|
|
|
/* Setup the shift register */ |
|
pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET); |
|
pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_CLR); |
|
|
|
/* Tick the clock to program the shift register */ |
|
gxpcic_cpld_clk(); |
|
|
|
/* Now set shift register into read mode */ |
|
pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR); |
|
pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_SET); |
|
|
|
/* We can read the bits now -- 0xc2 means "Dual compact flash" */ |
|
if (gxpcic_cpld_read_bits(8) != 0xc2) |
|
/* We do not have 2 CF slots */ |
|
nslot = 1; |
|
else |
|
/* We have 2 CF slots */ |
|
nslot = 2; |
|
|
|
delay(50); |
|
pxa2x0_gpio_set_function(8, GPIO_OUT | GPIO_CLR); /* clr RESET */ |
|
|
|
pxa2x0_gpio_set_function(48, poe); |
|
pxa2x0_gpio_set_function(52, pce1); |
|
pxa2x0_gpio_set_function(53, pce2); |
|
|
|
return nslot; |
} |
} |