121f9f90cSImre Vadász /*- 221f9f90cSImre Vadász * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org> 321f9f90cSImre Vadász * All rights reserved. 421f9f90cSImre Vadász * 521f9f90cSImre Vadász * Redistribution and use in source and binary forms, with or without 621f9f90cSImre Vadász * modification, are permitted provided that the following conditions 721f9f90cSImre Vadász * are met: 821f9f90cSImre Vadász * 1. Redistributions of source code must retain the above copyright 921f9f90cSImre Vadász * notice, this list of conditions and the following disclaimer. 1021f9f90cSImre Vadász * 2. Redistributions in binary form must reproduce the above copyright 1121f9f90cSImre Vadász * notice, this list of conditions and the following disclaimer in the 1221f9f90cSImre Vadász * documentation and/or other materials provided with the distribution. 1321f9f90cSImre Vadász * 1421f9f90cSImre Vadász * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1521f9f90cSImre Vadász * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1621f9f90cSImre Vadász * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1721f9f90cSImre Vadász * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1821f9f90cSImre Vadász * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1921f9f90cSImre Vadász * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2021f9f90cSImre Vadász * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2121f9f90cSImre Vadász * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2221f9f90cSImre Vadász * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2321f9f90cSImre Vadász * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2421f9f90cSImre Vadász */ 2521f9f90cSImre Vadász 2621f9f90cSImre Vadász #include <sys/param.h> 2721f9f90cSImre Vadász #include <sys/systm.h> 2821f9f90cSImre Vadász #include <sys/bus.h> 2921f9f90cSImre Vadász #include <sys/kernel.h> 3021f9f90cSImre Vadász #include <sys/module.h> 3121f9f90cSImre Vadász #include <sys/resource.h> 3221f9f90cSImre Vadász #include <sys/rman.h> 3321f9f90cSImre Vadász #include <sys/taskqueue.h> 3421f9f90cSImre Vadász 3521f9f90cSImre Vadász #include "acpi.h" 3621f9f90cSImre Vadász #include "opt_acpi.h" 3721f9f90cSImre Vadász #include <dev/acpica/acpivar.h> 3821f9f90cSImre Vadász 3921f9f90cSImre Vadász #include <bus/pci/pcivar.h> 4021f9f90cSImre Vadász 4121f9f90cSImre Vadász #include <bus/mmc/bridge.h> 4221f9f90cSImre Vadász 43*4d3ae590SImre Vadász #include <dev/disk/sdhci/sdhci.h> 44*4d3ae590SImre Vadász 4521f9f90cSImre Vadász #include "mmcbr_if.h" 4621f9f90cSImre Vadász #include "sdhci_if.h" 4721f9f90cSImre Vadász 4821f9f90cSImre Vadász ACPI_MODULE_NAME("sdhci_acpi"); 4921f9f90cSImre Vadász 5021f9f90cSImre Vadász struct sdhci_acpi_softc { 5121f9f90cSImre Vadász device_t dev; /* Controller device */ 5221f9f90cSImre Vadász ACPI_HANDLE handle; 5321f9f90cSImre Vadász struct resource *irq_res; /* IRQ resource */ 5421f9f90cSImre Vadász void *intrhand; /* Interrupt handle */ 5521f9f90cSImre Vadász 5621f9f90cSImre Vadász struct sdhci_slot slot; 5721f9f90cSImre Vadász struct resource *mem_res; /* Memory resource */ 5821f9f90cSImre Vadász }; 5921f9f90cSImre Vadász 6021f9f90cSImre Vadász static uint8_t 6170a02aadSImre Vadász sdhci_acpi_read_1(device_t dev, struct sdhci_slot *slot __unused, 6270a02aadSImre Vadász bus_size_t off) 6321f9f90cSImre Vadász { 6421f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 6521f9f90cSImre Vadász 6621f9f90cSImre Vadász bus_barrier(sc->mem_res, 0, 0xFF, 6721f9f90cSImre Vadász BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 6821f9f90cSImre Vadász return bus_read_1(sc->mem_res, off); 6921f9f90cSImre Vadász } 7021f9f90cSImre Vadász 7121f9f90cSImre Vadász static void 7270a02aadSImre Vadász sdhci_acpi_write_1(device_t dev, struct sdhci_slot *slot __unused, 7370a02aadSImre Vadász bus_size_t off, uint8_t val) 7421f9f90cSImre Vadász { 7521f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 7621f9f90cSImre Vadász 7721f9f90cSImre Vadász bus_barrier(sc->mem_res, 0, 0xFF, 7821f9f90cSImre Vadász BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 7921f9f90cSImre Vadász bus_write_1(sc->mem_res, off, val); 8021f9f90cSImre Vadász } 8121f9f90cSImre Vadász 8221f9f90cSImre Vadász static uint16_t 8370a02aadSImre Vadász sdhci_acpi_read_2(device_t dev, struct sdhci_slot *slot __unused, 8470a02aadSImre Vadász bus_size_t off) 8521f9f90cSImre Vadász { 8621f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 8721f9f90cSImre Vadász 8821f9f90cSImre Vadász bus_barrier(sc->mem_res, 0, 0xFF, 8921f9f90cSImre Vadász BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 9021f9f90cSImre Vadász return bus_read_2(sc->mem_res, off); 9121f9f90cSImre Vadász } 9221f9f90cSImre Vadász 9321f9f90cSImre Vadász static void 9470a02aadSImre Vadász sdhci_acpi_write_2(device_t dev, struct sdhci_slot *slot __unused, 9570a02aadSImre Vadász bus_size_t off, uint16_t val) 9621f9f90cSImre Vadász { 9721f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 9821f9f90cSImre Vadász 9921f9f90cSImre Vadász bus_barrier(sc->mem_res, 0, 0xFF, 10021f9f90cSImre Vadász BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 10121f9f90cSImre Vadász bus_write_2(sc->mem_res, off, val); 10221f9f90cSImre Vadász } 10321f9f90cSImre Vadász 10421f9f90cSImre Vadász static uint32_t 10570a02aadSImre Vadász sdhci_acpi_read_4(device_t dev, struct sdhci_slot *slot __unused, 10670a02aadSImre Vadász bus_size_t off) 10721f9f90cSImre Vadász { 10821f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 10921f9f90cSImre Vadász 11021f9f90cSImre Vadász bus_barrier(sc->mem_res, 0, 0xFF, 11121f9f90cSImre Vadász BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 11221f9f90cSImre Vadász return bus_read_4(sc->mem_res, off); 11321f9f90cSImre Vadász } 11421f9f90cSImre Vadász 11521f9f90cSImre Vadász static void 11670a02aadSImre Vadász sdhci_acpi_write_4(device_t dev, struct sdhci_slot *slot __unused, 11770a02aadSImre Vadász bus_size_t off, uint32_t val) 11821f9f90cSImre Vadász { 11921f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 12021f9f90cSImre Vadász 12121f9f90cSImre Vadász bus_barrier(sc->mem_res, 0, 0xFF, 12221f9f90cSImre Vadász BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 12321f9f90cSImre Vadász bus_write_4(sc->mem_res, off, val); 12421f9f90cSImre Vadász } 12521f9f90cSImre Vadász 12621f9f90cSImre Vadász static void 12770a02aadSImre Vadász sdhci_acpi_read_multi_4(device_t dev, struct sdhci_slot *slot __unused, 12821f9f90cSImre Vadász bus_size_t off, uint32_t *data, bus_size_t count) 12921f9f90cSImre Vadász { 13021f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 13121f9f90cSImre Vadász 13221f9f90cSImre Vadász bus_read_multi_stream_4(sc->mem_res, off, data, count); 13321f9f90cSImre Vadász } 13421f9f90cSImre Vadász 13521f9f90cSImre Vadász static void 13670a02aadSImre Vadász sdhci_acpi_write_multi_4(device_t dev, struct sdhci_slot *slot __unused, 13721f9f90cSImre Vadász bus_size_t off, uint32_t *data, bus_size_t count) 13821f9f90cSImre Vadász { 13921f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 14021f9f90cSImre Vadász 14121f9f90cSImre Vadász bus_write_multi_stream_4(sc->mem_res, off, data, count); 14221f9f90cSImre Vadász } 14321f9f90cSImre Vadász 14421f9f90cSImre Vadász static void sdhci_acpi_intr(void *arg); 14521f9f90cSImre Vadász 14621f9f90cSImre Vadász static int 14721f9f90cSImre Vadász sdhci_acpi_probe(device_t dev) 14821f9f90cSImre Vadász { 14921f9f90cSImre Vadász static char *sdhci_ids[] = { "80860F14", "80860F16", NULL }; 15021f9f90cSImre Vadász 15121f9f90cSImre Vadász if (acpi_disabled("sdhci") || 15221f9f90cSImre Vadász ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL) 15321f9f90cSImre Vadász return (ENXIO); 15421f9f90cSImre Vadász 15521f9f90cSImre Vadász device_set_desc(dev, "SDHCI controller"); 15621f9f90cSImre Vadász return (0); 15721f9f90cSImre Vadász } 15821f9f90cSImre Vadász 15921f9f90cSImre Vadász static int 16021f9f90cSImre Vadász sdhci_acpi_attach(device_t dev) 16121f9f90cSImre Vadász { 16221f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 16321f9f90cSImre Vadász int err, rid; 16421f9f90cSImre Vadász 16521f9f90cSImre Vadász sc->dev = dev; 16621f9f90cSImre Vadász sc->handle = acpi_get_handle(dev); 16721f9f90cSImre Vadász 16821f9f90cSImre Vadász /* Allocate IRQ. */ 16921f9f90cSImre Vadász rid = 0; 17021f9f90cSImre Vadász sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 17121f9f90cSImre Vadász RF_SHAREABLE); 17221f9f90cSImre Vadász if (sc->irq_res == NULL) { 17321f9f90cSImre Vadász device_printf(dev, "Can't allocate IRQ\n"); 17421f9f90cSImre Vadász err = ENOMEM; 17521f9f90cSImre Vadász goto error; 17621f9f90cSImre Vadász } 17721f9f90cSImre Vadász 17821f9f90cSImre Vadász /* Allocate memory. */ 17921f9f90cSImre Vadász rid = 0; 18021f9f90cSImre Vadász sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 18121f9f90cSImre Vadász RF_ACTIVE); 18221f9f90cSImre Vadász if (sc->mem_res == NULL) { 18321f9f90cSImre Vadász device_printf(dev, "Can't allocate memory for slot %d\n", 0); 18421f9f90cSImre Vadász err = ENOMEM; 18521f9f90cSImre Vadász goto error; 18621f9f90cSImre Vadász } 18721f9f90cSImre Vadász 18821f9f90cSImre Vadász pci_set_powerstate(dev, PCI_POWERSTATE_D0); 1894f67f60cSImre Vadász /* The Intel sdhci controllers all work fine with ADMA2. */ 1904f67f60cSImre Vadász sc->slot.quirks = SDHCI_QUIRK_WHITELIST_ADMA2; 19121f9f90cSImre Vadász if (sdhci_init_slot(dev, &sc->slot, 0) != 0) { 19221f9f90cSImre Vadász device_printf(dev, "sdhci initialization failed\n"); 19321f9f90cSImre Vadász pci_set_powerstate(dev, PCI_POWERSTATE_D3); 19421f9f90cSImre Vadász err = ENXIO; 19521f9f90cSImre Vadász goto error; 19621f9f90cSImre Vadász } 19721f9f90cSImre Vadász 19821f9f90cSImre Vadász device_printf(dev, "%d slot(s) allocated\n", 1); 19921f9f90cSImre Vadász /* Activate the interrupt */ 20021f9f90cSImre Vadász err = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE, 20121f9f90cSImre Vadász sdhci_acpi_intr, sc, &sc->intrhand, NULL); 20221f9f90cSImre Vadász if (err) 20321f9f90cSImre Vadász device_printf(dev, "Can't setup IRQ\n"); 20421f9f90cSImre Vadász 20521f9f90cSImre Vadász /* Process cards detection. */ 20621f9f90cSImre Vadász sdhci_start_slot(&sc->slot); 20721f9f90cSImre Vadász 20821f9f90cSImre Vadász return (0); 20921f9f90cSImre Vadász 21021f9f90cSImre Vadász error: 21121f9f90cSImre Vadász if (sc->irq_res != NULL) { 21221f9f90cSImre Vadász bus_release_resource(dev, SYS_RES_IRQ, 21321f9f90cSImre Vadász rman_get_rid(sc->irq_res), sc->irq_res); 21421f9f90cSImre Vadász } 21521f9f90cSImre Vadász if (sc->mem_res != NULL) { 21621f9f90cSImre Vadász bus_release_resource(dev, SYS_RES_MEMORY, 21721f9f90cSImre Vadász rman_get_rid(sc->mem_res), sc->mem_res); 21821f9f90cSImre Vadász } 21921f9f90cSImre Vadász return (err); 22021f9f90cSImre Vadász } 22121f9f90cSImre Vadász 22221f9f90cSImre Vadász static int 22321f9f90cSImre Vadász sdhci_acpi_detach(device_t dev) 22421f9f90cSImre Vadász { 22521f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 22621f9f90cSImre Vadász 22721f9f90cSImre Vadász bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 22821f9f90cSImre Vadász bus_release_resource(dev, SYS_RES_IRQ, 22921f9f90cSImre Vadász rman_get_rid(sc->irq_res), sc->irq_res); 23021f9f90cSImre Vadász 23121f9f90cSImre Vadász sdhci_cleanup_slot(&sc->slot); 23221f9f90cSImre Vadász bus_release_resource(dev, SYS_RES_MEMORY, 23321f9f90cSImre Vadász rman_get_rid(sc->mem_res), sc->mem_res); 23421f9f90cSImre Vadász pci_set_powerstate(dev, PCI_POWERSTATE_D3); 23521f9f90cSImre Vadász return (0); 23621f9f90cSImre Vadász } 23721f9f90cSImre Vadász 23821f9f90cSImre Vadász static int 23921f9f90cSImre Vadász sdhci_acpi_suspend(device_t dev) 24021f9f90cSImre Vadász { 24121f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 24221f9f90cSImre Vadász int err; 24321f9f90cSImre Vadász 24421f9f90cSImre Vadász err = bus_generic_suspend(dev); 24521f9f90cSImre Vadász if (err) 24621f9f90cSImre Vadász return (err); 24721f9f90cSImre Vadász sdhci_generic_suspend(&sc->slot); 24821f9f90cSImre Vadász return (0); 24921f9f90cSImre Vadász } 25021f9f90cSImre Vadász 25121f9f90cSImre Vadász static int 25221f9f90cSImre Vadász sdhci_acpi_resume(device_t dev) 25321f9f90cSImre Vadász { 25421f9f90cSImre Vadász struct sdhci_acpi_softc *sc = device_get_softc(dev); 25521f9f90cSImre Vadász 25621f9f90cSImre Vadász sdhci_generic_resume(&sc->slot); 25721f9f90cSImre Vadász return (bus_generic_resume(dev)); 25821f9f90cSImre Vadász } 25921f9f90cSImre Vadász 26021f9f90cSImre Vadász static void 26121f9f90cSImre Vadász sdhci_acpi_intr(void *arg) 26221f9f90cSImre Vadász { 26321f9f90cSImre Vadász struct sdhci_acpi_softc *sc = (struct sdhci_acpi_softc *)arg; 26421f9f90cSImre Vadász 26521f9f90cSImre Vadász sdhci_generic_intr(&sc->slot); 26621f9f90cSImre Vadász } 26721f9f90cSImre Vadász 26821f9f90cSImre Vadász static device_method_t sdhci_methods[] = { 26921f9f90cSImre Vadász /* device_if */ 27021f9f90cSImre Vadász DEVMETHOD(device_probe, sdhci_acpi_probe), 27121f9f90cSImre Vadász DEVMETHOD(device_attach, sdhci_acpi_attach), 27221f9f90cSImre Vadász DEVMETHOD(device_detach, sdhci_acpi_detach), 27321f9f90cSImre Vadász DEVMETHOD(device_suspend, sdhci_acpi_suspend), 27421f9f90cSImre Vadász DEVMETHOD(device_resume, sdhci_acpi_resume), 27521f9f90cSImre Vadász 27621f9f90cSImre Vadász /* Bus interface */ 27721f9f90cSImre Vadász DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), 27821f9f90cSImre Vadász DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), 27921f9f90cSImre Vadász 28021f9f90cSImre Vadász /* mmcbr_if */ 28121f9f90cSImre Vadász DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), 28221f9f90cSImre Vadász DEVMETHOD(mmcbr_request, sdhci_generic_request), 28321f9f90cSImre Vadász DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro), 28421f9f90cSImre Vadász DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), 28521f9f90cSImre Vadász DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), 28621f9f90cSImre Vadász 28721f9f90cSImre Vadász /* SDHCI registers accessors */ 28821f9f90cSImre Vadász DEVMETHOD(sdhci_read_1, sdhci_acpi_read_1), 28921f9f90cSImre Vadász DEVMETHOD(sdhci_read_2, sdhci_acpi_read_2), 29021f9f90cSImre Vadász DEVMETHOD(sdhci_read_4, sdhci_acpi_read_4), 29121f9f90cSImre Vadász DEVMETHOD(sdhci_read_multi_4, sdhci_acpi_read_multi_4), 29221f9f90cSImre Vadász DEVMETHOD(sdhci_write_1, sdhci_acpi_write_1), 29321f9f90cSImre Vadász DEVMETHOD(sdhci_write_2, sdhci_acpi_write_2), 29421f9f90cSImre Vadász DEVMETHOD(sdhci_write_4, sdhci_acpi_write_4), 29521f9f90cSImre Vadász DEVMETHOD(sdhci_write_multi_4, sdhci_acpi_write_multi_4), 29621f9f90cSImre Vadász 29721f9f90cSImre Vadász DEVMETHOD_END 29821f9f90cSImre Vadász }; 29921f9f90cSImre Vadász 30021f9f90cSImre Vadász static driver_t sdhci_acpi_driver = { 30121f9f90cSImre Vadász "sdhci_acpi", 30221f9f90cSImre Vadász sdhci_methods, 30321f9f90cSImre Vadász sizeof(struct sdhci_acpi_softc), 30421f9f90cSImre Vadász }; 30521f9f90cSImre Vadász static devclass_t sdhci_acpi_devclass; 30621f9f90cSImre Vadász 30721f9f90cSImre Vadász DRIVER_MODULE(sdhci_acpi, acpi, sdhci_acpi_driver, sdhci_acpi_devclass, NULL, 30821f9f90cSImre Vadász NULL); 30921f9f90cSImre Vadász MODULE_DEPEND(sdhci_acpi, sdhci, 1, 1, 1); 310