1 /*- 2 * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/bus.h> 29 #include <sys/conf.h> 30 #include <sys/kernel.h> 31 #include <sys/module.h> 32 #include <sys/resource.h> 33 #include <sys/rman.h> 34 #include <sys/taskqueue.h> 35 36 #include "acpi.h" 37 #include "opt_acpi.h" 38 #include <dev/acpica/acpivar.h> 39 40 #include <bus/pci/pcivar.h> 41 42 #include <machine/stdarg.h> 43 44 #include <bus/mmc/bridge.h> 45 #include <bus/mmc/mmcreg.h> 46 #include <bus/mmc/mmcbrvar.h> 47 48 #include "sdhci.h" 49 #include "mmcbr_if.h" 50 #include "sdhci_if.h" 51 52 ACPI_MODULE_NAME("sdhci_acpi"); 53 54 struct sdhci_acpi_softc { 55 device_t dev; /* Controller device */ 56 ACPI_HANDLE handle; 57 struct resource *irq_res; /* IRQ resource */ 58 void *intrhand; /* Interrupt handle */ 59 60 struct sdhci_slot slot; 61 struct resource *mem_res; /* Memory resource */ 62 }; 63 64 static uint8_t 65 sdhci_acpi_read_1(device_t dev, struct sdhci_slot *slot __unused, 66 bus_size_t off) 67 { 68 struct sdhci_acpi_softc *sc = device_get_softc(dev); 69 70 bus_barrier(sc->mem_res, 0, 0xFF, 71 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 72 return bus_read_1(sc->mem_res, off); 73 } 74 75 static void 76 sdhci_acpi_write_1(device_t dev, struct sdhci_slot *slot __unused, 77 bus_size_t off, uint8_t val) 78 { 79 struct sdhci_acpi_softc *sc = device_get_softc(dev); 80 81 bus_barrier(sc->mem_res, 0, 0xFF, 82 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 83 bus_write_1(sc->mem_res, off, val); 84 } 85 86 static uint16_t 87 sdhci_acpi_read_2(device_t dev, struct sdhci_slot *slot __unused, 88 bus_size_t off) 89 { 90 struct sdhci_acpi_softc *sc = device_get_softc(dev); 91 92 bus_barrier(sc->mem_res, 0, 0xFF, 93 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 94 return bus_read_2(sc->mem_res, off); 95 } 96 97 static void 98 sdhci_acpi_write_2(device_t dev, struct sdhci_slot *slot __unused, 99 bus_size_t off, uint16_t val) 100 { 101 struct sdhci_acpi_softc *sc = device_get_softc(dev); 102 103 bus_barrier(sc->mem_res, 0, 0xFF, 104 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 105 bus_write_2(sc->mem_res, off, val); 106 } 107 108 static uint32_t 109 sdhci_acpi_read_4(device_t dev, struct sdhci_slot *slot __unused, 110 bus_size_t off) 111 { 112 struct sdhci_acpi_softc *sc = device_get_softc(dev); 113 114 bus_barrier(sc->mem_res, 0, 0xFF, 115 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 116 return bus_read_4(sc->mem_res, off); 117 } 118 119 static void 120 sdhci_acpi_write_4(device_t dev, struct sdhci_slot *slot __unused, 121 bus_size_t off, uint32_t val) 122 { 123 struct sdhci_acpi_softc *sc = device_get_softc(dev); 124 125 bus_barrier(sc->mem_res, 0, 0xFF, 126 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 127 bus_write_4(sc->mem_res, off, val); 128 } 129 130 static void 131 sdhci_acpi_read_multi_4(device_t dev, struct sdhci_slot *slot __unused, 132 bus_size_t off, uint32_t *data, bus_size_t count) 133 { 134 struct sdhci_acpi_softc *sc = device_get_softc(dev); 135 136 bus_read_multi_stream_4(sc->mem_res, off, data, count); 137 } 138 139 static void 140 sdhci_acpi_write_multi_4(device_t dev, struct sdhci_slot *slot __unused, 141 bus_size_t off, uint32_t *data, bus_size_t count) 142 { 143 struct sdhci_acpi_softc *sc = device_get_softc(dev); 144 145 bus_write_multi_stream_4(sc->mem_res, off, data, count); 146 } 147 148 static void sdhci_acpi_intr(void *arg); 149 150 static int 151 sdhci_acpi_probe(device_t dev) 152 { 153 static char *sdhci_ids[] = { "80860F14", "80860F16", NULL }; 154 155 if (acpi_disabled("sdhci") || 156 ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL) 157 return (ENXIO); 158 159 device_set_desc(dev, "SDHCI controller"); 160 return (0); 161 } 162 163 static int 164 sdhci_acpi_attach(device_t dev) 165 { 166 struct sdhci_acpi_softc *sc = device_get_softc(dev); 167 int err, rid; 168 169 sc->dev = dev; 170 sc->handle = acpi_get_handle(dev); 171 172 /* Allocate IRQ. */ 173 rid = 0; 174 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 175 RF_SHAREABLE); 176 if (sc->irq_res == NULL) { 177 device_printf(dev, "Can't allocate IRQ\n"); 178 err = ENOMEM; 179 goto error; 180 } 181 182 /* Allocate memory. */ 183 rid = 0; 184 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 185 RF_ACTIVE); 186 if (sc->mem_res == NULL) { 187 device_printf(dev, "Can't allocate memory for slot %d\n", 0); 188 err = ENOMEM; 189 goto error; 190 } 191 192 pci_set_powerstate(dev, PCI_POWERSTATE_D0); 193 /* The Intel sdhci controllers all work fine with ADMA2. */ 194 sc->slot.quirks = SDHCI_QUIRK_WHITELIST_ADMA2; 195 if (sdhci_init_slot(dev, &sc->slot, 0) != 0) { 196 device_printf(dev, "sdhci initialization failed\n"); 197 pci_set_powerstate(dev, PCI_POWERSTATE_D3); 198 err = ENXIO; 199 goto error; 200 } 201 202 device_printf(dev, "%d slot(s) allocated\n", 1); 203 /* Activate the interrupt */ 204 err = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE, 205 sdhci_acpi_intr, sc, &sc->intrhand, NULL); 206 if (err) 207 device_printf(dev, "Can't setup IRQ\n"); 208 209 /* Process cards detection. */ 210 sdhci_start_slot(&sc->slot); 211 212 return (0); 213 214 error: 215 if (sc->irq_res != NULL) { 216 bus_release_resource(dev, SYS_RES_IRQ, 217 rman_get_rid(sc->irq_res), sc->irq_res); 218 } 219 if (sc->mem_res != NULL) { 220 bus_release_resource(dev, SYS_RES_MEMORY, 221 rman_get_rid(sc->mem_res), sc->mem_res); 222 } 223 return (err); 224 } 225 226 static int 227 sdhci_acpi_detach(device_t dev) 228 { 229 struct sdhci_acpi_softc *sc = device_get_softc(dev); 230 231 bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 232 bus_release_resource(dev, SYS_RES_IRQ, 233 rman_get_rid(sc->irq_res), sc->irq_res); 234 235 sdhci_cleanup_slot(&sc->slot); 236 bus_release_resource(dev, SYS_RES_MEMORY, 237 rman_get_rid(sc->mem_res), sc->mem_res); 238 pci_set_powerstate(dev, PCI_POWERSTATE_D3); 239 return (0); 240 } 241 242 static int 243 sdhci_acpi_suspend(device_t dev) 244 { 245 struct sdhci_acpi_softc *sc = device_get_softc(dev); 246 int err; 247 248 err = bus_generic_suspend(dev); 249 if (err) 250 return (err); 251 sdhci_generic_suspend(&sc->slot); 252 return (0); 253 } 254 255 static int 256 sdhci_acpi_resume(device_t dev) 257 { 258 struct sdhci_acpi_softc *sc = device_get_softc(dev); 259 260 sdhci_generic_resume(&sc->slot); 261 return (bus_generic_resume(dev)); 262 } 263 264 static void 265 sdhci_acpi_intr(void *arg) 266 { 267 struct sdhci_acpi_softc *sc = (struct sdhci_acpi_softc *)arg; 268 269 sdhci_generic_intr(&sc->slot); 270 } 271 272 static device_method_t sdhci_methods[] = { 273 /* device_if */ 274 DEVMETHOD(device_probe, sdhci_acpi_probe), 275 DEVMETHOD(device_attach, sdhci_acpi_attach), 276 DEVMETHOD(device_detach, sdhci_acpi_detach), 277 DEVMETHOD(device_suspend, sdhci_acpi_suspend), 278 DEVMETHOD(device_resume, sdhci_acpi_resume), 279 280 /* Bus interface */ 281 DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), 282 DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), 283 284 /* mmcbr_if */ 285 DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), 286 DEVMETHOD(mmcbr_request, sdhci_generic_request), 287 DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), 288 DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), 289 DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), 290 291 /* SDHCI registers accessors */ 292 DEVMETHOD(sdhci_read_1, sdhci_acpi_read_1), 293 DEVMETHOD(sdhci_read_2, sdhci_acpi_read_2), 294 DEVMETHOD(sdhci_read_4, sdhci_acpi_read_4), 295 DEVMETHOD(sdhci_read_multi_4, sdhci_acpi_read_multi_4), 296 DEVMETHOD(sdhci_write_1, sdhci_acpi_write_1), 297 DEVMETHOD(sdhci_write_2, sdhci_acpi_write_2), 298 DEVMETHOD(sdhci_write_4, sdhci_acpi_write_4), 299 DEVMETHOD(sdhci_write_multi_4, sdhci_acpi_write_multi_4), 300 301 DEVMETHOD_END 302 }; 303 304 static driver_t sdhci_acpi_driver = { 305 "sdhci_acpi", 306 sdhci_methods, 307 sizeof(struct sdhci_acpi_softc), 308 }; 309 static devclass_t sdhci_acpi_devclass; 310 311 DRIVER_MODULE(sdhci_acpi, acpi, sdhci_acpi_driver, sdhci_acpi_devclass, NULL, 312 NULL); 313 MODULE_DEPEND(sdhci_acpi, sdhci, 1, 1, 1); 314