All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] omap4: hsmmc: Adding ADMA support
@ 2011-01-18 17:26 Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 1/4] omap: hsmmc: Rename use_dma to xfer_type and define possible transfers Kishore Kadiyala
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Kishore Kadiyala @ 2011-01-18 17:26 UTC (permalink / raw)
  To: linux-mmc, linux-omap; +Cc: tony, cjb, madhu.cr, Kishore Kadiyala

This patch series adds support for ADMA on MMC1 & MMC2 controllers on OMAP4.
There is no performance improvement observed using ADMA over SDMA.
Advantage using ADMA could be reducing contention over SDMA.
Also the series includes some cleanup.

The series is based on 2.6.37-rc8 and tested on OMAP4430SDP & OMAP3430SDP.


Kishore Kadiyala (4):
  omap: hsmmc: Rename use_dma to xfer_type and define possible
    transfers
  omap: hsmmc: Rename and cleanup omap_hsmmc_dma_cleanup
  omap4: hsmmc: Adding ADMA support for MMC1 & MMC2 controllers
  omap4: hsmmc: enable ADMA for MMC1 & MMC2

 arch/arm/mach-omap2/hsmmc.c           |   13 ++-
 arch/arm/plat-omap/include/plat/mmc.h |    1 +
 drivers/mmc/host/omap_hsmmc.c         |  241 +++++++++++++++++++++++++++------
 3 files changed, 210 insertions(+), 45 deletions(-)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] omap: hsmmc: Rename use_dma to xfer_type and define possible transfers
  2011-01-18 17:26 [PATCH 0/4] omap4: hsmmc: Adding ADMA support Kishore Kadiyala
@ 2011-01-18 17:26 ` Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 2/4] omap: hsmmc: Rename and cleanup omap_hsmmc_dma_cleanup Kishore Kadiyala
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Kishore Kadiyala @ 2011-01-18 17:26 UTC (permalink / raw)
  To: linux-mmc, linux-omap; +Cc: tony, cjb, madhu.cr, Kishore Kadiyala

OMAP4 introduces dedicated internal DMA which is ADMA for its MMC
controllers HSMMC1 & HSMMC2.
Renaming "use_dma" member of the struct omap_hsmmc_host to "xfer_type"
and defining the transfer modes PIO/SDMA/ADMA that can be used by the
MMC controller.

Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Reviewed-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 5d46021..8fb8586 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -125,6 +125,11 @@
 #define OMAP_MMC_SLEEP_TIMEOUT		1000
 #define OMAP_MMC_OFF_TIMEOUT		8000
 
+/* Transfer Modes used by MMC controller */
+#define	OMAP_HSMMC_USE_PIO_XFER		0
+#define	OMAP_HSMMC_USE_SDMA_XFER	1
+#define	OMAP_HSMMC_USE_ADMA_XFER	2
+
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -172,7 +177,8 @@ struct omap_hsmmc_host {
 	u32			bytesleft;
 	int			suspended;
 	int			irq;
-	int			use_dma, dma_ch;
+	int			dma_ch;
+	int			xfer_type; /* Transfer can be PIO/SDMA/ADMA */
 	int			dma_line_tx, dma_line_rx;
 	int			slot_id;
 	int			got_dbclk;
@@ -545,7 +551,7 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
 {
 	unsigned int irq_mask;
 
-	if (host->use_dma)
+	if (host->xfer_type != OMAP_HSMMC_USE_PIO_XFER)
 		irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
 	else
 		irq_mask = INT_EN_MASK;
@@ -835,7 +841,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 			cmdreg &= ~(DDIR);
 	}
 
-	if (host->use_dma)
+	if (host->xfer_type != OMAP_HSMMC_USE_PIO_XFER)
 		cmdreg |= DMA_EN;
 
 	host->req_in_progress = 1;
@@ -864,7 +870,7 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
 
 	omap_hsmmc_disable_irq(host);
 	/* Do not complete the request if DMA is still in progress */
-	if (mrq->data && host->use_dma && dma_ch != -1)
+	if (mrq->data && host->xfer_type && dma_ch != -1)
 		return;
 	host->mrq = NULL;
 	mmc_request_done(host->mmc, mrq);
@@ -942,7 +948,7 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
 	host->dma_ch = -1;
 	spin_unlock(&host->irq_lock);
 
-	if (host->use_dma && dma_ch != -1) {
+	if (host->xfer_type && dma_ch != -1) {
 		dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
 			omap_hsmmc_get_dma_dir(host, host->data));
 		omap_free_dma(dma_ch);
@@ -1451,7 +1457,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
 					| (req->data->blocks << 16));
 	set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
 
-	if (host->use_dma) {
+	if (host->xfer_type) {
 		ret = omap_hsmmc_start_dma_transfer(host, req);
 		if (ret != 0) {
 			dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
@@ -2050,7 +2056,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 	host->mmc	= mmc;
 	host->pdata	= pdata;
 	host->dev	= &pdev->dev;
-	host->use_dma	= 1;
+	host->xfer_type	= OMAP_HSMMC_USE_SDMA_XFER;
 	host->dev->dma_mask = &pdata->dma_mask;
 	host->dma_ch	= -1;
 	host->irq	= irq;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] omap: hsmmc: Rename and cleanup omap_hsmmc_dma_cleanup
  2011-01-18 17:26 [PATCH 0/4] omap4: hsmmc: Adding ADMA support Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 1/4] omap: hsmmc: Rename use_dma to xfer_type and define possible transfers Kishore Kadiyala
@ 2011-01-18 17:26 ` Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 3/4] omap4: hsmmc: Adding ADMA support for MMC1 & MMC2 controllers Kishore Kadiyala
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Kishore Kadiyala @ 2011-01-18 17:26 UTC (permalink / raw)
  To: linux-mmc, linux-omap; +Cc: tony, cjb, madhu.cr, Kishore Kadiyala

Renaming omap_hsmmc_dma_cleanup as omap_hsmmc_xfer_cleanup and doing some
cleanup by handling the error & success scenarios during a transfer for
different xfer_type.

Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Reviewed-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 drivers/mmc/host/omap_hsmmc.c |   52 ++++++++++++++++++++++------------------
 1 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 8fb8586..7cf0383 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -935,25 +935,37 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
 }
 
 /*
- * DMA clean up for command errors
+ * SDMA clean up during SDMA transfers.
+ * Also unmapping of sg list in case of error/transfer done during
+ * SDMA/ADMA transfers.
  */
-static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
+static void omap_hsmmc_xfer_cleanup(struct omap_hsmmc_host *host, int errno)
 {
 	int dma_ch;
+	struct mmc_data *data = errno ? host->data : host->mrq->data;
 
-	host->data->error = errno;
-
-	spin_lock(&host->irq_lock);
-	dma_ch = host->dma_ch;
-	host->dma_ch = -1;
-	spin_unlock(&host->irq_lock);
-
-	if (host->xfer_type && dma_ch != -1) {
-		dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
-			omap_hsmmc_get_dma_dir(host, host->data));
+	switch (host->xfer_type) {
+	case OMAP_HSMMC_USE_SDMA_XFER:
+		spin_lock(&host->irq_lock);
+		dma_ch = host->dma_ch;
+		host->dma_ch = -1;
+		spin_unlock(&host->irq_lock);
+		if (dma_ch != -1)
+			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+				host->dma_len,
+				omap_hsmmc_get_dma_dir(host, data));
 		omap_free_dma(dma_ch);
+		break;
+	case OMAP_HSMMC_USE_PIO_XFER:
+		/* TODO */
+		break;
+	default:
+		dev_dbg(mmc_dev(host->mmc), "Unknown xfer_type\n");
+	}
+	if (errno) {
+		host->data->error = errno;
+		host->data = NULL;
 	}
-	host->data = NULL;
 }
 
 /*
@@ -1059,7 +1071,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 			}
 			if (host->data || host->response_busy) {
 				if (host->data)
-					omap_hsmmc_dma_cleanup(host,
+					omap_hsmmc_xfer_cleanup(host,
 								-ETIMEDOUT);
 				host->response_busy = 0;
 				omap_hsmmc_reset_controller_fsm(host, SRD);
@@ -1072,7 +1084,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 						-ETIMEDOUT : -EILSEQ;
 
 				if (host->data)
-					omap_hsmmc_dma_cleanup(host, err);
+					omap_hsmmc_xfer_cleanup(host, err);
 				else
 					host->mrq->cmd->error = err;
 				host->response_busy = 0;
@@ -1310,7 +1322,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
 {
 	struct omap_hsmmc_host *host = cb_data;
 	struct mmc_data *data = host->mrq->data;
-	int dma_ch, req_in_progress;
+	int req_in_progress;
 
 	if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
 		dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n",
@@ -1332,16 +1344,10 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
 		spin_unlock(&host->irq_lock);
 		return;
 	}
-
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
-		omap_hsmmc_get_dma_dir(host, data));
-
 	req_in_progress = host->req_in_progress;
-	dma_ch = host->dma_ch;
-	host->dma_ch = -1;
 	spin_unlock(&host->irq_lock);
 
-	omap_free_dma(dma_ch);
+	omap_hsmmc_xfer_cleanup(host, 0);
 
 	/* If DMA has finished after TC, complete the request */
 	if (!req_in_progress) {
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] omap4: hsmmc: Adding ADMA support for MMC1 & MMC2 controllers
  2011-01-18 17:26 [PATCH 0/4] omap4: hsmmc: Adding ADMA support Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 1/4] omap: hsmmc: Rename use_dma to xfer_type and define possible transfers Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 2/4] omap: hsmmc: Rename and cleanup omap_hsmmc_dma_cleanup Kishore Kadiyala
@ 2011-01-18 17:26 ` Kishore Kadiyala
  2011-01-18 17:26 ` [PATCH 4/4] omap4: hsmmc: enable ADMA for MMC1 & MMC2 Kishore Kadiyala
  2011-01-20 17:42 ` [PATCH 0/4] omap4: hsmmc: Adding ADMA support Tony Lindgren
  4 siblings, 0 replies; 7+ messages in thread
From: Kishore Kadiyala @ 2011-01-18 17:26 UTC (permalink / raw)
  To: linux-mmc, linux-omap
  Cc: tony, cjb, madhu.cr, Kishore Kadiyala, Venkatraman S, Santosh Shilimkar

On OMAP4, MMC1 & MMC2 controllers support ADMA feature which will
provide direct access to internal data.
Basically ADMA is a DMA controller embedded in the MMC controller.
It fetches each descriptor line [address+length+attributes] from a
descriptor table and executes the corresponding action [based on attributes].
Base address of Descriptor table in stored in MMCHS_ADMASAL register.

Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Signed-off-by: Venkatraman S <svenkatr@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Reviewed-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/plat-omap/include/plat/mmc.h |    1 +
 drivers/mmc/host/omap_hsmmc.c         |  223 +++++++++++++++++++++++++++------
 2 files changed, 184 insertions(+), 40 deletions(-)

diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index f57f36a..b13e927 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -110,6 +110,7 @@ struct omap_mmc_platform_data {
 		/* we can put the features above into this variable */
 #define HSMMC_HAS_PBIAS		(1 << 0)
 #define HSMMC_HAS_UPDATED_RESET	(1 << 1)
+#define HSMMC_HAS_ADMA_SUPPORT	(1 << 2)
 		unsigned features;
 
 		int switch_pin;			/* gpio (card detect) */
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 7cf0383..aaa113b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -51,12 +51,15 @@
 #define OMAP_HSMMC_RSP54	0x0118
 #define OMAP_HSMMC_RSP76	0x011C
 #define OMAP_HSMMC_DATA		0x0120
+#define OMAP_HSMMC_PSTATE	0x0124
 #define OMAP_HSMMC_HCTL		0x0128
 #define OMAP_HSMMC_SYSCTL	0x012C
 #define OMAP_HSMMC_STAT		0x0130
 #define OMAP_HSMMC_IE		0x0134
 #define OMAP_HSMMC_ISE		0x0138
 #define OMAP_HSMMC_CAPA		0x0140
+#define OMAP_HSMMC_ADMA_ES	0x0154
+#define OMAP_HSMMC_ADMA_SAL	0x0158
 
 #define VS18			(1 << 26)
 #define VS30			(1 << 25)
@@ -104,6 +107,25 @@
 #define SRD			(1 << 26)
 #define SOFTRESET		(1 << 1)
 #define RESETDONE		(1 << 0)
+#define DMAS			(0x2 << 3)
+#define CAPA_ADMA_SUPPORT	(1 << 19)
+#define ADMA_XFER_VALID		(1 << 0)
+#define ADMA_XFER_END		(1 << 1)
+#define ADMA_XFER_LINK		(1 << 4)
+#define ADMA_XFER_DESC		(1 << 5)
+#define DMA_MNS_ADMA_MODE	(1 << 20)
+#define ADMA_ERR		(1 << 25)
+#define ADMA_XFER_INT		(1 << 3)
+
+#define ADMA_TABLE_SZ		(PAGE_SIZE)
+#define ADMA_TABLE_NUM_ENTRIES	(ADMA_TABLE_SZ / sizeof(struct adma_desc_table))
+
+/*
+ * According to TRM, it is possible to transfer upto 64kB per ADMA table entry.
+ * But 64kB = 0x10000 cannot be represented using a 16bit integer
+ * in 1 ADMA table row. Hence rounding it to a lesser value.
+ */
+#define ADMA_MAX_XFER_PER_ROW (63 * 1024)
 
 /*
  * FIXME: Most likely all the data using these _DEVID defines should come
@@ -146,6 +168,13 @@
 #define OMAP_HSMMC_WRITE(base, reg, val) \
 	__raw_writel((val), (base) + OMAP_HSMMC_##reg)
 
+/* ADMA descriptor table entry */
+struct adma_desc_table {
+	u16 attr;
+	u16 length;
+	dma_addr_t addr;
+};
+
 struct omap_hsmmc_host {
 	struct	device		*dev;
 	struct	mmc_host	*mmc;
@@ -179,6 +208,8 @@ struct omap_hsmmc_host {
 	int			irq;
 	int			dma_ch;
 	int			xfer_type; /* Transfer can be PIO/SDMA/ADMA */
+	struct adma_desc_table	*adma_table;
+	dma_addr_t		phy_adma_table;
 	int			dma_line_tx, dma_line_rx;
 	int			slot_id;
 	int			got_dbclk;
@@ -877,6 +908,44 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
 }
 
 /*
+ * SDMA clean up during SDMA transfers.
+ * Also unmapping of sg list in case of error/transfer done during
+ * SDMA/ADMA transfers.
+ */
+static void omap_hsmmc_xfer_cleanup(struct omap_hsmmc_host *host, int errno)
+{
+	int dma_ch;
+	struct mmc_data *data = errno ? host->data : host->mrq->data;
+
+	switch (host->xfer_type) {
+	case OMAP_HSMMC_USE_SDMA_XFER:
+		spin_lock(&host->irq_lock);
+		dma_ch = host->dma_ch;
+		host->dma_ch = -1;
+		spin_unlock(&host->irq_lock);
+		if (dma_ch != -1)
+			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+				host->dma_len,
+				omap_hsmmc_get_dma_dir(host, data));
+		omap_free_dma(dma_ch);
+		break;
+	case OMAP_HSMMC_USE_ADMA_XFER:
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+			host->dma_len, omap_hsmmc_get_dma_dir(host, data));
+		break;
+	case OMAP_HSMMC_USE_PIO_XFER:
+		/* TODO */
+		break;
+	default:
+		dev_dbg(mmc_dev(host->mmc), "Unknown xfer_type\n");
+	}
+	if (errno) {
+		host->data->error = errno;
+		host->data = NULL;
+	}
+}
+
+/*
  * Notify the transfer complete to MMC core
  */
 static void
@@ -898,6 +967,9 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
 
 	host->data = NULL;
 
+	if (host->xfer_type == OMAP_HSMMC_USE_ADMA_XFER)
+		omap_hsmmc_xfer_cleanup(host, 0);
+
 	if (!data->error)
 		data->bytes_xfered += data->blocks * (data->blksz);
 	else
@@ -935,40 +1007,6 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
 }
 
 /*
- * SDMA clean up during SDMA transfers.
- * Also unmapping of sg list in case of error/transfer done during
- * SDMA/ADMA transfers.
- */
-static void omap_hsmmc_xfer_cleanup(struct omap_hsmmc_host *host, int errno)
-{
-	int dma_ch;
-	struct mmc_data *data = errno ? host->data : host->mrq->data;
-
-	switch (host->xfer_type) {
-	case OMAP_HSMMC_USE_SDMA_XFER:
-		spin_lock(&host->irq_lock);
-		dma_ch = host->dma_ch;
-		host->dma_ch = -1;
-		spin_unlock(&host->irq_lock);
-		if (dma_ch != -1)
-			dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-				host->dma_len,
-				omap_hsmmc_get_dma_dir(host, data));
-		omap_free_dma(dma_ch);
-		break;
-	case OMAP_HSMMC_USE_PIO_XFER:
-		/* TODO */
-		break;
-	default:
-		dev_dbg(mmc_dev(host->mmc), "Unknown xfer_type\n");
-	}
-	if (errno) {
-		host->data->error = errno;
-		host->data = NULL;
-	}
-}
-
-/*
  * Readable error output
  */
 #ifdef CONFIG_MMC_DEBUG
@@ -976,10 +1014,10 @@ static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status)
 {
 	/* --- means reserved bit without definition at documentation */
 	static const char *omap_hsmmc_status_bits[] = {
-		"CC", "TC", "BGE", "---", "BWR", "BRR", "---", "---", "CIRQ",
-		"OBI", "---", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
-		"CEB", "CIE", "DTO", "DCRC", "DEB", "---", "ACE", "---",
-		"---", "---", "---", "CERR", "CERR", "BADA", "---", "---", "---"
+		"CC", "TC", "BGE", "DMA", "BWR", "BRR", "CINS", "CREM", "CIRQ",
+		"OBI", "BSR", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
+		"CEB", "CIE", "DTO", "DCRC", "DEB", "CLE", "ACE", "ADMA",
+		"---", "---", "CERR", "BADA", "---", "---"
 	};
 	char res[256];
 	char *buf = res;
@@ -1100,6 +1138,24 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 			if (host->data)
 				end_trans = 1;
 		}
+		if (status & ADMA_ERR) {
+			dev_dbg(mmc_dev(host->mmc),
+				"ADMA err: ADMA_ES=%x, SAL=%x; Ignored!\n",
+					OMAP_HSMMC_READ(host->base, ADMA_ES),
+					OMAP_HSMMC_READ(host->base, ADMA_SAL));
+			if (host->cmd)
+				end_cmd = 1;
+			if (host->data)
+				end_trans = 1;
+		}
+	}
+	if (status & ADMA_XFER_INT) {
+		dev_dbg(mmc_dev(host->mmc),
+			"ADMA XFERINT: blk=%x at table=%x pstate=%x\n",
+			OMAP_HSMMC_READ(host->base, BLK),
+			OMAP_HSMMC_READ(host->base, ADMA_SAL),
+			OMAP_HSMMC_READ(host->base, PSTATE));
+
 	}
 
 	OMAP_HSMMC_WRITE(host->base, STAT, status);
@@ -1402,6 +1458,63 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
 	return 0;
 }
 
+static int mmc_populate_adma_desc_table(struct omap_hsmmc_host *host,
+		struct mmc_request *req, struct adma_desc_table *pdesc)
+{
+	int i, j, dmalen;
+	int splitseg, xferaddr;
+	int numblocks = 0;
+	dma_addr_t dmaaddr;
+	struct mmc_data *data = req->data;
+
+	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+		data->sg_len, omap_hsmmc_get_dma_dir(host, data));
+	for (i = 0, j = 0; i < host->dma_len; i++) {
+		dmaaddr = sg_dma_address(data->sg + i);
+		dmalen = sg_dma_len(data->sg + i);
+		numblocks += dmalen / data->blksz;
+
+		if (dmalen <= ADMA_MAX_XFER_PER_ROW) {
+			pdesc[i + j].length = dmalen;
+			pdesc[i + j].addr = dmaaddr;
+			pdesc[i + j].attr = (ADMA_XFER_DESC |
+						ADMA_XFER_VALID);
+		} else {
+			/* Each descriptor row can only support
+			 * transfer upto ADMA_MAX_XFER_PER_ROW.
+			 * If the current segment is bigger, it has to be
+			 * split to multiple ADMA table entries.
+			 */
+			xferaddr = 0;
+			do {
+				splitseg = min(dmalen, ADMA_MAX_XFER_PER_ROW);
+				dmalen -= splitseg;
+				pdesc[i + j].length = splitseg;
+				pdesc[i + j].addr = dmaaddr + xferaddr;
+				xferaddr += splitseg;
+				pdesc[i + j].attr = (ADMA_XFER_DESC |
+							ADMA_XFER_VALID);
+				j++;
+			} while (dmalen);
+			j--; /* Compensate for i++ */
+		}
+	}
+	/* Setup last entry to terminate */
+	pdesc[i + j - 1].attr |= ADMA_XFER_END;
+	WARN_ON((i + j - 1) > ADMA_TABLE_NUM_ENTRIES);
+	dev_dbg(mmc_dev(host->mmc),
+		"ADMA table has %d entries from %d sglist\n",
+		i + j, host->dma_len);
+	return numblocks;
+}
+
+static void omap_hsmmc_start_adma_transfer(struct omap_hsmmc_host *host)
+{
+	/* Enforcing ordering in write operations */
+	wmb();
+	OMAP_HSMMC_WRITE(host->base, ADMA_SAL, host->phy_adma_table);
+}
+
 static void set_data_timeout(struct omap_hsmmc_host *host,
 			     unsigned int timeout_ns,
 			     unsigned int timeout_clks)
@@ -1446,6 +1559,7 @@ static int
 omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
 {
 	int ret;
+	int numblks;
 	host->data = req->data;
 
 	if (req->data == NULL) {
@@ -1463,12 +1577,17 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
 					| (req->data->blocks << 16));
 	set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
 
-	if (host->xfer_type) {
+	if (host->xfer_type == OMAP_HSMMC_USE_SDMA_XFER) {
 		ret = omap_hsmmc_start_dma_transfer(host, req);
 		if (ret != 0) {
 			dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
 			return ret;
 		}
+	} else if (host->xfer_type == OMAP_HSMMC_USE_ADMA_XFER) {
+		numblks = mmc_populate_adma_desc_table(host, req,
+							host->adma_table);
+		WARN_ON(numblks != req->data->blocks);
+		omap_hsmmc_start_adma_transfer(host);
 	}
 	return 0;
 }
@@ -1667,6 +1786,11 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
 		capa = VS18;
 	}
 
+	if (host->xfer_type == OMAP_HSMMC_USE_ADMA_XFER) {
+		hctl |= DMAS;
+		value = OMAP_HSMMC_READ(host->base, CON);
+		OMAP_HSMMC_WRITE(host->base, CON, value | DMA_MNS_ADMA_MODE);
+	}
 	value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
 	OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
 
@@ -2024,7 +2148,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 	struct mmc_host *mmc;
 	struct omap_hsmmc_host *host = NULL;
 	struct resource *res;
-	int ret, irq;
+	int ret, irq, capa;
 
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "Platform Data is missing\n");
@@ -2162,6 +2286,19 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 	if (mmc_slot(host).nonremovable)
 		mmc->caps |= MMC_CAP_NONREMOVABLE;
 
+	if (mmc_slot(host).features & HSMMC_HAS_ADMA_SUPPORT) {
+		capa = OMAP_HSMMC_READ(host->base, CAPA);
+		if (capa & CAPA_ADMA_SUPPORT) {
+			/* Allocating memory for ADMA Descriptor Table */
+			host->adma_table = dma_alloc_coherent(NULL,
+				ADMA_TABLE_SZ, &host->phy_adma_table, 0);
+			/* If allocation is success go with ADMA else SDMA */
+			if (host->adma_table != NULL)
+				host->xfer_type = OMAP_HSMMC_USE_ADMA_XFER;
+		}
+	}
+	dev_dbg(mmc_dev(host->mmc), "xfer_type=%d\n", host->xfer_type);
+
 	omap_hsmmc_conf_bus_power(host);
 
 	/* Select DMA lines */
@@ -2277,6 +2414,9 @@ err_irq:
 		clk_put(host->dbclk);
 	}
 err1:
+	if (host->adma_table != NULL)
+		dma_free_coherent(NULL, ADMA_TABLE_SZ,
+			host->adma_table, host->phy_adma_table);
 	iounmap(host->base);
 	platform_set_drvdata(pdev, NULL);
 	mmc_free_host(mmc);
@@ -2304,6 +2444,9 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
 			free_irq(mmc_slot(host).card_detect_irq, host);
 		flush_scheduled_work();
 
+		if (host->adma_table != NULL)
+			dma_free_coherent(NULL, ADMA_TABLE_SZ,
+				host->adma_table, host->phy_adma_table);
 		mmc_host_disable(host->mmc);
 		clk_disable(host->iclk);
 		clk_put(host->fclk);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] omap4: hsmmc: enable ADMA for MMC1 & MMC2
  2011-01-18 17:26 [PATCH 0/4] omap4: hsmmc: Adding ADMA support Kishore Kadiyala
                   ` (2 preceding siblings ...)
  2011-01-18 17:26 ` [PATCH 3/4] omap4: hsmmc: Adding ADMA support for MMC1 & MMC2 controllers Kishore Kadiyala
@ 2011-01-18 17:26 ` Kishore Kadiyala
  2011-01-20 17:42 ` [PATCH 0/4] omap4: hsmmc: Adding ADMA support Tony Lindgren
  4 siblings, 0 replies; 7+ messages in thread
From: Kishore Kadiyala @ 2011-01-18 17:26 UTC (permalink / raw)
  To: linux-mmc, linux-omap
  Cc: tony, cjb, madhu.cr, Kishore Kadiyala, Venkatraman S

Enable ADMA support for MMC1 & MMC2 controller on omap4 by updating
"features" of struct omap_mmc_platform_data.

Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Signed-off-by: Venkatraman S <svenkatr@ti.com>
Reviewed-by: Sukumar Ghorai <s-ghorai@ti.com>
---
 arch/arm/mach-omap2/hsmmc.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 34272e4..2ac7271 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -307,8 +307,17 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
 		else
 			mmc->slots[0].features |= HSMMC_HAS_PBIAS;
 
-		if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
-			mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+		/*
+		 * OMAP4: MMC1 & MMC2 controllers support ADMA.
+		 * Default works with SDMA.
+		 * For ADMA support, update respective BIT in features.
+		 */
+		if (cpu_is_omap44xx()) {
+			mmc->slots[0].features |= HSMMC_HAS_ADMA_SUPPORT;
+			if (omap_rev() > OMAP4430_REV_ES1_0)
+				mmc->slots[0].features |=
+						HSMMC_HAS_UPDATED_RESET;
+		}
 
 		switch (c->mmc) {
 		case 1:
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] omap4: hsmmc: Adding ADMA support
  2011-01-18 17:26 [PATCH 0/4] omap4: hsmmc: Adding ADMA support Kishore Kadiyala
                   ` (3 preceding siblings ...)
  2011-01-18 17:26 ` [PATCH 4/4] omap4: hsmmc: enable ADMA for MMC1 & MMC2 Kishore Kadiyala
@ 2011-01-20 17:42 ` Tony Lindgren
  2011-02-03  6:14   ` Kadiyala, Kishore
  4 siblings, 1 reply; 7+ messages in thread
From: Tony Lindgren @ 2011-01-20 17:42 UTC (permalink / raw)
  To: Kishore Kadiyala; +Cc: linux-mmc, linux-omap, cjb, madhu.cr

* Kishore Kadiyala <kishore.kadiyala@ti.com> [110118 09:19]:
> This patch series adds support for ADMA on MMC1 & MMC2 controllers on OMAP4.
> There is no performance improvement observed using ADMA over SDMA.
> Advantage using ADMA could be reducing contention over SDMA.
> Also the series includes some cleanup.

To me it seems that the only sane way to deal with multiple different
DMA enginges is to implement them all with drivers/dma/dmaengine.c.
Otherwise we'll end up with multiple custom ADMA implementations in
each driver. We need to also make SDMA use the dmaengine code.

If the current dmaengine code does not support this, we need to
improve it to deal with cases like these.

Regards,

Tony

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] omap4: hsmmc: Adding ADMA support
  2011-01-20 17:42 ` [PATCH 0/4] omap4: hsmmc: Adding ADMA support Tony Lindgren
@ 2011-02-03  6:14   ` Kadiyala, Kishore
  0 siblings, 0 replies; 7+ messages in thread
From: Kadiyala, Kishore @ 2011-02-03  6:14 UTC (permalink / raw)
  To: Tony Lindgren; +Cc: linux-mmc, linux-omap, cjb, madhu.cr

Tony,

On Thu, Jan 20, 2011 at 11:12 PM, Tony Lindgren <tony@atomide.com> wrote:
> * Kishore Kadiyala <kishore.kadiyala@ti.com> [110118 09:19]:
>> This patch series adds support for ADMA on MMC1 & MMC2 controllers on OMAP4.
>> There is no performance improvement observed using ADMA over SDMA.
>> Advantage using ADMA could be reducing contention over SDMA.
>> Also the series includes some cleanup.
>
> To me it seems that the only sane way to deal with multiple different
> DMA enginges is to implement them all with drivers/dma/dmaengine.c.
> Otherwise we'll end up with multiple custom ADMA implementations in
> each driver. We need to also make SDMA use the dmaengine code.
>
> If the current dmaengine code does not support this, we need to
> improve it to deal with cases like these.

Ok, I will check the feasibility of implementing ADMA through dmaengine .


-- 
Regards,
Kishore

>
> Regards,
>
> Tony
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-02-03  6:14 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-18 17:26 [PATCH 0/4] omap4: hsmmc: Adding ADMA support Kishore Kadiyala
2011-01-18 17:26 ` [PATCH 1/4] omap: hsmmc: Rename use_dma to xfer_type and define possible transfers Kishore Kadiyala
2011-01-18 17:26 ` [PATCH 2/4] omap: hsmmc: Rename and cleanup omap_hsmmc_dma_cleanup Kishore Kadiyala
2011-01-18 17:26 ` [PATCH 3/4] omap4: hsmmc: Adding ADMA support for MMC1 & MMC2 controllers Kishore Kadiyala
2011-01-18 17:26 ` [PATCH 4/4] omap4: hsmmc: enable ADMA for MMC1 & MMC2 Kishore Kadiyala
2011-01-20 17:42 ` [PATCH 0/4] omap4: hsmmc: Adding ADMA support Tony Lindgren
2011-02-03  6:14   ` Kadiyala, Kishore

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.