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;
+}

Reply via email to