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 <[email protected]>
@@ -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;
+}