xref: /netbsd-src/sys/dev/acpi/sdhc_acpi.c (revision da79f4d789854dd7df0356d40f186d52b8d38c4a)
1*da79f4d7Sskrll /*	$NetBSD: sdhc_acpi.c,v 1.22 2024/08/17 07:00:35 skrll Exp $	*/
2038e2d2dSnonaka 
3038e2d2dSnonaka /*
4038e2d2dSnonaka  * Copyright (c) 2016 Kimihiro Nonaka <nonaka@NetBSD.org>
5038e2d2dSnonaka  * All rights reserved.
6038e2d2dSnonaka  *
7038e2d2dSnonaka  * Redistribution and use in source and binary forms, with or without
8038e2d2dSnonaka  * modification, are permitted provided that the following conditions
9038e2d2dSnonaka  * are met:
10038e2d2dSnonaka  * 1. Redistributions of source code must retain the above copyright
11038e2d2dSnonaka  *    notice, this list of conditions and the following disclaimer.
12038e2d2dSnonaka  * 2. The name of the author may not be used to endorse or promote products
13038e2d2dSnonaka  *    derived from this software without specific prior written permission.
14038e2d2dSnonaka  *
15038e2d2dSnonaka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16038e2d2dSnonaka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17038e2d2dSnonaka  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18038e2d2dSnonaka  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19038e2d2dSnonaka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20038e2d2dSnonaka  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21038e2d2dSnonaka  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22038e2d2dSnonaka  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23038e2d2dSnonaka  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24038e2d2dSnonaka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25038e2d2dSnonaka  * SUCH DAMAGE.
26038e2d2dSnonaka  */
27038e2d2dSnonaka 
28038e2d2dSnonaka #include <sys/cdefs.h>
29*da79f4d7Sskrll __KERNEL_RCSID(0, "$NetBSD: sdhc_acpi.c,v 1.22 2024/08/17 07:00:35 skrll Exp $");
30038e2d2dSnonaka 
31038e2d2dSnonaka #include <sys/param.h>
32038e2d2dSnonaka #include <sys/device.h>
33038e2d2dSnonaka #include <sys/systm.h>
34038e2d2dSnonaka #include <sys/kmem.h>
35038e2d2dSnonaka 
36038e2d2dSnonaka #include <dev/acpi/acpireg.h>
37038e2d2dSnonaka #include <dev/acpi/acpivar.h>
38f62244a8Sjmcneill #include <dev/acpi/acpi_intr.h>
39038e2d2dSnonaka 
40038e2d2dSnonaka #include <dev/sdmmc/sdhcreg.h>
41038e2d2dSnonaka #include <dev/sdmmc/sdhcvar.h>
42038e2d2dSnonaka #include <dev/sdmmc/sdmmcvar.h>
43038e2d2dSnonaka 
448507cd68Sjmcneill /* Freescale ESDHC */
458507cd68Sjmcneill #define	SDHC_ESDHC_FLAGS	\
468507cd68Sjmcneill     (SDHC_FLAG_HAVE_DVS|SDHC_FLAG_NO_PWR0|SDHC_FLAG_32BIT_ACCESS|SDHC_FLAG_ENHANCED)
478507cd68Sjmcneill 
48f30b89bbSjmcneill /* Rockchip eMMC device-specific method (_DSM) - 434addb0-8ff3-49d5-a724-95844b79ad1f */
49f30b89bbSjmcneill static UINT8 sdhc_acpi_rockchip_dsm_uuid[ACPI_UUID_LENGTH] = {
50f30b89bbSjmcneill 	0xb0, 0xdd, 0x4a, 0x43, 0xf3, 0x8f, 0xd5, 0x49,
51f30b89bbSjmcneill 	0xa7, 0x24, 0x95, 0x84, 0x4b, 0x79, 0xad, 0x1f
52f30b89bbSjmcneill };
53f30b89bbSjmcneill #define	ROCKCHIP_DSM_REV			0
54f30b89bbSjmcneill #define	ROCKCHIP_DSM_FUNC_SET_CARD_CLOCK	1
55f30b89bbSjmcneill 
56038e2d2dSnonaka #define _COMPONENT	ACPI_RESOURCE_COMPONENT
57038e2d2dSnonaka ACPI_MODULE_NAME	("sdhc_acpi")
58038e2d2dSnonaka 
59038e2d2dSnonaka static int	sdhc_acpi_match(device_t, cfdata_t, void *);
60038e2d2dSnonaka static void	sdhc_acpi_attach(device_t, device_t, void *);
61038e2d2dSnonaka static int	sdhc_acpi_detach(device_t, int);
62038e2d2dSnonaka static bool	sdhc_acpi_resume(device_t, const pmf_qual_t *);
63038e2d2dSnonaka 
64038e2d2dSnonaka struct sdhc_acpi_softc {
65038e2d2dSnonaka 	struct sdhc_softc sc;
667003a765Snonaka 	bus_space_tag_t sc_memt;
677003a765Snonaka 	bus_space_handle_t sc_memh;
687003a765Snonaka 	bus_size_t sc_memsize;
69f62244a8Sjmcneill 	void *sc_ih;
70f30b89bbSjmcneill 	ACPI_HANDLE sc_handle;
71038e2d2dSnonaka 
72038e2d2dSnonaka 	ACPI_HANDLE sc_crs, sc_srs;
73038e2d2dSnonaka 	ACPI_BUFFER sc_crs_buffer;
74038e2d2dSnonaka };
75038e2d2dSnonaka 
76038e2d2dSnonaka CFATTACH_DECL_NEW(sdhc_acpi, sizeof(struct sdhc_acpi_softc),
77038e2d2dSnonaka     sdhc_acpi_match, sdhc_acpi_attach, sdhc_acpi_detach, NULL);
78038e2d2dSnonaka 
797003a765Snonaka static void	sdhc_acpi_intel_emmc_hw_reset(struct sdhc_softc *,
807003a765Snonaka 		    struct sdhc_host *);
81038e2d2dSnonaka 
82f30b89bbSjmcneill static int	sdhc_acpi_rockchip_bus_clock(struct sdhc_softc *,
83f30b89bbSjmcneill 		    int);
84f30b89bbSjmcneill 
857003a765Snonaka static const struct sdhc_acpi_slot {
867003a765Snonaka 	const char *hid;
877003a765Snonaka 	const char *uid;
887003a765Snonaka 	int type;
897003a765Snonaka #define	SLOT_TYPE_SD	0	/* SD or SDIO */
907003a765Snonaka #define	SLOT_TYPE_EMMC	1	/* eMMC */
918507cd68Sjmcneill 	uint32_t flags;
927003a765Snonaka } sdhc_acpi_slot_map[] = {
93d26e0438Schristos 	{ .hid = "80865ACA",		 .type = SLOT_TYPE_SD },
94d26e0438Schristos 	{ .hid = "80865ACC",		 .type = SLOT_TYPE_EMMC },
95d26e0438Schristos 	{ .hid = "80865AD0",		 .type = SLOT_TYPE_SD },
96d26e0438Schristos 	{ .hid = "80860F14", .uid = "1", .type = SLOT_TYPE_EMMC },
97d26e0438Schristos 	{ .hid = "80860F14", .uid = "3", .type = SLOT_TYPE_SD },
98d26e0438Schristos 	{ .hid = "80860F16",   		 .type = SLOT_TYPE_SD },
99d26e0438Schristos 	{ .hid = "INT33BB",  .uid = "2", .type = SLOT_TYPE_SD },
100d26e0438Schristos 	{ .hid = "INT33BB",  .uid = "3", .type = SLOT_TYPE_SD },
101d26e0438Schristos 	{ .hid = "INT33C6",		 .type = SLOT_TYPE_SD },
102d26e0438Schristos 	{ .hid = "INT3436",		 .type = SLOT_TYPE_SD },
103d26e0438Schristos 	{ .hid = "INT344D",		 .type = SLOT_TYPE_SD },
104d26e0438Schristos 	{ .hid = "NXP0003",  .uid = "0", .type = SLOT_TYPE_SD,
105d26e0438Schristos 					 .flags = SDHC_ESDHC_FLAGS },
1068fd56fc1Stnn 	{ .hid = "NXP0003",  .uid = "1", .type = SLOT_TYPE_EMMC,
107d26e0438Schristos 					 .flags = SDHC_ESDHC_FLAGS },
108f30b89bbSjmcneill 	{ .hid = "RKCP0D40",		 .type = SLOT_TYPE_SD,
109f30b89bbSjmcneill 					 .flags = SDHC_FLAG_32BIT_ACCESS |
110f30b89bbSjmcneill 						  SDHC_FLAG_8BIT_MODE |
111f30b89bbSjmcneill 						  SDHC_FLAG_SINGLE_POWER_WRITE },
112d26e0438Schristos 
1138507cd68Sjmcneill 	/* Generic IDs last */
114d26e0438Schristos 	{ .hid = "PNP0D40",		 .type = SLOT_TYPE_SD },
115d26e0438Schristos 	{ .hid = "PNP0FFF",  .uid = "3", .type = SLOT_TYPE_SD },
116038e2d2dSnonaka };
117038e2d2dSnonaka 
1187003a765Snonaka static const struct sdhc_acpi_slot *
1197003a765Snonaka sdhc_acpi_find_slot(ACPI_DEVICE_INFO *ad)
1207003a765Snonaka {
1217003a765Snonaka 	const struct sdhc_acpi_slot *slot;
1227003a765Snonaka 	const char *hid, *uid;
1237003a765Snonaka 	size_t i;
1247003a765Snonaka 
1257003a765Snonaka 	hid = ad->HardwareId.String;
1267003a765Snonaka 	uid = ad->UniqueId.String;
1277003a765Snonaka 
1287003a765Snonaka 	if (!(ad->Valid & ACPI_VALID_HID) || hid == NULL)
1297003a765Snonaka 		return NULL;
1307003a765Snonaka 
1317003a765Snonaka 	for (i = 0; i < __arraycount(sdhc_acpi_slot_map); i++) {
1327003a765Snonaka 		slot = &sdhc_acpi_slot_map[i];
133996c868aSjmcneill 		const char * const slot_id[] = { slot->hid, NULL };
134996c868aSjmcneill 		if (acpi_match_hid(ad, slot_id)) {
1357003a765Snonaka 			if (slot->uid == NULL ||
1367003a765Snonaka 			    ((ad->Valid & ACPI_VALID_UID) != 0 &&
1377003a765Snonaka 			     uid != NULL &&
1387003a765Snonaka 			     strcmp(uid, slot->uid) == 0))
1397003a765Snonaka 				return slot;
1407003a765Snonaka 		}
1417003a765Snonaka 	}
1427003a765Snonaka 	return NULL;
1437003a765Snonaka }
1447003a765Snonaka 
145038e2d2dSnonaka static int
146038e2d2dSnonaka sdhc_acpi_match(device_t parent, cfdata_t match, void *opaque)
147038e2d2dSnonaka {
148038e2d2dSnonaka 	struct acpi_attach_args *aa = opaque;
149038e2d2dSnonaka 
150038e2d2dSnonaka 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
151038e2d2dSnonaka 		return 0;
152038e2d2dSnonaka 
1537003a765Snonaka 	return sdhc_acpi_find_slot(aa->aa_node->ad_devinfo) != NULL;
154038e2d2dSnonaka }
155038e2d2dSnonaka 
156038e2d2dSnonaka static void
157038e2d2dSnonaka sdhc_acpi_attach(device_t parent, device_t self, void *opaque)
158038e2d2dSnonaka {
159038e2d2dSnonaka 	struct sdhc_acpi_softc *sc = device_private(self);
160038e2d2dSnonaka 	struct acpi_attach_args *aa = opaque;
1617003a765Snonaka 	const struct sdhc_acpi_slot *slot;
162038e2d2dSnonaka 	struct acpi_resources res;
163038e2d2dSnonaka 	struct acpi_mem *mem;
164038e2d2dSnonaka 	struct acpi_irq *irq;
165038e2d2dSnonaka 	ACPI_STATUS rv;
1663d5564abSjmcneill 	ACPI_INTEGER clock_freq;
167d76ef063Sjmcneill 	ACPI_INTEGER caps, caps_mask;
168f30b89bbSjmcneill 	ACPI_INTEGER funcs;
1690d209957Sdyoung 	bool non_removable;
170038e2d2dSnonaka 
171038e2d2dSnonaka 	sc->sc.sc_dev = self;
172038e2d2dSnonaka 	sc->sc.sc_dmat = aa->aa_dmat;
173038e2d2dSnonaka 	sc->sc.sc_host = NULL;
1747003a765Snonaka 	sc->sc_memt = aa->aa_memt;
175f30b89bbSjmcneill 	sc->sc_handle = aa->aa_node->ad_handle;
176038e2d2dSnonaka 
1777003a765Snonaka 	slot = sdhc_acpi_find_slot(aa->aa_node->ad_devinfo);
1787003a765Snonaka 	if (slot->type == SLOT_TYPE_EMMC)
1797003a765Snonaka 		sc->sc.sc_vendor_hw_reset = sdhc_acpi_intel_emmc_hw_reset;
1807003a765Snonaka 
181f30b89bbSjmcneill 	rv = acpi_dsm_query(sc->sc_handle, sdhc_acpi_rockchip_dsm_uuid,
182f30b89bbSjmcneill 	    ROCKCHIP_DSM_REV, &funcs);
183f30b89bbSjmcneill 	if (ACPI_SUCCESS(rv) &&
184f30b89bbSjmcneill 	    ISSET(funcs, __BIT(ROCKCHIP_DSM_FUNC_SET_CARD_CLOCK))) {
185f30b89bbSjmcneill 		sc->sc.sc_vendor_bus_clock = sdhc_acpi_rockchip_bus_clock;
186f30b89bbSjmcneill 	}
187f30b89bbSjmcneill 
188038e2d2dSnonaka 	rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
189038e2d2dSnonaka 	    &res, &acpi_resource_parse_ops_default);
190038e2d2dSnonaka 	if (ACPI_FAILURE(rv))
191038e2d2dSnonaka 		return;
192038e2d2dSnonaka 
193038e2d2dSnonaka 	AcpiGetHandle(aa->aa_node->ad_handle, "_CRS", &sc->sc_crs);
194038e2d2dSnonaka 	AcpiGetHandle(aa->aa_node->ad_handle, "_SRS", &sc->sc_srs);
195038e2d2dSnonaka 	if (sc->sc_crs && sc->sc_srs) {
196038e2d2dSnonaka 		/* XXX Why need this? */
197038e2d2dSnonaka 		sc->sc_crs_buffer.Pointer = NULL;
198038e2d2dSnonaka 		sc->sc_crs_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
199038e2d2dSnonaka 		rv = AcpiGetCurrentResources(sc->sc_crs, &sc->sc_crs_buffer);
200038e2d2dSnonaka 		if (ACPI_FAILURE(rv))
201038e2d2dSnonaka 			sc->sc_crs = sc->sc_srs = NULL;
202038e2d2dSnonaka 	}
203038e2d2dSnonaka 
204038e2d2dSnonaka 	mem = acpi_res_mem(&res, 0);
205038e2d2dSnonaka 	irq = acpi_res_irq(&res, 0);
206038e2d2dSnonaka 	if (mem == NULL || irq == NULL) {
207038e2d2dSnonaka 		aprint_error_dev(self, "incomplete resources\n");
208038e2d2dSnonaka 		goto cleanup;
209038e2d2dSnonaka 	}
210b23590a5Smlelstv 	if (mem->ar_length == 0) {
211b23590a5Smlelstv 		aprint_error_dev(self, "zero length memory resource\n");
212b23590a5Smlelstv 		goto cleanup;
213b23590a5Smlelstv 	}
2147003a765Snonaka 	sc->sc_memsize = mem->ar_length;
215038e2d2dSnonaka 
2167003a765Snonaka 	if (bus_space_map(sc->sc_memt, mem->ar_base, sc->sc_memsize, 0,
2177003a765Snonaka 	    &sc->sc_memh)) {
218038e2d2dSnonaka 		aprint_error_dev(self, "couldn't map registers\n");
219038e2d2dSnonaka 		goto cleanup;
220038e2d2dSnonaka 	}
221038e2d2dSnonaka 
2221a05c81cSkre 	sc->sc_ih = acpi_intr_establish(self,
2231a05c81cSkre 	    (uint64_t)(uintptr_t)aa->aa_node->ad_handle,
224f62244a8Sjmcneill 	    IPL_BIO, false, sdhc_intr, &sc->sc, device_xname(self));
225f62244a8Sjmcneill 	if (sc->sc_ih == NULL) {
226038e2d2dSnonaka 		aprint_error_dev(self,
227038e2d2dSnonaka 		    "couldn't establish interrupt handler\n");
2287003a765Snonaka 		goto unmap;
229038e2d2dSnonaka 	}
230038e2d2dSnonaka 
2310a827a3fSchs 	sc->sc.sc_host = kmem_zalloc(sizeof(struct sdhc_host *), KM_SLEEP);
232038e2d2dSnonaka 
2338507cd68Sjmcneill 	sc->sc.sc_flags |= slot->flags;
2348507cd68Sjmcneill 
23521c1cf7dSnonaka 	/* Enable DMA transfer */
23621c1cf7dSnonaka 	sc->sc.sc_flags |= SDHC_FLAG_USE_DMA;
23721c1cf7dSnonaka 
2380d209957Sdyoung 	rv = acpi_dsd_bool(aa->aa_node->ad_handle, "non-removable",
2390d209957Sdyoung 	    &non_removable);
2400d209957Sdyoung 	if (ACPI_SUCCESS(rv) && non_removable)
2410d209957Sdyoung 		sc->sc.sc_flags |= SDHC_FLAG_NON_REMOVABLE;
2420d209957Sdyoung 
2433d5564abSjmcneill 	/* Read clock frequency from device properties */
2443d5564abSjmcneill 	rv = acpi_dsd_integer(aa->aa_node->ad_handle, "clock-frequency",
2453d5564abSjmcneill 	    &clock_freq);
2466225e78eSjmcneill 	if (ACPI_SUCCESS(rv)) {
2473d5564abSjmcneill 		sc->sc.sc_clkbase = clock_freq / 1000;
2486225e78eSjmcneill 		sc->sc.sc_flags |= SDHC_FLAG_NO_CLKBASE;
2496225e78eSjmcneill 	}
2503d5564abSjmcneill 
251d76ef063Sjmcneill 	/* Capability overrides */
252d76ef063Sjmcneill 	caps = caps_mask = 0;
253d76ef063Sjmcneill 	acpi_dsd_integer(aa->aa_node->ad_handle, "sdhci-caps-mask", &caps_mask);
254d76ef063Sjmcneill 	acpi_dsd_integer(aa->aa_node->ad_handle, "sdhci-caps", &caps);
255d76ef063Sjmcneill 	if (caps || caps_mask) {
256d76ef063Sjmcneill 		sc->sc.sc_caps = bus_space_read_4(sc->sc_memt, sc->sc_memh,
257d76ef063Sjmcneill 		    SDHC_CAPABILITIES);
258d76ef063Sjmcneill 		sc->sc.sc_caps &= ~(caps_mask & 0xffffffff);
259d76ef063Sjmcneill 		sc->sc.sc_caps |= (caps & 0xffffffff);
260d76ef063Sjmcneill 		sc->sc.sc_caps2 = bus_space_read_4(sc->sc_memt,
261d76ef063Sjmcneill 		    sc->sc_memh, SDHC_CAPABILITIES2);
262d76ef063Sjmcneill 		sc->sc.sc_caps2 &= ~(caps_mask >> 32);
263d76ef063Sjmcneill 		sc->sc.sc_caps2 |= (caps >> 32);
264d76ef063Sjmcneill 		sc->sc.sc_flags |= SDHC_FLAG_HOSTCAPS;
265d76ef063Sjmcneill 	}
266d76ef063Sjmcneill 
2677003a765Snonaka 	if (sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh,
2687003a765Snonaka 	    sc->sc_memsize) != 0) {
269038e2d2dSnonaka 		aprint_error_dev(self, "couldn't initialize host\n");
2707003a765Snonaka 		goto fail;
271038e2d2dSnonaka 	}
272038e2d2dSnonaka 
273038e2d2dSnonaka 	if (!pmf_device_register1(self, sdhc_suspend, sdhc_acpi_resume,
274038e2d2dSnonaka 	    sdhc_shutdown)) {
275038e2d2dSnonaka 		aprint_error_dev(self, "couldn't establish powerhook\n");
276038e2d2dSnonaka 	}
277038e2d2dSnonaka 
278038e2d2dSnonaka 	acpi_resource_cleanup(&res);
279038e2d2dSnonaka 	return;
280038e2d2dSnonaka 
2817003a765Snonaka fail:
2827003a765Snonaka 	if (sc->sc.sc_host != NULL)
2837003a765Snonaka 		kmem_free(sc->sc.sc_host, sizeof(struct sdhc_host *));
2847003a765Snonaka 	sc->sc.sc_host = NULL;
285f62244a8Sjmcneill 	if (sc->sc_ih != NULL)
286f62244a8Sjmcneill 		acpi_intr_disestablish(sc->sc_ih);
287f62244a8Sjmcneill 	sc->sc_ih = NULL;
2887003a765Snonaka unmap:
2897003a765Snonaka 	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize);
2907003a765Snonaka 	sc->sc_memsize = 0;
2917003a765Snonaka cleanup:
2927003a765Snonaka 	if (sc->sc_crs_buffer.Pointer)
2937003a765Snonaka 		ACPI_FREE(sc->sc_crs_buffer.Pointer);
2947003a765Snonaka 	sc->sc_crs_buffer.Pointer = NULL;
2957003a765Snonaka 	acpi_resource_cleanup(&res);
296038e2d2dSnonaka }
297038e2d2dSnonaka 
298038e2d2dSnonaka static int
299038e2d2dSnonaka sdhc_acpi_detach(device_t self, int flags)
300038e2d2dSnonaka {
301038e2d2dSnonaka 	struct sdhc_acpi_softc *sc = device_private(self);
302038e2d2dSnonaka 	int rv;
303038e2d2dSnonaka 
304038e2d2dSnonaka 	pmf_device_deregister(self);
305038e2d2dSnonaka 
306038e2d2dSnonaka 	rv = sdhc_detach(&sc->sc, flags);
307038e2d2dSnonaka 	if (rv)
308038e2d2dSnonaka 		return rv;
309038e2d2dSnonaka 
310f62244a8Sjmcneill 	if (sc->sc_ih != NULL)
311f62244a8Sjmcneill 		acpi_intr_disestablish(sc->sc_ih);
312038e2d2dSnonaka 
313038e2d2dSnonaka 	if (sc->sc.sc_host != NULL)
314038e2d2dSnonaka 		kmem_free(sc->sc.sc_host, sizeof(struct sdhc_host *));
315038e2d2dSnonaka 
3167003a765Snonaka 	if (sc->sc_memsize > 0)
3177003a765Snonaka 		bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize);
3187003a765Snonaka 
3197003a765Snonaka 	if (sc->sc_crs_buffer.Pointer)
3207003a765Snonaka 		ACPI_FREE(sc->sc_crs_buffer.Pointer);
3217003a765Snonaka 
322038e2d2dSnonaka 	return 0;
323038e2d2dSnonaka }
324038e2d2dSnonaka 
325038e2d2dSnonaka static bool
326038e2d2dSnonaka sdhc_acpi_resume(device_t self, const pmf_qual_t *qual)
327038e2d2dSnonaka {
328038e2d2dSnonaka 	struct sdhc_acpi_softc *sc = device_private(self);
329038e2d2dSnonaka 	ACPI_STATUS rv;
330038e2d2dSnonaka 
331038e2d2dSnonaka 	if (sc->sc_crs && sc->sc_srs) {
332038e2d2dSnonaka 		rv = AcpiSetCurrentResources(sc->sc_srs, &sc->sc_crs_buffer);
333038e2d2dSnonaka 		if (ACPI_FAILURE(rv))
334038e2d2dSnonaka 			printf("%s: _SRS failed: %s\n",
335038e2d2dSnonaka 			    device_xname(self), AcpiFormatException(rv));
336038e2d2dSnonaka 	}
337038e2d2dSnonaka 
338038e2d2dSnonaka 	return sdhc_resume(self, qual);
339038e2d2dSnonaka }
340038e2d2dSnonaka 
3417003a765Snonaka static void
3427003a765Snonaka sdhc_acpi_intel_emmc_hw_reset(struct sdhc_softc *sc, struct sdhc_host *hp)
3437003a765Snonaka {
3447003a765Snonaka 	kmutex_t *plock = sdhc_host_lock(hp);
3457003a765Snonaka 	uint8_t reg;
3467003a765Snonaka 
3477003a765Snonaka 	mutex_enter(plock);
3487003a765Snonaka 
3497003a765Snonaka 	reg = sdhc_host_read_1(hp, SDHC_POWER_CTL);
3507003a765Snonaka 	reg |= 0x10;
3517003a765Snonaka 	sdhc_host_write_1(hp, SDHC_POWER_CTL, reg);
3527003a765Snonaka 
3537003a765Snonaka 	sdmmc_delay(10);
3547003a765Snonaka 
3557003a765Snonaka 	reg &= ~0x10;
3567003a765Snonaka 	sdhc_host_write_1(hp, SDHC_POWER_CTL, reg);
3577003a765Snonaka 
3587003a765Snonaka 	sdmmc_delay(1000);
3597003a765Snonaka 
3607003a765Snonaka 	mutex_exit(plock);
3617003a765Snonaka }
362f30b89bbSjmcneill 
363f30b89bbSjmcneill static int
364f30b89bbSjmcneill sdhc_acpi_rockchip_bus_clock(struct sdhc_softc *sc, int freq)
365f30b89bbSjmcneill {
366f30b89bbSjmcneill 	struct sdhc_acpi_softc *asc = (struct sdhc_acpi_softc *)sc;
367f30b89bbSjmcneill 	ACPI_STATUS rv;
368f30b89bbSjmcneill 	ACPI_OBJECT targetfreq;
369f30b89bbSjmcneill 	ACPI_OBJECT arg3;
370f30b89bbSjmcneill 	ACPI_INTEGER actfreq;
371f30b89bbSjmcneill 
372f30b89bbSjmcneill 	targetfreq.Integer.Type = ACPI_TYPE_INTEGER;
373f30b89bbSjmcneill 	targetfreq.Integer.Value = freq * 1000;
374f30b89bbSjmcneill 	arg3.Package.Type = ACPI_TYPE_PACKAGE;
375f30b89bbSjmcneill 	arg3.Package.Count = 1;
376f30b89bbSjmcneill 	arg3.Package.Elements = &targetfreq;
377f30b89bbSjmcneill 
378f30b89bbSjmcneill 	rv = acpi_dsm_integer(asc->sc_handle, sdhc_acpi_rockchip_dsm_uuid,
379f30b89bbSjmcneill 	    ROCKCHIP_DSM_REV, ROCKCHIP_DSM_FUNC_SET_CARD_CLOCK, &arg3,
380f30b89bbSjmcneill 	    &actfreq);
381f30b89bbSjmcneill 	if (ACPI_FAILURE(rv)) {
382f30b89bbSjmcneill 		aprint_error_dev(sc->sc_dev,
383f30b89bbSjmcneill 		    "eMMC Set Card Clock DSM failed: %s\n",
384f30b89bbSjmcneill 		    AcpiFormatException(rv));
385f30b89bbSjmcneill 		return ENXIO;
386f30b89bbSjmcneill 	}
387f30b89bbSjmcneill 
388f30b89bbSjmcneill 	aprint_debug_dev(sc->sc_dev,
38903f9182eSjmcneill 	    "eMMC Set Card Clock DSM returned %" PRIu64 " Hz\n", actfreq);
39003f9182eSjmcneill 	if (actfreq == 0 && freq != 0) {
391f30b89bbSjmcneill 		return EINVAL;
392f30b89bbSjmcneill 	}
393f30b89bbSjmcneill 
394f30b89bbSjmcneill 	return 0;
395f30b89bbSjmcneill }
396