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