summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYangbo Lu <yangbo.lu@freescale.com>2015-08-04 08:57:03 (GMT)
committerYangbo Lu <yangbo.lu@freescale.com>2015-09-24 04:06:17 (GMT)
commit9ac6075dac23a36e185606c305396add68e84f19 (patch)
tree4296499faf27daee451b7ea2d41372824719593d
parente89634e2b51f4d8170b58603d1e38940dede646a (diff)
downloadlinux-fsl-qoriq-9ac6075dac23a36e185606c305396add68e84f19.tar.xz
mmc: esdhc: add eMMC45 Adapter Card HS200 mode support
The eSDHC is not compatible with SD spec well, it's needed to add callbacks for signal voltage switching and tuning block setting for eSDHC for eMMC45 Adapter Card HS200 mode support. Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h7
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c44
-rw-r--r--drivers/mmc/host/sdhci.c8
-rw-r--r--drivers/mmc/host/sdhci.h3
4 files changed, 62 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 6bb6c52..a4aa096 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -39,11 +39,18 @@
#define ESDHCI_PRESENT_STATE 0x24
#define ESDHC_CLK_STABLE 0x00000008
+#define ESDHC_PROCTL 0x28
+#define ESDHC_VOLT_SEL 0x00000400
+
#define ESDHC_CAPABILITIES_1 0x114
#define ESDHC_MODE_MASK 0x00000007
#define ESDHC_MODE_DDR50_SEL 0xfffffffc
+#define ESDHC_MODE_SDR104 0x00000002
#define ESDHC_MODE_DDR50 0x00000004
+#define ESDHC_TBCTL 0x120
+#define ESDHC_TB_EN 0x00000004
+
#define ESDHC_CLOCK_CONTROL 0x144
#define ESDHC_CLKLPBK_EXTPIN 0x80000000
#define ESDHC_CMDCLK_SHIFTED 0x00008000
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index d6799a8..afdf21a 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -43,6 +43,11 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg)
if (reg == SDHCI_CAPABILITIES_1) {
ret = sdhci_32bs_readl(host, ESDHC_CAPABILITIES_1);
switch (adapter_type) {
+ case ESDHC_ADAPTER_TYPE_1:
+ if (ret & ESDHC_MODE_SDR104)
+ host->mmc->caps2 |= MMC_CAP2_HS200;
+ ret &= ~ESDHC_MODE_MASK;
+ break;
case ESDHC_ADAPTER_TYPE_3:
if (ret & ESDHC_MODE_DDR50) {
ret &= ESDHC_MODE_DDR50_SEL;
@@ -637,6 +642,43 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0;
}
+void esdhc_set_tuning_block(struct sdhci_host *host)
+{
+ u32 value;
+
+ esdhc_clock_control(host, false);
+ value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ value |= ESDHC_FLUSH_ASYNC_FIFO;
+ sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
+
+ value = sdhci_readl(host, ESDHC_TBCTL);
+ value |= ESDHC_TB_EN;
+ sdhci_writel(host, value, ESDHC_TBCTL);
+ esdhc_clock_control(host, true);
+
+}
+
+void esdhc_signal_voltage_switch(struct sdhci_host *host,
+ unsigned char signal_voltage)
+{
+ u32 value;
+
+ value = sdhci_32bs_readl(host, ESDHC_PROCTL);
+
+ switch (signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ value &= (~ESDHC_VOLT_SEL);
+ sdhci_32bs_writel(host, value, ESDHC_PROCTL);
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ value |= ESDHC_VOLT_SEL;
+ sdhci_32bs_writel(host, value, ESDHC_PROCTL);
+ break;
+ default:
+ return;
+ }
+}
+
static const struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl,
.read_w = esdhc_readw,
@@ -661,6 +703,8 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
.adma_workaround = esdhci_of_adma_workaround,
.platform_bus_width = esdhc_pltfm_bus_width,
.set_uhs_signaling = esdhc_set_uhs_signaling,
+ .set_tuning_block = esdhc_set_tuning_block,
+ .signal_voltage_switch = esdhc_signal_voltage_switch,
};
static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 8f0e396..1bc025d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1750,6 +1750,11 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
if (host->version < SDHCI_SPEC_300)
return 0;
+ if (host->ops->signal_voltage_switch) {
+ host->ops->signal_voltage_switch(host, ios->signal_voltage);
+ return 0;
+ }
+
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
switch (ios->signal_voltage) {
@@ -1890,6 +1895,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return 0;
}
+ if (host->ops->set_tuning_block)
+ host->ops->set_tuning_block(host);
+
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
/*
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 096b203..8de8936 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -299,6 +299,9 @@ struct sdhci_ops {
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
void (*card_event)(struct sdhci_host *host);
+ void (*set_tuning_block)(struct sdhci_host *host);
+ void (*signal_voltage_switch)(struct sdhci_host *host,
+ unsigned char signal_voltage);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS