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