1/* $Id: imx31lk_pcic.c,v 1.6 2012/11/12 18:00:39 skrll Exp $ */ 2/* $NetBSD: imx31lk_pcic.c,v 1.5 2012/10/27 17:17:47 chs Exp $ */ 3/* $OpenBSD: pxapcic.c,v 1.1 2005/07/01 23:51:55 uwe Exp $ */ 4 5/* 6 * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include <sys/cdefs.h> 22__KERNEL_RCSID(0, "$Id: imx31lk_pcic.c,v 1.6 2012/11/12 18:00:39 skrll Exp $"); 23 24#include <sys/param.h> 25#include <sys/systm.h> 26#include <sys/device.h> 27 28#include <machine/intr.h> 29#include <sys/bus.h> 30 31#include <uvm/uvm.h> 32 33#ifdef NOTYET 34#include <arch/arm/imx/imx_emifs.h> 35#include <arch/arm/imx/imx_gpio.h> 36#endif 37#include <arch/arm/imx/imx31var.h> 38#include <arch/arm/imx/imx_pcic.h> 39 40 41static int imx31lk_pcic_match(device_t, cfdata_t, void *); 42static void imx31lk_pcic_attach(device_t, device_t, void *); 43 44CFATTACH_DECL_NEW(imx31lk_pcic, sizeof(struct imx_pcic_softc), 45 imx31lk_pcic_match, imx31lk_pcic_attach, NULL, NULL); 46 47static void imx31lk_pcic_socket_setup(struct imx_pcic_socket *); 48static u_int imx31lk_pcic_read(struct imx_pcic_socket *, int); 49static void imx31lk_pcic_write(struct imx_pcic_socket *, int, u_int); 50static void imx31lk_pcic_set_power(struct imx_pcic_socket *, int); 51static void imx31lk_pcic_clear_intr(struct imx_pcic_socket *); 52static void *imx31lk_pcic_intr_establish(struct imx_pcic_socket *, int, 53 int (*)(void *), void *); 54static void imx31lk_pcic_intr_disestablish(struct imx_pcic_socket *, void *); 55 56struct imx_pcic_tag imx31lk_pcic_functions = { 57 imx31lk_pcic_read, 58 imx31lk_pcic_write, 59 imx31lk_pcic_set_power, 60 imx31lk_pcic_clear_intr, 61 imx31lk_pcic_intr_establish, 62 imx31lk_pcic_intr_disestablish 63}; 64 65static int 66imx31lk_pcic_match(device_t parent, cfdata_t cf, void *aux) 67{ 68 69 return 1; /* XXX */ 70} 71 72static void 73imx31lk_pcic_attach(device_t parent, device_t self, void *aux) 74{ 75 struct imx_pcic_softc *sc = device_private(self); 76 struct aips_attach_args * const aipsa = aux; 77 78 sc->sc_dev = self; 79 80printf("\n"); 81printf("imx_iot %p\n", aipsa->aipsa_memt); 82printf("imx_addr %lx\n", aipsa->aipsa_addr); 83printf("imx_size %lx\n", aipsa->aipsa_size); 84printf("imx_intr %d\n", aipsa->aipsa_intr); 85 86 sc->sc_pa = aipsa->aipsa_addr; 87 sc->sc_iot = aipsa->aipsa_memt; 88 89 sc->sc_nslots = 1; 90#ifdef NOTYET 91 sc->sc_irqpin[0] = aa->emifs_intr; /* XXX */ 92 sc->sc_irqcfpin[0] = -1; /* XXX */ 93#endif 94 95 sc->sc_flags |= PPF_REVERSE_ORDER; 96 97 imx_pcic_attach_common(sc, &imx31lk_pcic_socket_setup); 98} 99 100static void 101imx31lk_pcic_socket_setup(struct imx_pcic_socket *so) 102{ 103 struct imx_pcic_softc *sc; 104 bus_addr_t pa; 105 bus_size_t size = 0x2000; /* XXX */ 106 bus_space_tag_t iot; 107 bus_space_handle_t imx31lkh; 108 int error; 109 110 sc = so->sc; 111 iot = sc->sc_iot; 112 113 if (so->socket != 0) 114 panic("%s: CF slot %d not supported", device_xname(sc->sc_dev), so->socket); 115 116 pa = sc->sc_pa; 117 118 error = bus_space_map(iot, trunc_page(pa), round_page(size), 119 0, &imx31lkh); 120 if (error) { 121 panic("%s: failed to map memory %x for imx31lk", 122 device_xname(sc->sc_dev), (uint32_t)pa); 123 } 124 imx31lkh += pa - trunc_page(pa); 125 126#ifdef NOTYET 127 /* setup */ 128#endif 129 130#ifdef NOTYET 131 so->power_capability = PXAPCIC_POWER_3V; 132 if (so->socket == 0) 133 so->power_capability |= PXAPCIC_POWER_5V; 134#endif 135 136 so->pcictag_cookie = (void *)imx31lkh; 137 so->pcictag = &imx31lk_pcic_functions; 138} 139 140static u_int 141imx31lk_pcic_read(struct imx_pcic_socket *so, int reg) 142{ 143#ifdef NOTYET 144 bus_space_tag_t iot = so->sc->sc_iot; 145 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 146 uint16_t csr; 147 148 csr = bus_space_read_2(iot, ioh, SCOOP_CSR); 149 150 switch (reg) { 151 case PXAPCIC_CARD_STATUS: 152 if (csr & SCP_CSR_MISSING) 153 return (PXAPCIC_CARD_INVALID); 154 else 155 return (PXAPCIC_CARD_VALID); 156 157 case PXAPCIC_CARD_READY: 158 return ((bus_space_read_2(iot, ioh, SCOOP_CSR) & 159 SCP_CSR_READY) != 0); 160 161 default: 162 panic("imx31lk_pcic_read: bogus register"); 163 } 164 /*NOTREACHED*/ 165#else 166 panic("imx31lk_pcic_read"); 167#endif 168} 169 170static void 171imx31lk_pcic_write(struct imx_pcic_socket *so, int reg, u_int val) 172{ 173#ifdef NOTYET 174 bus_space_tag_t iot = so->sc->sc_iot; 175 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 176 uint16_t newval; 177 int s; 178 179 s = splhigh(); 180 181 switch (reg) { 182 case PXAPCIC_CARD_POWER: 183 newval = bus_space_read_2(iot, ioh, SCOOP_CPR); 184 newval &= ~(SCP_CPR_PWR | SCP_CPR_3V | SCP_CPR_5V); 185 186 if (val == PXAPCIC_POWER_3V) 187 newval |= (SCP_CPR_PWR | SCP_CPR_3V); 188 else if (val == PXAPCIC_POWER_5V) 189 newval |= (SCP_CPR_PWR | SCP_CPR_5V); 190 191 bus_space_write_2(iot, ioh, SCOOP_CPR, newval); 192 break; 193 194 case PXAPCIC_CARD_RESET: 195 bus_space_write_2(iot, ioh, SCOOP_CCR, 196 val ? SCP_CCR_RESET : 0); 197 break; 198 199 default: 200 panic("imx31lk_pcic_write: bogus register"); 201 } 202 203 splx(s); 204#else 205 panic("imx31lk_pcic_write"); 206#endif 207} 208 209static void 210imx31lk_pcic_set_power(struct imx_pcic_socket *so, int pwr) 211{ 212#ifdef NOTYET 213 bus_space_tag_t iot = so->sc->sc_iot; 214 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 215 uint16_t reg; 216 int s; 217 218 s = splhigh(); 219 220 switch (pwr) { 221 case PXAPCIC_POWER_OFF: 222#if 0 223 /* XXX does this disable power to both sockets? */ 224 reg = bus_space_read_2(iot, ioh, SCOOP_GPWR); 225 bus_space_write_2(iot, ioh, SCOOP_GPWR, 226 reg & ~(1 << SCOOP0_CF_POWER_C3000)); 227#endif 228 break; 229 230 case PXAPCIC_POWER_3V: 231 case PXAPCIC_POWER_5V: 232 /* XXX */ 233 if (so->socket == 0) { 234 reg = bus_space_read_2(iot, ioh, SCOOP_GPWR); 235 bus_space_write_2(iot, ioh, SCOOP_GPWR, 236 reg | (1 << SCOOP0_CF_POWER_C3000)); 237 } 238 break; 239 240 default: 241 splx(s); 242 panic("imx31lk_pcic_set_power: bogus power state"); 243 } 244 245 splx(s); 246#else 247 panic("imx31lk_pcic_set_power"); 248#endif 249} 250 251static void 252imx31lk_pcic_clear_intr(struct imx_pcic_socket *so) 253{ 254#ifdef NOTYET 255 bus_space_tag_t iot = so->sc->sc_iot; 256 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 257 258 bus_space_write_2(iot, ioh, SCOOP_IRM, 0x00ff); 259 bus_space_write_2(iot, ioh, SCOOP_ISR, 0x0000); 260 bus_space_write_2(iot, ioh, SCOOP_IRM, 0x0000); 261#else 262 panic("imx31lk_pcic_clear_intr"); 263#endif 264} 265 266static void * 267imx31lk_pcic_intr_establish(struct imx_pcic_socket *so, int ipl, 268 int (*func)(void *), void *arg) 269{ 270#ifdef NOTYET 271printf("%s: irqpin %d\n", __func__, so->irqpin); 272 return (imx_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING, 273 ipl, "pcic", func, arg)); 274#else 275 return 0; /* XXX */ 276#endif 277} 278 279static void 280imx31lk_pcic_intr_disestablish(struct imx_pcic_socket *so, void *ih) 281{ 282 283#ifdef NOTYET 284 imx_gpio_intr_disestablish(ih); 285#endif 286} 287