From 53c8297e916eaa9bca2452dbd7862032611c1d45 Mon Sep 17 00:00:00 2001 From: "duk hyun.kwon" Date: Thu, 4 May 2017 17:30:03 +0900 Subject: [PATCH] [COMOON] mmc: dw_mmc: enhanched strobe support Change-Id: I77b0b149c141e70fa25d838f4f22a0b0706513c9 Signed-off-by: duk hyun.kwon --- drivers/mmc/core/mmc.c | 2 +- drivers/mmc/host/dw_mmc-exynos.c | 59 ++++++++++++++---------- drivers/mmc/host/dw_mmc-exynos.h | 79 ++++++++++++++++++++++++++++++-- drivers/mmc/host/dw_mmc.c | 13 +++--- include/linux/mmc/host.h | 1 + 5 files changed, 118 insertions(+), 36 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 13871e2bcb0a..b77c0f2c3a41 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -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; diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index a84aa3f1ae85..5944c3953b78 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -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; } diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h index 595c934e6166..4819b92b733f 100644 --- a/drivers/mmc/host/dw_mmc-exynos.h +++ b/drivers/mmc/host/dw_mmc-exynos.h @@ -12,6 +12,46 @@ #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 @@ -22,22 +62,53 @@ /* 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) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index de31e20dc56c..03f7ee855fbd 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -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); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 227961c5011b..ea82b7b6d8db 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -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) */ -- 2.20.1