msm_shared: mmc: Add BAM and DML support.

Change-Id: I81fb4105a313cb6d555587418e806c5f22dcb37b
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index e04c64f..803a1e2 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -39,6 +39,11 @@
 #include "adm.h"
 #endif
 
+#if MMC_BOOT_BAM
+#include "bam.h"
+#include "mmc_dml.h"
+#endif
+
 #ifndef NULL
 #define NULL        0
 #endif
@@ -46,7 +51,7 @@
 #define MMC_BOOT_DATA_READ     0
 #define MMC_BOOT_DATA_WRITE    1
 
-static unsigned int mmc_boot_fifo_data_transfer(unsigned int *data_ptr,
+static unsigned int mmc_boot_data_transfer(unsigned int *data_ptr,
 						unsigned int data_len,
 						unsigned char direction);
 
@@ -56,6 +61,32 @@
 static unsigned int mmc_boot_fifo_write(unsigned int *data_ptr,
 					unsigned int data_len);
 
+static unsigned int mmc_boot_status_error(unsigned mmc_status);
+
+#if MMC_BOOT_BAM
+
+void mmc_boot_dml_init();
+
+static void mmc_boot_dml_producer_trans_init(unsigned trans_end,
+										     unsigned size);
+
+static void mmc_boot_dml_consumer_trans_init();
+
+static uint32_t mmc_boot_dml_chk_producer_idle();
+
+static void mmc_boot_dml_wait_producer_idle();
+static void mmc_boot_dml_wait_consumer_idle();
+static void mmc_boot_dml_reset();
+static int mmc_bam_init(uint32_t bam_base);
+static int mmc_bam_transfer_data();
+static unsigned int
+mmc_boot_bam_setup_desc(unsigned int *data_ptr,
+			    unsigned int data_len, unsigned char direction);
+
+
+#endif
+
+
 #define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
 
 /* data access time unit in ns */
@@ -78,6 +109,30 @@
 static unsigned char ext_csd_buf[512];
 static unsigned char wp_status_buf[8];
 
+#if MMC_BOOT_BAM
+
+static uint32_t mmc_sdc_bam_base[] =
+	{ MSM_SDC1_BAM_BASE, MSM_SDC2_BAM_BASE, MSM_SDC3_BAM_BASE, MSM_SDC4_BAM_BASE };
+
+static uint32_t mmc_sdc_dml_base[] =
+	{ MSM_SDC1_DML_BASE, MSM_SDC2_DML_BASE, MSM_SDC3_DML_BASE, MSM_SDC4_DML_BASE };
+
+uint32_t dml_base;
+static struct bam_instance bam;
+
+#define MMC_BOOT_BAM_FIFO_SIZE           100
+
+#define MMC_BOOT_BAM_READ_PIPE_INDEX     0
+#define MMC_BOOT_BAM_WRITE_PIPE_INDEX    1
+
+#define MMC_BOOT_BAM_READ_PIPE           0
+#define MMC_BOOT_BAM_WRITE_PIPE          1
+
+/* Align at BAM_DESC_SIZE boundary */
+static struct bam_desc desc_fifo[MMC_BOOT_BAM_FIFO_SIZE] __attribute__ ((aligned(BAM_DESC_SIZE)));
+
+#endif
+
 int mmc_clock_enable_disable(unsigned id, unsigned enable);
 int mmc_clock_get_rate(unsigned id);
 int mmc_clock_set_rate(unsigned id, unsigned rate);
@@ -1071,12 +1126,17 @@
 	    MMC_BOOT_MCI_DATA_ENABLE | MMC_BOOT_MCI_DATA_DIR | (512 <<
 								MMC_BOOT_MCI_BLKSIZE_POS);
 
-#if MMC_BOOT_ADM
+#if MMC_BOOT_ADM || MMC_BOOT_BAM
 	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
 #endif
 
 	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL);
 
+#if MMC_BOOT_BAM
+	/*  Setup SDCC BAM descriptors for Read operation. */
+	mmc_ret = mmc_boot_bam_setup_desc(mmc_ptr, 512, MMC_BOOT_DATA_READ);
+#endif
+
 	memset((struct mmc_boot_command *)&cmd, 0,
 	       sizeof(struct mmc_boot_command));
 	/* CMD8 */
@@ -1092,7 +1152,10 @@
 	}
 
 	/* Read the transfer data from SDCC FIFO. */
-	mmc_ret = mmc_boot_fifo_data_transfer(mmc_ptr, 512, MMC_BOOT_DATA_READ);
+	mmc_ret = mmc_boot_data_transfer(mmc_ptr, 512, MMC_BOOT_DATA_READ);
+
+	/* Reset DPSM */
+	writel(0, MMC_BOOT_MCI_DATA_CTL);
 
 	return mmc_ret;
 }
@@ -1361,6 +1424,10 @@
 	/* Write the total size of the transfer data to MCI_DATA_LENGTH register */
 	writel(data_len, MMC_BOOT_MCI_DATA_LENGTH);
 
+#if MMC_BOOT_BAM
+		mmc_boot_bam_setup_desc(in, data_len, MMC_BOOT_DATA_WRITE);
+#endif
+
 	/* Send command to the card/device in order to start the write data xfer.
 	   The possible commands are CMD24/25/53/60/61 */
 	mmc_ret = mmc_boot_send_write_command(card, xfer_type, addr);
@@ -1382,7 +1449,7 @@
 
 	/* Set DM_ENABLE bit to 1 in order to enable DMA, otherwise set 0 */
 
-#if MMC_BOOT_ADM
+#if MMC_BOOT_ADM || MMC_BOOT_BAM
 	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
 #endif
 
@@ -1393,7 +1460,7 @@
 
 	/* write data to FIFO */
 	mmc_ret =
-	    mmc_boot_fifo_data_transfer(in, data_len, MMC_BOOT_DATA_WRITE);
+	    mmc_boot_data_transfer(in, data_len, MMC_BOOT_DATA_WRITE);
 
 	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
 		dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \
@@ -1438,6 +1505,14 @@
 	}
 	while (1);
 
+#if MMC_BOOT_BAM
+	/* Wait for DML trasaction to end */
+	mmc_boot_dml_wait_consumer_idle();
+#endif
+
+	/* Reset DPSM */
+	writel(0, MMC_BOOT_MCI_DATA_CTL);
+
 	return MMC_BOOT_E_SUCCESS;
 }
 
@@ -1619,7 +1694,7 @@
 
 	/* If DMA is to be used, Set DM_ENABLE bit to 1 */
 
-#if MMC_BOOT_ADM
+#if MMC_BOOT_ADM || MMC_BOOT_BAM
 	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
 #endif
 
@@ -1628,6 +1703,10 @@
 	mmc_reg |= (card->rd_block_len << MMC_BOOT_MCI_BLKSIZE_POS);
 	writel(mmc_reg, MMC_BOOT_MCI_DATA_CTL);
 
+#if MMC_BOOT_BAM
+	/* Setup SDCC FIFO descriptors for Read operation. */
+	mmc_ret = mmc_boot_bam_setup_desc(out, data_len, MMC_BOOT_DATA_READ);
+#endif
 	/* Send command to the card/device in order to start the read data
 	   transfer. Possible commands: CMD17/18/53/60/61. */
 	mmc_ret = mmc_boot_send_read_command(card, xfer_type, addr);
@@ -1639,8 +1718,7 @@
 	}
 
 	/* Read the transfer data from SDCC FIFO. */
-	mmc_ret =
-	    mmc_boot_fifo_data_transfer(out, data_len, MMC_BOOT_DATA_READ);
+	mmc_ret = mmc_boot_data_transfer(out, data_len, MMC_BOOT_DATA_READ);
 
 	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
 		dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \
@@ -1661,6 +1739,9 @@
 		}
 	}
 
+	/* Reset DPSM */
+	writel(0, MMC_BOOT_MCI_DATA_CTL);
+
 	return MMC_BOOT_E_SUCCESS;
 }
 
@@ -2143,6 +2224,12 @@
 		return MMC_BOOT_E_FAILURE;
 	}
 
+#if MMC_BOOT_BAM
+
+	mmc_ret = mmc_bam_init(mmc_sdc_bam_base[slot - 1]);
+	dml_base = mmc_sdc_dml_base[slot - 1];
+#endif
+
 	/* Initialize and identify cards connected to host */
 	mmc_ret = mmc_boot_init_and_identify_cards(&mmc_host, &mmc_card);
 	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
@@ -2235,7 +2322,7 @@
 	    MMC_BOOT_MCI_DATA_ENABLE | MMC_BOOT_MCI_DATA_DIR | (data_len <<
 								MMC_BOOT_MCI_BLKSIZE_POS);
 
-#if MMC_BOOT_ADM
+#if MMC_BOOT_ADM || MMC_BOOT_BAM
 	mmc_reg |= MMC_BOOT_MCI_DATA_DM_ENABLE;
 #endif
 
@@ -2257,7 +2344,7 @@
 
 	/* Read the transfer data from SDCC FIFO. */
 	mmc_ret =
-	    mmc_boot_fifo_data_transfer(out, data_len, MMC_BOOT_DATA_READ);
+	    mmc_boot_data_transfer(out, data_len, MMC_BOOT_DATA_READ);
 
 	if (mmc_ret != MMC_BOOT_E_SUCCESS) {
 		dprintf(CRITICAL, "Error No.%d: Failure on data transfer from the \
@@ -2468,7 +2555,7 @@
  * Read/write data from/to SDC FIFO.
  */
 static unsigned int
-mmc_boot_fifo_data_transfer(unsigned int *data_ptr,
+mmc_boot_data_transfer(unsigned int *data_ptr,
 			    unsigned int data_len, unsigned char direction)
 {
 	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
@@ -2491,6 +2578,9 @@
 		dprintf(CRITICAL, "MMC ADM transfer error: %d\n", ret);
 		mmc_ret = MMC_BOOT_E_FAILURE;
 	}
+
+#elif MMC_BOOT_BAM
+	mmc_ret = mmc_bam_transfer_data(data_ptr, data_len, direction);
 #else
 
 	if (direction == MMC_BOOT_DATA_READ) {
@@ -2499,6 +2589,7 @@
 		mmc_ret = mmc_boot_fifo_write(data_ptr, data_len);
 	}
 #endif
+
 	return mmc_ret;
 }
 
@@ -2830,3 +2921,273 @@
 {
 	return &mmc_card;
 }
+
+#if MMC_BOOT_BAM
+
+void mmc_boot_dml_init()
+{
+	uint32_t val = 0;
+
+	/* Initialize s/w reset for DML core */
+	mmc_boot_dml_reset();
+
+	/* Program DML config:
+	 * 1. Disable producer and consumer CRCI.
+	 * 2. Set Bypass mode for the DML for Direct access.
+	 */
+	val = 0;
+	val |= 1 >> SDCC_BYPASS_SHIFT;
+	writel(val, SDCC_DML_CONFIG(dml_base));
+
+	/* Program consumer logic size:
+	 * This is for handshaking between the BAM and the DML blocks.
+	 */
+	writel(4096, SDCC_DML_CONSUMER_PIPE_LOGICAL_SIZE(dml_base));
+
+	/* Program producer logic size
+	 * This is for handshaking between the BAM and the DML blocks.
+	 */
+	writel(4096, SDCC_DML_PRODUCER_PIPE_LOGICAL_SIZE(dml_base));
+
+
+	/* Write the pipe id numbers. */
+	val = 0;
+	val |= bam.pipe[MMC_BOOT_BAM_READ_PIPE_INDEX].pipe_num << SDCC_PRODUCER_PIPE_ID_SHIFT;
+	val |= bam.pipe[MMC_BOOT_BAM_WRITE_PIPE_INDEX].pipe_num << SDCC_CONSUMER_PIPE_ID_SHIFT;
+
+	writel(val, SDCC_DML_PIPE_ID(dml_base));
+
+}
+
+/* Function to set up SDCC dml for System producer transaction. */
+static void mmc_boot_dml_consumer_trans_init()
+{
+	uint32_t val = 0;
+
+	val = 0 << SDCC_PRODUCER_CRCI_SEL_SHIFT;
+	val |= 1 << SDCC_CONSUMER_CRCI_SEL_SHIFT;
+	writel(val, SDCC_DML_CONFIG(dml_base));
+
+
+	/* Start the consumer transaction */
+	writel(1, SDCC_DML_CONSUMER_START(dml_base));
+
+}
+
+/* Function to set up SDCC dml for System consumer transaction.
+ * trans_end: 1: Assert DML trasaction signal
+ *                 at the end of transaction.
+ *                 0: Do not assert DML transaction signal.
+ * size: Transaction size
+ */
+static void mmc_boot_dml_producer_trans_init(unsigned trans_end,
+                                             unsigned size)
+{
+	uint32_t val = 0;
+
+	val = 1 << SDCC_PRODUCER_CRCI_SEL_SHIFT;
+	val |= 0 << SDCC_CONSUMER_CRCI_SEL_SHIFT;
+	val |=  trans_end << SDCC_PRODUCER_TRANS_END_EN_SHIFT;
+	writel(val, SDCC_DML_CONFIG(dml_base));
+
+	/* Set block size */
+    writel(BLOCK_SIZE, SDCC_DML_PRODUCER_BAM_BLOCK_SIZE(dml_base));
+
+	/* Write transaction size */
+	writel(size, SDCC_DML_PRODUCER_BAM_TRANS_SIZE(dml_base));
+
+	/* Start the producer transaction */
+	writel(1, SDCC_DML_PRODUCER_START(dml_base));
+}
+
+/* Function to check producer idle status of the DML.
+ * return value: 1: Producer is idle
+ *                    0: Producer is busy
+ */
+static uint32_t mmc_boot_dml_chk_producer_idle()
+{
+	uint32_t val = 0;
+
+	val = readl(SDCC_DML_STATUS(dml_base));
+
+	/* Read only the producer idle status */
+	val &= (1 << SDCC_DML_PRODUCER_IDLE_SHIFT);
+
+	return val;
+}
+
+/* Function to clear transaction complete flag */
+static void mmc_boot_dml_clr_trans_complete()
+{
+	uint32_t val;
+
+	val = readl(SDCC_DML_CONFIG(dml_base));
+
+	val &=  ~(1 << SDCC_PRODUCER_TRANS_END_EN_SHIFT);
+	writel(val, SDCC_DML_CONFIG(dml_base));
+}
+
+/* Blocking function to wait until DML is idle. */
+static void mmc_boot_dml_wait_producer_idle()
+{
+	while(!(readl(SDCC_DML_STATUS(dml_base)) & 1));
+}
+
+/* Blocking function to wait until DML is idle. */
+static void mmc_boot_dml_wait_consumer_idle()
+{
+	while(!(readl(SDCC_DML_STATUS(dml_base)) & (1 << SDCC_DML_CONSUMER_IDLE_SHIFT)));
+}
+
+/* Initialize S/W reset */
+static void mmc_boot_dml_reset()
+{
+	/* Initialize s/w reset for DML core */
+	writel(1, SDCC_DML_SW_RESET(dml_base));
+
+}
+
+static int mmc_bam_init(uint32_t bam_base)
+{
+
+	uint32_t mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	bam.base = bam_base;
+	/* Read pipe parameter initializations. */
+	bam.pipe[MMC_BOOT_BAM_READ_PIPE_INDEX].pipe_num = MMC_BOOT_BAM_READ_PIPE;
+	/* System consumer */
+	bam.pipe[MMC_BOOT_BAM_READ_PIPE_INDEX].trans_type = BAM2SYS;
+	/* Set the descriptor FIFO start ptr */
+	bam.pipe[MMC_BOOT_BAM_READ_PIPE_INDEX].fifo.head = desc_fifo;
+	/* Set the descriptor FIFO lengths */
+	bam.pipe[MMC_BOOT_BAM_READ_PIPE_INDEX].fifo.size = MMC_BOOT_BAM_FIFO_SIZE;
+
+	/* Write pipe parameter initializations.*/
+	bam.pipe[MMC_BOOT_BAM_WRITE_PIPE_INDEX].pipe_num = MMC_BOOT_BAM_WRITE_PIPE;
+	/* System producer */
+	bam.pipe[MMC_BOOT_BAM_WRITE_PIPE_INDEX].trans_type = SYS2BAM;
+	/* Write fifo uses the same fifo as read */
+	bam.pipe[MMC_BOOT_BAM_WRITE_PIPE_INDEX].fifo.head = desc_fifo;
+	/* Set the descriptor FIFO lengths */
+	bam.pipe[MMC_BOOT_BAM_WRITE_PIPE_INDEX].fifo.size = MMC_BOOT_BAM_FIFO_SIZE;
+
+	/* Programs the minimum threshold for BAM transfer*/
+	bam.threshold = BLOCK_SIZE;
+
+	/* Initialize MMC BAM */
+	bam_init(&bam);
+
+	/* Initialize BAM MMC read pipe */
+	bam_sys_pipe_init(&bam, MMC_BOOT_BAM_READ_PIPE_INDEX);
+
+	mmc_ret = bam_pipe_fifo_init(&bam, bam.pipe[MMC_BOOT_BAM_READ_PIPE_INDEX].pipe_num);
+
+	if (mmc_ret)
+	{
+		dprintf(CRITICAL, "MMC: BAM Read pipe fifo init error\n");
+		goto mmc_bam_init_error;
+	}
+
+	/* Initialize BAM MMC write pipe */
+	bam_sys_pipe_init(&bam, MMC_BOOT_BAM_WRITE_PIPE_INDEX);
+
+	mmc_ret = bam_pipe_fifo_init(&bam, bam.pipe[MMC_BOOT_BAM_WRITE_PIPE_INDEX].pipe_num);
+
+	if (mmc_ret)
+	{
+		dprintf(CRITICAL, "MMC: BAM Write pipe fifo init error\n");
+		goto mmc_bam_init_error;
+	}
+
+	mmc_boot_dml_init();
+
+	mmc_bam_init_error:
+
+	return mmc_ret;
+}
+
+static int mmc_bam_transfer_data(unsigned int *data_ptr,
+                                 unsigned int data_len,
+			                     unsigned int dir)
+{
+	uint32_t mmc_ret;
+	uint32_t offset;
+
+	mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	if(dir == MMC_BOOT_DATA_READ)
+	{
+		/* Check BAM IRQ status reg to verify the desc has been processed */
+		mmc_ret = bam_wait_for_interrupt(&bam,
+					MMC_BOOT_BAM_READ_PIPE_INDEX, P_PRCSD_DESC_EN_MASK);
+
+		if (mmc_ret != BAM_RESULT_SUCCESS)
+		{
+			dprintf(CRITICAL, "BAM transfer error \n");
+			mmc_ret = MMC_BOOT_E_FAILURE;
+			goto mmc_bam_transfer_err;
+		}
+
+		mmc_boot_dml_wait_producer_idle();
+
+		/* Update BAM pipe fifo offsets */
+		offset = bam_read_offset_update(&bam, MMC_BOOT_BAM_READ_PIPE_INDEX);
+
+		/* Reset DPSM */
+		writel(0, MMC_BOOT_MCI_DATA_CTL);
+
+		dprintf(SPEW, "Offset value is %d \n", offset);
+	}
+	else
+	{
+		/* Check BAM IRQ status reg to verify the desc has been processed */
+		mmc_ret = bam_wait_for_interrupt(&bam,
+					MMC_BOOT_BAM_WRITE_PIPE_INDEX, P_TRNSFR_END_EN_MASK);
+
+		if (mmc_ret != BAM_RESULT_SUCCESS)
+		{
+			dprintf(CRITICAL, "BAM transfer error \n");
+			mmc_ret = MMC_BOOT_E_FAILURE;
+			goto mmc_bam_transfer_err;
+		}
+
+		/* Update BAM pipe fifo offsets */
+		offset = bam_read_offset_update(&bam, MMC_BOOT_BAM_WRITE_PIPE_INDEX);
+
+		dprintf(SPEW, "Offset value is %d \n", offset);
+	}
+
+mmc_bam_transfer_err:
+
+	return mmc_ret;
+}
+
+static unsigned int
+mmc_boot_bam_setup_desc(unsigned int *data_ptr,
+                        unsigned int data_len,
+                        unsigned char direction)
+{
+	unsigned int mmc_ret = MMC_BOOT_E_SUCCESS;
+
+	if (direction == MMC_BOOT_DATA_READ)
+	{
+		mmc_boot_dml_producer_trans_init(1, data_len);
+		mmc_ret = bam_add_desc(&bam, MMC_BOOT_BAM_READ_PIPE_INDEX,
+					(unsigned char *)data_ptr, data_len);
+	}
+	else
+	{
+		mmc_boot_dml_consumer_trans_init();
+		mmc_ret = bam_add_desc(&bam, MMC_BOOT_BAM_WRITE_PIPE_INDEX,
+					(unsigned char *)data_ptr, data_len);
+	}
+
+	/* Update return value enums */
+	if (mmc_ret != BAM_RESULT_SUCCESS)
+	{
+		dprintf(CRITICAL, "MMC BAM transfer error: %d\n", mmc_ret);
+		mmc_ret = MMC_BOOT_E_FAILURE;
+	}
+}
+
+#endif