[COMOON] mmc: dw_mmc: enhanched strobe support
authorduk hyun.kwon <d_hyun.kwon@samsung.com>
Thu, 4 May 2017 08:30:03 +0000 (17:30 +0900)
committerJaehun Jung <jh0801.jung@samsung.com>
Wed, 20 Jun 2018 00:17:29 +0000 (09:17 +0900)
Change-Id: I77b0b149c141e70fa25d838f4f22a0b0706513c9
Signed-off-by: duk hyun.kwon <d_hyun.kwon@samsung.com>
drivers/mmc/core/mmc.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-exynos.h
drivers/mmc/host/dw_mmc.c
include/linux/mmc/host.h

index 13871e2bcb0ae83fa55cb438b69d4159bae44c3c..b77c0f2c3a41bdffa74bd4972d357ecb97114957 100644 (file)
@@ -1376,7 +1376,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
        }
 
        /* Set host controller to HS400 timing and frequency */
-       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+       mmc_set_timing(host, MMC_TIMING_MMC_HS400_ES);
 
        /* Controller enable enhanced strobe function */
        host->ios.enhanced_strobe = true;
index a84aa3f1ae8547c4cdbf24cb05ef7e32dca8d94a..5944c3953b7823b4d093ee718256da221ee2f673 100644 (file)
@@ -34,20 +34,6 @@ enum dw_mci_exynos_type {
        DW_MCI_TYPE_EXYNOS7_SMU,
 };
 
-/* Exynos implementation specific driver private data */
-struct dw_mci_exynos_priv_data {
-       enum dw_mci_exynos_type         ctrl_type;
-       u8                              ciu_div;
-       u32                             sdr_timing;
-       u32                             ddr_timing;
-       u32                             hs400_timing;
-       u32                             tuned_sample;
-       u32                             cur_speed;
-       u32                             dqs_delay;
-       u32                             saved_dqs_en;
-       u32                             saved_strobe_ctrl;
-};
-
 static struct dw_mci_exynos_compatible {
        char                            *compatible;
        enum dw_mci_exynos_type         ctrl_type;
@@ -232,9 +218,31 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
        dqs = priv->saved_dqs_en;
        strobe = priv->saved_strobe_ctrl;
 
-       if (timing == MMC_TIMING_MMC_HS400) {
-               dqs |= DATA_STROBE_EN;
-               strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
+       if (timing == MMC_TIMING_MMC_HS400 ||
+                       timing == MMC_TIMING_MMC_HS400_ES) {
+               dqs &= ~(DWMCI_TXDT_CRC_TIMER_SET(0xFF, 0xFF));
+               dqs |= (DWMCI_TXDT_CRC_TIMER_SET(priv->ddr200_tx_t_fastlimit,
+                       priv->ddr200_tx_t_initval) | DWMCI_RDDQS_EN |
+                               DWMCI_AXI_NON_BLOCKING_WRITE);
+               if (host->pdata->quirks & DW_MCI_QUIRK_ENABLE_ULP) {
+                       if (priv->delay_line || priv->tx_delay_line)
+                               strobe = DWMCI_WD_DQS_DELAY_CTRL(priv->tx_delay_line) |
+                               DWMCI_FIFO_CLK_DELAY_CTRL(0x2) |
+                               DWMCI_RD_DQS_DELAY_CTRL(priv->delay_line);
+                       else
+                               strobe = DWMCI_FIFO_CLK_DELAY_CTRL(0x2) |
+                               DWMCI_RD_DQS_DELAY_CTRL(90);
+               } else {
+                       if (priv->delay_line)
+                               strobe = DWMCI_FIFO_CLK_DELAY_CTRL(0x2) |
+                               DWMCI_RD_DQS_DELAY_CTRL(priv->delay_line);
+                       else
+                               strobe = DWMCI_FIFO_CLK_DELAY_CTRL(0x2) |
+                               DWMCI_RD_DQS_DELAY_CTRL(90);
+               }
+               dqs |= (DATA_STROBE_EN | DWMCI_AXI_NON_BLOCKING_WRITE);
+               if (timing == MMC_TIMING_MMC_HS400_ES)
+                       dqs |= DWMCI_RESP_RCLK_MODE;
        } else {
                dqs &= ~DATA_STROBE_EN;
        }
@@ -283,6 +291,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 
        switch (timing) {
        case MMC_TIMING_MMC_HS400:
+       case MMC_TIMING_MMC_HS400_ES:
                /* Update tuned sample timing */
                clksel = SDMMC_CLKSEL_UP_SAMPLE(
                                priv->hs400_timing, priv->tuned_sample);
@@ -312,7 +321,7 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
 {
        struct dw_mci_exynos_priv_data *priv;
        struct device_node *np = host->dev->of_node;
-       u32 timing[2];
+       u32 timing[4];
        u32 div = 0;
        int idx;
        int ret;
@@ -336,28 +345,28 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
        }
 
        ret = of_property_read_u32_array(np,
-                       "samsung,dw-mshc-sdr-timing", timing, 2);
+                       "samsung,dw-mshc-sdr-timing", timing, 4);
        if (ret)
                return ret;
 
-       priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+       priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2], timing[3]);
 
        ret = of_property_read_u32_array(np,
-                       "samsung,dw-mshc-ddr-timing", timing, 2);
+                       "samsung,dw-mshc-ddr-timing", timing, 4);
        if (ret)
                return ret;
 
-       priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+       priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2], timing[3]);
 
        ret = of_property_read_u32_array(np,
-                       "samsung,dw-mshc-hs400-timing", timing, 2);
+                       "samsung,dw-mshc-hs400-timing", timing, 4);
        if (!ret && of_property_read_u32(np,
                                "samsung,read-strobe-delay", &priv->dqs_delay))
                dev_dbg(host->dev,
                        "read-strobe-delay is not found, assuming usage of default value\n");
 
-       priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
-                                               HS400_FIXED_CIU_CLK_DIV);
+       priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2], timing[3]);
+
        host->priv = priv;
        return 0;
 }
index 595c934e6166cf1b9aef2c18a8a28ec3c3062163..4819b92b733f00fd67da009017e3442c262652f6 100644 (file)
 #ifndef _DW_MMC_EXYNOS_H_
 #define _DW_MMC_EXYNOS_H_
 
+/* Exynos implementation specific driver private data */
+struct dw_mci_exynos_priv_data {
+       u8                      ctrl_type;
+       u8                      ciu_div;
+       u32                     sdr_timing;
+       u32                     ddr_timing;
+       u32                     hs400_timing;
+       u32                     tuned_sample;
+       u32                     cur_speed;
+       u32                     dqs_delay;
+       u32                     saved_dqs_en;
+       u32                     saved_strobe_ctrl;
+       u32                     hs200_timing;
+       u32                     ddr200_timing;
+       u32                     ddr200_ulp_timing;
+       u32                     ddr200_tx_t_fastlimit;
+       u32                     ddr200_tx_t_initval;
+       u32                     sdr104_timing;
+       u32                     sdr50_timing;
+       u32                     *ref_clk;
+       u32                     delay_line;
+       u32                     tx_delay_line;
+       struct pinctrl          *pinctrl;
+       u32                     clk_drive_number;
+       u32                     clk_drive_tuning;
+       struct pinctrl_state    *clk_drive_base;
+       struct pinctrl_state    *clk_drive_str[6];
+       int                     cd_gpio;
+       u32                     caps;
+       u32                     ctrl_flag;
+       u32                     ctrl_windows;
+       u32                     ignore_phase;
+       u32                     selclk_drv;
+       u32                     voltage_int_extra;
+
+#define DW_MMC_EXYNOS_USE_FINE_TUNING          BIT(0)
+#define DW_MMC_EXYNOS_BYPASS_FOR_ALL_PASS      BIT(1)
+#define DW_MMC_EXYNOS_ENABLE_SHIFT             BIT(2)
+};
+
 #define SDMMC_CLKSEL                   0x09C
 #define SDMMC_CLKSEL64                 0x0A8
 
 
 /* CLKSEL register defines */
 #define SDMMC_CLKSEL_CCLK_SAMPLE(x)    (((x) & 7) << 0)
+#define SDMMC_CLKSEL_CCLK_FINE_SAMPLE(x)       (((x) & 0xF) << 0)
 #define SDMMC_CLKSEL_CCLK_DRIVE(x)     (((x) & 7) << 16)
+#define SDMMC_CLKSEL_CCLK_FINE_DRIVE(x)        (((x) & 3) << 22)
 #define SDMMC_CLKSEL_CCLK_DIVIDER(x)   (((x) & 7) << 24)
 #define SDMMC_CLKSEL_GET_DRV_WD3(x)    (((x) >> 16) & 0x7)
 #define SDMMC_CLKSEL_GET_DIV(x)                (((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_GET_DIVRATIO(x)   ((((x) >> 24) & 0x7) + 1)
 #define SDMMC_CLKSEL_UP_SAMPLE(x, y)   (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
                                         SDMMC_CLKSEL_CCLK_SAMPLE(y))
-#define SDMMC_CLKSEL_TIMING(x, y, z)   (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
-                                        SDMMC_CLKSEL_CCLK_DRIVE(y) |   \
-                                        SDMMC_CLKSEL_CCLK_DIVIDER(z))
-#define SDMMC_CLKSEL_TIMING_MASK       SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
+#define SDMMC_CLKSEL_TIMING(div, f_drv, drv, sample) \
+       (SDMMC_CLKSEL_CCLK_DIVIDER(div) |       \
+        SDMMC_CLKSEL_CCLK_FINE_DRIVE(f_drv) |  \
+        SDMMC_CLKSEL_CCLK_DRIVE(drv) |         \
+        SDMMC_CLKSEL_CCLK_SAMPLE(sample))
+#define SDMMC_CLKSEL_TIMING_MASK       SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7, 0x7)
 #define SDMMC_CLKSEL_WAKEUP_INT                BIT(11)
 
 /* RCLK_EN register defines */
 #define DATA_STROBE_EN                 BIT(0)
 #define AXI_NON_BLOCKING_WR    BIT(7)
 
+/* SDMMC_DDR200_RDDQS_EN */
+#define DWMCI_TXDT_CRC_TIMER_FASTLIMIT(x)      (((x) & 0xFF) << 16)
+#define DWMCI_TXDT_CRC_TIMER_INITVAL(x)                (((x) & 0xFF) << 8)
+#define DWMCI_TXDT_CRC_TIMER_SET(x, y) (DWMCI_TXDT_CRC_TIMER_FASTLIMIT(x) | \
+                                       DWMCI_TXDT_CRC_TIMER_INITVAL(y))
+#define DWMCI_AXI_NON_BLOCKING_WRITE           BIT(7)
+#define DWMCI_RESP_RCLK_MODE                   BIT(5)
+#define DWMCI_BUSY_CHK_CLK_STOP_EN             BIT(2)
+#define DWMCI_RXDATA_START_BIT_SEL             BIT(1)
+#define DWMCI_RDDQS_EN                         BIT(0)
+#define DWMCI_DDR200_RDDQS_EN_DEF      (DWMCI_TXDT_CRC_TIMER_FASTLIMIT(0x13) | \
+                                       DWMCI_TXDT_CRC_TIMER_INITVAL(0x15))
+
+/* SDMMC_DDR200_ASYNC_FIFO_CTRL */
+#define DWMCI_ASYNC_FIFO_RESET         BIT(0)
+
+/* SDMMC_DDR200_DLINE_CTRL */
+#define DWMCI_WD_DQS_DELAY_CTRL(x)             (((x) & 0x3FF) << 20)
+#define DWMCI_FIFO_CLK_DELAY_CTRL(x)           (((x) & 0x3) << 16)
+#define DWMCI_RD_DQS_DELAY_CTRL(x)             ((x) & 0x3FF)
+#define DWMCI_DDR200_DLINE_CTRL_SET(x, y, z)   (DWMCI_WD_DQS_DELAY_CTRL(x) | \
+                                               DWMCI_FIFO_CLK_DELAY_CTRL(y) | \
+                                               DWMCI_RD_DQS_DELAY_CTRL(z))
+#define DWMCI_DDR200_DLINE_CTRL_DEF    (DWMCI_FIFO_CLK_DELAY_CTRL(0x2) | \
+                                       DWMCI_RD_DQS_DELAY_CTRL(0x40))
+
 /* DLINE_CTRL register defines */
 #define DQS_CTRL_RD_DELAY(x, y)                (((x) & ~0x3FF) | ((y) & 0x3FF))
 #define DQS_CTRL_GET_RD_DELAY(x)       ((x) & 0x3FF)
index de31e20dc56c5f5fe834b5b34e6365f9a4dd3af3..03f7ee855fbd68b8e4aaa74bf56bbf2a2557b13b 100644 (file)
@@ -203,26 +203,26 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
        if (!root)
                return;
 
-       node = debugfs_create_file("regs", S_IRUSR, root, host,
+       node = debugfs_create_file("regs", 0400, root, host,
                                   &dw_mci_regs_fops);
        if (!node)
                goto err;
 
-       node = debugfs_create_file("req", S_IRUSR, root, slot,
+       node = debugfs_create_file("req", 0400, root, slot,
                                   &dw_mci_req_fops);
        if (!node)
                goto err;
 
-       node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+       node = debugfs_create_u32("state", 0400, root, (u32 *)&host->state);
        if (!node)
                goto err;
 
-       node = debugfs_create_x32("pending_events", S_IRUSR, root,
+       node = debugfs_create_x32("pending_events", 0400, root,
                                  (u32 *)&host->pending_events);
        if (!node)
                goto err;
 
-       node = debugfs_create_x32("completed_events", S_IRUSR, root,
+       node = debugfs_create_x32("completed_events", 0400, root,
                                  (u32 *)&host->completed_events);
        if (!node)
                goto err;
@@ -1469,7 +1469,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        /* DDR mode set */
        if (ios->timing == MMC_TIMING_MMC_DDR52 ||
            ios->timing == MMC_TIMING_UHS_DDR50 ||
-           ios->timing == MMC_TIMING_MMC_HS400)
+           ios->timing == MMC_TIMING_MMC_HS400 ||
+               ios->timing == MMC_TIMING_MMC_HS400_ES)
                regs |= ((0x1 << slot->id) << 16);
        else
                regs &= ~((0x1 << slot->id) << 16);
index 227961c5011b523e820b78c11cb70e0f33506504..ea82b7b6d8dbde78d17ec786b9d9a85cbf09f9c1 100644 (file)
@@ -62,6 +62,7 @@ struct mmc_ios {
 #define MMC_TIMING_MMC_DDR52   8
 #define MMC_TIMING_MMC_HS200   9
 #define MMC_TIMING_MMC_HS400   10
+#define MMC_TIMING_MMC_HS400_ES        11
 
        unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */