mmc: dw_mmc: check fifo status with a timeout in fifo mode

While trying to enable the dw_mmc on rk3188 I managed to confuse
and hang the dw_mmc controller into not delivering further data.
The fifo state never became ready and the driver was iterating in
the while loop reading 0-byte packets forever.

So inspired by how other implementations handle this, check the fifo-
state beforhand and add a timeout to catch any glaring fifo issues
without hanging uboot altogether.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Acked-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
lime2-spi
Heiko Stuebner 6 years ago committed by Philipp Tomsich
parent 2ba8bf2074
commit 05fa06b960
  1. 32
      drivers/mmc/dw_mmc.c
  2. 2
      include/dwmmc.h

@ -92,6 +92,24 @@ static void dwmci_prepare_data(struct dwmci_host *host,
dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks);
}
static int dwmci_fifo_ready(struct dwmci_host *host, u32 bit, u32 *len)
{
u32 timeout = 20000;
*len = dwmci_readl(host, DWMCI_STATUS);
while (--timeout && (*len & bit)) {
udelay(200);
*len = dwmci_readl(host, DWMCI_STATUS);
}
if (!timeout) {
debug("%s: FIFO underflow timeout\n", __func__);
return -ETIMEDOUT;
}
return 0;
}
static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
{
int ret = 0;
@ -122,7 +140,12 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
if (data->flags == MMC_DATA_READ &&
(mask & DWMCI_INTMSK_RXDR)) {
while (size) {
len = dwmci_readl(host, DWMCI_STATUS);
ret = dwmci_fifo_ready(host,
DWMCI_FIFO_EMPTY,
&len);
if (ret < 0)
break;
len = (len >> DWMCI_FIFO_SHIFT) &
DWMCI_FIFO_MASK;
len = min(size, len);
@ -136,7 +159,12 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
} else if (data->flags == MMC_DATA_WRITE &&
(mask & DWMCI_INTMSK_TXDR)) {
while (size) {
len = dwmci_readl(host, DWMCI_STATUS);
ret = dwmci_fifo_ready(host,
DWMCI_FIFO_FULL,
&len);
if (ret < 0)
break;
len = fifo_depth - ((len >>
DWMCI_FIFO_SHIFT) &
DWMCI_FIFO_MASK);

@ -103,6 +103,8 @@
#define DWMCI_CTYPE_8BIT (1 << 16)
/* Status Register */
#define DWMCI_FIFO_EMPTY (1 << 2)
#define DWMCI_FIFO_FULL (1 << 3)
#define DWMCI_BUSY (1 << 9)
#define DWMCI_FIFO_MASK 0x1fff
#define DWMCI_FIFO_SHIFT 17

Loading…
Cancel
Save