Page MenuHomeFreeBSD

D42377.diff
No OneTemporary

D42377.diff

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
@@ -347,6 +354,38 @@
return (0);
}
+static int
+sdhci_init_rk3568(device_t dev)
+{
+ struct sdhci_fdt_softc *sc = device_get_softc(dev);
+ int err, i;
+ char *rk35xx_clocks[] = {"bus", "timer", "axi", "block" };
+
+ /* 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);
+ }
+ err = clk_enable(sc->clk_core);
+ if(err) {
+ device_printf(dev, "cannot enable core clock\n");
+ return (err);
+ }
+ 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);
+ }
+ err = clk_enable(clk_tmp);
+ if(err) break;
+ device_printf(dev, "enabled clock %s => %s\n", rk35xx_clocks[i],
+ clk_get_name(clk_tmp));
+ }
+
+ return (err);
+}
+
static uint8_t
sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
{
@@ -441,30 +480,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);
}
@@ -485,13 +580,13 @@
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 +629,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 +664,7 @@
struct sdhci_fdt_softc *sc = device_get_softc(dev);
struct sdhci_slot *slot;
int err, slots, rid, i, compat;
+ uint32_t temp;
sc->dev = dev;
@@ -607,12 +704,11 @@
}
break;
case 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);
+ err = sdhci_init_rk3568(dev);
+ if (err != 0) {
+ device_printf(dev, "Cannot init RK3568 SDHCI\n");
+ return (err);
+ }
break;
default:
break;
@@ -638,7 +734,12 @@
slot->caps = sc->caps;
slot->max_clk = sc->max_clk;
slot->sdma_boundary = sc->sdma_boundary;
-
+ if(compat == SDHCI_FDT_RK3568) {
+ 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;
@@ -697,6 +798,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 +813,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
};

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 9, 12:56 AM (3 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15728070
Default Alt Text
D42377.diff (8 KB)

Event Timeline