xref: /dflybsd-src/sys/dev/disk/sdhci/sdhci_acpi.c (revision 4d3ae5900ccbcc3c6787707334347ba4e6da7e5e)
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