git: e00774a91750 - main - Add support for Rockchip RK3568 SDHCI controller.

From: Ganbold Tsagaankhuu <ganbold_at_FreeBSD.org>
Date: Sat, 24 Dec 2022 12:40:55 UTC
The branch main has been updated by ganbold:

URL: https://cgit.FreeBSD.org/src/commit/?id=e00774a917503e7e23c469954471c2b519e852c1

commit e00774a917503e7e23c469954471c2b519e852c1
Author:     Søren Schmidt <sos@FreeBSD.org>
AuthorDate: 2022-12-24 12:38:33 +0000
Commit:     Ganbold Tsagaankhuu <ganbold@FreeBSD.org>
CommitDate: 2022-12-24 12:38:33 +0000

    Add support for Rockchip RK3568 SDHCI controller.
---
 sys/dev/sdhci/sdhci.c     |   1 +
 sys/dev/sdhci/sdhci_fdt.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/sdhci/sdhci_if.m  |  14 +++++++
 3 files changed, 119 insertions(+)

diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c
index d8532b132ac5..a7283e66df31 100644
--- a/sys/dev/sdhci/sdhci.c
+++ b/sys/dev/sdhci/sdhci.c
@@ -419,6 +419,7 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
 
 	if (clock == slot->clock)
 		return;
+	clock = SDHCI_SET_CLOCK(slot->bus, slot, clock);
 	slot->clock = clock;
 
 	/* Turn off the clock. */
diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c
index f7e6eb27d180..dcc16a87a9f8 100644
--- a/sys/dev/sdhci/sdhci_fdt.c
+++ b/sys/dev/sdhci/sdhci_fdt.c
@@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$");
 #define	SDHCI_FDT_XLNX_ZY7	3
 #define	SDHCI_FDT_QUALCOMM	4
 #define	SDHCI_FDT_RK3399	5
+#define	SDHCI_FDT_RK3568	6
 
 #define	RK3399_GRF_EMMCCORE_CON0		0xf000
 #define	 RK3399_CORECFG_BASECLKFREQ		0xff00
@@ -84,6 +85,33 @@ __FBSDID("$FreeBSD$");
 #define	RK3399_GRF_EMMCCORE_CON11		0xf02c
 #define	 RK3399_CORECFG_CLOCKMULTIPLIER		0xff
 
+#define	RK3568_EMMC_HOST_CTRL			0x0508
+#define	RK3568_EMMC_EMMC_CTRL			0x052c
+#define	RK3568_EMMC_ATCTRL			0x0540
+#define	RK3568_EMMC_DLL_CTRL			0x0800
+#define	 DLL_CTRL_SRST				0x00000001
+#define	 DLL_CTRL_START				0x00000002
+#define	 DLL_CTRL_START_POINT_DEFAULT		0x00050000
+#define	 DLL_CTRL_INCREMENT_DEFAULT		0x00000200
+
+#define	RK3568_EMMC_DLL_RXCLK			0x0804
+#define	 DLL_RXCLK_DELAY_ENABLE			0x08000000
+#define	 DLL_RXCLK_NO_INV			0x20000000
+
+#define	RK3568_EMMC_DLL_TXCLK			0x0808
+#define	 DLL_TXCLK_DELAY_ENABLE			0x08000000
+#define	 DLL_TXCLK_TAPNUM_DEFAULT		0x00000008
+#define	 DLL_TXCLK_TAPNUM_FROM_SW		0x01000000
+
+#define	RK3568_EMMC_DLL_STRBIN			0x080c
+#define	 DLL_STRBIN_DELAY_ENABLE		0x08000000
+#define	 DLL_STRBIN_TAPNUM_DEFAULT		0x00000008
+#define	DLL_STRBIN_TAPNUM_FROM_SW		0x01000000
+
+#define	RK3568_EMMC_DLL_STATUS0			0x0840
+#define	 DLL_STATUS0_DLL_LOCK			0x00000100
+#define	 DLL_STATUS0_DLL_TIMEOUT		0x00000200
+
 #define	LOWEST_SET_BIT(mask)	((((mask) - 1) & (mask)) ^ (mask))
 #define	SHIFTIN(x, mask)	((x) * LOWEST_SET_BIT(mask))
 
@@ -95,6 +123,7 @@ static struct ofw_compat_data compat_data[] = {
 	{ "qcom,sdhci-msm-v4",		SDHCI_FDT_QUALCOMM },
 	{ "rockchip,rk3399-sdhci-5.1",	SDHCI_FDT_RK3399 },
 	{ "xlnx,zy7_sdhci",		SDHCI_FDT_XLNX_ZY7 },
+	{ "rockchip,rk3568-dwcmshc",	SDHCI_FDT_RK3568 },
 	{ NULL, 0 }
 };
 
@@ -116,6 +145,7 @@ struct sdhci_fdt_softc {
 
 	clk_t		clk_xin;	/* xin24m fixed clock */
 	clk_t		clk_ahb;	/* ahb clock */
+	clk_t		clk_core;	/* core clock */
 	phy_t		phy;		/* phy to be used */
 };
 
@@ -404,6 +434,66 @@ sdhci_fdt_get_ro(device_t bus, device_t dev)
 	return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted);
 }
 
+static int
+sdhci_fdt_set_clock(device_t dev, struct sdhci_slot *slot, int clock)
+{
+	struct sdhci_fdt_softc *sc = device_get_softc(dev);
+	int32_t val;
+	int i;
+
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
+	    SDHCI_FDT_RK3568) {
+		if (clock == 400000)
+			clock = 375000;
+
+		if (clock) {
+			clk_set_freq(sc->clk_core, clock, 0);
+
+			if (clock <= 52000000) {
+				bus_write_4(sc->mem_res[slot->num],
+				    RK3568_EMMC_DLL_CTRL, 0x0);
+				bus_write_4(sc->mem_res[slot->num],
+				    RK3568_EMMC_DLL_RXCLK, DLL_RXCLK_NO_INV);
+				bus_write_4(sc->mem_res[slot->num],
+				    RK3568_EMMC_DLL_TXCLK, 0x0);
+				bus_write_4(sc->mem_res[slot->num],
+				    RK3568_EMMC_DLL_STRBIN, 0x0);
+				return (clock);
+			}
+
+			bus_write_4(sc->mem_res[slot->num],
+			    RK3568_EMMC_DLL_CTRL, DLL_CTRL_START);
+			DELAY(1000);
+			bus_write_4(sc->mem_res[slot->num],
+			    RK3568_EMMC_DLL_CTRL, 0);
+			bus_write_4(sc->mem_res[slot->num],
+			    RK3568_EMMC_DLL_CTRL, DLL_CTRL_START_POINT_DEFAULT |
+			    DLL_CTRL_INCREMENT_DEFAULT | DLL_CTRL_START);
+			for (i = 0; i < 500; i++) {
+				val = bus_read_4(sc->mem_res[slot->num],
+				    RK3568_EMMC_DLL_STATUS0);
+				if (val & DLL_STATUS0_DLL_LOCK &&
+				    !(val & DLL_STATUS0_DLL_TIMEOUT))
+					break;
+				DELAY(1000);
+			}
+			bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL,
+			    (0x1 << 16 | 0x2 << 17 | 0x3 << 19));
+			bus_write_4(sc->mem_res[slot->num],
+			    RK3568_EMMC_DLL_RXCLK,
+			    DLL_RXCLK_DELAY_ENABLE | DLL_RXCLK_NO_INV);
+			bus_write_4(sc->mem_res[slot->num],
+			    RK3568_EMMC_DLL_TXCLK, DLL_TXCLK_DELAY_ENABLE |
+			    DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW);
+			bus_write_4(sc->mem_res[slot->num],
+			    RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE |
+			    DLL_STRBIN_TAPNUM_DEFAULT |
+			    DLL_STRBIN_TAPNUM_FROM_SW);
+		}
+	}
+	return (clock);
+}
+
 static int
 sdhci_fdt_probe(device_t dev)
 {
@@ -439,6 +529,9 @@ sdhci_fdt_probe(device_t dev)
 		sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
 		device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller");
 		break;
+	case SDHCI_FDT_RK3568:
+		device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller");
+		break;
 	default:
 		return (ENXIO);
 	}
@@ -488,6 +581,16 @@ sdhci_fdt_attach(device_t dev)
 		}
 	}
 
+	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
+	    SDHCI_FDT_RK3568) {
+		/* setup & enable clocks */
+		if (clk_get_by_ofw_name(dev, 0, "core", &sc->clk_core)) {
+			device_printf(dev, "cannot get core clock\n");
+			return (ENXIO);
+		}
+		clk_enable(sc->clk_core);
+	}
+
 	/* Scan all slots. */
 	slots = sc->num_slots;	/* number of slots determined in probe(). */
 	sc->num_slots = 0;
@@ -577,6 +680,7 @@ static device_method_t sdhci_fdt_methods[] = {
 	DEVMETHOD(sdhci_write_2,	sdhci_fdt_write_2),
 	DEVMETHOD(sdhci_write_4,	sdhci_fdt_write_4),
 	DEVMETHOD(sdhci_write_multi_4,	sdhci_fdt_write_multi_4),
+	DEVMETHOD(sdhci_set_clock,	sdhci_fdt_set_clock),
 
 	DEVMETHOD_END
 };
diff --git a/sys/dev/sdhci/sdhci_if.m b/sys/dev/sdhci/sdhci_if.m
index c888f35bdaf0..531ef0e3adec 100644
--- a/sys/dev/sdhci/sdhci_if.m
+++ b/sys/dev/sdhci/sdhci_if.m
@@ -69,6 +69,14 @@
 #include <dev/sdhci/sdhci.h>
 
 CODE {
+	static int
+	null_set_clock(device_t brdev __unused,
+	    struct sdhci_slot *slot __unused,
+	    int clock)
+	{
+		return (clock);
+	}
+
 	static void
 	null_set_uhs_timing(device_t brdev __unused,
 	    struct sdhci_slot *slot __unused)
@@ -165,6 +173,12 @@ METHOD void set_uhs_timing {
 	struct sdhci_slot	*slot;
 } DEFAULT null_set_uhs_timing;
 
+METHOD int set_clock {
+	device_t		brdev;
+	struct sdhci_slot	*slot;
+	int			clock;
+} DEFAULT null_set_clock;
+
 METHOD void reset {
 	device_t		brdev;
 	struct sdhci_slot	*slot;