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