提交 8b1c2ba2 编写于 作者: S San Mehat 提交者: Daniel Walker

mmc: msm_sdcc: Wrap readl/writel calls with appropriate clk delays

As it turns out, all sdcc register writes must be delayed by at
least 3 core clock cycles for the writes to take effect. *sigh*

    Also removes the 30us constant delay on clock enable in favor
of a 3 core clock delay.
Signed-off-by: NSan Mehat <san@google.com>
Signed-off-by: NDaniel Walker <dwalker@codeaurora.org>
上级 865c8064
...@@ -62,6 +62,7 @@ static inline int ...@@ -62,6 +62,7 @@ static inline int
msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
{ {
int rc; int rc;
WARN_ON(enable == host->clks_on); WARN_ON(enable == host->clks_on);
if (enable) { if (enable) {
rc = clk_enable(host->pclk); rc = clk_enable(host->pclk);
...@@ -72,7 +73,8 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) ...@@ -72,7 +73,8 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
clk_disable(host->pclk); clk_disable(host->pclk);
return rc; return rc;
} }
udelay(30); udelay(1 + ((3 * USEC_PER_SEC) /
(host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
host->clks_on = 1; host->clks_on = 1;
} else { } else {
clk_disable(host->clk); clk_disable(host->clk);
...@@ -82,6 +84,20 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) ...@@ -82,6 +84,20 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
return 0; return 0;
} }
static inline unsigned int
msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg)
{
return readl(host->base + reg);
}
static inline void
msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg)
{
writel(data, host->base + reg);
/* 3 clk delay required! */
udelay(1 + ((3 * USEC_PER_SEC) /
(host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
}
static void static void
msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
...@@ -90,7 +106,7 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, ...@@ -90,7 +106,7 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
static void static void
msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
{ {
writel(0, host->base + MMCICOMMAND); msmsdcc_writel(host, 0, MMCICOMMAND);
BUG_ON(host->curr.data); BUG_ON(host->curr.data);
...@@ -116,7 +132,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) ...@@ -116,7 +132,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
static void static void
msmsdcc_stop_data(struct msmsdcc_host *host) msmsdcc_stop_data(struct msmsdcc_host *host)
{ {
writel(0, host->base + MMCIDATACTRL); msmsdcc_writel(host, 0, MMCIDATACTRL);
host->curr.data = NULL; host->curr.data = NULL;
host->curr.got_dataend = host->curr.got_datablkend = 0; host->curr.got_dataend = host->curr.got_datablkend = 0;
} }
...@@ -200,7 +216,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, ...@@ -200,7 +216,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
if (!mrq->data->error) if (!mrq->data->error)
host->curr.data_xfered = host->curr.xfer_size; host->curr.data_xfered = host->curr.xfer_size;
if (!mrq->data->stop || mrq->cmd->error) { if (!mrq->data->stop || mrq->cmd->error) {
writel(0, host->base + MMCICOMMAND); msmsdcc_writel(host, 0, MMCICOMMAND);
host->curr.mrq = NULL; host->curr.mrq = NULL;
host->curr.cmd = NULL; host->curr.cmd = NULL;
mrq->data->bytes_xfered = host->curr.data_xfered; mrq->data->bytes_xfered = host->curr.data_xfered;
...@@ -337,7 +353,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) ...@@ -337,7 +353,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data)
{ {
unsigned int datactrl, timeout; unsigned int datactrl, timeout;
unsigned long long clks; unsigned long long clks;
void __iomem *base = host->base;
unsigned int pio_irqmask = 0; unsigned int pio_irqmask = 0;
host->curr.data = data; host->curr.data = data;
...@@ -352,9 +367,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) ...@@ -352,9 +367,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data)
clks = (unsigned long long)data->timeout_ns * host->clk_rate; clks = (unsigned long long)data->timeout_ns * host->clk_rate;
do_div(clks, NSEC_PER_SEC); do_div(clks, NSEC_PER_SEC);
timeout = data->timeout_clks + (unsigned int)clks; timeout = data->timeout_clks + (unsigned int)clks;
writel(timeout, base + MMCIDATATIMER); msmsdcc_writel(host, timeout, MMCIDATATIMER);
writel(host->curr.xfer_size, base + MMCIDATALENGTH); msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
...@@ -376,8 +391,8 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) ...@@ -376,8 +391,8 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data)
if (data->flags & MMC_DATA_READ) if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION; datactrl |= MCI_DPSM_DIRECTION;
writel(pio_irqmask, base + MMCIMASK1); msmsdcc_writel(host, pio_irqmask, MMCIMASK1);
writel(datactrl, base + MMCIDATACTRL); msmsdcc_writel(host, datactrl, MMCIDATACTRL);
if (datactrl & MCI_DPSM_DMAENABLE) { if (datactrl & MCI_DPSM_DMAENABLE) {
host->dma.busy = 1; host->dma.busy = 1;
...@@ -398,12 +413,8 @@ snoop_cccr_abort(struct mmc_command *cmd) ...@@ -398,12 +413,8 @@ snoop_cccr_abort(struct mmc_command *cmd)
static void static void
msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
{ {
void __iomem *base = host->base; if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE)
msmsdcc_writel(host, 0, MMCICOMMAND);
if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
writel(0, base + MMCICOMMAND);
udelay(2 + ((5 * 1000000) / host->clk_rate));
}
c |= cmd->opcode | MCI_CPSM_ENABLE; c |= cmd->opcode | MCI_CPSM_ENABLE;
...@@ -428,8 +439,8 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) ...@@ -428,8 +439,8 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
host->stats.cmds++; host->stats.cmds++;
writel(cmd->arg, base + MMCIARGUMENT); msmsdcc_writel(host, cmd->arg, MMCIARGUMENT);
writel(c, base + MMCICOMMAND); msmsdcc_writel(host, c, MMCICOMMAND);
} }
static void static void
...@@ -463,13 +474,11 @@ msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, ...@@ -463,13 +474,11 @@ msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
static int static int
msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
{ {
void __iomem *base = host->base;
uint32_t *ptr = (uint32_t *) buffer; uint32_t *ptr = (uint32_t *) buffer;
int count = 0; int count = 0;
while (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) { while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
*ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
*ptr = readl(base + MMCIFIFO + (count % MCI_FIFOSIZE));
ptr++; ptr++;
count += sizeof(uint32_t); count += sizeof(uint32_t);
...@@ -501,7 +510,7 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, ...@@ -501,7 +510,7 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
if (remain == 0) if (remain == 0)
break; break;
status = readl(base + MMCISTATUS); status = msmsdcc_readl(host, MMCISTATUS);
} while (status & MCI_TXFIFOHALFEMPTY); } while (status & MCI_TXFIFOHALFEMPTY);
return ptr - buffer; return ptr - buffer;
...@@ -511,7 +520,7 @@ static int ...@@ -511,7 +520,7 @@ static int
msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin)
{ {
while (maxspin) { while (maxspin) {
if ((readl(host->base + MMCISTATUS) & mask)) if ((msmsdcc_readl(host, MMCISTATUS) & mask))
return 0; return 0;
udelay(1); udelay(1);
--maxspin; --maxspin;
...@@ -523,10 +532,9 @@ static int ...@@ -523,10 +532,9 @@ static int
msmsdcc_pio_irq(int irq, void *dev_id) msmsdcc_pio_irq(int irq, void *dev_id)
{ {
struct msmsdcc_host *host = dev_id; struct msmsdcc_host *host = dev_id;
void __iomem *base = host->base;
uint32_t status; uint32_t status;
status = readl(base + MMCISTATUS); status = msmsdcc_readl(host, MMCISTATUS);
do { do {
unsigned long flags; unsigned long flags;
...@@ -581,14 +589,14 @@ msmsdcc_pio_irq(int irq, void *dev_id) ...@@ -581,14 +589,14 @@ msmsdcc_pio_irq(int irq, void *dev_id)
host->pio.sg_off = 0; host->pio.sg_off = 0;
} }
status = readl(base + MMCISTATUS); status = msmsdcc_readl(host, MMCISTATUS);
} while (1); } while (1);
if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE)
writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1);
if (!host->curr.xfer_remain) if (!host->curr.xfer_remain)
writel(0, base + MMCIMASK1); msmsdcc_writel(host, 0, MMCIMASK1);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -596,13 +604,12 @@ msmsdcc_pio_irq(int irq, void *dev_id) ...@@ -596,13 +604,12 @@ msmsdcc_pio_irq(int irq, void *dev_id)
static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
{ {
struct mmc_command *cmd = host->curr.cmd; struct mmc_command *cmd = host->curr.cmd;
void __iomem *base = host->base;
host->curr.cmd = NULL; host->curr.cmd = NULL;
cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0);
cmd->resp[1] = readl(base + MMCIRESPONSE1); cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1);
cmd->resp[2] = readl(base + MMCIRESPONSE2); cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
cmd->resp[3] = readl(base + MMCIRESPONSE3); cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
del_timer(&host->command_timer); del_timer(&host->command_timer);
if (status & MCI_CMDTIMEOUT) { if (status & MCI_CMDTIMEOUT) {
...@@ -699,10 +706,11 @@ msmsdcc_irq(int irq, void *dev_id) ...@@ -699,10 +706,11 @@ msmsdcc_irq(int irq, void *dev_id)
spin_lock(&host->lock); spin_lock(&host->lock);
do { do {
status = readl(base + MMCISTATUS); struct mmc_data *data;
status = msmsdcc_readl(host, MMCISTATUS);
status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); status &= (msmsdcc_readl(host, MMCIMASK0) |
writel(status, base + MMCICLEAR); MCI_DATABLOCKENDMASK);
msmsdcc_writel(host, status, MMCICLEAR);
if (status & MCI_SDIOINTR) if (status & MCI_SDIOINTR)
status &= ~MCI_SDIOINTR; status &= ~MCI_SDIOINTR;
...@@ -774,10 +782,11 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -774,10 +782,11 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (host->cmdpoll && !msmsdcc_spin_on_status(host, if (host->cmdpoll && !msmsdcc_spin_on_status(host,
MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
CMD_SPINMAX)) { CMD_SPINMAX)) {
uint32_t status = readl(host->base + MMCISTATUS); uint32_t status = msmsdcc_readl(host, MMCISTATUS);
msmsdcc_do_cmdirq(host, status); msmsdcc_do_cmdirq(host, status);
writel(MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, msmsdcc_writel(host,
host->base + MMCICLEAR); MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT,
MMCICLEAR);
host->stats.cmdpoll_hits++; host->stats.cmdpoll_hits++;
} else { } else {
host->stats.cmdpoll_misses++; host->stats.cmdpoll_misses++;
...@@ -836,11 +845,11 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -836,11 +845,11 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
pwr |= MCI_OD; pwr |= MCI_OD;
writel(clk, host->base + MMCICLOCK); msmsdcc_writel(host, clk, MMCICLOCK);
if (host->pwr != pwr) { if (host->pwr != pwr) {
host->pwr = pwr; host->pwr = pwr;
writel(pwr, host->base + MMCIPOWER); msmsdcc_writel(host, pwr, MMCIPOWER);
} }
if (host->clks_on) if (host->clks_on)
msmsdcc_enable_clocks(host, 0); msmsdcc_enable_clocks(host, 0);
...@@ -855,13 +864,13 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) ...@@ -855,13 +864,13 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (msmsdcc_sdioirq == 1) { if (msmsdcc_sdioirq == 1) {
status = readl(host->base + MMCIMASK0); status = msmsdcc_readl(host, MMCIMASK0);
if (enable) if (enable)
status |= MCI_SDIOINTOPERMASK; status |= MCI_SDIOINTOPERMASK;
else else
status &= ~MCI_SDIOINTOPERMASK; status &= ~MCI_SDIOINTOPERMASK;
host->saved_irq0mask = status; host->saved_irq0mask = status;
writel(status, host->base + MMCIMASK0); msmsdcc_writel(host, status, MMCIMASK0);
} }
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
...@@ -950,19 +959,16 @@ msmsdcc_command_expired(unsigned long _data) ...@@ -950,19 +959,16 @@ msmsdcc_command_expired(unsigned long _data)
mrq = host->curr.mrq; mrq = host->curr.mrq;
if (!mrq) { if (!mrq) {
pr_info("%s: Command expiry misfire\n",
mmc_hostname(host->mmc));
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
return; return;
} }
pr_err("%s: Command timeout (%p %p %p %p)\n", pr_err("%s: Controller lockup detected\n",
mmc_hostname(host->mmc), mrq, mrq->cmd, mmc_hostname(host->mmc));
mrq->data, host->dma.sg);
mrq->cmd->error = -ETIMEDOUT; mrq->cmd->error = -ETIMEDOUT;
msmsdcc_stop_data(host); msmsdcc_stop_data(host);
writel(0, host->base + MMCICOMMAND); msmsdcc_writel(host, 0, MMCICOMMAND);
host->curr.mrq = NULL; host->curr.mrq = NULL;
host->curr.cmd = NULL; host->curr.cmd = NULL;
...@@ -1143,10 +1149,10 @@ msmsdcc_probe(struct platform_device *pdev) ...@@ -1143,10 +1149,10 @@ msmsdcc_probe(struct platform_device *pdev)
mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
mmc->max_seg_size = mmc->max_req_size; mmc->max_seg_size = mmc->max_req_size;
writel(0, host->base + MMCIMASK0); msmsdcc_writel(host, 0, MMCIMASK0);
writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
writel(MCI_IRQENABLE, host->base + MMCIMASK0); msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
host->saved_irq0mask = MCI_IRQENABLE; host->saved_irq0mask = MCI_IRQENABLE;
/* /*
...@@ -1269,7 +1275,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) ...@@ -1269,7 +1275,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
rc = mmc_suspend_host(mmc, state); rc = mmc_suspend_host(mmc, state);
if (!rc) { if (!rc) {
writel(0, host->base + MMCIMASK0); msmsdcc_writel(host, 0, MMCIMASK0);
if (host->clks_on) if (host->clks_on)
msmsdcc_enable_clocks(host, 0); msmsdcc_enable_clocks(host, 0);
...@@ -1292,7 +1298,7 @@ msmsdcc_resume(struct platform_device *dev) ...@@ -1292,7 +1298,7 @@ msmsdcc_resume(struct platform_device *dev)
if (!host->clks_on) if (!host->clks_on)
msmsdcc_enable_clocks(host, 1); msmsdcc_enable_clocks(host, 1);
writel(host->saved_irq0mask, host->base + MMCIMASK0); msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册