summaryrefslogtreecommitdiff
path: root/drivers/mmc/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/mx_sdhci.c130
-rw-r--r--drivers/mmc/host/mx_sdhci.h3
-rw-r--r--drivers/mmc/host/mxs-mmc.c24
-rw-r--r--drivers/mmc/host/pxamci.c4
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,