xref: /dragonfly/sys/dev/disk/sdhci/sdhci_acpi.c (revision 70344474)
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 #define INTEL_ATOM_QUIRKS_SDCARD					\
147 	SDHCI_QUIRK_WHITELIST_ADMA2 | SDHCI_QUIRK_WAIT_WHILE_BUSY
148 #define INTEL_ATOM_QUIRKS_EMMC						\
149 	INTEL_ATOM_QUIRKS_SDCARD | SDHCI_QUIRK_MMC_DDR52 |		\
150 	SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 | SDHCI_QUIRK_PRESET_VALUE_BROKEN
151 
152 static struct {
153 	char *hid;
154 	char *uid;
155 	u_int quirks;
156 } sdhci_devices[] = {
157 	/* The Intel Atom integrated controllers work fine with ADMA2. */
158 	/* Bay Trail / Braswell */
159 	{"80860F14", "1", INTEL_ATOM_QUIRKS_EMMC},
160 	{"80860F14", "3", INTEL_ATOM_QUIRKS_SDCARD},
161 	{"80860F16", NULL, INTEL_ATOM_QUIRKS_SDCARD},
162 	/* Apollo Lake */
163 	{"80865ACA", NULL,
164 	    SDHCI_QUIRK_BROKEN_DMA |	/* APL18 erratum */
165 	    INTEL_ATOM_QUIRKS_SDCARD},
166 	{"80865ACC", NULL,
167 	    SDHCI_QUIRK_BROKEN_DMA |	/* APL18 erratum */
168 	    INTEL_ATOM_QUIRKS_EMMC},
169 };
170 
171 static char *sdhci_ids[] = {
172 	"80860F14",
173 	"80860F16",
174 	"80865ACA",
175 	"80865ACC",
176 	NULL
177 };
178 
179 static int
180 sdhci_acpi_probe(device_t dev)
181 {
182 	if (acpi_disabled("sdhci"))
183 		return (ENXIO);
184 
185 	if (ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL)
186 		return (ENXIO);
187 
188 	device_set_desc(dev, "SDHCI controller");
189 	return (0);
190 }
191 
192 static int
193 sdhci_acpi_attach(device_t dev)
194 {
195 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
196 	char *id;
197 	int err, i, rid, quirks;
198 
199 	id = ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids);
200 	if (id == NULL)
201 		return (ENXIO);
202 
203 	sc->dev = dev;
204 	sc->handle = acpi_get_handle(dev);
205 
206 	quirks = 0;
207 	for (i = 0; i < NELEM(sdhci_devices); i++) {
208 		if (strcmp(sdhci_devices[i].hid, id) == 0 &&
209 		    (sdhci_devices[i].uid == NULL ||
210 		     acpi_MatchUid(sc->handle, sdhci_devices[i].uid))) {
211 			quirks = sdhci_devices[i].quirks;
212 			break;
213 		}
214 	}
215 	quirks &= ~sdhci_quirk_clear;
216 	quirks |= sdhci_quirk_set;
217 
218 	/* Allocate IRQ. */
219 	rid = 0;
220 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
221 		RF_SHAREABLE);
222 	if (sc->irq_res == NULL) {
223 		device_printf(dev, "Can't allocate IRQ\n");
224 		err = ENOMEM;
225 		goto error;
226 	}
227 
228 	/* Allocate memory. */
229 	rid = 0;
230 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
231 	    RF_ACTIVE);
232 	if (sc->mem_res == NULL) {
233 		device_printf(dev, "Can't allocate memory for slot %d\n", 0);
234 		err = ENOMEM;
235 		goto error;
236 	}
237 
238 	pci_set_powerstate(dev, PCI_POWERSTATE_D0);
239 
240 	sc->slot.quirks = quirks;
241 	if (sdhci_init_slot(dev, &sc->slot, 0) != 0) {
242 		device_printf(dev, "sdhci initialization failed\n");
243 		pci_set_powerstate(dev, PCI_POWERSTATE_D3);
244 		err = ENXIO;
245 		goto error;
246 	}
247 
248 	device_printf(dev, "%d slot(s) allocated\n", 1);
249 	/* Activate the interrupt */
250 	err = bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE,
251 	    sdhci_acpi_intr, sc, &sc->intrhand, NULL);
252 	if (err)
253 		device_printf(dev, "Can't setup IRQ\n");
254 
255 	/* Process cards detection. */
256 	sdhci_start_slot(&sc->slot);
257 
258 	return (0);
259 
260 error:
261 	if (sc->irq_res != NULL) {
262 		bus_release_resource(dev, SYS_RES_IRQ,
263 		    rman_get_rid(sc->irq_res), sc->irq_res);
264 	}
265 	if (sc->mem_res != NULL) {
266 		bus_release_resource(dev, SYS_RES_MEMORY,
267 		    rman_get_rid(sc->mem_res), sc->mem_res);
268 	}
269 	return (err);
270 }
271 
272 static int
273 sdhci_acpi_detach(device_t dev)
274 {
275 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
276 
277 	bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
278 	bus_release_resource(dev, SYS_RES_IRQ,
279 	    rman_get_rid(sc->irq_res), sc->irq_res);
280 
281 	sdhci_cleanup_slot(&sc->slot);
282 	bus_release_resource(dev, SYS_RES_MEMORY,
283 	    rman_get_rid(sc->mem_res), sc->mem_res);
284 	pci_set_powerstate(dev, PCI_POWERSTATE_D3);
285 	return (0);
286 }
287 
288 static int
289 sdhci_acpi_suspend(device_t dev)
290 {
291 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
292 	int err;
293 
294 	err = bus_generic_suspend(dev);
295 	if (err)
296 		return (err);
297 	sdhci_generic_suspend(&sc->slot);
298 	return (0);
299 }
300 
301 static int
302 sdhci_acpi_resume(device_t dev)
303 {
304 	struct sdhci_acpi_softc *sc = device_get_softc(dev);
305 
306 	sdhci_generic_resume(&sc->slot);
307 	return (bus_generic_resume(dev));
308 }
309 
310 static void
311 sdhci_acpi_intr(void *arg)
312 {
313 	struct sdhci_acpi_softc *sc = (struct sdhci_acpi_softc *)arg;
314 
315 	sdhci_generic_intr(&sc->slot);
316 }
317 
318 static device_method_t sdhci_methods[] = {
319 	/* device_if */
320 	DEVMETHOD(device_probe, sdhci_acpi_probe),
321 	DEVMETHOD(device_attach, sdhci_acpi_attach),
322 	DEVMETHOD(device_detach, sdhci_acpi_detach),
323 	DEVMETHOD(device_suspend, sdhci_acpi_suspend),
324 	DEVMETHOD(device_resume, sdhci_acpi_resume),
325 
326 	/* Bus interface */
327 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
328 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
329 
330 	/* mmcbr_if */
331 	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
332 	DEVMETHOD(mmcbr_switch_vccq,	sdhci_generic_switch_vccq),
333 	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
334 	DEVMETHOD(mmcbr_get_ro,		sdhci_generic_get_ro),
335 	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
336 	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
337 
338 	/* SDHCI accessors */
339 	DEVMETHOD(sdhci_read_1,		sdhci_acpi_read_1),
340 	DEVMETHOD(sdhci_read_2,		sdhci_acpi_read_2),
341 	DEVMETHOD(sdhci_read_4,		sdhci_acpi_read_4),
342 	DEVMETHOD(sdhci_read_multi_4,	sdhci_acpi_read_multi_4),
343 	DEVMETHOD(sdhci_write_1,	sdhci_acpi_write_1),
344 	DEVMETHOD(sdhci_write_2,	sdhci_acpi_write_2),
345 	DEVMETHOD(sdhci_write_4,	sdhci_acpi_write_4),
346 	DEVMETHOD(sdhci_write_multi_4,	sdhci_acpi_write_multi_4),
347 	DEVMETHOD(sdhci_set_uhs_timing,	sdhci_generic_set_uhs_timing),
348 
349 	DEVMETHOD_END
350 };
351 
352 static driver_t sdhci_acpi_driver = {
353 	"sdhci_acpi",
354 	sdhci_methods,
355 	sizeof(struct sdhci_acpi_softc),
356 	.gpri = KOBJ_GPRI_ACPI
357 };
358 static devclass_t sdhci_acpi_devclass;
359 
360 DRIVER_MODULE(sdhci_acpi, acpi, sdhci_acpi_driver, sdhci_acpi_devclass, NULL,
361     NULL);
362 MODULE_DEPEND(sdhci_acpi, sdhci, 1, 1, 1);
363