summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/dw_mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
-rw-r--r--drivers/mmc/host/dw_mmc.c397
1 files changed, 185 insertions, 212 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 8718432751c5..e45129f48174 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -19,6 +19,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -65,6 +66,8 @@
struct idmac_desc_64addr {
u32 des0; /* Control Descriptor */
+#define IDMAC_OWN_CLR64(x) \
+ !((x) & cpu_to_le32(IDMAC_DES0_OWN))
u32 des1; /* Reserved */
@@ -104,11 +107,6 @@ struct idmac_desc {
/* Each descriptor can transfer up to 4KB of data in chained mode */
#define DW_MCI_DESC_DATA_LENGTH 0x1000
-static bool dw_mci_reset(struct dw_mci *host);
-static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
-static int dw_mci_card_busy(struct mmc_host *mmc);
-static int dw_mci_get_cd(struct mmc_host *mmc);
-
#if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v)
{
@@ -232,7 +230,66 @@ err:
}
#endif /* defined(CONFIG_DEBUG_FS) */
-static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg);
+static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
+{
+ u32 ctrl;
+
+ ctrl = mci_readl(host, CTRL);
+ ctrl |= reset;
+ mci_writel(host, CTRL, ctrl);
+
+ /* wait till resets clear */
+ if (readl_poll_timeout_atomic(host->regs + SDMMC_CTRL, ctrl,
+ !(ctrl & reset),
+ 1, 500 * USEC_PER_MSEC)) {
+ dev_err(host->dev,
+ "Timeout resetting block (ctrl reset %#x)\n",
+ ctrl & reset);
+ return false;
+ }
+
+ return true;
+}
+
+static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags)
+{
+ u32 status;
+
+ /*
+ * Databook says that before issuing a new data transfer command
+ * we need to check to see if the card is busy. Data transfer commands
+ * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that.
+ *
+ * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is
+ * expected.
+ */
+ if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) &&
+ !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) {
+ if (readl_poll_timeout_atomic(host->regs + SDMMC_STATUS,
+ status,
+ !(status & SDMMC_STATUS_BUSY),
+ 10, 500 * USEC_PER_MSEC))
+ dev_err(host->dev, "Busy; trying anyway\n");
+ }
+}
+
+static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
+{
+ struct dw_mci *host = slot->host;
+ unsigned int cmd_status = 0;
+
+ mci_writel(host, CMDARG, arg);
+ wmb(); /* drain writebuffer */
+ dw_mci_wait_while_busy(host, cmd);
+ mci_writel(host, CMD, SDMMC_CMD_START | cmd);
+
+ if (readl_poll_timeout_atomic(host->regs + SDMMC_CMD, cmd_status,
+ !(cmd_status & SDMMC_CMD_START),
+ 1, 500 * USEC_PER_MSEC))
+ dev_err(&slot->mmc->class_dev,
+ "Timeout sending command (cmd %#x arg %#x status %#x)\n",
+ cmd, arg, cmd_status);
+}
static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
@@ -341,31 +398,6 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
return cmdr;
}
-static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
-
- /*
- * Databook says that before issuing a new data transfer command
- * we need to check to see if the card is busy. Data transfer commands
- * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that.
- *
- * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is
- * expected.
- */
- if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) &&
- !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) {
- while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) {
- if (time_after(jiffies, timeout)) {
- /* Command will fail; we'll pass error then */
- dev_err(host->dev, "Busy; trying anyway\n");
- break;
- }
- udelay(10);
- }
- }
-}
-
static void dw_mci_start_command(struct dw_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
@@ -400,14 +432,6 @@ static void dw_mci_stop_dma(struct dw_mci *host)
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}
-static int dw_mci_get_dma_dir(struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_WRITE)
- return DMA_TO_DEVICE;
- else
- return DMA_FROM_DEVICE;
-}
-
static void dw_mci_dma_cleanup(struct dw_mci *host)
{
struct mmc_data *data = host->data;
@@ -416,7 +440,7 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
dma_unmap_sg(host->dev,
data->sg,
data->sg_len,
- dw_mci_get_dma_dir(data));
+ mmc_get_dma_dir(data));
data->host_cookie = COOKIE_UNMAPPED;
}
}
@@ -555,7 +579,7 @@ static inline int dw_mci_prepare_desc64(struct dw_mci *host,
{
unsigned int desc_len;
struct idmac_desc_64addr *desc_first, *desc_last, *desc;
- unsigned long timeout;
+ u32 val;
int i;
desc_first = desc_last = desc = host->sg_cpu;
@@ -577,12 +601,10 @@ static inline int dw_mci_prepare_desc64(struct dw_mci *host,
* isn't still owned by IDMAC as IDMAC's write
* ops and CPU's read ops are asynchronous.
*/
- timeout = jiffies + msecs_to_jiffies(100);
- while (readl(&desc->des0) & IDMAC_DES0_OWN) {
- if (time_after(jiffies, timeout))
- goto err_own_bit;
- udelay(10);
- }
+ if (readl_poll_timeout_atomic(&desc->des0, val,
+ !(val & IDMAC_DES0_OWN),
+ 10, 100 * USEC_PER_MSEC))
+ goto err_own_bit;
/*
* Set the OWN bit and disable interrupts
@@ -629,7 +651,7 @@ static inline int dw_mci_prepare_desc32(struct dw_mci *host,
{
unsigned int desc_len;
struct idmac_desc *desc_first, *desc_last, *desc;
- unsigned long timeout;
+ u32 val;
int i;
desc_first = desc_last = desc = host->sg_cpu;
@@ -651,13 +673,11 @@ static inline int dw_mci_prepare_desc32(struct dw_mci *host,
* isn't still owned by IDMAC as IDMAC's write
* ops and CPU's read ops are asynchronous.
*/
- timeout = jiffies + msecs_to_jiffies(100);
- while (readl(&desc->des0) &
- cpu_to_le32(IDMAC_DES0_OWN)) {
- if (time_after(jiffies, timeout))
- goto err_own_bit;
- udelay(10);
- }
+ if (readl_poll_timeout_atomic(&desc->des0, val,
+ IDMAC_OWN_CLR64(val),
+ 10,
+ 100 * USEC_PER_MSEC))
+ goto err_own_bit;
/*
* Set the OWN bit and disable interrupts
@@ -876,7 +896,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
sg_len = dma_map_sg(host->dev,
data->sg,
data->sg_len,
- dw_mci_get_dma_dir(data));
+ mmc_get_dma_dir(data));
if (sg_len == 0)
return -EINVAL;
@@ -916,10 +936,51 @@ static void dw_mci_post_req(struct mmc_host *mmc,
dma_unmap_sg(slot->host->dev,
data->sg,
data->sg_len,
- dw_mci_get_dma_dir(data));
+ mmc_get_dma_dir(data));
data->host_cookie = COOKIE_UNMAPPED;
}
+static int dw_mci_get_cd(struct mmc_host *mmc)
+{
+ int present;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+ int gpio_cd = mmc_gpio_get_cd(mmc);
+
+ /* Use platform get_cd function, else try onboard card detect */
+ if (((mmc->caps & MMC_CAP_NEEDS_POLL)
+ || !mmc_card_is_removable(mmc))) {
+ present = 1;
+
+ if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
+ if (mmc->caps & MMC_CAP_NEEDS_POLL) {
+ dev_info(&mmc->class_dev,
+ "card is polling.\n");
+ } else {
+ dev_info(&mmc->class_dev,
+ "card is non-removable.\n");
+ }
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+ }
+
+ return present;
+ } else if (gpio_cd >= 0)
+ present = gpio_cd;
+ else
+ present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
+ == 0 ? 1 : 0;
+
+ spin_lock_bh(&host->lock);
+ if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags))
+ dev_dbg(&mmc->class_dev, "card is present\n");
+ else if (!present &&
+ !test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags))
+ dev_dbg(&mmc->class_dev, "card is not present\n");
+ spin_unlock_bh(&host->lock);
+
+ return present;
+}
+
static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
{
unsigned int blksz = data->blksz;
@@ -1133,27 +1194,6 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
}
}
-static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
-{
- struct dw_mci *host = slot->host;
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
- unsigned int cmd_status = 0;
-
- mci_writel(host, CMDARG, arg);
- wmb(); /* drain writebuffer */
- dw_mci_wait_while_busy(host, cmd);
- mci_writel(host, CMD, SDMMC_CMD_START | cmd);
-
- while (time_before(jiffies, timeout)) {
- cmd_status = mci_readl(host, CMD);
- if (!(cmd_status & SDMMC_CMD_START))
- return;
- }
- dev_err(&slot->mmc->class_dev,
- "Timeout sending command (cmd %#x arg %#x status %#x)\n",
- cmd, arg, cmd_status);
-}
-
static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
{
struct dw_mci *host = slot->host;
@@ -1534,47 +1574,6 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
return read_only;
}
-static int dw_mci_get_cd(struct mmc_host *mmc)
-{
- int present;
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci *host = slot->host;
- int gpio_cd = mmc_gpio_get_cd(mmc);
-
- /* Use platform get_cd function, else try onboard card detect */
- if (((mmc->caps & MMC_CAP_NEEDS_POLL)
- || !mmc_card_is_removable(mmc))) {
- present = 1;
-
- if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
- if (mmc->caps & MMC_CAP_NEEDS_POLL) {
- dev_info(&mmc->class_dev,
- "card is polling.\n");
- } else {
- dev_info(&mmc->class_dev,
- "card is non-removable.\n");
- }
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- }
-
- return present;
- } else if (gpio_cd >= 0)
- present = gpio_cd;
- else
- present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
- == 0 ? 1 : 0;
-
- spin_lock_bh(&host->lock);
- if (present && !test_and_set_bit(DW_MMC_CARD_PRESENT, &slot->flags))
- dev_dbg(&mmc->class_dev, "card is present\n");
- else if (!present &&
- !test_and_clear_bit(DW_MMC_CARD_PRESENT, &slot->flags))
- dev_dbg(&mmc->class_dev, "card is not present\n");
- spin_unlock_bh(&host->lock);
-
- return present;
-}
-
static void dw_mci_hw_reset(struct mmc_host *mmc)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
@@ -1688,6 +1687,73 @@ static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc,
return 0;
}
+static bool dw_mci_reset(struct dw_mci *host)
+{
+ u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET;
+ bool ret = false;
+ u32 status = 0;
+
+ /*
+ * Resetting generates a block interrupt, hence setting
+ * the scatter-gather pointer to NULL.
+ */
+ if (host->sg) {
+ sg_miter_stop(&host->sg_miter);
+ host->sg = NULL;
+ }
+
+ if (host->use_dma)
+ flags |= SDMMC_CTRL_DMA_RESET;
+
+ if (dw_mci_ctrl_reset(host, flags)) {
+ /*
+ * In all cases we clear the RAWINTS
+ * register to clear any interrupts.
+ */
+ mci_writel(host, RINTSTS, 0xFFFFFFFF);
+
+ if (!host->use_dma) {
+ ret = true;
+ goto ciu_out;
+ }
+
+ /* Wait for dma_req to be cleared */
+ if (readl_poll_timeout_atomic(host->regs + SDMMC_STATUS,
+ status,
+ !(status & SDMMC_STATUS_DMA_REQ),
+ 1, 500 * USEC_PER_MSEC)) {
+ dev_err(host->dev,
+ "%s: Timeout waiting for dma_req to be cleared\n",
+ __func__);
+ goto ciu_out;
+ }
+
+ /* when using DMA next we reset the fifo again */
+ if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET))
+ goto ciu_out;
+ } else {
+ /* if the controller reset bit did clear, then set clock regs */
+ if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) {
+ dev_err(host->dev,
+ "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n",
+ __func__);
+ goto ciu_out;
+ }
+ }
+
+ if (host->use_dma == TRANS_MODE_IDMAC)
+ /* It is also recommended that we reset and reprogram idmac */
+ dw_mci_idmac_reset(host);
+
+ ret = true;
+
+ciu_out:
+ /* After a CTRL reset we need to have CIU set clock registers */
+ mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0);
+
+ return ret;
+}
+
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
.pre_req = dw_mci_pre_req,
@@ -2830,99 +2896,6 @@ no_dma:
host->use_dma = TRANS_MODE_PIO;
}
-static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
- u32 ctrl;
-
- ctrl = mci_readl(host, CTRL);
- ctrl |= reset;
- mci_writel(host, CTRL, ctrl);
-
- /* wait till resets clear */
- do {
- ctrl = mci_readl(host, CTRL);
- if (!(ctrl & reset))
- return true;
- } while (time_before(jiffies, timeout));
-
- dev_err(host->dev,
- "Timeout resetting block (ctrl reset %#x)\n",
- ctrl & reset);
-
- return false;
-}
-
-static bool dw_mci_reset(struct dw_mci *host)
-{
- u32 flags = SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET;
- bool ret = false;
-
- /*
- * Reseting generates a block interrupt, hence setting
- * the scatter-gather pointer to NULL.
- */
- if (host->sg) {
- sg_miter_stop(&host->sg_miter);
- host->sg = NULL;
- }
-
- if (host->use_dma)
- flags |= SDMMC_CTRL_DMA_RESET;
-
- if (dw_mci_ctrl_reset(host, flags)) {
- /*
- * In all cases we clear the RAWINTS register to clear any
- * interrupts.
- */
- mci_writel(host, RINTSTS, 0xFFFFFFFF);
-
- /* if using dma we wait for dma_req to clear */
- if (host->use_dma) {
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
- u32 status;
-
- do {
- status = mci_readl(host, STATUS);
- if (!(status & SDMMC_STATUS_DMA_REQ))
- break;
- cpu_relax();
- } while (time_before(jiffies, timeout));
-
- if (status & SDMMC_STATUS_DMA_REQ) {
- dev_err(host->dev,
- "%s: Timeout waiting for dma_req to clear during reset\n",
- __func__);
- goto ciu_out;
- }
-
- /* when using DMA next we reset the fifo again */
- if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_FIFO_RESET))
- goto ciu_out;
- }
- } else {
- /* if the controller reset bit did clear, then set clock regs */
- if (!(mci_readl(host, CTRL) & SDMMC_CTRL_RESET)) {
- dev_err(host->dev,
- "%s: fifo/dma reset bits didn't clear but ciu was reset, doing clock update\n",
- __func__);
- goto ciu_out;
- }
- }
-
- if (host->use_dma == TRANS_MODE_IDMAC)
- /* It is also recommended that we reset and reprogram idmac */
- dw_mci_idmac_reset(host);
-
- ret = true;
-
-ciu_out:
- /* After a CTRL reset we need to have CIU set clock registers */
- mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0);
-
- return ret;
-}
-
static void dw_mci_cmd11_timer(unsigned long arg)
{
struct dw_mci *host = (struct dw_mci *)arg;