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