1 /* $NetBSD: scoop_pcic.c,v 1.2 2006/12/17 16:07:11 peter 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.2 2006/12/17 16:07:11 peter 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(struct device *, struct cfdata *, void *); 39 static void scoop_pcic_attach(struct device *, struct device *, void *); 40 41 CFATTACH_DECL(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 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(struct device *parent, struct cfdata *cf, void *aux) 64 { 65 66 return (ZAURUS_ISC860 || ZAURUS_ISC3000); 67 } 68 69 static void 70 scoop_pcic_attach(struct device *parent, struct device *self, void *aux) 71 { 72 struct pxapcic_softc *sc = (struct pxapcic_softc *)self; 73 struct pxaip_attach_args *pxa = (struct pxaip_attach_args *)aux; 74 75 sc->sc_iot = pxa->pxa_iot; 76 77 if (ZAURUS_ISC860) { 78 sc->sc_nslots = 1; 79 sc->sc_irqpin[0] = C860_CF0_IRQ; 80 sc->sc_irqcfpin[0] = C860_CF0_IRQ_PIN; 81 } else if (ZAURUS_ISC3000) { 82 sc->sc_nslots = 2; 83 sc->sc_irqpin[0] = C3000_CF0_IRQ; 84 sc->sc_irqcfpin[0] = C3000_CF0_IRQ_PIN; 85 sc->sc_irqpin[1] = C3000_CF1_IRQ; 86 sc->sc_irqcfpin[1] = C3000_CF1_IRQ_PIN; 87 } 88 sc->sc_flags |= PPF_REVERSE_ORDER; 89 90 pxapcic_attach_common(sc, &scoop_pcic_socket_setup); 91 } 92 93 static void 94 scoop_pcic_socket_setup(struct pxapcic_socket *so) 95 { 96 struct pxapcic_softc *sc; 97 bus_addr_t pa; 98 bus_size_t size = SCOOP_SIZE; 99 bus_space_tag_t iot; 100 bus_space_handle_t scooph; 101 int error; 102 103 sc = so->sc; 104 iot = sc->sc_iot; 105 106 if (so->socket == 0) { 107 pa = C3000_SCOOP0_BASE; 108 } else if (so->socket == 1) { 109 pa = C3000_SCOOP1_BASE; 110 } else { 111 panic("%s: invalid CF slot %d", sc->sc_dev.dv_xname, 112 so->socket); 113 } 114 115 error = bus_space_map(iot, trunc_page(pa), round_page(size), 116 0, &scooph); 117 if (error) { 118 panic("%s: failed to map memory %x for scoop", 119 sc->sc_dev.dv_xname, (uint32_t)pa); 120 } 121 scooph += pa - trunc_page(pa); 122 123 bus_space_write_2(iot, scooph, SCOOP_IMR, 124 SCP_IMR_UNKN0 | SCP_IMR_UNKN1); 125 126 /* setup */ 127 bus_space_write_2(iot, scooph, SCOOP_MCR, 0x0100); 128 bus_space_write_2(iot, scooph, SCOOP_CDR, 0x0000); 129 bus_space_write_2(iot, scooph, SCOOP_CPR, 0x0000); 130 bus_space_write_2(iot, scooph, SCOOP_IMR, 0x0000); 131 bus_space_write_2(iot, scooph, SCOOP_IRM, 0x00ff); 132 bus_space_write_2(iot, scooph, SCOOP_ISR, 0x0000); 133 bus_space_write_2(iot, scooph, SCOOP_IRM, 0x0000); 134 135 /* C3000 */ 136 if (so->socket == 1) { 137 bus_space_write_2(iot, scooph, SCOOP_CPR, 0x80c1); 138 bus_space_write_2(iot, scooph, SCOOP_IMR, 0x00c4); 139 bus_space_write_2(iot, scooph, SCOOP_MCR, 0x0111); 140 } else { 141 bus_space_write_2(iot, scooph, SCOOP_CPR, 142 SCP_CPR_PWR|SCP_CPR_5V); 143 } 144 145 bus_space_write_2(iot, scooph, SCOOP_IMR, 0x00ce); 146 bus_space_write_2(iot, scooph, SCOOP_MCR, 0x0111); 147 148 /* C3000 */ 149 so->power_capability = PXAPCIC_POWER_3V; 150 if (so->socket == 0) 151 so->power_capability |= PXAPCIC_POWER_5V; 152 153 so->pcictag_cookie = (void *)scooph; 154 so->pcictag = &scoop_pcic_functions; 155 } 156 157 static u_int 158 scoop_pcic_read(struct pxapcic_socket *so, int reg) 159 { 160 bus_space_tag_t iot = so->sc->sc_iot; 161 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 162 uint16_t csr; 163 164 csr = bus_space_read_2(iot, ioh, SCOOP_CSR); 165 166 switch (reg) { 167 case PXAPCIC_CARD_STATUS: 168 if (csr & SCP_CSR_MISSING) 169 return (PXAPCIC_CARD_INVALID); 170 else 171 return (PXAPCIC_CARD_VALID); 172 173 case PXAPCIC_CARD_READY: 174 return ((bus_space_read_2(iot, ioh, SCOOP_CSR) & 175 SCP_CSR_READY) != 0); 176 177 default: 178 panic("scoop_pcic_read: bogus register"); 179 } 180 /*NOTREACHED*/ 181 } 182 183 static void 184 scoop_pcic_write(struct pxapcic_socket *so, int reg, u_int val) 185 { 186 bus_space_tag_t iot = so->sc->sc_iot; 187 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 188 uint16_t newval; 189 int s; 190 191 s = splhigh(); 192 193 switch (reg) { 194 case PXAPCIC_CARD_POWER: 195 newval = bus_space_read_2(iot, ioh, SCOOP_CPR); 196 newval &= ~(SCP_CPR_PWR | SCP_CPR_3V | SCP_CPR_5V); 197 198 if (val == PXAPCIC_POWER_3V) 199 newval |= (SCP_CPR_PWR | SCP_CPR_3V); 200 else if (val == PXAPCIC_POWER_5V) 201 newval |= (SCP_CPR_PWR | SCP_CPR_5V); 202 203 bus_space_write_2(iot, ioh, SCOOP_CPR, newval); 204 break; 205 206 case PXAPCIC_CARD_RESET: 207 bus_space_write_2(iot, ioh, SCOOP_CCR, 208 val ? SCP_CCR_RESET : 0); 209 break; 210 211 default: 212 panic("scoop_pcic_write: bogus register"); 213 } 214 215 splx(s); 216 } 217 218 static void 219 scoop_pcic_set_power(struct pxapcic_socket *so, int pwr) 220 { 221 bus_space_tag_t iot = so->sc->sc_iot; 222 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 223 u_int16_t reg; 224 int s; 225 226 s = splhigh(); 227 228 switch (pwr) { 229 case PXAPCIC_POWER_OFF: 230 #if 0 231 /* XXX does this disable power to both sockets? */ 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 #endif 236 break; 237 238 case PXAPCIC_POWER_3V: 239 case PXAPCIC_POWER_5V: 240 /* XXX */ 241 if (so->socket == 0) { 242 reg = bus_space_read_2(iot, ioh, SCOOP_GPWR); 243 bus_space_write_2(iot, ioh, SCOOP_GPWR, 244 reg | (1 << SCOOP0_CF_POWER_C3000)); 245 } 246 break; 247 248 default: 249 splx(s); 250 panic("scoop_pcic_set_power: bogus power state"); 251 } 252 253 splx(s); 254 } 255 256 static void 257 scoop_pcic_clear_intr(struct pxapcic_socket *so) 258 { 259 bus_space_tag_t iot = so->sc->sc_iot; 260 bus_space_handle_t ioh = (bus_space_handle_t)so->pcictag_cookie; 261 262 bus_space_write_2(iot, ioh, SCOOP_IRM, 0x00ff); 263 bus_space_write_2(iot, ioh, SCOOP_ISR, 0x0000); 264 bus_space_write_2(iot, ioh, SCOOP_IRM, 0x0000); 265 } 266 267 static void * 268 scoop_pcic_intr_establish(struct pxapcic_socket *so, int ipl, 269 int (*func)(void *), void *arg) 270 { 271 272 return (pxa2x0_gpio_intr_establish(so->irqpin, IST_EDGE_FALLING, 273 ipl, func, arg)); 274 } 275 276 static void 277 scoop_pcic_intr_disestablish(struct pxapcic_socket *so, void *ih) 278 { 279 280 pxa2x0_gpio_intr_disestablish(ih); 281 } 282