[Differential] D42377: patch for sdhci_fdt.c so emmc works on rk356x boards

"titus_edc.ro (Titus Manea)" <[email protected]>
Newsgroups gmane.os.freebsd.devel.arm
Message-ID <[email protected]>
titus_edc.ro created this revision.
titus_edc.ro added a reviewer: freebsd-arm-list.
Herald added a subscriber: imp.
titus_edc.ro requested review of this revision.

REVISION SUMMARY
  mostly changed some constants and added uhs timing function (from linux)

TEST PLAN
  tested on orange pi 3b
  dts needs disable-wp otherwise the emmc is reported readonly

REPOSITORY
  rG FreeBSD src repository

REVISION DETAIL
  https://reviews.freebsd.org/D42377

AFFECTED FILES
  sys/dev/sdhci/sdhci_fdt.c

EMAIL PREFERENCES
  https://reviews.freebsd.org/settings/panel/emailpreferences/

To: titus_edc.ro, freebsd-arm-list
Cc: imp, pstef, dsl
D42377.129446.patch (text/x-patch, 7.6 KB)
diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c
--- a/sys/dev/sdhci/sdhci_fdt.c
+++ b/sys/dev/sdhci/sdhci_fdt.c
@@ -83,14 +83,16 @@
 #define	RK3399_GRF_EMMCCORE_CON11		0xf02c
 #define	 RK3399_CORECFG_CLOCKMULTIPLIER		0xff
 
+#define RK35XX_CTRL_HS400			0x7
 #define	RK3568_EMMC_HOST_CTRL			0x0508
 #define	RK3568_EMMC_EMMC_CTRL			0x052c
+#define  RK35XX_CARD_IS_EMMC			0x1
 #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				0x00000001
 #define	 DLL_CTRL_START_POINT_DEFAULT		0x00050000
 #define	 DLL_CTRL_INCREMENT_DEFAULT		0x00000200
+#define	 DLL_CTRL_BYPASS			0x01000000
 
 #define	RK3568_EMMC_DLL_RXCLK			0x0804
 #define	 DLL_RXCLK_DELAY_ENABLE			0x08000000
@@ -98,13 +100,18 @@
 
 #define	RK3568_EMMC_DLL_TXCLK			0x0808
 #define	 DLL_TXCLK_DELAY_ENABLE			0x08000000
-#define	 DLL_TXCLK_TAPNUM_DEFAULT		0x00000008
+#define	 DLL_TXCLK_TAPNUM_DEFAULT		0x00000010
 #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  DLL_STRBIN_DELAY_NUM_SEL		0x04000000
+#define  DLL_STRBIN_DELAY_NUM_OFFSET		16
+#define  DLL_STRBIN_DELAY_NUM_DEFAULT		0x16
+#define	 DLL_STRBIN_TAPNUM_FROM_SW		0x01000000
+
+#define	RK3568_EMMC_DLL_CMDOUT			0x0810
 
 #define	RK3568_EMMC_DLL_STATUS0			0x0840
 #define	 DLL_STATUS0_DLL_LOCK			0x00000100
@@ -441,30 +448,86 @@
 	return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted);
 }
 
+static void
+rk35xx_set_uhs_timing(device_t brdev, struct sdhci_slot *slot)
+{
+	uint16_t ctrl, ctrl_2;
+	const struct mmc_ios *ios;
+
+	if (slot->version < SDHCI_SPEC_300) return;
+
+	mtx_assert(&slot->mtx, MA_OWNED);
+	ios = &slot->host.ios;
+
+	ctrl_2 = sdhci_fdt_read_2(brdev, slot, SDHCI_HOST_CONTROL2);
+	/* Select Bus Speed Mode for host */
+	ctrl_2 &= ~SDHCI_CTRL2_UHS_MASK;
+
+	if ((ios->timing == bus_timing_mmc_hs200) ||
+	    (ios->timing == bus_timing_uhs_sdr104))
+		ctrl_2 |= SDHCI_CTRL2_UHS_SDR104;
+	else if (ios->timing == bus_timing_uhs_sdr12)
+		ctrl_2 |= SDHCI_CTRL2_UHS_SDR12;
+	else if ((ios->timing == bus_timing_uhs_sdr25))
+		ctrl_2 |= SDHCI_CTRL2_UHS_SDR25;
+	else if (ios->timing == bus_timing_uhs_sdr50)
+		ctrl_2 |= SDHCI_CTRL2_UHS_SDR50;
+	else if ((ios->timing == bus_timing_uhs_ddr50) ||
+		 (ios->timing == bus_timing_mmc_ddr52))
+		ctrl_2 |= SDHCI_CTRL2_UHS_DDR50;
+	else if (ios->timing == bus_timing_mmc_hs400) {
+		/* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */
+		ctrl = sdhci_fdt_read_2(brdev, slot, RK3568_EMMC_EMMC_CTRL);
+		ctrl |= RK35XX_CARD_IS_EMMC;
+		sdhci_fdt_write_2(brdev, slot, RK3568_EMMC_EMMC_CTRL, ctrl);
+		ctrl_2 |= RK35XX_CTRL_HS400;
+	}
+
+	sdhci_fdt_write_2(brdev, slot, SDHCI_HOST_CONTROL2, ctrl_2);
+/*	device_printf(brdev,"SUPER FAKE timing\n"); */
+}
+static void
+sdhci_fdt_set_uhs_timing(device_t brdev, struct sdhci_slot *slot)
+{
+if (ofw_bus_search_compatible(brdev, compat_data)->ocd_data ==
+            SDHCI_FDT_RK3568) {
+             rk35xx_set_uhs_timing(brdev, slot);
+             return;
+ } else {
+  device_printf(brdev, "UHS timings not implemented -- card might not work in UHS mode\n");
+  }
+}
+
 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;
+	uint32_t uval;
 	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);
+			uval = bus_read_4(sc->mem_res[slot->num], RK3568_EMMC_HOST_CTRL) & (~1);
+	                bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_HOST_CTRL, uval);
 
 			if (clock <= 52000000) {
 				bus_write_4(sc->mem_res[slot->num],
-				    RK3568_EMMC_DLL_CTRL, 0x0);
+				    RK3568_EMMC_DLL_CTRL, DLL_CTRL_START|DLL_CTRL_BYPASS);
 				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);
+				    RK3568_EMMC_DLL_CMDOUT, 0x0);
+
+				uval = DLL_STRBIN_DELAY_ENABLE | DLL_STRBIN_DELAY_NUM_SEL |
+				       DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
+				bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_DLL_STRBIN, uval);
 				return (clock);
 			}
 
@@ -473,6 +536,7 @@
 			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);
@@ -484,14 +548,17 @@
 					break;
 				DELAY(1000);
 			}
+
 			bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL,
-			    (0x1 << 16 | 0x2 << 17 | 0x3 << 19));
+			    (0x1 << 16 | 0x3 << 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);
+			    DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW | DLL_RXCLK_NO_INV);
+
 			bus_write_4(sc->mem_res[slot->num],
 			    RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE |
 			    DLL_STRBIN_TAPNUM_DEFAULT |
@@ -534,6 +601,7 @@
 		device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller");
 		break;
 	case SDHCI_FDT_RK3568:
+		sc->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 		device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller");
 		break;
 	case SDHCI_FDT_XLNX_ZMP:
@@ -568,6 +636,9 @@
 	struct sdhci_fdt_softc *sc = device_get_softc(dev);
 	struct sdhci_slot *slot;
 	int err, slots, rid, i, compat;
+	uint32_t temp;
+
+	char *rk35xx_clocks[] = {"bus", "timer", "axi", "block" };
 
 	sc->dev = dev;
 
@@ -613,6 +684,14 @@
 			return (ENXIO);
 		}
 		clk_enable(sc->clk_core);
+		for(i = 0; i < nitems(rk35xx_clocks);i++) {
+			clk_t clk_tmp;
+			if (clk_get_by_ofw_name(dev, 0,rk35xx_clocks[i], &clk_tmp)) {
+				device_printf(dev, "cannot get %s clock\n", rk35xx_clocks[i]);
+				return (ENXIO);
+				}
+			clk_enable(clk_tmp);
+		 }
 		break;
 	default:
 		break;
@@ -638,11 +717,15 @@
 		slot->caps = sc->caps;
 		slot->max_clk = sc->max_clk;
 		slot->sdma_boundary = sc->sdma_boundary;
-
+		temp = sdhci_fdt_read_4(dev, slot, RK3568_EMMC_HOST_CTRL) & (~1);
+		sdhci_fdt_write_4(dev, slot, RK3568_EMMC_HOST_CTRL, temp);
+		sdhci_fdt_write_4(dev, slot, RK3568_EMMC_DLL_TXCLK, 0);
+		sdhci_fdt_write_4(dev, slot, RK3568_EMMC_DLL_STRBIN, 0);
 		if (sdhci_init_slot(dev, slot, i) != 0)
 			continue;
 
 		sc->num_slots++;
+
 	}
 	device_printf(dev, "%d slot(s) allocated\n", sc->num_slots);
 
@@ -658,6 +741,7 @@
 	for (i = 0; i < sc->num_slots; i++)
 		sdhci_start_slot(&sc->slots[i]);
 
+
 	return (0);
 }
 
@@ -697,6 +781,10 @@
 	DEVMETHOD(mmcbr_get_ro,		sdhci_fdt_get_ro),
 	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
 	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
+	DEVMETHOD(mmcbr_tune,           sdhci_generic_tune),
+        DEVMETHOD(mmcbr_retune,         sdhci_generic_retune),
+        DEVMETHOD(mmcbr_switch_vccq,    sdhci_generic_switch_vccq),
+
 
 	/* SDHCI registers accessors */
 	DEVMETHOD(sdhci_read_1,		sdhci_fdt_read_1),
@@ -708,7 +796,7 @@
 	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(sdhci_set_uhs_timing, sdhci_fdt_set_uhs_timing),
 	DEVMETHOD_END
 };
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.