diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/mx_sdhci.c | 127 | ||||
-rw-r--r-- | drivers/mmc/host/mx_sdhci.h | 17 | ||||
-rw-r--r-- | drivers/mmc/host/mxc_mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/mxs-mmc.c | 92 |
4 files changed, 174 insertions, 66 deletions
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c index 5a68a8e02fe2..732135308eb6 100644 --- a/drivers/mmc/host/mx_sdhci.c +++ b/drivers/mmc/host/mx_sdhci.c @@ -142,32 +142,32 @@ EXPORT_SYMBOL(mxc_mmc_force_detect); static void sdhci_dumpregs(struct sdhci_host *host) { - printk(KERN_DEBUG DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": ============== REGISTER DUMP ==============\n"); - printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n", readl(host->ioaddr + SDHCI_DMA_ADDRESS), readl(host->ioaddr + SDHCI_HOST_VERSION)); - printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n", (readl(host->ioaddr + SDHCI_BLOCK_SIZE) & 0xFFFF), (readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16)); - printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", readl(host->ioaddr + SDHCI_ARGUMENT), readl(host->ioaddr + SDHCI_TRANSFER_MODE)); - printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n", readl(host->ioaddr + SDHCI_PRESENT_STATE), readl(host->ioaddr + SDHCI_HOST_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Clock: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Clock: 0x%08x\n", readl(host->ioaddr + SDHCI_CLOCK_CONTROL)); - printk(KERN_DEBUG DRIVER_NAME ": Int stat: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Int stat: 0x%08x\n", readl(host->ioaddr + SDHCI_INT_STATUS)); - printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", readl(host->ioaddr + SDHCI_INT_ENABLE), readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)); - printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x\n", + printk(KERN_INFO DRIVER_NAME ": Caps: 0x%08x\n", readl(host->ioaddr + SDHCI_CAPABILITIES)); - printk(KERN_DEBUG DRIVER_NAME + printk(KERN_INFO DRIVER_NAME ": ===========================================\n"); } @@ -506,6 +506,30 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) host->flags &= ~SDHCI_REQ_USE_DMA; } + if (cpu_is_mx25() && (data->blksz * data->blocks < 0x10)) { + host->flags &= ~SDHCI_REQ_USE_DMA; + DBG("Reverting to PIO in small data transfer.\n"); + writel(readl(host->ioaddr + SDHCI_INT_ENABLE) + | SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL, + host->ioaddr + SDHCI_INT_ENABLE); + writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) + | SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL, + host->ioaddr + SDHCI_SIGNAL_ENABLE); + } else if (cpu_is_mx25() && (host->flags & SDHCI_USE_DMA)) { + host->flags |= SDHCI_REQ_USE_DMA; + DBG("Reverting to DMA in large data transfer.\n"); + writel(readl(host->ioaddr + SDHCI_INT_ENABLE) + & ~(SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL), + host->ioaddr + SDHCI_INT_ENABLE); + writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) + & ~(SDHCI_INT_DATA_AVAIL + | SDHCI_INT_SPACE_AVAIL), + host->ioaddr + SDHCI_SIGNAL_ENABLE); + } + if (host->flags & SDHCI_REQ_USE_DMA) { int i; struct scatterlist *tsg; @@ -644,7 +668,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) WARN_ON(host->cmd); /* Wait max 10 ms */ - timeout = 5000; + timeout = 500; mask = SDHCI_CMD_INHIBIT; if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) @@ -695,7 +719,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) mode |= SDHCI_TRNS_READ; else mode &= ~SDHCI_TRNS_READ; - if (host->flags & SDHCI_USE_DMA) + if (host->flags & SDHCI_REQ_USE_DMA) mode |= SDHCI_TRNS_DMA; if (host->flags & SDHCI_USE_EXTERNAL_DMA) DBG("Prepare data completely in %s transfer mode.\n", @@ -727,6 +751,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_DATA; mode |= SDHCI_MAKE_CMD(cmd->opcode, flags); + if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR) { + /* Eanble the DDR mode */ + mode |= SDHCI_TRNS_DDR_EN; + } else + mode &= ~SDHCI_TRNS_DDR_EN; DBG("Complete sending cmd, transfer mode would be 0x%x.\n", mode); writel(mode, host->ioaddr + SDHCI_TRANSFER_MODE); } @@ -775,6 +804,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) int clk_rate = 0; u32 clk; unsigned long timeout; + struct mmc_ios ios = host->mmc->ios; if (clock == 0) { goto out; @@ -784,17 +814,21 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->plat_data->clk_flg = 1; } } - if (clock == host->clock) + + if (clock == host->clock && !(ios.bus_width & MMC_BUS_WIDTH_DDR)) return; clk_rate = clk_get_rate(host->clk); clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK; - if (!cpu_is_mx53()) + if (cpu_is_mx53() || cpu_is_mx50()) + writel(clk | SDHCI_CLOCK_SDCLKFS1, + host->ioaddr + SDHCI_CLOCK_CONTROL); + else writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); if (clock == host->min_clk) prescaler = 16; - else if (cpu_is_mx53()) + else if (cpu_is_mx53() || cpu_is_mx50()) prescaler = 1; else prescaler = 0; @@ -820,6 +854,21 @@ 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 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); + /* Configure the clock control register */ clk |= (readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & (~SDHCI_CLOCK_MASK)); @@ -830,7 +879,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->ioaddr + SDHCI_CLOCK_CONTROL); /* Wait max 10 ms */ - timeout = 5000; + timeout = 500; while (timeout > 0) { timeout--; udelay(20); @@ -933,8 +982,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) u32 tmp; mxc_dma_device_t dev_id = 0; - DBG("%s: clock %u, bus %lu, power %u, vdd %u\n", DRIVER_NAME, - ios->clock, 1UL << ios->bus_width, ios->power_mode, ios->vdd); + DBG("%s: clock %u, bus %u, power %u, vdd %u\n", DRIVER_NAME, + ios->clock, ios->bus_width, ios->power_mode, ios->vdd); host = mmc_priv(mmc); @@ -1000,10 +1049,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmp = readl(host->ioaddr + SDHCI_HOST_CONTROL); - if (ios->bus_width == MMC_BUS_WIDTH_4) { + if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) { tmp &= ~SDHCI_CTRL_8BITBUS; tmp |= SDHCI_CTRL_4BITBUS; - } else if (ios->bus_width == MMC_BUS_WIDTH_8) { + } else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) { tmp &= ~SDHCI_CTRL_4BITBUS; tmp |= SDHCI_CTRL_8BITBUS; } else if (ios->bus_width == MMC_BUS_WIDTH_1) { @@ -1044,7 +1093,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) { struct sdhci_host *host; unsigned long flags; - u32 ier, prot, clk, present; + u32 ier, prot, present; host = mmc_priv(mmc); @@ -1057,19 +1106,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) if (--(host->sdio_enable)) goto exit_unlock; } - /* 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); + + ier = readl(host->ioaddr + SDHCI_INT_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, @@ -1077,12 +1119,24 @@ 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); - writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL); + + /* + * 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); mmiowb(); exit_unlock: @@ -1208,7 +1262,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 (!machine_is_mx35_3ds() && req_done && host->plat_data->clk_flg && + if (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; @@ -1786,8 +1840,10 @@ 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); @@ -2001,9 +2057,6 @@ 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 0bd79934952e..83d02975ecd1 100644 --- a/drivers/mmc/host/mx_sdhci.h +++ b/drivers/mmc/host/mx_sdhci.h @@ -2,7 +2,6 @@ * linux/drivers/mmc/host/mx_sdhci.h - Secure Digital Host * Controller Interface driver * - * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -28,6 +27,7 @@ #define SDHCI_TRNS_DMA 0x00000001 #define SDHCI_TRNS_BLK_CNT_EN 0x00000002 #define SDHCI_TRNS_ACMD12 0x00000004 +#define SDHCI_TRNS_DDR_EN 0x00000008 #define SDHCI_TRNS_READ 0x00000010 #define SDHCI_TRNS_MULTI 0x00000020 #define SDHCI_TRNS_DPSEL 0x00200000 @@ -69,6 +69,7 @@ #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 @@ -95,6 +96,7 @@ #define SDHCI_CLOCK_PER_EN 0x00000004 #define SDHCI_CLOCK_HLK_EN 0x00000002 #define SDHCI_CLOCK_IPG_EN 0x00000001 +#define SDHCI_CLOCK_SDCLKFS1 0x00000100 #define SDHCI_CLOCK_MASK 0x0000FFFF #define SDHCI_TIMEOUT_CONTROL 0x2E @@ -188,6 +190,18 @@ #define SDHCI_ADMA_ADDRESS 0x58 /* 60-FB reserved */ +#define SDHCI_DLL_CONTROL 0x60 +#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 + +#define SDHCI_DLL_STATUS 0x64 +#define DLL_STS_SLV_LOCK 0x00000001 +#define DLL_STS_REF_LOCK 0x00000002 /* ADMA Addr Descriptor Attribute Filed */ enum { @@ -207,6 +221,7 @@ 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/mxc_mmc.c b/drivers/mmc/host/mxc_mmc.c index 980dc98c9b5f..9cb492f40145 100644 --- a/drivers/mmc/host/mxc_mmc.c +++ b/drivers/mmc/host/mxc_mmc.c @@ -13,7 +13,7 @@ */ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -1232,7 +1232,7 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->f_max = mmc_plat->max_clk; mmc->max_req_size = 32 * 1024; mmc->max_seg_size = mmc->max_req_size; - mmc->max_blk_count = 65536; + mmc->max_blk_count = 32; spin_lock_init(&host->lock); host->mmc = mmc; diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index c60352247c49..b7210b7d7af3 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 (65536) +#define SSP_BUFFER_SIZE (65535) #ifndef BF #define BF(value, field) (((value) << BP_##field) & BM_##field) @@ -93,6 +93,9 @@ #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; @@ -159,6 +162,7 @@ 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) { @@ -167,6 +171,8 @@ 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); } @@ -183,6 +189,12 @@ static void mxs_mmc_detect_poll(unsigned long arg) BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) +#define MXS_MMC_ERR_BITS (BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ) + /* SSP DMA interrupt handler */ static irqreturn_t mmc_irq_handler(int irq, void *dev_id) { @@ -198,19 +210,17 @@ static irqreturn_t mmc_irq_handler(int irq, void *dev_id) /* STOP the dma transfer here. */ mxs_dma_cooked(host->dmach, NULL); } - host->status = - __raw_readl(host->ssp_base + HW_SSP_STATUS); - if (host->cmd) /* else it is a bogus interrupt */ - complete(&host->dma_done); + if ((irq == host->dmairq) || (c1 & MXS_MMC_ERR_BITS)) + if (host->cmd) { + host->status = + __raw_readl(host->ssp_base + HW_SSP_STATUS); + complete(&host->dma_done); + } - if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) { - __raw_writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, host->ssp_base + \ - HW_SSP_CTRL0_CLR); - __raw_writel(BM_SSP_CTRL1_SDIO_IRQ_EN, host->ssp_base + \ - HW_SSP_CTRL1_CLR); + if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); - } + return IRQ_HANDLED; } @@ -239,6 +249,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct mxs_dma_desc *dma_desc = host->dma_desc; + unsigned long flags; dma_desc->cmd.cmd.bits.command = NO_DMA_XFER; dma_desc->cmd.cmd.bits.irq = 1; @@ -255,7 +266,8 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) if (host->sdio_irq_en) { dma_desc->cmd.pio_words[0] |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN; + dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } init_completion(&host->dma_done); @@ -265,6 +277,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) dev_dbg(host->dev, "%s start DMA.\n", __func__); if (mxs_dma_enable(host->dmach) < 0) dev_err(host->dev, "mmc_dma_enable failed\n"); + wait_for_completion(&host->dma_done); cmd->error = mxs_mmc_cmd_error(host->status); @@ -273,6 +286,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host) dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); mxs_dma_reset(host->dmach); } + mxs_dma_disable(host->dmach); } /* Send the ac command to the device */ @@ -284,6 +298,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) u32 ssp_ctrl0; u32 ssp_cmd0; u32 ssp_cmd1; + unsigned long flags; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; @@ -305,7 +320,8 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) if (host->sdio_irq_en) { ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN; + ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } dma_desc->cmd.pio_words[0] = ssp_ctrl0; @@ -356,6 +372,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); mxs_dma_reset(host->dmach); } + mxs_dma_disable(host->dmach); } /* Copy data between sg list and dma buffer */ @@ -451,6 +468,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) u32 data_size = cmd->data->blksz * cmd->data->blocks; u32 log2_block_size; + unsigned long flags; ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1; resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0; @@ -540,6 +558,9 @@ 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); @@ -548,20 +569,32 @@ 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); - } - /* Configure the CMD0 */ - ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); - } else - ssp_cmd0 = - BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | - BF(cmd->opcode, SSP_CMD0_CMD) | - BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); + 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; + } + } else { + if ((1<<log2_block_size) != cmd->data->blksz) { + BUG_ON(cmd->data->blocks > 1); + ssp_cmd0 = + BF(0, SSP_BLOCK_SIZE_BLOCK_SIZE) | + BF(cmd->opcode, SSP_CMD0_CMD) | + BF(0, SSP_BLOCK_SIZE_BLOCK_COUNT); + } else + ssp_cmd0 = + BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) | + BF(cmd->opcode, SSP_CMD0_CMD) | + BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT); + } if (host->sdio_irq_en) { ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; - ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN; + ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \ + | BM_SSP_CMD0_SLOW_CLKING_EN; } - if (cmd->opcode == 12) + if ((cmd->opcode == 12) || (cmd->opcode == 53)) ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC; ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG); @@ -628,6 +661,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) dev_dbg(host->dev, "Transferred %u bytes\n", cmd->data->bytes_xfered); } + mxs_dma_disable(host->dmach); } /* Begin sedning a command to the card */ @@ -672,6 +706,13 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) dev_dbg(host->dev, "MMC request\n"); + if (!host->present) { + mrq->cmd->error = -ETIMEDOUT; + mmc_request_done(mmc, mrq); + return; + } + + BUG_ON(host->mrq != NULL); host->mrq = mrq; mxs_mmc_start_cmd(host, mrq->cmd); @@ -777,9 +818,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_8) + if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) host->bus_width = 2; - else if (ios->bus_width == MMC_BUS_WIDTH_4) + else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) host->bus_width = 1; else host->bus_width = 0; @@ -851,7 +892,6 @@ 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 | |