提交 a6d297f0 编写于 作者: N Nicolas Pitre 提交者: Pierre Ossman

mvsdio: fix config failure with some high speed SDHC cards

Especially with Sandisk SDHC cards, the second SWITCH command was failing
with a timeout and the card was not recognized at all.  However if the
system was busy, or debugging was enabled, or a udelay(100) was inserted
before the second SWITCH command in the core code, then the timing was
so that the card started to work.

With some unusual block sizes, the data FIFO status doesn't indicate a
"empty" state right away when the data transfer is done.  Queuing
another data transfer in that condition results in a transfer timeout.

The empty FIFO bit eventually get set by itself in less than 50 usecs
when it is not set right away. So let's just poll for that bit before
configuring the controller with a new data transfer.
Signed-off-by: NNicolas Pitre <nico@marvell.com>
Signed-off-by: NPierre Ossman <pierre@ossman.eu>
上级 9ca6944c
...@@ -64,6 +64,31 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) ...@@ -64,6 +64,31 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
unsigned int tmout; unsigned int tmout;
int tmout_index; int tmout_index;
/*
* Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE
* register is sometimes not set before a while when some
* "unusual" data block sizes are used (such as with the SWITCH
* command), even despite the fact that the XFER_DONE interrupt
* was raised. And if another data transfer starts before
* this bit comes to good sense (which eventually happens by
* itself) then the new transfer simply fails with a timeout.
*/
if (!(mvsd_read(MVSD_HW_STATE) & (1 << 13))) {
unsigned long t = jiffies + HZ;
unsigned int hw_state, count = 0;
do {
if (time_after(jiffies, t)) {
dev_warn(host->dev, "FIFO_EMPTY bit missing\n");
break;
}
hw_state = mvsd_read(MVSD_HW_STATE);
count++;
} while (!(hw_state & (1 << 13)));
dev_dbg(host->dev, "*** wait for FIFO_EMPTY bit "
"(hw=0x%04x, count=%d, jiffies=%ld)\n",
hw_state, count, jiffies - (t - HZ));
}
/* If timeout=0 then maximum timeout index is used. */ /* If timeout=0 then maximum timeout index is used. */
tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk); tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk);
tmout += data->timeout_clks; tmout += data->timeout_clks;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册