summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Lin <tony.lin@freescale.com>2011-08-11 17:35:20 +0800
committerJason Liu <r64343@freescale.com>2012-07-20 13:15:25 +0800
commitc867c3ae18903eb4ad4f50ca225b69acd3a8e61c (patch)
tree1f6ef0ee0093956eb18776ef3b789bccc2549fb7
parentd97dec95a997033089dbd4d4ab38b30323c7fba3 (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.h34
-rw-r--r--drivers/mmc/core/core.c1
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c84
-rw-r--r--drivers/mmc/host/sdhci.c5
-rw-r--r--drivers/mmc/host/sdhci.h2
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 958a0ed88259..f20e4ad34af7 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
@@ -224,7 +231,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);
@@ -281,6 +293,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;
@@ -317,6 +330,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,
@@ -327,14 +369,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 308c36197306..134a02ed8280 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