diff options
| author | jmcneill <jmcneill@NetBSD.org> | 2022-01-15 14:49:43 +0000 |
|---|---|---|
| committer | jmcneill <jmcneill@NetBSD.org> | 2022-01-15 14:49:43 +0000 |
| commit | 1bec56f0c39694f0fdf64bf7399d4085e2d4aecf (patch) | |
| tree | 533e554cf5b4c17cf5875dd70d6887332b6623cd /sys/dev | |
| parent | ae008ef2e10be72043021430d593d170ee4417f5 (diff) | |
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.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/acpi/sdhc_acpi.c | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/sys/dev/acpi/sdhc_acpi.c b/sys/dev/acpi/sdhc_acpi.c index 4af2d1eb893..f74d98e91f5 100644 --- a/sys/dev/acpi/sdhc_acpi.c +++ b/sys/dev/acpi/sdhc_acpi.c @@ -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 <nonaka@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,v 1.16 2022/01/11 22:32:44 jmcneill Exp #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(struct sdhc_acpi_softc), 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_t self, void *opaque) 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 sdhc_softc *sc, struct sdhc_host *hp) 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; +} |
