diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/mx_sdhci.c | 130 | ||||
-rw-r--r-- | drivers/mmc/host/mx_sdhci.h | 3 | ||||
-rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 24 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.c | 4 |
4 files changed, 103 insertions, 58 deletions
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c index 732135308eb6..0557d4d337c1 100644 --- a/drivers/mmc/host/mx_sdhci.c +++ b/drivers/mmc/host/mx_sdhci.c @@ -814,7 +814,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->plat_data->clk_flg = 1; } } - if (clock == host->clock && !(ios.bus_width & MMC_BUS_WIDTH_DDR)) return; @@ -854,20 +853,85 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) DBG("prescaler = 0x%x, divider = 0x%x\n", prescaler, div); clk |= (prescaler << 8) | (div << 4); - if (host->plat_data->clk_always_on - | (host->mmc->card && mmc_card_sdio(host->mmc->card))) - clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_HLK_EN - | SDHCI_CLOCK_IPG_EN; - else - clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_HLK_EN - | SDHCI_CLOCK_IPG_EN); + /* Configure the DLL when DDR mode is enabled */ + if (ios.bus_width & MMC_BUS_WIDTH_DDR) { + /* Make sure that the PER, HLK, IPG are all enabled */ + writel(readl(host->ioaddr + SDHCI_CLOCK_CONTROL) + | SDHCI_CLOCK_IPG_EN + | SDHCI_CLOCK_HLK_EN + | SDHCI_CLOCK_PER_EN, + host->ioaddr + SDHCI_CLOCK_CONTROL); - /* Configure the clock delay line */ - if ((host->plat_data->vendor_ver >= ESDHC_VENDOR_V3) - && host->plat_data->dll_override_en) - writel((host->plat_data->dll_delay_cells << 10) - | DLL_CTRL_SLV_OVERRIDE, - host->ioaddr + SDHCI_DLL_CONTROL); + /* Enable the DLL and delay chain */ + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + | DLL_CTRL_ENABLE, + host->ioaddr + SDHCI_DLL_CONTROL); + + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_REF_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL REF LOCK Timeout!\n"); + }; + DBG("dll stat: 0x%x\n", readl(host->ioaddr + SDHCI_DLL_STATUS)); + + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + | DLL_CTRL_SLV_UP_INT | DLL_CTRL_REF_UP_INT + | DLL_CTRL_SLV_DLY_TAR, + host->ioaddr + SDHCI_DLL_CONTROL); + + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_SLV_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL SLV LOCK Timeout!\n"); + }; + + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + | DLL_CTRL_SLV_FORCE_UPD, + host->ioaddr + SDHCI_DLL_CONTROL); + + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) + & (~DLL_CTRL_SLV_FORCE_UPD), + host->ioaddr + SDHCI_DLL_CONTROL); + + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_REF_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL REF LOCK Timeout!\n"); + }; + timeout = 1000000; + while (timeout > 0) { + timeout--; + if (readl(host->ioaddr + SDHCI_DLL_STATUS) + & DLL_STS_SLV_LOCK) + break; + else if (timeout == 0) + printk(KERN_ERR "DLL SLV LOCK Timeout!\n"); + }; + DBG("dll stat: 0x%x\n", readl(host->ioaddr + SDHCI_DLL_STATUS)); + + /* Let the PER, HLK, IPG to be auto-gate */ + writel(readl(host->ioaddr + SDHCI_CLOCK_CONTROL) + & ~(SDHCI_CLOCK_IPG_EN | SDHCI_CLOCK_HLK_EN + | SDHCI_CLOCK_PER_EN), + host->ioaddr + SDHCI_CLOCK_CONTROL); + + } else if (readl(host->ioaddr + SDHCI_DLL_STATUS) & DLL_STS_SLV_LOCK) { + /* reset DLL CTRL */ + writel(readl(host->ioaddr + SDHCI_DLL_CONTROL) | DLL_CTRL_RESET, + host->ioaddr + SDHCI_DLL_CONTROL); + } /* Configure the clock control register */ clk |= @@ -1093,7 +1157,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host; unsigned long flags; - u32 ier, prot, present; + u32 ier, prot, clk, present; host = mmc_priv(mmc); @@ -1106,12 +1170,19 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) if (--(host->sdio_enable)) goto exit_unlock; } - - ier = readl(host->ioaddr + SDHCI_INT_ENABLE); + /* Enable the clock */ + if (!host->plat_data->clk_flg) { + clk_enable(host->clk); + host->plat_data->clk_flg = 1; + } + ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE); prot = readl(host->ioaddr + SDHCI_HOST_CONTROL); + clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL); if (enable) { ier |= SDHCI_INT_CARD_INT; + prot |= SDHCI_CTRL_D3CD; + clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN; present = readl(host->ioaddr + SDHCI_PRESENT_STATE); if ((present & SDHCI_CARD_INT_MASK) != SDHCI_CARD_INT_ID) writel(SDHCI_INT_CARD_INT, @@ -1119,24 +1190,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) } else { ier &= ~SDHCI_INT_CARD_INT; prot &= ~SDHCI_CTRL_D3CD; + clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN); } writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); - writel(ier, host->ioaddr + SDHCI_INT_ENABLE); writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE); - - /* - * Using D3CD to manually driver the HW to re-sample the SDIO interrupt - * on bus one more time to guarantee the SDIO interrupt signal sent - * from card during the interrupt signal disabled period will not - * be lost. - */ - prot |= SDHCI_CTRL_CDSS; - writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); - prot &= ~SDHCI_CTRL_D3CD; - writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); - prot |= SDHCI_CTRL_D3CD; - writel(prot, host->ioaddr + SDHCI_HOST_CONTROL); + writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); mmiowb(); exit_unlock: @@ -1262,7 +1321,7 @@ static void sdhci_tasklet_finish(unsigned long param) * The root cause is that the ROM code don't ensure * the SD/MMC clk is running when boot system. * */ - if (req_done && host->plat_data->clk_flg && + if (!machine_is_mx35_3ds() && req_done && host->plat_data->clk_flg && !(host->mmc && host->mmc->card && mmc_card_sdio(host->mmc->card))) { clk_disable(host->clk); host->plat_data->clk_flg = 0; @@ -1840,10 +1899,8 @@ static int __devinit sdhci_probe_slot(struct platform_device /* Get the SDHC clock from clock system APIs */ host->clk = clk_get(&pdev->dev, mmc_plat->clock_mmc); - if (NULL == host->clk) { + if (NULL == host->clk) printk(KERN_ERR "MXC MMC can't get clock.\n"); - goto out1; - } DBG("SDHC:%d clock:%lu\n", pdev->id, clk_get_rate(host->clk)); host->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -2057,6 +2114,9 @@ static int __devinit sdhci_probe_slot(struct platform_device } mxc_dma_callback_set(host->dma, sdhci_dma_irq, (void *)host); } +#ifdef CONFIG_MMC_DEBUG + sdhci_dumpregs(host); +#endif mmiowb(); diff --git a/drivers/mmc/host/mx_sdhci.h b/drivers/mmc/host/mx_sdhci.h index 83d02975ecd1..fa36dff0fd9a 100644 --- a/drivers/mmc/host/mx_sdhci.h +++ b/drivers/mmc/host/mx_sdhci.h @@ -69,7 +69,6 @@ #define SDHCI_CTRL_4BITBUS 0x00000002 #define SDHCI_CTRL_8BITBUS 0x00000004 #define SDHCI_CTRL_HISPD 0x00000004 -#define SDHCI_CTRL_CDSS 0x80 #define SDHCI_CTRL_DMA_MASK 0x18 #define SDHCI_CTRL_SDMA 0x00 #define SDHCI_CTRL_ADMA1 0x08 @@ -194,7 +193,6 @@ #define DLL_CTRL_ENABLE 0x00000001 #define DLL_CTRL_RESET 0x00000002 #define DLL_CTRL_SLV_FORCE_UPD 0x00000004 -#define DLL_CTRL_SLV_OVERRIDE 0x00000200 #define DLL_CTRL_SLV_DLY_TAR 0x00000000 #define DLL_CTRL_SLV_UP_INT 0x00200000 #define DLL_CTRL_REF_UP_INT 0x20000000 @@ -221,7 +219,6 @@ enum { #define SDHCI_SPEC_100 0 #define SDHCI_SPEC_200 1 #define ESDHC_VENDOR_V22 0x12 -#define ESDHC_VENDOR_V3 0x13 struct sdhci_chip; diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index b7210b7d7af3..b849e873613b 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -49,7 +49,7 @@ #define MXS_MMC_DETECT_TIMEOUT (HZ/2) /* Max value supported for XFER_COUNT */ -#define SSP_BUFFER_SIZE (65535) +#define SSP_BUFFER_SIZE (65536) #ifndef BF #define BF(value, field) (((value) << BP_##field) & BM_##field) @@ -93,9 +93,6 @@ #define BF_SSP_BLOCK_SIZE_BLOCK_SIZE(v) \ (((v) << 16) & BM_SSP_BLOCK_SIZE_BLOCK_SIZE) #endif -#ifndef BM_SSP_CMD0_DBL_DATA_RATE_EN -#define BM_SSP_CMD0_DBL_DATA_RATE_EN 0x02000000 -#endif struct mxs_mmc_host { struct device *dev; @@ -162,7 +159,6 @@ static inline int mxs_mmc_is_plugged(struct mxs_mmc_host *host) return !(status & BM_SSP_STATUS_CARD_DETECT); } -static void mxs_mmc_reset(struct mxs_mmc_host *host); /* Card detection polling function */ static void mxs_mmc_detect_poll(unsigned long arg) { @@ -171,8 +167,6 @@ static void mxs_mmc_detect_poll(unsigned long arg) card_status = mxs_mmc_is_plugged(host); if (card_status != host->present) { - /* Reset MMC block */ - mxs_mmc_reset(host); host->present = card_status; mmc_detect_change(host->mmc, 0); } @@ -558,9 +552,6 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) dev_dbg(host->dev, "%s blksz is 0x%x.\n", __func__, log2_block_size); if (ssp_ver_major > 3) { - /* Configure the CMD0 */ - ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); - /* Configure the BLOCK SIZE and BLOCK COUNT */ if ((1<<log2_block_size) != cmd->data->blksz) { BUG_ON(cmd->data->blocks > 1); @@ -569,13 +560,9 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) val = BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); __raw_writel(val, host->ssp_base + HW_SSP_BLOCK_SIZE); - if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR) - /* Enable the DDR mode */ - ssp_cmd0 |= BM_SSP_CMD0_DBL_DATA_RATE_EN; - else - ssp_cmd0 &= ~BM_SSP_CMD0_DBL_DATA_RATE_EN; - } + /* Configure the CMD0 */ + ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); } else { if ((1<<log2_block_size) != cmd->data->blksz) { BUG_ON(cmd->data->blocks > 1); @@ -818,9 +805,9 @@ static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) dev_warn(host->dev, "Platform does not support CMD pin pullup control\n"); - if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) + if (ios->bus_width == MMC_BUS_WIDTH_8) host->bus_width = 2; - else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) + else if (ios->bus_width == MMC_BUS_WIDTH_4) host->bus_width = 1; else host->bus_width = 0; @@ -892,6 +879,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) /* Configure SSP Control Register 1 */ ssp_ctrl1 = BM_SSP_CTRL1_DMA_ENABLE | + BM_SSP_CTRL1_POLARITY | BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | BM_SSP_CTRL1_DATA_CRC_IRQ_EN | BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index e55ac792d68c..c8c0a7e4f0af 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -694,14 +694,14 @@ static int pxamci_remove(struct platform_device *pdev) if (mmc) { struct pxamci_host *host = mmc_priv(mmc); + mmc_remove_host(mmc); + if (host->vcc) regulator_put(host->vcc); if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); - mmc_remove_host(mmc); - pxamci_stop_clock(host); writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, |