summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/mx_sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/mx_sdhci.c')
-rw-r--r--drivers/mmc/host/mx_sdhci.c130
1 files changed, 95 insertions, 35 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();