xref: /dragonfly/sys/dev/disk/sdhci/sdhci_acpi.c (revision afc5d5f3)
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/kernel.h>
30 #include <sys/module.h>
31 #include <sys/resource.h>
32 #include <sys/rman.h>
33 #include <sys/taskqueue.h>
34 
35 #include "acpi.h"
36 #include "opt_acpi.h"
37 #include <dev/acpica/acpivar.h>
38 
39 #include <bus/pci/pcivar.h>
40 
41 #include <bus/mmc/bridge.h>
42 
43 #include <dev/disk/sdhci/sdhci.h>
44 
45 #include "mmcbr_if.h"
46 #include "sdhci_if.h"
47 
48 ACPI_MODULE_NAME("sdhci_acpi");
49 
50 struct sdhci_acpi_softc {
51 	device_t	dev;		/* Controller device */
52 	ACPI_HANDLE	handle;
53 	struct resource *irq_res;	/* IRQ resource */
54 	void 		*intrhand;	/* Interrupt handle */
55 
56 	struct sdhci_slot slot;
57 	struct resource	*mem_res;	/* Memory resource */
58 };
59 
60 static uint8_t
61 sdhci_acpi_read_1(device_t dev, struct sdhci_slot *slot __unused,
62     bus_size_t off)
63 {
64 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
65 
66 	bus_barrier(sc->mem_res, 0, 0xFF,
67 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
68 	return bus_read_1(sc->mem_res, off);
69 }
70 
71 static void
72 sdhci_acpi_write_1(device_t dev, struct sdhci_slot *slot __unused,
73     bus_size_t off, uint8_t val)
74 {
75 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
76 
77 	bus_barrier(sc->mem_res, 0, 0xFF,
78 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
79 	bus_write_1(sc->mem_res, off, val);
80 }
81 
82 static uint16_t
83 sdhci_acpi_read_2(device_t dev, struct sdhci_slot *slot __unused,
84     bus_size_t off)
85 {
86 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
87 
88 	bus_barrier(sc->mem_res, 0, 0xFF,
89 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
90 	return bus_read_2(sc->mem_res, off);
91 }
92 
93 static void
94 sdhci_acpi_write_2(device_t dev, struct sdhci_slot *slot __unused,
95     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 __unused,
106     bus_size_t off)
107 {
108 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
109 
110 	bus_barrier(sc->mem_res, 0, 0xFF,
111 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
112 	return bus_read_4(sc->mem_res, off);
113 }
114 
115 static void
116 sdhci_acpi_write_4(device_t dev, struct sdhci_slot *slot __unused,
117     bus_size_t off, uint32_t val)
118 {
119 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
120 
121 	bus_barrier(sc->mem_res, 0, 0xFF,
122 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
123 	bus_write_4(sc->mem_res, off, val);
124 }
125 
126 static void
127 sdhci_acpi_read_multi_4(device_t dev, struct sdhci_slot *slot __unused,
128     bus_size_t off, uint32_t *data, bus_size_t count)
129 {
130 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
131 
132 	bus_read_multi_stream_4(sc->mem_res, off, data, count);
133 }
134 
135 static void
136 sdhci_acpi_write_multi_4(device_t dev, struct sdhci_slot *slot __unused,
137     bus_size_t off, uint32_t *data, bus_size_t count)
138 {
139 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
140 
141 	bus_write_multi_stream_4(sc->mem_res, off, data, count);
142 }
143 
144 static void sdhci_acpi_intr(void *arg);
145 
146 static struct {
147 	char *hid;
148 	u_int quirks;
149 } sdhci_devices[] = {
150 	/* The Intel Bay Trail and Braswell controllers work fine with ADMA2. */
151 	{"80860F14", SDHCI_QUIRK_WHITELIST_ADMA2 | SDHCI_QUIRK_WAIT_WHILE_BUSY},
152 	{"80860F16", SDHCI_QUIRK_WHITELIST_ADMA2 | SDHCI_QUIRK_WAIT_WHILE_BUSY},
153 };
154 
155 static char *sdhci_ids[] = {
156 	"80860F14",
157 	"80860F16",
158 	NULL
159 };
160 
161 static int
162 sdhci_acpi_probe(device_t dev)
163 {
164 	if (acpi_disabled("sdhci"))
165 		return (ENXIO);
166 
167 	if (ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL)
168 		return (ENXIO);
169 
170 	device_set_desc(dev, "SDHCI controller");
171 	return (0);
172 }
173 
174 static int
175 sdhci_acpi_attach(device_t dev)
176 {
177 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
178 	char *id;
179 	int err, i, rid, quirks;
180 
181 	id = ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids);
182 	if (id == NULL)
183 		return (ENXIO);
184 
185 	sc->dev = dev;
186 	sc->handle = acpi_get_handle(dev);
187 
188 	quirks = 0;
189 	for (i = 0; i < NELEM(sdhci_devices); i++) {
190 		if (strcmp(sdhci_devices[i].hid, id) == 0) {
191 			quirks = sdhci_devices[i].quirks;
192 			break;
193 		}
194 	}
195 
196 	/* Allocate IRQ. */
197 	rid = 0;
198 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
199 		RF_SHAREABLE);
200 	if (sc->irq_res == NULL) {
201 		device_printf(dev, "Can't allocate IRQ\n");
202 		err = ENOMEM;
203 		goto error;
204 	}
205 
206 	/* Allocate memory. */
207 	rid = 0;
208 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
209 	    RF_ACTIVE);
210 	if (sc->mem_res == NULL) {
211 		device_printf(dev, "Can't allocate memory for slot %d\n", 0);
212 		err = ENOMEM;
213 		goto error;
214 	}
215 
216 	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
217 
218 	sc->slot.quirks = quirks;
219 	if (sdhci_init_slot(dev, &sc->slot, 0) != 0) {
220 		device_printf(dev, "sdhci initialization failed\n");
221 		pci_set_powerstate(dev, PCI_POWERSTATE_D3);
222 		err = ENXIO;
223 		goto error;
224 	}
225 
226 	device_printf(dev, "%d slot(s) allocated\n", 1);
227 	/* Activate the interrupt */
228 	err = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
229 	    sdhci_acpi_intr, sc, &sc->intrhand, NULL);
230 	if (err)
231 		device_printf(dev, "Can't setup IRQ\n");
232 
233 	/* Process cards detection. */
234 	sdhci_start_slot(&sc->slot);
235 
236 	return (0);
237 
238 error:
239 	if (sc->irq_res != NULL) {
240 		bus_release_resource(dev, SYS_RES_IRQ,
241 		    rman_get_rid(sc->irq_res), sc->irq_res);
242 	}
243 	if (sc->mem_res != NULL) {
244 		bus_release_resource(dev, SYS_RES_MEMORY,
245 		    rman_get_rid(sc->mem_res), sc->mem_res);
246 	}
247 	return (err);
248 }
249 
250 static int
251 sdhci_acpi_detach(device_t dev)
252 {
253 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
254 
255 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
256 	bus_release_resource(dev, SYS_RES_IRQ,
257 	    rman_get_rid(sc->irq_res), sc->irq_res);
258 
259 	sdhci_cleanup_slot(&sc->slot);
260 	bus_release_resource(dev, SYS_RES_MEMORY,
261 	    rman_get_rid(sc->mem_res), sc->mem_res);
262 	pci_set_powerstate(dev, PCI_POWERSTATE_D3);
263 	return (0);
264 }
265 
266 static int
267 sdhci_acpi_suspend(device_t dev)
268 {
269 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
270 	int err;
271 
272 	err = bus_generic_suspend(dev);
273 	if (err)
274 		return (err);
275 	sdhci_generic_suspend(&sc->slot);
276 	return (0);
277 }
278 
279 static int
280 sdhci_acpi_resume(device_t dev)
281 {
282 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
283 
284 	sdhci_generic_resume(&sc->slot);
285 	return (bus_generic_resume(dev));
286 }
287 
288 static void
289 sdhci_acpi_intr(void *arg)
290 {
291 	struct sdhci_acpi_softc *sc = (struct sdhci_acpi_softc *)arg;
292 
293 	sdhci_generic_intr(&sc->slot);
294 }
295 
296 static device_method_t sdhci_methods[] = {
297 	/* device_if */
298 	DEVMETHOD(device_probe, sdhci_acpi_probe),
299 	DEVMETHOD(device_attach, sdhci_acpi_attach),
300 	DEVMETHOD(device_detach, sdhci_acpi_detach),
301 	DEVMETHOD(device_suspend, sdhci_acpi_suspend),
302 	DEVMETHOD(device_resume, sdhci_acpi_resume),
303 
304 	/* Bus interface */
305 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
306 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
307 
308 	/* mmcbr_if */
309 	DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
310 	DEVMETHOD(mmcbr_request, sdhci_generic_request),
311 	DEVMETHOD(mmcbr_get_ro, sdhci_generic_get_ro),
312 	DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
313 	DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
314 
315 	/* SDHCI registers accessors */
316 	DEVMETHOD(sdhci_read_1,		sdhci_acpi_read_1),
317 	DEVMETHOD(sdhci_read_2,		sdhci_acpi_read_2),
318 	DEVMETHOD(sdhci_read_4,		sdhci_acpi_read_4),
319 	DEVMETHOD(sdhci_read_multi_4,	sdhci_acpi_read_multi_4),
320 	DEVMETHOD(sdhci_write_1,	sdhci_acpi_write_1),
321 	DEVMETHOD(sdhci_write_2,	sdhci_acpi_write_2),
322 	DEVMETHOD(sdhci_write_4,	sdhci_acpi_write_4),
323 	DEVMETHOD(sdhci_write_multi_4,	sdhci_acpi_write_multi_4),
324 
325 	DEVMETHOD_END
326 };
327 
328 static driver_t sdhci_acpi_driver = {
329 	"sdhci_acpi",
330 	sdhci_methods,
331 	sizeof(struct sdhci_acpi_softc),
332 };
333 static devclass_t sdhci_acpi_devclass;
334 
335 DRIVER_MODULE(sdhci_acpi, acpi, sdhci_acpi_driver, sdhci_acpi_devclass, NULL,
336     NULL);
337 MODULE_DEPEND(sdhci_acpi, sdhci, 1, 1, 1);
338