1 /* $Id: imx31lk_pcic.c,v 1.3 2008/06/30 00:49:31 perry Exp $ */ 2 /* $NetBSD: imx31lk_pcic.c,v 1.3 2008/06/30 00:49:31 perry 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.3 2008/06/30 00:49:31 perry 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 <machine/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 41 static int imx31lk_pcic_match(struct device *, struct cfdata *, void *); 42 static void imx31lk_pcic_attach(struct device *, struct device *, void *); 43 44 CFATTACH_DECL(imx31lk_pcic, sizeof(struct imx_pcic_softc), 45 imx31lk_pcic_match, imx31lk_pcic_attach, NULL, NULL); 46 47 static void imx31lk_pcic_socket_setup(struct imx_pcic_socket *); 48 static u_int imx31lk_pcic_read(struct imx_pcic_socket *, int); 49 static void imx31lk_pcic_write(struct imx_pcic_socket *, int, u_int); 50 static void imx31lk_pcic_set_power(struct imx_pcic_socket *, int); 51 static void imx31lk_pcic_clear_intr(struct imx_pcic_socket *); 52 static void *imx31lk_pcic_intr_establish(struct imx_pcic_socket *, int, 53 int (*)(void *), void *); 54 static void imx31lk_pcic_intr_disestablish(struct imx_pcic_socket *, void *); 55 56 struct 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 65 static int 66 imx31lk_pcic_match(struct device *parent, struct cfdata *cf, void *aux) 67 { 68 69 return 1; /* XXX */ 70 } 71 72 static void 73 imx31lk_pcic_attach(struct device *parent, struct device *self, void *aux) 74 { 75 struct imx_pcic_softc *sc = (struct imx_pcic_softc *)self; 76 struct aips_attach_args * const aipsa = aux; 77 78 printf("\n"); 79 printf("imx_iot %p\n", aipsa->aipsa_memt); 80 printf("imx_addr %lx\n", aipsa->aipsa_addr); 81 printf("imx_size %lx\n", aipsa->aipsa_size); 82 printf("imx_intr %d\n", aipsa->aipsa_intr); 83 84 sc->sc_pa = aipsa->aipsa_addr; 85 sc->sc_iot = aipsa->aipsa_memt; 86 87 sc->sc_nslots = 1; 88 #ifdef NOTYET 89 sc->sc_irqpin[0] = aa->emifs_intr; /* XXX */ 90 sc->sc_irqcfpin[0] = -1; /* XXX */ 91 #endif 92 93 sc->sc_flags |= PPF_REVERSE_ORDER; 94 95 imx_pcic_attach_common(sc, &imx31lk_pcic_socket_setup); 96 } 97 98 static void 99 imx31lk_pcic_socket_setup(struct imx_pcic_socket *so) 100 { 101 struct imx_pcic_softc *sc; 102 bus_addr_t pa; 103 bus_size_t size = 0x2000; /* XXX */ 104 bus_space_tag_t iot; 105 bus_space_handle_t imx31lkh; 106 int error; 107 108 sc = so->sc; 109 iot = sc->sc_iot; 110 111 if (so->socket != 0) 112 panic("%s: CF slot %d not supported", sc->sc_dev.dv_xname, so->socket); 113 114 pa = sc->sc_pa; 115 116 error = bus_space_map(iot, trunc_page(pa), round_page(size), 117 0, &imx31lkh); 118 if (error) { 119 panic("%s: failed to map memory %x for imx31lk", 120 sc->sc_dev.dv_xname, (uint32_t)pa); 121 } 122 imx31lkh += pa - trunc_page(pa); 123 124 #ifdef NOTYET 125 /* setup */ 126 #endif 127 128 #ifdef NOTYET 129 so->power_capability = PXAPCIC_POWER_3V; 130 if (so->socket == 0) 131 so->power_capability |= PXAPCIC_POWER_5V; 132 #endif 133 134 so->pcictag_cookie = (void *)imx31lkh; 135 so->pcictag = &imx31lk_pcic_functions; 136 } 137 138 static u_int 139 imx31lk_pcic_read(struct imx_pcic_socket *so, int reg) 140 { 141 #ifdef NOTYET 142 bus_space_tag_t iot = so->sc->sc_iot; 143 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 144 uint16_t csr; 145 146 csr = bus_space_read_2(iot, ioh, SCOOP_CSR); 147 148 switch (reg) { 149 case PXAPCIC_CARD_STATUS: 150 if (csr & SCP_CSR_MISSING) 151 return (PXAPCIC_CARD_INVALID); 152 else 153 return (PXAPCIC_CARD_VALID); 154 155 case PXAPCIC_CARD_READY: 156 return ((bus_space_read_2(iot, ioh, SCOOP_CSR) & 157 SCP_CSR_READY) != 0); 158 159 default: 160 panic("imx31lk_pcic_read: bogus register"); 161 } 162 /*NOTREACHED*/ 163 #else 164 panic("imx31lk_pcic_read"); 165 #endif 166 } 167 168 static void 169 imx31lk_pcic_write(struct imx_pcic_socket *so, int reg, u_int val) 170 { 171 #ifdef NOTYET 172 bus_space_tag_t iot = so->sc->sc_iot; 173 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 174 uint16_t newval; 175 int s; 176 177 s = splhigh(); 178 179 switch (reg) { 180 case PXAPCIC_CARD_POWER: 181 newval = bus_space_read_2(iot, ioh, SCOOP_CPR); 182 newval &= ~(SCP_CPR_PWR | SCP_CPR_3V | SCP_CPR_5V); 183 184 if (val == PXAPCIC_POWER_3V) 185 newval |= (SCP_CPR_PWR | SCP_CPR_3V); 186 else if (val == PXAPCIC_POWER_5V) 187 newval |= (SCP_CPR_PWR | SCP_CPR_5V); 188 189 bus_space_write_2(iot, ioh, SCOOP_CPR, newval); 190 break; 191 192 case PXAPCIC_CARD_RESET: 193 bus_space_write_2(iot, ioh, SCOOP_CCR, 194 val ? SCP_CCR_RESET : 0); 195 break; 196 197 default: 198 panic("imx31lk_pcic_write: bogus register"); 199 } 200 201 splx(s); 202 #else 203 panic("imx31lk_pcic_write"); 204 #endif 205 } 206 207 static void 208 imx31lk_pcic_set_power(struct imx_pcic_socket *so, int pwr) 209 { 210 #ifdef NOTYET 211 bus_space_tag_t iot = so->sc->sc_iot; 212 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 213 u_int16_t reg; 214 int s; 215 216 s = splhigh(); 217 218 switch (pwr) { 219 case PXAPCIC_POWER_OFF: 220 #if 0 221 /* XXX does this disable power to both sockets? */ 222 reg = bus_space_read_2(iot, ioh, SCOOP_GPWR); 223 bus_space_write_2(iot, ioh, SCOOP_GPWR, 224 reg & ~(1 << SCOOP0_CF_POWER_C3000)); 225 #endif 226 break; 227 228 case PXAPCIC_POWER_3V: 229 case PXAPCIC_POWER_5V: 230 /* XXX */ 231 if (so->socket == 0) { 232 reg = bus_space_read_2(iot, ioh, SCOOP_GPWR); 233 bus_space_write_2(iot, ioh, SCOOP_GPWR, 234 reg | (1 << SCOOP0_CF_POWER_C3000)); 235 } 236 break; 237 238 default: 239 splx(s); 240 panic("imx31lk_pcic_set_power: bogus power state"); 241 } 242 243 splx(s); 244 #else 245 panic("imx31lk_pcic_set_power"); 246 #endif 247 } 248 249 static void 250 imx31lk_pcic_clear_intr(struct imx_pcic_socket *so) 251 { 252 #ifdef NOTYET 253 bus_space_tag_t iot = so->sc->sc_iot; 254 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 255 256 bus_space_write_2(iot, ioh, SCOOP_IRM, 0x00ff); 257 bus_space_write_2(iot, ioh, SCOOP_ISR, 0x0000); 258 bus_space_write_2(iot, ioh, SCOOP_IRM, 0x0000); 259 #else 260 panic("imx31lk_pcic_clear_intr"); 261 #endif 262 } 263 264 static void * 265 imx31lk_pcic_intr_establish(struct imx_pcic_socket *so, int ipl, 266 int (*func)(void *), void *arg) 267 { 268 #ifdef NOTYET 269 printf("%s: irqpin %d\n", __func__, so->irqpin); 270 return (imx_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING, 271 ipl, "pcic", func, arg)); 272 #else 273 return 0; /* XXX */ 274 #endif 275 } 276 277 static void 278 imx31lk_pcic_intr_disestablish(struct imx_pcic_socket *so, void *ih) 279 { 280 281 #ifdef NOTYET 282 imx_gpio_intr_disestablish(ih); 283 #endif 284 } 285