xref: /dragonfly/sys/dev/disk/sdhci/sdhci_acpi.c (revision 38b720cd)
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, bus_size_t off)
66 {
67 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
68 
69 	bus_barrier(sc->mem_res, 0, 0xFF,
70 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
71 	return bus_read_1(sc->mem_res, off);
72 }
73 
74 static void
75 sdhci_acpi_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
76 {
77 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
78 
79 	bus_barrier(sc->mem_res, 0, 0xFF,
80 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
81 	bus_write_1(sc->mem_res, off, val);
82 }
83 
84 static uint16_t
85 sdhci_acpi_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
86 {
87 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
88 
89 	bus_barrier(sc->mem_res, 0, 0xFF,
90 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
91 	return bus_read_2(sc->mem_res, off);
92 }
93 
94 static void
95 sdhci_acpi_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
96 {
97 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
98 
99 	bus_barrier(sc->mem_res, 0, 0xFF,
100 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
101 	bus_write_2(sc->mem_res, off, val);
102 }
103 
104 static uint32_t
105 sdhci_acpi_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
106 {
107 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
108 
109 	bus_barrier(sc->mem_res, 0, 0xFF,
110 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
111 	return bus_read_4(sc->mem_res, off);
112 }
113 
114 static void
115 sdhci_acpi_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
116 {
117 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
118 
119 	bus_barrier(sc->mem_res, 0, 0xFF,
120 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
121 	bus_write_4(sc->mem_res, off, val);
122 }
123 
124 static void
125 sdhci_acpi_read_multi_4(device_t dev, struct sdhci_slot *slot,
126     bus_size_t off, uint32_t *data, bus_size_t count)
127 {
128 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
129 
130 	bus_read_multi_stream_4(sc->mem_res, off, data, count);
131 }
132 
133 static void
134 sdhci_acpi_write_multi_4(device_t dev, struct sdhci_slot *slot,
135     bus_size_t off, uint32_t *data, bus_size_t count)
136 {
137 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
138 
139 	bus_write_multi_stream_4(sc->mem_res, off, data, count);
140 }
141 
142 static void sdhci_acpi_intr(void *arg);
143 
144 static int
145 sdhci_acpi_probe(device_t dev)
146 {
147 	static char *sdhci_ids[] = { "80860F14", "80860F16", NULL };
148 
149 	if (acpi_disabled("sdhci") ||
150 	    ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL)
151 		return (ENXIO);
152 
153 	device_set_desc(dev, "SDHCI controller");
154 	return (0);
155 }
156 
157 static int
158 sdhci_acpi_attach(device_t dev)
159 {
160 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
161 	int err, rid;
162 
163 	sc->dev = dev;
164 	sc->handle = acpi_get_handle(dev);
165 
166 	/* Allocate IRQ. */
167 	rid = 0;
168 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
169 		RF_SHAREABLE);
170 	if (sc->irq_res == NULL) {
171 		device_printf(dev, "Can't allocate IRQ\n");
172 		err = ENOMEM;
173 		goto error;
174 	}
175 
176 	/* Allocate memory. */
177 	rid = 0;
178 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
179 	    RF_ACTIVE);
180 	if (sc->mem_res == NULL) {
181 		device_printf(dev, "Can't allocate memory for slot %d\n", 0);
182 		err = ENOMEM;
183 		goto error;
184 	}
185 
186 	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
187 	sc->slot.quirks = 0;
188 	if (sdhci_init_slot(dev, &sc->slot, 0) != 0) {
189 		device_printf(dev, "sdhci initialization failed\n");
190 		pci_set_powerstate(dev, PCI_POWERSTATE_D3);
191 		err = ENXIO;
192 		goto error;
193 	}
194 
195 	device_printf(dev, "%d slot(s) allocated\n", 1);
196 	/* Activate the interrupt */
197 	err = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
198 	    sdhci_acpi_intr, sc, &sc->intrhand, NULL);
199 	if (err)
200 		device_printf(dev, "Can't setup IRQ\n");
201 
202 	/* Process cards detection. */
203 	sdhci_start_slot(&sc->slot);
204 
205 	return (0);
206 
207 error:
208 	if (sc->irq_res != NULL) {
209 		bus_release_resource(dev, SYS_RES_IRQ,
210 		    rman_get_rid(sc->irq_res), sc->irq_res);
211 	}
212 	if (sc->mem_res != NULL) {
213 		bus_release_resource(dev, SYS_RES_MEMORY,
214 		    rman_get_rid(sc->mem_res), sc->mem_res);
215 	}
216 	return (err);
217 }
218 
219 static int
220 sdhci_acpi_detach(device_t dev)
221 {
222 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
223 
224 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
225 	bus_release_resource(dev, SYS_RES_IRQ,
226 	    rman_get_rid(sc->irq_res), sc->irq_res);
227 
228 	sdhci_cleanup_slot(&sc->slot);
229 	bus_release_resource(dev, SYS_RES_MEMORY,
230 	    rman_get_rid(sc->mem_res), sc->mem_res);
231 	pci_set_powerstate(dev, PCI_POWERSTATE_D3);
232 	return (0);
233 }
234 
235 static int
236 sdhci_acpi_suspend(device_t dev)
237 {
238 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
239 	int err;
240 
241 	err = bus_generic_suspend(dev);
242 	if (err)
243 		return (err);
244 	sdhci_generic_suspend(&sc->slot);
245 	return (0);
246 }
247 
248 static int
249 sdhci_acpi_resume(device_t dev)
250 {
251 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
252 
253 	sdhci_generic_resume(&sc->slot);
254 	return (bus_generic_resume(dev));
255 }
256 
257 static void
258 sdhci_acpi_intr(void *arg)
259 {
260 	struct sdhci_acpi_softc *sc = (struct sdhci_acpi_softc *)arg;
261 
262 	sdhci_generic_intr(&sc->slot);
263 }
264 
265 static device_method_t sdhci_methods[] = {
266 	/* device_if */
267 	DEVMETHOD(device_probe, sdhci_acpi_probe),
268 	DEVMETHOD(device_attach, sdhci_acpi_attach),
269 	DEVMETHOD(device_detach, sdhci_acpi_detach),
270 	DEVMETHOD(device_suspend, sdhci_acpi_suspend),
271 	DEVMETHOD(device_resume, sdhci_acpi_resume),
272 
273 	/* Bus interface */
274 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
275 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
276 
277 	/* mmcbr_if */
278 	DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
279 	DEVMETHOD(mmcbr_request, sdhci_generic_request),
280 	DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro),
281 	DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
282 	DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
283 
284 	/* SDHCI registers accessors */
285 	DEVMETHOD(sdhci_read_1,		sdhci_acpi_read_1),
286 	DEVMETHOD(sdhci_read_2,		sdhci_acpi_read_2),
287 	DEVMETHOD(sdhci_read_4,		sdhci_acpi_read_4),
288 	DEVMETHOD(sdhci_read_multi_4,	sdhci_acpi_read_multi_4),
289 	DEVMETHOD(sdhci_write_1,	sdhci_acpi_write_1),
290 	DEVMETHOD(sdhci_write_2,	sdhci_acpi_write_2),
291 	DEVMETHOD(sdhci_write_4,	sdhci_acpi_write_4),
292 	DEVMETHOD(sdhci_write_multi_4,	sdhci_acpi_write_multi_4),
293 
294 	DEVMETHOD_END
295 };
296 
297 static driver_t sdhci_acpi_driver = {
298 	"sdhci_acpi",
299 	sdhci_methods,
300 	sizeof(struct sdhci_acpi_softc),
301 };
302 static devclass_t sdhci_acpi_devclass;
303 
304 DRIVER_MODULE(sdhci_acpi, acpi, sdhci_acpi_driver, sdhci_acpi_devclass, NULL,
305     NULL);
306 MODULE_DEPEND(sdhci_acpi, sdhci, 1, 1, 1);
307