Module Name: src Committed By: jmcneill Date: Sat Jan 15 14:49:43 UTC 2022
Modified Files: src/sys/dev/acpi: sdhc_acpi.c Log Message: acpi: sdhc: Add support for RK356x eMMC controller. RK356x has a DesignWare eMMC controller that is somewhat SDHCI compliant, with one major problem -- the clock divisor doesn't actually work. To change the clock card on Rockchip SoCs, the clock frequency needs to be adjusted in the Clock & Reset Unit (CRU) directly. The RK356x UEFI implementation introduces a DSM that allows drivers to request firmware assistance in setting the card clock rate, for instances like this where the divisor is broken. >From the UEFI README: Function 1: Set Card Clock The _DSM control method parameters for the Set Card Clock function are as follows: Arguments * Arg0: UUID = 434addb0-8ff3-49d5-a724-95844b79ad1f * Arg1: Revision = 0 * Arg2: Function Index = 1 * Arg3: Target card clock rate in Hz. Return The actual card clock rate in Hz. Will be less than or equal to the target clock rate. Returns 0 if the target clock rate could not be set. To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/sys/dev/acpi/sdhc_acpi.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/acpi/sdhc_acpi.c diff -u src/sys/dev/acpi/sdhc_acpi.c:1.16 src/sys/dev/acpi/sdhc_acpi.c:1.17 --- src/sys/dev/acpi/sdhc_acpi.c:1.16 Tue Jan 11 22:32:44 2022 +++ src/sys/dev/acpi/sdhc_acpi.c Sat Jan 15 14:49:43 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc_acpi.c,v 1.16 2022/01/11 22:32:44 jmcneill Exp $ */ +/* $NetBSD: sdhc_acpi.c,v 1.17 2022/01/15 14:49:43 jmcneill Exp $ */ /* * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc_acpi.c,v 1.16 2022/01/11 22:32:44 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc_acpi.c,v 1.17 2022/01/15 14:49:43 jmcneill Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -45,6 +45,14 @@ __KERNEL_RCSID(0, "$NetBSD: sdhc_acpi.c, #define SDHC_ESDHC_FLAGS \ (SDHC_FLAG_HAVE_DVS|SDHC_FLAG_NO_PWR0|SDHC_FLAG_32BIT_ACCESS|SDHC_FLAG_ENHANCED) +/* Rockchip eMMC device-specific method (_DSM) - 434addb0-8ff3-49d5-a724-95844b79ad1f */ +static UINT8 sdhc_acpi_rockchip_dsm_uuid[ACPI_UUID_LENGTH] = { + 0xb0, 0xdd, 0x4a, 0x43, 0xf3, 0x8f, 0xd5, 0x49, + 0xa7, 0x24, 0x95, 0x84, 0x4b, 0x79, 0xad, 0x1f +}; +#define ROCKCHIP_DSM_REV 0 +#define ROCKCHIP_DSM_FUNC_SET_CARD_CLOCK 1 + #define _COMPONENT ACPI_RESOURCE_COMPONENT ACPI_MODULE_NAME ("sdhc_acpi") @@ -59,6 +67,7 @@ struct sdhc_acpi_softc { bus_space_handle_t sc_memh; bus_size_t sc_memsize; void *sc_ih; + ACPI_HANDLE sc_handle; ACPI_HANDLE sc_crs, sc_srs; ACPI_BUFFER sc_crs_buffer; @@ -70,6 +79,9 @@ CFATTACH_DECL_NEW(sdhc_acpi, sizeof(stru static void sdhc_acpi_intel_emmc_hw_reset(struct sdhc_softc *, struct sdhc_host *); +static int sdhc_acpi_rockchip_bus_clock(struct sdhc_softc *, + int); + static const struct sdhc_acpi_slot { const char *hid; const char *uid; @@ -93,6 +105,11 @@ static const struct sdhc_acpi_slot { .flags = SDHC_ESDHC_FLAGS }, { .hid = "NXP0003", .uid = "1", .type = SLOT_TYPE_EMMC, .flags = SDHC_ESDHC_FLAGS }, + { .hid = "RKCP0D40", .type = SLOT_TYPE_SD, + .flags = SDHC_FLAG_32BIT_ACCESS | + SDHC_FLAG_8BIT_MODE | + SDHC_FLAG_USE_ADMA2 | + SDHC_FLAG_SINGLE_POWER_WRITE }, /* Generic IDs last */ { .hid = "PNP0D40", .type = SLOT_TYPE_SD }, @@ -149,16 +166,25 @@ sdhc_acpi_attach(device_t parent, device ACPI_STATUS rv; ACPI_INTEGER clock_freq; ACPI_INTEGER caps, caps_mask; + ACPI_INTEGER funcs; sc->sc.sc_dev = self; sc->sc.sc_dmat = aa->aa_dmat; sc->sc.sc_host = NULL; sc->sc_memt = aa->aa_memt; + sc->sc_handle = aa->aa_node->ad_handle; slot = sdhc_acpi_find_slot(aa->aa_node->ad_devinfo); if (slot->type == SLOT_TYPE_EMMC) sc->sc.sc_vendor_hw_reset = sdhc_acpi_intel_emmc_hw_reset; + rv = acpi_dsm_query(sc->sc_handle, sdhc_acpi_rockchip_dsm_uuid, + ROCKCHIP_DSM_REV, &funcs); + if (ACPI_SUCCESS(rv) && + ISSET(funcs, __BIT(ROCKCHIP_DSM_FUNC_SET_CARD_CLOCK))) { + sc->sc.sc_vendor_bus_clock = sdhc_acpi_rockchip_bus_clock; + } + rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res, &acpi_resource_parse_ops_default); if (ACPI_FAILURE(rv)) @@ -330,3 +356,37 @@ sdhc_acpi_intel_emmc_hw_reset(struct sdh mutex_exit(plock); } + +static int +sdhc_acpi_rockchip_bus_clock(struct sdhc_softc *sc, int freq) +{ + struct sdhc_acpi_softc *asc = (struct sdhc_acpi_softc *)sc; + ACPI_STATUS rv; + ACPI_OBJECT targetfreq; + ACPI_OBJECT arg3; + ACPI_INTEGER actfreq; + + targetfreq.Integer.Type = ACPI_TYPE_INTEGER; + targetfreq.Integer.Value = freq * 1000; + arg3.Package.Type = ACPI_TYPE_PACKAGE; + arg3.Package.Count = 1; + arg3.Package.Elements = &targetfreq; + + rv = acpi_dsm_integer(asc->sc_handle, sdhc_acpi_rockchip_dsm_uuid, + ROCKCHIP_DSM_REV, ROCKCHIP_DSM_FUNC_SET_CARD_CLOCK, &arg3, + &actfreq); + if (ACPI_FAILURE(rv)) { + aprint_error_dev(sc->sc_dev, + "eMMC Set Card Clock DSM failed: %s\n", + AcpiFormatException(rv)); + return ENXIO; + } + + aprint_debug_dev(sc->sc_dev, + "eMMC Set Card Clock DSM returned %lu Hz\n", actfreq); + if (actfreq == 0) { + return EINVAL; + } + + return 0; +}