diff options
author | Tony Lin <tony.lin@freescale.com> | 2011-08-11 17:35:20 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-01-09 20:23:15 +0800 |
commit | 1e5fce1587efddbcaac563ede720c5e5bcc9024e (patch) | |
tree | 622da5ac381fabbfa98c395af5bfbcf0cfa8ba4b | |
parent | a00b14f996f091f463bd769d8d4bd6370cb9ea68 (diff) |
ENGR00139261 [MX6Q]support 8 bit MMC and eMMC DDR mode
enable 8 bit MMC mode according to mmc stack.
enable eMMC DDR mode according to mmc stack, but change
sdhci a little, since sdhci does not support DDR mode so
far.
Signed-off-by: Tony Lin <tony.lin@freescale.com>
-rw-r--r-- | arch/arm/include/asm/futex.h | 34 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 84 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 5 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 2 |
5 files changed, 93 insertions, 33 deletions
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 253cc86318bf..8c73900da9ed 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -25,17 +25,17 @@ #ifdef CONFIG_SMP -#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ +#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ smp_mb(); \ __asm__ __volatile__( \ - "1: ldrex %1, [%3]\n" \ + "1: ldrex %1, [%2]\n" \ " " insn "\n" \ - "2: strex %2, %0, [%3]\n" \ - " teq %2, #0\n" \ + "2: strex %1, %0, [%2]\n" \ + " teq %1, #0\n" \ " bne 1b\n" \ " mov %0, #0\n" \ - __futex_atomic_ex_table("%5") \ - : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ + __futex_atomic_ex_table("%4") \ + : "=&r" (ret), "=&r" (oldval) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ : "cc", "memory") @@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, #include <linux/preempt.h> #include <asm/domain.h> -#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ +#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ __asm__ __volatile__( \ - "1: " T(ldr) " %1, [%3]\n" \ + "1: " T(ldr) " %1, [%2]\n" \ " " insn "\n" \ - "2: " T(str) " %0, [%3]\n" \ + "2: " T(str) " %0, [%2]\n" \ " mov %0, #0\n" \ - __futex_atomic_ex_table("%5") \ - : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ + __futex_atomic_ex_table("%4") \ + : "=&r" (ret), "=&r" (oldval) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ : "cc", "memory") @@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tmp; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; @@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) switch (op) { case FUTEX_OP_SET: - __futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg); + __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ADD: - __futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg); + __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg); break; case FUTEX_OP_OR: - __futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg); + __futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg); break; case FUTEX_OP_ANDN: - __futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg); + __futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg); break; case FUTEX_OP_XOR: - __futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg); + __futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg); break; default: ret = -ENOSYS; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index fb541cc8a92c..9a9c70805bca 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1089,6 +1089,7 @@ void mmc_power_off(struct mmc_host *host) host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; + host->ios.ddr = MMC_SDR_MODE; mmc_set_ios(host); mmc_host_clk_release(host); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index d50f7b689e2e..fe48f13b5647 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -32,15 +32,17 @@ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 #define SDHCI_MIX_CTRL 0x48 +#define SDHCI_MIX_CTRL_DDREN (1 << 3) +#define SDHCI_MIX_CTRL_EXE_TUNE (1 << 22) +#define SDHCI_MIX_CTRL_SMPCLK_SEL (1 << 23) +#define SDHCI_MIX_CTRL_AUTO_TUNE (1 << 24) +#define SDHCI_MIX_CTRL_FBCLK_SEL (1 << 25) + #define SDHCI_TUNE_CTRL_STATUS 0x68 #define SDHCI_TUNE_CTRL_STEP 0x1 #define SDHCI_TUNE_CTRL_MIN 0x0 #define SDHCI_TUNE_CTRL_MAX ((1 << 7) - 1) -#define SDHCI_MIX_CTRL_EXE_TUNE (1 << 22) -#define SDHCI_MIX_CTRL_SMPCLK_SEL (1 << 23) -#define SDHCI_MIX_CTRL_FBCLK_SEL (1 << 25) - #define SDHCI_VENDOR_SPEC_VSELECT (1 << 1) #define SDHCI_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) @@ -51,6 +53,11 @@ #define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) #define SDHCI_CTRL_D3CD 0x08 + +#define SDHCI_PROT_CTRL_DTW (3 << 1) +#define SDHCI_PROT_CTRL_8BIT (2 << 1) +#define SDHCI_PROT_CTRL_4BIT (1 << 1) +#define SDHCI_PROT_CTRL_1BIT (0 << 1) /* * The CMDTYPE of the CMD register (offset 0xE) should be set to * "11" when the STOP CMD12 is issued on imx53 to abort one @@ -223,7 +230,12 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) writel(0x08800880, host->ioaddr + SDHCI_CAPABILITIES_1); if (cpu_is_mx6q()) { imx_data->scratchpad |= \ - (readl(host->ioaddr + SDHCI_MIX_CTRL) & (0xf << 22)); + (readl(host->ioaddr + SDHCI_MIX_CTRL) & \ + (SDHCI_MIX_CTRL_EXE_TUNE | \ + SDHCI_MIX_CTRL_SMPCLK_SEL | \ + SDHCI_MIX_CTRL_AUTO_TUNE | \ + SDHCI_MIX_CTRL_FBCLK_SEL | \ + SDHCI_MIX_CTRL_DDREN)); writel(imx_data->scratchpad, host->ioaddr + SDHCI_MIX_CTRL); @@ -280,6 +292,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) /* FSL messed up here, so we can just keep those three */ new_val = val & (SDHCI_CTRL_LED | \ SDHCI_CTRL_4BITBUS | \ + SDHCI_CTRL_HISPD | \ SDHCI_CTRL_D3CD); /* ensure the endianess */ new_val |= ESDHC_HOST_CONTROL_LE; @@ -316,6 +329,35 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) return -ENOSYS; } +static int plt_ddr_mode(struct sdhci_host *host, int mode) +{ + u32 reg = sdhci_readl(host, SDHCI_MIX_CTRL); + + if (mode == MMC_1_8V_DDR_MODE) + reg |= SDHCI_MIX_CTRL_DDREN; + else if (mode == MMC_SDR_MODE) + reg &= ~SDHCI_MIX_CTRL_DDREN; + + sdhci_writel(host, reg, SDHCI_MIX_CTRL); + + return 0; +} + +static int plt_8bit_width(struct sdhci_host *host, int width) +{ + u32 reg = sdhci_readl(host, SDHCI_HOST_CONTROL); + + reg &= ~SDHCI_PROT_CTRL_DTW; + + if (width == MMC_BUS_WIDTH_8) + reg |= SDHCI_PROT_CTRL_8BIT; + else if (width == MMC_BUS_WIDTH_4) + reg |= SDHCI_PROT_CTRL_4BIT; + + sdhci_writel(host, reg, SDHCI_HOST_CONTROL); + + return 0; +} static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, @@ -326,14 +368,21 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_max_clock = esdhc_pltfm_get_max_clock, .get_min_clock = esdhc_pltfm_get_min_clock, .pre_tuning = esdhc_prepare_tuning, + .platform_8bit_width = plt_8bit_width, + .platform_ddr_mode = plt_ddr_mode, }; static irqreturn_t cd_irq(int irq, void *data) { struct sdhci_host *sdhost = (struct sdhci_host *)data; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhost); + struct pltfm_imx_data *imx_data = pltfm_host->priv; sdhci_writel(sdhost, 0, SDHCI_MIX_CTRL); sdhci_writel(sdhost, 0, SDHCI_TUNE_CTRL_STATUS); + + if (cpu_is_mx6q()) + imx_data->scratchpad &= ~SDHCI_MIX_CTRL_DDREN; tasklet_schedule(&sdhost->card_tasklet); return IRQ_HANDLED; }; @@ -375,6 +424,22 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51() || cpu_is_mx6q())) imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; + host->ocr_avail_sd = MMC_VDD_29_30 | MMC_VDD_30_31 | \ + MMC_VDD_32_33 | MMC_VDD_33_34; + host->ocr_avail_mmc = MMC_VDD_29_30 | MMC_VDD_30_31 | \ + MMC_VDD_32_33 | MMC_VDD_33_34; + + if (boarddata->support_18v) + host->ocr_avail_sd |= MMC_VDD_165_195; + if (boarddata->support_8bit) + host->mmc->caps |= MMC_CAP_8_BIT_DATA; + if (cpu_is_mx6q()) { + host->mmc->caps |= MMC_CAP_1_8V_DDR; + host->tuning_min = SDHCI_TUNE_CTRL_MIN; + host->tuning_max = SDHCI_TUNE_CTRL_MAX; + host->tuning_step = SDHCI_TUNE_CTRL_STEP; + } + if (boarddata) { /* Device is always present, e.x, populated emmc device */ if (boarddata->always_present) { @@ -409,15 +474,6 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd /* Now we have a working card_detect again */ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } - host->ocr_avail_sd = MMC_VDD_29_30 | MMC_VDD_30_31 | \ - MMC_VDD_32_33 | MMC_VDD_33_34; - - if (boarddata->support_18v) - host->ocr_avail_sd |= MMC_VDD_165_195; - - host->tuning_min = SDHCI_TUNE_CTRL_MIN; - host->tuning_max = SDHCI_TUNE_CTRL_MAX; - host->tuning_step = SDHCI_TUNE_CTRL_STEP; return 0; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 01ba90a60138..777bbac27f83 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1329,14 +1329,15 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } + if (host->ops->platform_ddr_mode) + host->ops->platform_ddr_mode(host, ios->ddr); + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if ((ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_MMC_HS) && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) ctrl |= SDHCI_CTRL_HISPD; - else - ctrl &= ~SDHCI_CTRL_HISPD; if (host->version >= SDHCI_SPEC_300) { u16 clk, ctrl_2; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 2899a9fc8df4..3c8cf951fa88 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -275,6 +275,8 @@ struct sdhci_ops { int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); void (*pre_tuning)(struct sdhci_host *host, u32 val); + int (*platform_ddr_mode)(struct sdhci_host *host, + int mode); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS |