1*7433666eSthorpej /* $NetBSD: gxpcic.c,v 1.15 2023/12/20 13:55:17 thorpej Exp $ */
260e982e8Skiyohara /*
360e982e8Skiyohara * Copyright (C) 2005, 2006 WIDE Project and SOUM Corporation.
460e982e8Skiyohara * All rights reserved.
560e982e8Skiyohara *
660e982e8Skiyohara * Written by Takashi Kiyohara and Susumu Miki for WIDE Project and SOUM
760e982e8Skiyohara * Corporation.
860e982e8Skiyohara *
960e982e8Skiyohara * Redistribution and use in source and binary forms, with or without
1060e982e8Skiyohara * modification, are permitted provided that the following conditions
1160e982e8Skiyohara * are met:
1260e982e8Skiyohara * 1. Redistributions of source code must retain the above copyright
1360e982e8Skiyohara * notice, this list of conditions and the following disclaimer.
1460e982e8Skiyohara * 2. Redistributions in binary form must reproduce the above copyright
1560e982e8Skiyohara * notice, this list of conditions and the following disclaimer in the
1660e982e8Skiyohara * documentation and/or other materials provided with the distribution.
1760e982e8Skiyohara * 3. Neither the name of the project nor the name of SOUM Corporation
1860e982e8Skiyohara * may be used to endorse or promote products derived from this software
1960e982e8Skiyohara * without specific prior written permission.
2060e982e8Skiyohara *
2160e982e8Skiyohara * THIS SOFTWARE IS PROVIDED BY THE PROJECT and SOUM CORPORATION ``AS IS''
2260e982e8Skiyohara * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2360e982e8Skiyohara * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2460e982e8Skiyohara * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT AND SOUM CORPORATION
2560e982e8Skiyohara * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2660e982e8Skiyohara * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2760e982e8Skiyohara * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2860e982e8Skiyohara * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2960e982e8Skiyohara * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3060e982e8Skiyohara * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3160e982e8Skiyohara * POSSIBILITY OF SUCH DAMAGE.
3260e982e8Skiyohara */
3360e982e8Skiyohara /*
3460e982e8Skiyohara * Copyright (c) 2002, 2003, 2005 Genetec corp. All rights reserved.
3560e982e8Skiyohara *
3660e982e8Skiyohara * PCMCIA/CF support for TWINTAIL (G4255EB)
3760e982e8Skiyohara * Written by Hiroyuki Bessho for Genetec corp.
3860e982e8Skiyohara *
3960e982e8Skiyohara * Redistribution and use in source and binary forms, with or without
4060e982e8Skiyohara * modification, are permitted provided that the following conditions
4160e982e8Skiyohara * are met:
4260e982e8Skiyohara * 1. Redistributions of source code must retain the above copyright
4360e982e8Skiyohara * notice, this list of conditions and the following disclaimer.
4460e982e8Skiyohara * 2. Redistributions in binary form must reproduce the above copyright
4560e982e8Skiyohara * notice, this list of conditions and the following disclaimer in the
4660e982e8Skiyohara * documentation and/or other materials provided with the distribution.
4760e982e8Skiyohara * 3. The name of Genetec corp. may not be used to endorse
4860e982e8Skiyohara * or promote products derived from this software without specific prior
4960e982e8Skiyohara * written permission.
5060e982e8Skiyohara *
5160e982e8Skiyohara * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
5260e982e8Skiyohara * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
5360e982e8Skiyohara * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
5460e982e8Skiyohara * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORP.
5560e982e8Skiyohara * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5660e982e8Skiyohara * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5760e982e8Skiyohara * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5860e982e8Skiyohara * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5960e982e8Skiyohara * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
6060e982e8Skiyohara * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6160e982e8Skiyohara * POSSIBILITY OF SUCH DAMAGE.
6260e982e8Skiyohara */
6360e982e8Skiyohara
6460e982e8Skiyohara #include <sys/types.h>
6560e982e8Skiyohara #include <sys/param.h>
6660e982e8Skiyohara #include <sys/systm.h>
6760e982e8Skiyohara #include <sys/device.h>
6860e982e8Skiyohara #include <sys/callout.h>
6960e982e8Skiyohara #include <sys/kernel.h>
7060e982e8Skiyohara #include <sys/kthread.h>
7160e982e8Skiyohara #include <uvm/uvm.h>
7260e982e8Skiyohara
73fea15f47Sdyoung #include <sys/bus.h>
7460e982e8Skiyohara #include <machine/intr.h>
7560e982e8Skiyohara
7660e982e8Skiyohara #include <dev/pcmcia/pcmciareg.h>
7760e982e8Skiyohara #include <dev/pcmcia/pcmciavar.h>
7860e982e8Skiyohara #include <dev/pcmcia/pcmciachip.h>
7960e982e8Skiyohara
80f1bbc244Skiyohara #include <arch/arm/xscale/pxa2x0cpu.h>
8160e982e8Skiyohara #include <arch/arm/xscale/pxa2x0var.h>
8260e982e8Skiyohara #include <arch/arm/xscale/pxa2x0reg.h>
83f1bbc244Skiyohara #include <arch/arm/xscale/pxa2x0_gpio.h>
843af5743dSkiyohara #include <arch/arm/xscale/pxa2x0_pcic.h>
8560e982e8Skiyohara #include <arch/evbarm/gumstix/gumstixvar.h>
8660e982e8Skiyohara
8760e982e8Skiyohara
8860e982e8Skiyohara #ifdef DEBUG
8960e982e8Skiyohara #define DPRINTF(arg) printf arg
9060e982e8Skiyohara #else
9160e982e8Skiyohara #define DPRINTF(arg)
9260e982e8Skiyohara #endif
9360e982e8Skiyohara
9460e982e8Skiyohara #define HAVE_CARD(r) (!((r) & GPIO_SET))
9560e982e8Skiyohara
9660e982e8Skiyohara
971c10f508Skiyohara static int gxpcic_match(device_t, cfdata_t, void *);
982438bca8Skiyohara static void gxpcic_attach(device_t, device_t, void *);
991c10f508Skiyohara static void gxpcic_socket_setup(struct pxapcic_socket *);
10060e982e8Skiyohara
1013af5743dSkiyohara static u_int gxpcic_read(struct pxapcic_socket *, int);
1023af5743dSkiyohara static void gxpcic_write(struct pxapcic_socket *, int, u_int);
1033af5743dSkiyohara static void gxpcic_set_power(struct pxapcic_socket *, int);
1043af5743dSkiyohara static void gxpcic_clear_intr(struct pxapcic_socket *);
1053af5743dSkiyohara static void *gxpcic_intr_establish(struct pxapcic_socket *, int,
10660e982e8Skiyohara int (*)(void *), void *);
1073af5743dSkiyohara static void gxpcic_intr_disestablish(struct pxapcic_socket *, void *);
1088ab3772aSchristos static __inline void gxpcic_cpld_clk(void);
1098ab3772aSchristos static __inline u_char gxpcic_cpld_read_bits(int bits);
1103af5743dSkiyohara static int gxpcic_count_slot(struct pxapcic_softc *);
11160e982e8Skiyohara
1121c10f508Skiyohara CFATTACH_DECL_NEW(gxpcic, sizeof(struct pxapcic_softc),
11360e982e8Skiyohara gxpcic_match, gxpcic_attach, NULL, NULL);
11460e982e8Skiyohara
1151c10f508Skiyohara static struct pxapcic_tag gxpcic_functions = {
11660e982e8Skiyohara gxpcic_read,
11760e982e8Skiyohara gxpcic_write,
11860e982e8Skiyohara gxpcic_set_power,
11960e982e8Skiyohara gxpcic_clear_intr,
12060e982e8Skiyohara gxpcic_intr_establish,
12160e982e8Skiyohara gxpcic_intr_disestablish,
12260e982e8Skiyohara };
12360e982e8Skiyohara
12460e982e8Skiyohara
12560e982e8Skiyohara static int
gxpcic_match(device_t parent,cfdata_t match,void * aux)1261c10f508Skiyohara gxpcic_match(device_t parent, cfdata_t match, void *aux)
12760e982e8Skiyohara {
1281c10f508Skiyohara struct pxaip_attach_args *pxa = aux;
129f1bbc244Skiyohara struct pxa2x0_gpioconf *gpioconf;
13060e982e8Skiyohara u_int reg;
13160e982e8Skiyohara int i;
13260e982e8Skiyohara
1331c10f508Skiyohara if (strcmp(pxa->pxa_name, match->cf_name) != 0)
1341c10f508Skiyohara return 0;
1351c10f508Skiyohara
1363af5743dSkiyohara /*
1373af5743dSkiyohara * Check GPIO configuration. If you use these, it is sure already
1383af5743dSkiyohara * to have been set by gxio.
1393af5743dSkiyohara */
140f1bbc244Skiyohara gpioconf = CPU_IS_PXA250 ? pxa25x_pcic_gpioconf :
141f1bbc244Skiyohara pxa27x_pcic_gpioconf;
142f1bbc244Skiyohara for (i = 0; gpioconf[i].pin != -1; i++) {
143f1bbc244Skiyohara reg = pxa2x0_gpio_get_function(gpioconf[i].pin);
144f1bbc244Skiyohara if (GPIO_FN(reg) != GPIO_FN(gpioconf[i].value) ||
1451c10f508Skiyohara GPIO_FN_IS_OUT(reg) != GPIO_FN_IS_OUT(gpioconf[i].value)) {
1461c10f508Skiyohara if (!CPU_IS_PXA250 && gpioconf[i].pin == 111)
1471c10f508Skiyohara continue;
1481c10f508Skiyohara return 0;
1491c10f508Skiyohara }
15060e982e8Skiyohara }
15160e982e8Skiyohara
15260e982e8Skiyohara return 1; /* match */
15360e982e8Skiyohara }
15460e982e8Skiyohara
15560e982e8Skiyohara static void
gxpcic_attach(device_t parent,device_t self,void * aux)1562438bca8Skiyohara gxpcic_attach(device_t parent, device_t self, void *aux)
15760e982e8Skiyohara {
1582438bca8Skiyohara struct pxapcic_softc *sc = device_private(self);
1591c10f508Skiyohara struct pxaip_attach_args *pxa = aux;
1606819c02fSskrll int nslot, i, j;
16160e982e8Skiyohara
1621a686006Snonaka sc->sc_dev = self;
1633af5743dSkiyohara sc->sc_iot = pxa->pxa_iot;
16460e982e8Skiyohara
1653af5743dSkiyohara nslot = gxpcic_count_slot(sc);
16660e982e8Skiyohara
1676819c02fSskrll for (i = 0, j = 0; i < nslot; i++) {
1686819c02fSskrll if (!gxpcic_slot_irqs[i].valid) {
1696819c02fSskrll j++;
1701c10f508Skiyohara continue;
1713af5743dSkiyohara }
1726819c02fSskrll sc->sc_irqpin[i - j] = gxpcic_slot_irqs[i].prdy;
1736819c02fSskrll sc->sc_irqcfpin[i - j] = gxpcic_slot_irqs[i].cd;
1746819c02fSskrll }
1756819c02fSskrll sc->sc_nslots = i - j;
1763af5743dSkiyohara
1771c10f508Skiyohara pxapcic_attach_common(sc, &gxpcic_socket_setup);
1783af5743dSkiyohara }
1793af5743dSkiyohara
1803af5743dSkiyohara static void
gxpcic_socket_setup(struct pxapcic_socket * so)1811c10f508Skiyohara gxpcic_socket_setup(struct pxapcic_socket *so)
1823af5743dSkiyohara {
1831c10f508Skiyohara #if 0
1843af5743dSkiyohara struct pxapcic_softc *sc = so->sc;
1851c10f508Skiyohara #endif
18660e982e8Skiyohara
18760e982e8Skiyohara /* 3.3V only? */
1883af5743dSkiyohara so->power_capability = PXAPCIC_POWER_3V;
1893af5743dSkiyohara so->pcictag_cookie = NULL;
1901c10f508Skiyohara so->pcictag = &gxpcic_functions;
19160e982e8Skiyohara
1921c10f508Skiyohara #if 0 /* We use already set values by u-boot. */
1933af5743dSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
1943af5743dSkiyohara MEMCTL_MCMEM(so->socket), MC_TIMING_VAL(9 ,9, 29));
1953af5743dSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
1963af5743dSkiyohara MEMCTL_MCATT(so->socket), MC_TIMING_VAL(9 ,9, 29));
1973af5743dSkiyohara bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
1983af5743dSkiyohara MEMCTL_MCIO(so->socket), MC_TIMING_VAL(5 ,5, 16));
1991c10f508Skiyohara #endif
20060e982e8Skiyohara }
20160e982e8Skiyohara
2023af5743dSkiyohara static u_int
gxpcic_read(struct pxapcic_socket * so,int which)2033af5743dSkiyohara gxpcic_read(struct pxapcic_socket *so, int which)
20460e982e8Skiyohara {
20560e982e8Skiyohara int reg;
20660e982e8Skiyohara
20760e982e8Skiyohara switch (which) {
2083af5743dSkiyohara case PXAPCIC_CARD_STATUS:
2096819c02fSskrll reg = pxa2x0_gpio_get_function(so->sc->sc_irqcfpin[so->socket]);
21060e982e8Skiyohara return (HAVE_CARD(reg) ?
2113af5743dSkiyohara PXAPCIC_CARD_VALID : PXAPCIC_CARD_INVALID);
21260e982e8Skiyohara
2133af5743dSkiyohara case PXAPCIC_CARD_READY:
2146819c02fSskrll reg = pxa2x0_gpio_get_function(so->sc->sc_irqpin[so->socket]);
21560e982e8Skiyohara return (reg & GPIO_SET ? 1 : 0);
21660e982e8Skiyohara
21760e982e8Skiyohara default:
2189b2b412cSperry panic("%s: bogus register", __func__);
21960e982e8Skiyohara }
2203af5743dSkiyohara /* NOTREACHED */
22160e982e8Skiyohara }
22260e982e8Skiyohara
22360e982e8Skiyohara /* ARGSUSED */
22460e982e8Skiyohara static void
gxpcic_write(struct pxapcic_socket * so,int which,u_int arg)2253af5743dSkiyohara gxpcic_write(struct pxapcic_socket *so, int which, u_int arg)
22660e982e8Skiyohara {
22760e982e8Skiyohara
22860e982e8Skiyohara switch (which) {
2293af5743dSkiyohara case PXAPCIC_CARD_POWER:
2303af5743dSkiyohara case PXAPCIC_CARD_RESET:
2313af5743dSkiyohara /* We can't */
23260e982e8Skiyohara break;
23360e982e8Skiyohara
23460e982e8Skiyohara default:
2359b2b412cSperry panic("%s: bogus register", __func__);
23660e982e8Skiyohara }
2373af5743dSkiyohara /* NOTREACHED */
23860e982e8Skiyohara }
23960e982e8Skiyohara
24060e982e8Skiyohara static void
gxpcic_set_power(struct pxapcic_socket * __so,int arg)2413af5743dSkiyohara gxpcic_set_power(struct pxapcic_socket *__so, int arg)
24260e982e8Skiyohara {
24360e982e8Skiyohara
2443af5743dSkiyohara if(arg != PXAPCIC_POWER_OFF && arg != PXAPCIC_POWER_3V)
2459b2b412cSperry panic("%s: bogus arg\n", __func__);
24660e982e8Skiyohara
24760e982e8Skiyohara /* 3.3V only? */
24860e982e8Skiyohara }
24960e982e8Skiyohara
25060e982e8Skiyohara /* ARGSUSED */
25160e982e8Skiyohara static void
gxpcic_clear_intr(struct pxapcic_socket * so)2523af5743dSkiyohara gxpcic_clear_intr(struct pxapcic_socket *so)
25360e982e8Skiyohara {
25460e982e8Skiyohara
25560e982e8Skiyohara /* nothing to do */
25660e982e8Skiyohara }
25760e982e8Skiyohara
25860e982e8Skiyohara static void *
gxpcic_intr_establish(struct pxapcic_socket * so,int level,int (* ih_fun)(void *),void * ih_arg)2593af5743dSkiyohara gxpcic_intr_establish(struct pxapcic_socket *so, int level,
26060e982e8Skiyohara int (* ih_fun)(void *), void *ih_arg)
26160e982e8Skiyohara {
26260e982e8Skiyohara
2633af5743dSkiyohara return pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING,
2643af5743dSkiyohara level, ih_fun, ih_arg);
26560e982e8Skiyohara }
26660e982e8Skiyohara
2673af5743dSkiyohara /* ARGSUSED */
26860e982e8Skiyohara static void
gxpcic_intr_disestablish(struct pxapcic_socket * so,void * ih)2693af5743dSkiyohara gxpcic_intr_disestablish(struct pxapcic_socket *so, void *ih)
27060e982e8Skiyohara {
27160e982e8Skiyohara
2723af5743dSkiyohara pxa2x0_gpio_intr_disestablish(ih);
2733af5743dSkiyohara }
2743af5743dSkiyohara
2753af5743dSkiyohara
2763af5743dSkiyohara /*
2773af5743dSkiyohara * XXXXX: slot count functions from Linux
2783af5743dSkiyohara */
2798ab3772aSchristos static __inline void
gxpcic_cpld_clk(void)280df7f595eScegger gxpcic_cpld_clk(void)
2813af5743dSkiyohara {
2823af5743dSkiyohara
2833af5743dSkiyohara pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_CLR);
2843af5743dSkiyohara pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_SET);
2853af5743dSkiyohara }
2863af5743dSkiyohara
2878ab3772aSchristos static inline u_char
gxpcic_cpld_read_bits(int bits)2883af5743dSkiyohara gxpcic_cpld_read_bits(int bits)
2893af5743dSkiyohara {
2903af5743dSkiyohara u_int shift = 0, gpio;
2913af5743dSkiyohara u_char result = 0;
2923af5743dSkiyohara
2933af5743dSkiyohara while (bits--) {
2943af5743dSkiyohara gpio = pxa2x0_gpio_get_function(11);
2953af5743dSkiyohara result |= ((gpio & GPIO_SET) == GPIO_SET) << shift;
2963af5743dSkiyohara shift++;
2973af5743dSkiyohara gxpcic_cpld_clk();
2983af5743dSkiyohara }
2993af5743dSkiyohara return result;
3003af5743dSkiyohara }
3013af5743dSkiyohara
3023af5743dSkiyohara /*
3033af5743dSkiyohara * We use the CPLD on the CF-CF card to read a value from a shift register.
3043af5743dSkiyohara * If we can read that magic sequence, then we have 2 CF cards; otherwise
3053af5743dSkiyohara * we assume just one. The CPLD will send the value of the shift register
3063af5743dSkiyohara * on GPIO11 (the CD line for slot 0) when RESET is held in reset. We use
3073af5743dSkiyohara * GPIO48 (nPWE) as a clock signal, GPIO52/53 (card enable for both cards)
3083af5743dSkiyohara * to control read/write to the shift register.
3093af5743dSkiyohara */
3103af5743dSkiyohara static int
gxpcic_count_slot(struct pxapcic_softc * sc)3113af5743dSkiyohara gxpcic_count_slot(struct pxapcic_softc *sc)
3123af5743dSkiyohara {
3133af5743dSkiyohara u_int poe, pce1, pce2;
3143af5743dSkiyohara int nslot;
3153af5743dSkiyohara
3163af5743dSkiyohara poe = pxa2x0_gpio_get_function(48);
3173af5743dSkiyohara pce1 = pxa2x0_gpio_get_function(52);
3183af5743dSkiyohara pce2 = pxa2x0_gpio_get_function(53);
3193af5743dSkiyohara
3201c10f508Skiyohara /* RESET */
3211c10f508Skiyohara pxa2x0_gpio_set_function(gxpcic_gpio_reset, GPIO_OUT | GPIO_CLR);
3223af5743dSkiyohara
3233af5743dSkiyohara /* Setup the shift register */
3243af5743dSkiyohara pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET);
3253af5743dSkiyohara pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_CLR);
3263af5743dSkiyohara
3273af5743dSkiyohara /* Tick the clock to program the shift register */
3283af5743dSkiyohara gxpcic_cpld_clk();
3293af5743dSkiyohara
3303af5743dSkiyohara /* Now set shift register into read mode */
3313af5743dSkiyohara pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR);
3323af5743dSkiyohara pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_SET);
3333af5743dSkiyohara
3343af5743dSkiyohara /* We can read the bits now -- 0xc2 means "Dual compact flash" */
3353af5743dSkiyohara if (gxpcic_cpld_read_bits(8) != 0xc2)
3363af5743dSkiyohara /* We do not have 2 CF slots */
3373af5743dSkiyohara nslot = 1;
3383af5743dSkiyohara else
3393af5743dSkiyohara /* We have 2 CF slots */
3403af5743dSkiyohara nslot = 2;
3413af5743dSkiyohara
3423af5743dSkiyohara delay(50);
3431c10f508Skiyohara /* clear RESET */
3441c10f508Skiyohara pxa2x0_gpio_set_function(gxpcic_gpio_reset, GPIO_OUT | GPIO_CLR);
3453af5743dSkiyohara
3463af5743dSkiyohara pxa2x0_gpio_set_function(48, poe);
3473af5743dSkiyohara pxa2x0_gpio_set_function(52, pce1);
3483af5743dSkiyohara pxa2x0_gpio_set_function(53, pce2);
3493af5743dSkiyohara
3503af5743dSkiyohara return nslot;
35160e982e8Skiyohara }
352