Patchwork [U-Boot,v3,2/4] Tegra2: mmc: Support DMA restarts at buffer boundaries

login
register
mail settings
Submitter Anton staaf
Date Nov. 10, 2011, 9:56 p.m.
Message ID <1320962212-11789-3-git-send-email-robotboy@chromium.org>
Download mbox | patch
Permalink /patch/125006/
State Accepted
Commit 5a762e2509a2d4b2e86168a2ffbc425087ecd75c
Delegated to: Andy Fleming
Headers show

Comments

Anton staaf - Nov. 10, 2011, 9:56 p.m.
Currently if a DMA buffer straddles a buffer alignment boundary
(512KiB) then the DMA engine will pause and generate a DMA
interrupt.  Since the DMA interrupt is not enabled it will hang
the MMC driver.

This patch adds support for restarting the DMA transfer.  The
SYSTEM_ADDRESS register contains the next address that would have
been read/written when a boundary is hit.  So we can read that
and write it back.  The write triggers the resumption of the
transfer.

Signed-off-by: Anton Staaf <robotboy@chromium.org>
Cc: Andy Fleming <afleming@gmail.com>
Cc: Tom Warren <twarren@nvidia.com>
Cc: Stephen Warren <swarren@nvidia.com>
Cc: Albert Aribaud <albert.u.boot@aribaud.net>
---
 drivers/mmc/tegra2_mmc.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

Patch

diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra2_mmc.c
index 2bea07d..159cef1 100644
--- a/drivers/mmc/tegra2_mmc.c
+++ b/drivers/mmc/tegra2_mmc.c
@@ -270,9 +270,16 @@  static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 						__func__, mask);
 				return -1;
 			} else if (mask & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) {
-				/* DMA Interrupt */
+				/*
+				 * DMA Interrupt, restart the transfer where
+				 * it was interrupted.
+				 */
+				unsigned int address = readl(&host->reg->sysad);
+
 				debug("DMA end\n");
-				break;
+				writel(TEGRA_MMC_NORINTSTS_DMA_INTERRUPT,
+				       &host->reg->norintsts);
+				writel(address, &host->reg->sysad);
 			} else if (mask & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) {
 				/* Transfer Complete */
 				debug("r/w is done\n");
@@ -419,6 +426,7 @@  static int mmc_core_init(struct mmc *mmc)
 	 * NORMAL Interrupt Status Enable Register init
 	 * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable
 	 * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable
+	 * [3] ENSTADMAINT   : DMA boundary interrupt
 	 * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable
 	 * [0] ENSTACMDCMPLT : Command Complete Status Enable
 	*/
@@ -426,6 +434,7 @@  static int mmc_core_init(struct mmc *mmc)
 	mask &= ~(0xffff);
 	mask |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE |
 		 TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE |
+		 TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT |
 		 TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY |
 		 TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY);
 	writel(mask, &host->reg->norintstsen);