Home | History | Annotate | Line # | Download | only in gumstix
      1 /*	$NetBSD: gxpcic.c,v 1.15 2023/12/20 13:55:17 thorpej Exp $ */
      2 /*
      3  * Copyright (C) 2005, 2006 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 /*
     34  * Copyright (c) 2002, 2003, 2005  Genetec corp.  All rights reserved.
     35  *
     36  * PCMCIA/CF support for TWINTAIL (G4255EB)
     37  * Written by Hiroyuki Bessho for Genetec corp.
     38  *
     39  * Redistribution and use in source and binary forms, with or without
     40  * modification, are permitted provided that the following conditions
     41  * are met:
     42  * 1. Redistributions of source code must retain the above copyright
     43  *    notice, this list of conditions and the following disclaimer.
     44  * 2. Redistributions in binary form must reproduce the above copyright
     45  *    notice, this list of conditions and the following disclaimer in the
     46  *    documentation and/or other materials provided with the distribution.
     47  * 3. The name of Genetec corp. may not be used to endorse
     48  *    or promote products derived from this software without specific prior
     49  *    written permission.
     50  *
     51  * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
     52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     53  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     54  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORP.
     55  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     56  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     57  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     58  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     59  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     60  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     61  * POSSIBILITY OF SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/types.h>
     65 #include <sys/param.h>
     66 #include <sys/systm.h>
     67 #include <sys/device.h>
     68 #include <sys/callout.h>
     69 #include <sys/kernel.h>
     70 #include <sys/kthread.h>
     71 #include <uvm/uvm.h>
     72 
     73 #include <sys/bus.h>
     74 #include <machine/intr.h>
     75 
     76 #include <dev/pcmcia/pcmciareg.h>
     77 #include <dev/pcmcia/pcmciavar.h>
     78 #include <dev/pcmcia/pcmciachip.h>
     79 
     80 #include <arch/arm/xscale/pxa2x0cpu.h>
     81 #include <arch/arm/xscale/pxa2x0var.h>
     82 #include <arch/arm/xscale/pxa2x0reg.h>
     83 #include <arch/arm/xscale/pxa2x0_gpio.h>
     84 #include <arch/arm/xscale/pxa2x0_pcic.h>
     85 #include <arch/evbarm/gumstix/gumstixvar.h>
     86 
     87 
     88 #ifdef DEBUG
     89 #define DPRINTF(arg)	printf arg
     90 #else
     91 #define DPRINTF(arg)
     92 #endif
     93 
     94 #define HAVE_CARD(r)	(!((r) & GPIO_SET))
     95 
     96 
     97 static	int  	gxpcic_match(device_t, cfdata_t, void *);
     98 static	void  	gxpcic_attach(device_t, device_t, void *);
     99 static	void	gxpcic_socket_setup(struct pxapcic_socket *);
    100 
    101 static	u_int	gxpcic_read(struct pxapcic_socket *, int);
    102 static	void	gxpcic_write(struct pxapcic_socket *, int, u_int);
    103 static	void	gxpcic_set_power(struct pxapcic_socket *, int);
    104 static	void	gxpcic_clear_intr(struct pxapcic_socket *);
    105 static	void	*gxpcic_intr_establish(struct pxapcic_socket *, int,
    106 				       int (*)(void *), void *);
    107 static	void	gxpcic_intr_disestablish(struct pxapcic_socket *, void *);
    108 static __inline void gxpcic_cpld_clk(void);
    109 static __inline u_char gxpcic_cpld_read_bits(int bits);
    110 static	int	gxpcic_count_slot(struct pxapcic_softc *);
    111 
    112 CFATTACH_DECL_NEW(gxpcic, sizeof(struct pxapcic_softc),
    113     gxpcic_match, gxpcic_attach, NULL, NULL);
    114 
    115 static struct pxapcic_tag gxpcic_functions = {
    116 	gxpcic_read,
    117 	gxpcic_write,
    118 	gxpcic_set_power,
    119 	gxpcic_clear_intr,
    120 	gxpcic_intr_establish,
    121 	gxpcic_intr_disestablish,
    122 };
    123 
    124 
    125 static int
    126 gxpcic_match(device_t parent, cfdata_t match, void *aux)
    127 {
    128 	struct pxaip_attach_args *pxa = aux;
    129 	struct pxa2x0_gpioconf *gpioconf;
    130 	u_int reg;
    131 	int i;
    132 
    133 	if (strcmp(pxa->pxa_name, match->cf_name) != 0)
    134 		return 0;
    135 
    136 	/*
    137 	 * Check GPIO configuration.  If you use these, it is sure already
    138 	 * to have been set by gxio.
    139 	 */
    140 	gpioconf = CPU_IS_PXA250 ? pxa25x_pcic_gpioconf :
    141 	    pxa27x_pcic_gpioconf;
    142 	for (i = 0; gpioconf[i].pin != -1; i++) {
    143 		reg = pxa2x0_gpio_get_function(gpioconf[i].pin);
    144 		if (GPIO_FN(reg) != GPIO_FN(gpioconf[i].value) ||
    145 		    GPIO_FN_IS_OUT(reg) != GPIO_FN_IS_OUT(gpioconf[i].value)) {
    146 			if (!CPU_IS_PXA250 && gpioconf[i].pin == 111)
    147 				continue;
    148 			return 0;
    149 		}
    150 	}
    151 
    152 	return	1;	/* match */
    153 }
    154 
    155 static void
    156 gxpcic_attach(device_t parent, device_t self, void *aux)
    157 {
    158 	struct pxapcic_softc *sc = device_private(self);
    159 	struct pxaip_attach_args *pxa = aux;
    160 	int nslot, i, j;
    161 
    162 	sc->sc_dev = self;
    163 	sc->sc_iot = pxa->pxa_iot;
    164 
    165 	nslot = gxpcic_count_slot(sc);
    166 
    167 	for (i = 0, j = 0; i < nslot; i++) {
    168 		if (!gxpcic_slot_irqs[i].valid) {
    169 			j++;
    170 			continue;
    171 		}
    172 		sc->sc_irqpin[i - j] = gxpcic_slot_irqs[i].prdy;
    173 		sc->sc_irqcfpin[i - j] = gxpcic_slot_irqs[i].cd;
    174 	}
    175 	sc->sc_nslots = i - j;
    176 
    177 	pxapcic_attach_common(sc, &gxpcic_socket_setup);
    178 }
    179 
    180 static void
    181 gxpcic_socket_setup(struct pxapcic_socket *so)
    182 {
    183 #if 0
    184 	struct pxapcic_softc *sc = so->sc;
    185 #endif
    186 
    187 	/* 3.3V only? */
    188 	so->power_capability = PXAPCIC_POWER_3V;
    189 	so->pcictag_cookie = NULL;
    190 	so->pcictag = &gxpcic_functions;
    191 
    192 #if 0	/* We use already set values by u-boot. */
    193 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
    194 	    MEMCTL_MCMEM(so->socket), MC_TIMING_VAL(9 ,9, 29));
    195 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
    196 	    MEMCTL_MCATT(so->socket), MC_TIMING_VAL(9 ,9, 29));
    197 	bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
    198 	    MEMCTL_MCIO(so->socket), MC_TIMING_VAL(5 ,5, 16));
    199 #endif
    200 }
    201 
    202 static u_int
    203 gxpcic_read(struct pxapcic_socket *so, int which)
    204 {
    205 	int reg;
    206 
    207 	switch (which) {
    208 	case PXAPCIC_CARD_STATUS:
    209 		reg = pxa2x0_gpio_get_function(so->sc->sc_irqcfpin[so->socket]);
    210 		return (HAVE_CARD(reg) ?
    211 		    PXAPCIC_CARD_VALID : PXAPCIC_CARD_INVALID);
    212 
    213 	case PXAPCIC_CARD_READY:
    214 		reg = pxa2x0_gpio_get_function(so->sc->sc_irqpin[so->socket]);
    215 		return (reg & GPIO_SET ? 1 : 0);
    216 
    217 	default:
    218 		panic("%s: bogus register", __func__);
    219 	}
    220 	/* NOTREACHED */
    221 }
    222 
    223 /* ARGSUSED */
    224 static void
    225 gxpcic_write(struct pxapcic_socket *so, int which, u_int arg)
    226 {
    227 
    228 	switch (which) {
    229 	case PXAPCIC_CARD_POWER:
    230 	case PXAPCIC_CARD_RESET:
    231 		/* We can't */
    232 		break;
    233 
    234 	default:
    235 		panic("%s: bogus register", __func__);
    236 	}
    237 	/* NOTREACHED */
    238 }
    239 
    240 static void
    241 gxpcic_set_power(struct pxapcic_socket *__so, int arg)
    242 {
    243 
    244 	if(arg != PXAPCIC_POWER_OFF && arg != PXAPCIC_POWER_3V)
    245 		panic("%s: bogus arg\n", __func__);
    246 
    247 	/* 3.3V only? */
    248 }
    249 
    250 /* ARGSUSED */
    251 static void
    252 gxpcic_clear_intr(struct pxapcic_socket *so)
    253 {
    254 
    255 	/* nothing to do */
    256 }
    257 
    258 static void *
    259 gxpcic_intr_establish(struct pxapcic_socket *so, int level,
    260     int (* ih_fun)(void *), void *ih_arg)
    261 {
    262 
    263 	return pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING,
    264 	    level, ih_fun, ih_arg);
    265 }
    266 
    267 /* ARGSUSED */
    268 static void
    269 gxpcic_intr_disestablish(struct pxapcic_socket *so, void *ih)
    270 {
    271 
    272 	pxa2x0_gpio_intr_disestablish(ih);
    273 }
    274 
    275 
    276 /*
    277  * XXXXX: slot count functions from Linux
    278  */
    279 static __inline void
    280 gxpcic_cpld_clk(void)
    281 {
    282 
    283 	pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_CLR);
    284 	pxa2x0_gpio_set_function(48, GPIO_OUT | GPIO_SET);
    285 }
    286 
    287 static inline u_char
    288 gxpcic_cpld_read_bits(int bits)
    289 {
    290 	u_int shift = 0, gpio;
    291 	u_char result = 0;
    292 
    293 	while (bits--) {
    294 		gpio = pxa2x0_gpio_get_function(11);
    295 		result |= ((gpio & GPIO_SET) == GPIO_SET) << shift;
    296 		shift++;
    297 		gxpcic_cpld_clk();
    298 	}
    299 	return result;
    300 }
    301 
    302 /*
    303  * We use the CPLD on the CF-CF card to read a value from a shift register.
    304  * If we can read that magic sequence, then we have 2 CF cards; otherwise
    305  * we assume just one.  The CPLD will send the value of the shift register
    306  * on GPIO11 (the CD line for slot 0) when RESET is held in reset.  We use
    307  * GPIO48 (nPWE) as a clock signal, GPIO52/53 (card enable for both cards)
    308  * to control read/write to the shift register.
    309  */
    310 static int
    311 gxpcic_count_slot(struct pxapcic_softc *sc)
    312 {
    313 	u_int poe, pce1, pce2;
    314 	int nslot;
    315 
    316 	poe = pxa2x0_gpio_get_function(48);
    317 	pce1 = pxa2x0_gpio_get_function(52);
    318 	pce2 = pxa2x0_gpio_get_function(53);
    319 
    320 	/* RESET */
    321 	pxa2x0_gpio_set_function(gxpcic_gpio_reset, GPIO_OUT | GPIO_CLR);
    322 
    323 	/* Setup the shift register */
    324 	pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_SET);
    325 	pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_CLR);
    326 
    327 	/* Tick the clock to program the shift register */
    328 	gxpcic_cpld_clk();
    329 
    330 	/* Now set shift register into read mode */
    331 	pxa2x0_gpio_set_function(52, GPIO_OUT | GPIO_CLR);
    332 	pxa2x0_gpio_set_function(53, GPIO_OUT | GPIO_SET);
    333 
    334 	/* We can read the bits now -- 0xc2 means "Dual compact flash" */
    335 	if (gxpcic_cpld_read_bits(8) != 0xc2)
    336 		/* We do not have 2 CF slots */
    337 		nslot = 1;
    338 	else
    339 		/* We have 2 CF slots */
    340 		nslot = 2;
    341 
    342 	delay(50);
    343 	/* clear RESET */
    344 	pxa2x0_gpio_set_function(gxpcic_gpio_reset, GPIO_OUT | GPIO_CLR);
    345 
    346 	pxa2x0_gpio_set_function(48, poe);
    347 	pxa2x0_gpio_set_function(52, pce1);
    348 	pxa2x0_gpio_set_function(53, pce2);
    349 
    350 	return nslot;
    351 }
    352