summaryrefslogtreecommitdiff
path: root/drivers/mmc/dw_mmc.c
diff options
context:
space:
mode:
authorhuang lin <hl@rock-chips.com>2015-11-17 14:20:22 +0800
committerSimon Glass <sjg@chromium.org>2015-12-01 08:07:22 -0700
commita65f51b97886f0b1d911eb1ea951fce9efd1700f (patch)
tree8643901d9ba712fb8eb6a5ea67d9a5fe02158472 /drivers/mmc/dw_mmc.c
parentf382eb833a06cf3d7cbf17603876a1fabca49144 (diff)
mmc: dw_mmc: support fifo mode in dwc mmc driver
some soc(rk3036 etc) use dw_mmc but do not have internal dma, so we implement fifo mode to read and write data. Signed-off-by: Lin Huang <hl@rock-chips.com> Acked-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/mmc/dw_mmc.c')
-rw-r--r--drivers/mmc/dw_mmc.c85
1 files changed, 67 insertions, 18 deletions
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index bee8fab332..909e3caf18 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -94,12 +94,21 @@ static void dwmci_prepare_data(struct dwmci_host *host,
dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks);
}
-static int dwmci_data_transfer(struct dwmci_host *host)
+static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
{
int ret = 0;
- unsigned int timeout = 240000;
- u32 mask;
+ u32 timeout = 240000;
+ u32 mask, size, i, len = 0;
+ u32 *buf = NULL;
ulong start = get_timer(0);
+ u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
+ RX_WMARK_SHIFT) + 1) * 2;
+
+ size = data->blocksize * data->blocks / 4;
+ if (data->flags == MMC_DATA_READ)
+ buf = (unsigned int *)data->dest;
+ else
+ buf = (unsigned int *)data->src;
for (;;) {
mask = dwmci_readl(host, DWMCI_RINTSTS);
@@ -110,6 +119,36 @@ static int dwmci_data_transfer(struct dwmci_host *host)
break;
}
+ if (host->fifo_mode && size) {
+ if (data->flags == MMC_DATA_READ) {
+ if ((dwmci_readl(host, DWMCI_RINTSTS) &&
+ DWMCI_INTMSK_RXDR)) {
+ len = dwmci_readl(host, DWMCI_STATUS);
+ len = (len >> DWMCI_FIFO_SHIFT) &
+ DWMCI_FIFO_MASK;
+ for (i = 0; i < len; i++)
+ *buf++ =
+ dwmci_readl(host, DWMCI_DATA);
+ dwmci_writel(host, DWMCI_RINTSTS,
+ DWMCI_INTMSK_RXDR);
+ }
+ } else {
+ if ((dwmci_readl(host, DWMCI_RINTSTS) &&
+ DWMCI_INTMSK_TXDR)) {
+ len = dwmci_readl(host, DWMCI_STATUS);
+ len = fifo_depth - ((len >>
+ DWMCI_FIFO_SHIFT) &
+ DWMCI_FIFO_MASK);
+ for (i = 0; i < len; i++)
+ dwmci_writel(host, DWMCI_DATA,
+ *buf++);
+ dwmci_writel(host, DWMCI_RINTSTS,
+ DWMCI_INTMSK_TXDR);
+ }
+ }
+ size = size > len ? (size - len) : 0;
+ }
+
/* Data arrived correctly. */
if (mask & DWMCI_INTMSK_DTO) {
ret = 0;
@@ -165,17 +204,24 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
if (data) {
- if (data->flags == MMC_DATA_READ) {
- bounce_buffer_start(&bbstate, (void*)data->dest,
- data->blocksize *
- data->blocks, GEN_BB_WRITE);
+ if (host->fifo_mode) {
+ dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize);
+ dwmci_writel(host, DWMCI_BYTCNT,
+ data->blocksize * data->blocks);
+ dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
} else {
- bounce_buffer_start(&bbstate, (void*)data->src,
- data->blocksize *
- data->blocks, GEN_BB_READ);
+ if (data->flags == MMC_DATA_READ) {
+ bounce_buffer_start(&bbstate, (void*)data->dest,
+ data->blocksize *
+ data->blocks, GEN_BB_WRITE);
+ } else {
+ bounce_buffer_start(&bbstate, (void*)data->src,
+ data->blocksize *
+ data->blocks, GEN_BB_READ);
+ }
+ dwmci_prepare_data(host, data, cur_idmac,
+ bbstate.bounce_buffer);
}
- dwmci_prepare_data(host, data, cur_idmac,
- bbstate.bounce_buffer);
}
dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);
@@ -249,12 +295,15 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
if (data) {
- ret = dwmci_data_transfer(host);
-
- ctrl = dwmci_readl(host, DWMCI_CTRL);
- ctrl &= ~(DWMCI_DMA_EN);
- dwmci_writel(host, DWMCI_CTRL, ctrl);
- bounce_buffer_stop(&bbstate);
+ ret = dwmci_data_transfer(host, data);
+
+ /* only dma mode need it */
+ if (!host->fifo_mode) {
+ ctrl = dwmci_readl(host, DWMCI_CTRL);
+ ctrl &= ~(DWMCI_DMA_EN);
+ dwmci_writel(host, DWMCI_CTRL, ctrl);
+ bounce_buffer_stop(&bbstate);
+ }
}
udelay(100);