}
/* 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;
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;
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;
}
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);
{
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;
}
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;
}
#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)
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;
/* 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);
#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) */