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