1 /* $Id: imx31lk_pcic.c,v 1.6 2012/11/12 18:00:39 skrll Exp $ */ 2 /* $NetBSD: imx31lk_pcic.c,v 1.6 2012/11/12 18:00:39 skrll 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 41 static int imx31lk_pcic_match(device_t, cfdata_t, void *); 42 static void imx31lk_pcic_attach(device_t, device_t, void *); 43 44 CFATTACH_DECL_NEW(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(device_t parent, cfdata_t cf, void *aux) 67 { 68 69 return 1; /* XXX */ 70 } 71 72 static void 73 imx31lk_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 80 printf("\n"); 81 printf("imx_iot %p\n", aipsa->aipsa_memt); 82 printf("imx_addr %lx\n", aipsa->aipsa_addr); 83 printf("imx_size %lx\n", aipsa->aipsa_size); 84 printf("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 100 static void 101 imx31lk_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 140 static u_int 141 imx31lk_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 170 static void 171 imx31lk_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 209 static void 210 imx31lk_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 251 static void 252 imx31lk_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 266 static void * 267 imx31lk_pcic_intr_establish(struct imx_pcic_socket *so, int ipl, 268 int (*func)(void *), void *arg) 269 { 270 #ifdef NOTYET 271 printf("%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 279 static void 280 imx31lk_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