From c68b33e4d23fbe733becfe6b2264f837e9459613 Mon Sep 17 00:00:00 2001 From: RichardZhu Date: Wed, 16 Nov 2011 11:28:50 +0800 Subject: mmc: sdhci-esdhc-imx: workaround for TC intr coming ealier than DMA intri On mx6, if TC interrupt bit is set but DMA interrupt bit is clear, read status register again in case DMA interrupt will come in next time cycle. Signed-off-by: Tony Lin Signed-off-by: RichardZhu --- drivers/mmc/host/sdhci-esdhc-imx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 38ebc4ea259..5888f041ae2 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -170,6 +170,19 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) } if (unlikely(reg == SDHCI_INT_STATUS)) { + if (is_imx6q_usdhc(imx_data)) { + /* + * on mx6q, there is low possibility that + * DATA END interrupt comes ealier than DMA + * END interrupt which is conflict with standard + * host controller spec. In this case, read the + * status register again will workaround this issue. + */ + if ((val & SDHCI_INT_DATA_END) && \ + !(val & SDHCI_INT_DMA_END)) + val = readl(host->ioaddr + reg); + } + if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) { val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR; val |= SDHCI_INT_ADMA_ERROR; -- cgit v1.2.3 From f8d83aa0d3d1abc91e0ceead5645227c772cc4b2 Mon Sep 17 00:00:00 2001 From: RichardZhu Date: Wed, 16 Nov 2011 13:14:31 +0800 Subject: mmc: sdhci-esdhc-imx: sd dat1 glitch causes system panic some sd cards insertion will cause a glitch on sd dat1 which is also a card interrupt signal. Thus the wrongly generated card interrupt will make system panic because there's no registered sdio interrupt handler. the patch fixes this issue. Signed-off-by: Tony Lin Signed-off-by: RichardZhu --- drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 5888f041ae2..42f1dd079ac 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -452,6 +452,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) struct clk *clk; int err; struct pltfm_imx_data *imx_data; + u32 reg; host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); if (IS_ERR(host)) @@ -479,6 +480,20 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) clk_enable(clk); pltfm_host->clk = clk; + /* disable card interrupt enable bit, and clear status bit + * the default value of this enable bit is 1, but it should + * be 0 regarding to standard host controller spec 2.1.3. + * if this bit is 1, it may cause some problems. + * there's dat1 glitch when some cards inserting into the slot, + * thus wrongly generate a card interrupt that will cause + * system panic because it lacks of sdio handler + * following code will solve the problem. + */ + reg = sdhci_readl(host, SDHCI_INT_ENABLE); + reg &= ~SDHCI_INT_CARD_INT; + sdhci_writel(host, reg, SDHCI_INT_ENABLE); + sdhci_writel(host, SDHCI_INT_CARD_INT, SDHCI_INT_STATUS); + if (!is_imx25_esdhc(imx_data)) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; -- cgit v1.2.3 From d514e4a6158e2ebfad3ccfa26607fad5b98909b9 Mon Sep 17 00:00:00 2001 From: RichardZhu Date: Wed, 16 Nov 2011 14:51:40 +0800 Subject: mmc: sdhci-esdhc-imx: support 8 bit MMC enable 8 bit MMC mode according to mmc stack. Signed-off-by: RichardZhu --- drivers/mmc/host/sdhci-esdhc-imx.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 42f1dd079ac..7f6d6250679 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -29,11 +29,21 @@ #include "sdhci-esdhc.h" #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) + /* VENDOR SPEC register */ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 #define SDHCI_WTMK_LVL 0x44 #define SDHCI_MIX_CTRL 0x48 +#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) /* * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: @@ -288,7 +298,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) if (is_imx6q_usdhc(imx_data)) { u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL); - m = imx_data->scratchpad | (m & 0xffff0000); + m = imx_data->scratchpad | \ + (m & (SDHCI_MIX_CTRL_EXE_TUNE | \ + SDHCI_MIX_CTRL_SMPCLK_SEL | \ + SDHCI_MIX_CTRL_AUTO_TUNE | \ + SDHCI_MIX_CTRL_FBCLK_SEL)); writel(m, host->ioaddr + SDHCI_MIX_CTRL); writel(val << 16, host->ioaddr + SDHCI_TRANSFER_MODE); @@ -376,6 +390,22 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) return -ENOSYS; } +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, @@ -386,6 +416,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_max_clock = esdhc_pltfm_get_max_clock, .get_min_clock = esdhc_pltfm_get_min_clock, .get_ro = esdhc_pltfm_get_ro, + .platform_8bit_width = plt_8bit_width, }; static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { -- cgit v1.2.3 From 2bb75d3fe1b99da89cb4d921841e2e99c7ad0055 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 9 Jan 2012 13:08:14 +0800 Subject: mmc: sdhci-esdhc-imx: support of 1.8V is board specific Signed-off-by: Eric Miao --- arch/arm/plat-mxc/include/mach/esdhc.h | 2 ++ drivers/mmc/core/sd.c | 7 +++---- drivers/mmc/host/sdhci-esdhc-imx.c | 14 ++++++++++++++ include/linux/mmc/host.h | 6 ++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h index aaf97481f41..4ab603e25b8 100644 --- a/arch/arm/plat-mxc/include/mach/esdhc.h +++ b/arch/arm/plat-mxc/include/mach/esdhc.h @@ -32,6 +32,7 @@ enum cd_types { * @cd_gpio: gpio for card_detect interrupt * @wp_type: type of write_protect method (see wp_types enum above) * @cd_type: type of card_detect method (see cd_types enum above) + * @vdd_180: 1.8V VDD supported */ struct esdhc_platform_data { @@ -39,5 +40,6 @@ struct esdhc_platform_data { unsigned int cd_gpio; enum wp_types wp_type; enum cd_types cd_type; + int vdd_180; }; #endif /* __ASM_ARCH_IMX_ESDHC_H */ diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index f2a05ea40f2..d426b0eb45f 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -740,11 +740,10 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) ocr |= SD_OCR_CCS; /* - * If the host supports one of UHS-I modes, request the card - * to switch to 1.8V signaling level. + * If the host supports one of UHS-I modes, and support 1.8V VDD, + * request the card to switch to 1.8V signaling level. */ - if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)) + if ((host->caps & (MMC_CAP_UHS)) && (host->ocr_avail_sd & MMC_VDD_165_195)) ocr |= SD_OCR_S18R; /* If the host can supply more than 150mA, XPC should be set to 1. */ diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 7f6d6250679..4a2a9f674b4 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1,4 +1,5 @@ /* +#define MMC_CAP_UHS ( * Freescale eSDHC i.MX controller driver for the platform bus. * * derived from the OF-version. @@ -77,6 +78,7 @@ enum imx_esdhc_type { struct pltfm_imx_data { int flags; u32 scratchpad; + int can_vdd_180; /* support 1.8V? */ enum imx_esdhc_type devtype; struct esdhc_platform_data boarddata; }; @@ -462,6 +464,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (gpio_is_valid(boarddata->wp_gpio)) boarddata->wp_type = ESDHC_WP_GPIO; + if (of_get_property(np, "support-vdd-180", NULL)) + boarddata->vdd_180 = 1; return 0; } #else @@ -566,6 +570,16 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) boarddata->wp_gpio = -EINVAL; } + /* The imx6q uSDHC capabilities will always claim to support 1.8V + * while this is board specific, should be initialized properly + */ + if (is_imx6q_usdhc(imx_data)) { + host->quirks |= SDHCI_QUIRK_MISSING_CAPS; + host->caps = readl(host->ioaddr + SDHCI_CAPABILITIES); + if (!boarddata->vdd_180) + host->caps &= ~SDHCI_CAN_VDD_180; + } + /* card_detect */ if (boarddata->cd_type != ESDHC_CD_GPIO) boarddata->cd_gpio = -EINVAL; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index a3ac9c48e5d..56b13b2dc81 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -236,6 +236,12 @@ struct mmc_host { #define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */ #define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */ +#define MMC_CAP_UHS (MMC_CAP_UHS_SDR12 |\ + MMC_CAP_UHS_SDR25 |\ + MMC_CAP_UHS_SDR50 |\ + MMC_CAP_UHS_SDR104 |\ + MMC_CAP_UHS_DDR50) + unsigned int caps2; /* More host capabilities */ #define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */ -- cgit v1.2.3