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