[U-Boot] [PATCH 2/3] dma: Add TI EDMA driver

Tom Rini trini at ti.com
Fri Jul 11 22:53:44 CEST 2014


From: Vinothkumar Rajendran <vinothr at ti.com>

Add a driver for the EDMA (EDMA3) IP block.  Provide an API to initialize
edma, program PaRAM, set register, enable and disable the interrupts,
map channel to eventq and enble and disable event triggers.

Signed-off-by: vinothkumar <a0131713 at ti.com>
Signed-off-by: Tom Rini <trini at ti.com>
---
 arch/arm/cpu/armv7/omap5/hw_data.c     |    2 +
 arch/arm/cpu/armv7/omap5/prcm-regs.c   |    4 +
 arch/arm/include/asm/arch-omap5/edma.h |   46 +++++++
 arch/arm/include/asm/omap_common.h     |    4 +
 drivers/dma/Makefile                   |    1 +
 drivers/dma/ti_edma.c                  |  225 ++++++++++++++++++++++++++++++++
 drivers/dma/ti_edma.h                  |  117 +++++++++++++++++
 include/configs/dra7xx_evm.h           |    4 +
 8 files changed, 403 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-omap5/edma.h
 create mode 100644 drivers/dma/ti_edma.c
 create mode 100644 drivers/dma/ti_edma.h

diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c
index 4baca11..a349525 100644
--- a/arch/arm/cpu/armv7/omap5/hw_data.c
+++ b/arch/arm/cpu/armv7/omap5/hw_data.c
@@ -499,6 +499,8 @@ void enable_basic_uboot_clocks(void)
 
 	u32 const clk_modules_hw_auto_essential[] = {
 		(*prcm)->cm_l3init_hsusbtll_clkctrl,
+		(*prcm)->cm_l3main1_tptc1_clkctrl,
+		(*prcm)->cm_l3main1_tptc2_clkctrl,
 		0
 	};
 
diff --git a/arch/arm/cpu/armv7/omap5/prcm-regs.c b/arch/arm/cpu/armv7/omap5/prcm-regs.c
index ff08ef4..edda406 100644
--- a/arch/arm/cpu/armv7/omap5/prcm-regs.c
+++ b/arch/arm/cpu/armv7/omap5/prcm-regs.c
@@ -975,4 +975,8 @@ struct prcm_regs const dra7xx_prcm = {
 
 	.prm_abbldo_mpu_setup			= 0x4AE07DDC,
 	.prm_abbldo_mpu_ctrl			= 0x4AE07DE0,
+
+	/*l3main1 edma*/
+	.cm_l3main1_tptc1_clkctrl		= 0x4a008778,
+	.cm_l3main1_tptc2_clkctrl		= 0x4a008780,
 };
diff --git a/arch/arm/include/asm/arch-omap5/edma.h b/arch/arm/include/asm/arch-omap5/edma.h
new file mode 100644
index 0000000..4483e84
--- /dev/null
+++ b/arch/arm/include/asm/arch-omap5/edma.h
@@ -0,0 +1,46 @@
+/*
+ * hw_edma_tpcc.h - register-level header file for EDMA_TPCC
+ *
+ * Copyright (C) 2014, Texas Instruments, Incorporated
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+
+#ifndef HW_EDMA_TPCC_H_
+#define HW_EDMA_TPCC_H_
+
+/* Register Definitions */
+
+#define EDMA_TPCC_DCHMAPN(n)		(0x100 + (n * 4))
+#define EDMA_TPCC_DMAQNUMN(n)		(0x240 + (n * 4))
+#define EDMA_TPCC_QDMAQNUM		(0x260)
+#define EDMA_TPCC_EMCR			(0x308)
+#define EDMA_TPCC_EMCRH			(0x30c)
+#define EDMA_TPCC_QEMCR			(0x314)
+#define EDMA_TPCC_CCERRCLR		(0x31c)
+#define EDMA_TPCC_DRAEM(n)		(0x340 + (n * 8))
+#define EDMA_TPCC_DRAEHM(n)		(0x344 + (n * 8))
+#define EDMA_TPCC_QRAEN(n)		(0x380 + (n * 4))
+#define EDMA_TPCC_IESRH_RN(n)		(0x2064 + (n * 512))
+#define EDMA_TPCC_ESR_RN(n)		(0x2010 + (n * 512))
+#define EDMA_TPCC_ICRH_RN(n)		(0x2074 + (n * 512))
+#define EDMA_TPCC_IESR_RN(n)		(0x2060 + (n * 512))
+#define EDMA_TPCC_SECR_RN(n)		(0x2040 + (n * 512))
+#define EDMA_TPCC_EESR_RN(n)		(0x2030 + (n * 512))
+#define EDMA_TPCC_SECRH_RN(n)		(0x2044 + (n * 512))
+#define EDMA_TPCC_EESRH_RN(n)		(0x2034 + (n * 512))
+#define EDMA_TPCC_ICR_RN(n)		(0x2070 + (n * 512))
+#define EDMA_TPCC_IPR_RN(n)		(0x2068 + (n * 512))
+#define EDMA_TPCC_ESRH_RN(n)		(0x2014 + (n * 512))
+#define EDMA_TPCC_OPT(n)		(0x4000 + (n * 32))
+
+/* Field Definition Macros */
+#define EDMA_TPCC_DCHMAPN_SHIFT		(5)
+#define EDMA_TPCC_DMAQNUMN_SHIFT	(3)
+#define EDMA_TPCC_OPT_TCC_SHIFT		(12)
+#define EDMA_TPCC_OPT_TCC_MASK		(0x0003f000)
+#define EDMA_TPCC_OPT_TCINTEN_MASK	(0x00100000)
+#define EDMA_TPCC_OPT_SYNCDIM_MASK	(0x00000004)
+
+#endif
diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h
index d1344ee..969a541 100644
--- a/arch/arm/include/asm/omap_common.h
+++ b/arch/arm/include/asm/omap_common.h
@@ -344,6 +344,10 @@ struct prcm_regs {
 	/* GMAC Clk Ctrl */
 	u32 cm_gmac_gmac_clkctrl;
 	u32 cm_gmac_clkstctrl;
+
+	/*l3main1 edma*/
+	u32 cm_l3main1_tptc1_clkctrl;
+	u32 cm_l3main1_tptc2_clkctrl;
 };
 
 struct omap_sys_ctrl_regs {
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 8b2821b..4ac6170 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
 obj-$(CONFIG_APBH_DMA) += apbh_dma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_OMAP3_DMA) += omap3_dma.o
+obj-$(CONFIG_TI_EDMA) += ti_edma.o
diff --git a/drivers/dma/ti_edma.c b/drivers/dma/ti_edma.c
new file mode 100644
index 0000000..e874b55
--- /dev/null
+++ b/drivers/dma/ti_edma.c
@@ -0,0 +1,225 @@
+/*
+ * TI edma driver
+ *
+ * Copyright (C) 2014, Texas Instruments, Incorporated
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Support for the EDMA (sometimes referred to as EDMA3) controller found
+ * in a number of TI parts.  This implementation does not support QDMA nor
+ * channels above 32.  We also only support region 0.  We only support manual
+ * triggering of DMA events as well.
+ */
+
+#include <common.h>
+#include <stdbool.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/arch/edma.h>
+#include "ti_edma.h"
+
+#define EDMA_BASE_ADDR     0x43300000
+
+static u32 base_add = EDMA_BASE_ADDR;
+
+/**
+ * @brief EDMA Initialization
+ *
+ * This function initializes the EDMA Driver Clears the error specific
+ * registers (EMCR/EMCRh, CCERRCLR) and initialize the Queue Number Registers
+ *
+ * @param  que_num	Event Queue Number to which the channel will be mapped
+ *			(valid only for the Master Channel (DMA/QDMA) request).
+ *
+ * @return None
+ *
+ * @note We only support region 0 (of the two that exist) and the Event Queue
+ * used is either (0 or 1). There are only four shadow regions and only two
+ * event Queues.
+ */
+void edma_init(u32 que_num)
+{
+	int i;
+	u32 addr;
+
+	/* Clear the Event miss Registers */
+	writel(EDMA_SET_ALL_BITS,(base_add + EDMA_TPCC_EMCR));
+	writel(EDMA_SET_ALL_BITS,(base_add + EDMA_TPCC_EMCRH));
+
+	/* Clear CCERR register */
+	writel(EDMA_SET_ALL_BITS,(base_add + EDMA_TPCC_CCERRCLR));
+
+	/* FOR TYPE EDMA*/
+	/* Enable the DMA (0 - 32) channels in the DRAE and DRAEH register */
+	writel(EDMA_SET_ALL_BITS,(base_add + EDMA_TPCC_DRAEM(0)));
+
+	for (i = 0; i < 32; i++)
+		/* All events are one to one mapped with the channels */
+		writel(i << EDMA_TPCC_DCHMAPN_SHIFT,
+				base_add + EDMA_TPCC_DCHMAPN(i));
+
+	/* Initialize the DMA Queue Number Registers */
+	for (i = 0; i < (SOC_EDMA_NUM_DMACH / 2); i++) {
+		addr = base_add;
+		addr += EDMA_TPCC_DMAQNUMN(i >> EDMA_TPCC_DMAQNUMN_SHIFT);
+		writel(readl(addr) & EDMACC_DMAQNUM_CLR(i), addr);
+		writel(readl(addr) | EDMACC_DMAQNUM_SET(i, que_num), addr);
+	}
+}
+
+/**
+ * @brief  Map channel to Event Queue
+ *
+ * This API maps DMA/QDMA channels to the Event Queue.  QDMA channels are
+ * not supported.
+ *
+ * @param  base_add    Memory address of the EDMA instance used.
+ *
+ * @param  ch_num      Allocated channel number.
+ *
+ * @param  evt_qnum    Event Queue Number to which the channel
+ *                    will be mapped (valid only for the
+ *                    Master Channel (DMA/QDMA) request).
+ *
+ * @return  None
+ */
+static void edma_mapch_to_evtq(u32 ch_num, u32 evt_qnum)
+{
+	u32 addr = base_add;
+
+	addr += EDMA_TPCC_DMAQNUMN((ch_num) >> EDMA_TPCC_DMAQNUMN_SHIFT);
+
+	/* Associate DMA Channel to Event Queue */
+	writel(readl(addr) & EDMACC_DMAQNUM_CLR(ch_num), addr);
+	writel(readl(addr) | EDMACC_DMAQNUM_SET((ch_num), evt_qnum), addr);
+}
+
+/**
+ * @brief Request a DMA/QDMA/Link channel.
+ *
+ * Each channel (DMA/QDMA/Link) must be requested  before initiating a DMA
+ * transfer on that channel.
+ *
+ * This API is used to allocate a logical channel (DMA/QDMA/Link) along with
+ * the associated resources. For DMA and QDMA channels, TCC and PaRAM Set are
+ * also allocated along with the requested channel.
+ *
+ * User can request a specific logical channel by passing the channel number
+ * in 'ch_num'.
+ *
+ * For DMA/QDMA channels, after allocating all the EDMA resources, this API
+ * sets the TCC field of the OPT PaRAM Word with the allocated TCC. It also
+ * sets the event queue for the channel allocated. The event queue needs to
+ * be specified by the user.
+ *
+ * For DMA channel, it also sets the DCHMAP register.
+ *
+ * @param  ch_num                    This is the channel number requested for a
+ *                                  particular event.
+ *
+ * @param  tcc_num                   The channel number on which the
+ *                                  completion/error interrupt is generated.
+ *                                  Not used if user requested for a Link
+ *                                  channel.
+ *
+ * @param  evt_qnum                  Event Queue Number to which the channel
+ *                                  will be mapped (valid only for the
+ *                                  Master Channel (DMA/QDMA) request).
+ *
+ * @return  true if parameters are valid, else false
+ */
+bool edma_request_channel(u32 ch_num, u32 tcc_num, u32 evt_qnum)
+{
+	bool ret_val = false;
+
+	if (ch_num < (SOC_EDMA_NUM_DMACH / 2)) {
+		/*
+		 * Enable the DMA channel in the enabled in the shadow region
+		 * specific register
+		 */
+		writel(readl(base_add + EDMA_TPCC_DRAEM(0)) | (0x01 << ch_num),
+				base_add + EDMA_TPCC_DRAEM(0));
+
+		edma_mapch_to_evtq(ch_num, evt_qnum);
+		/* Interrupt channel nums are < 32 */
+		if (tcc_num < (SOC_EDMA_NUM_DMACH / 2)) {
+			/* Enable the Event Interrupt */
+			writel(readl(base_add + EDMA_TPCC_IESR_RN(0)) |
+					(0x01 << ch_num),
+					base_add + EDMA_TPCC_IESR_RN(0));
+			ret_val = true;
+		}
+
+		writel(readl(base_add + EDMA_TPCC_OPT(ch_num))&
+				EDMACC_OPT_TCC_CLR, base_add +
+				EDMA_TPCC_OPT(ch_num));
+		writel(readl(base_add + EDMA_TPCC_OPT(ch_num)) |
+				EDMACC_OPT_TCC_SET(ch_num), base_add +
+				EDMA_TPCC_OPT(ch_num));
+	}
+
+	return ret_val;
+}
+
+/**
+ * @brief Copy the user specified PaRAM Set onto the PaRAM Set associated with
+ * the logical channel (DMA/Link).
+ *
+ * This API takes a PaRAM Set as input and copies it onto the actual PaRAM Set
+ * associated with the logical channel. OPT field of the PaRAM Set is written
+ * first and the CCNT field is written last.
+ *
+ * @param param_id	PaRAMset ID whose parameter set has to be updated
+ *
+ * @param new_param	Parameter RAM set to be copied onto existing PaRAM.
+ *
+ */
+void edma_set_param(u32 param_id, struct edma_param_entry *new_param)
+{
+	struct edma_param_entry *dest;
+
+	dest = (struct edma_param_entry *)(base_add + EDMA_TPCC_OPT(param_id));
+
+	memcpy(dest, new_param, sizeof(struct edma_param_entry));
+}
+
+/**
+ * @brief Start EDMA transfer on the specified channel.
+ *
+ * In manual triggered mode, CPU manually triggers a transfer by writing a 1
+ * in the Event Set Register ESR. This API writes to the ESR to start the
+ * transfer.
+ *
+ * @param  ch_num	Channel being used to enable transfer.
+ *
+ * @return true or false depending on a valid channel number being passed
+ *
+ */
+bool edma_enable_transfer(u32 ch_num)
+{
+	/* Only the first half of the channels are supported. */
+	if (ch_num < (SOC_EDMA_NUM_DMACH / 2)) {
+		/* (ESR) - set corresponding bit to set a event */
+		writel(readl(base_add + EDMA_TPCC_ESR_RN(0)) |
+				(0x01 << ch_num),
+				base_add + EDMA_TPCC_ESR_RN(0));
+		return true;
+	}
+	return false;
+}
+
+/**
+ * @brief This function returns interrupts status of those events which is less
+ * than 32.
+ *
+ * @return Status of the Interrupt Pending Register
+ */
+u32 edma_get_intr_status(void)
+{
+	return readl(base_add + EDMA_TPCC_IPR_RN(0));
+}
+
+void edma_clr_intr(u32 value)
+{
+	writel((1 << value), base_add + EDMA_TPCC_ICR_RN(0));
+}
diff --git a/drivers/dma/ti_edma.h b/drivers/dma/ti_edma.h
new file mode 100644
index 0000000..073a5a0
--- /dev/null
+++ b/drivers/dma/ti_edma.h
@@ -0,0 +1,117 @@
+/*
+ * TI edma driver
+ *
+ * Copyright (C) 2014, Texas Instruments, Incorporated
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <linux/compiler.h>
+
+/** DMAQNUM bits Clear */
+#define EDMACC_DMAQNUM_CLR(ch_num)	( ~ (0x7 << (((ch_num) % 8) \
+						* 4)))
+/** DMAQNUM bits Set */
+#define EDMACC_DMAQNUM_SET(ch_num,que_num)	((0x7 & (que_num)) << \
+							(((ch_num) % 8) * 4))
+
+/** OPT-TCC bitfield Clear */
+#define EDMACC_OPT_TCC_CLR		(~EDMA_TPCC_OPT_TCC_MASK)
+
+/** OPT-TCC bitfield Set */
+#define EDMACC_OPT_TCC_SET(tcc)	(((EDMA_TPCC_OPT_TCC_MASK >> \
+						EDMA_TPCC_OPT_TCC_SHIFT) & \
+						(tcc)) << \
+						EDMA_TPCC_OPT_TCC_SHIFT)
+
+#define EDMA_SET_ALL_BITS		(0xFFFFFFFF)
+
+#define EDMA_TRIG_MODE_MANUAL			(0)
+
+/*
+ * Number of PaRAM Entry fields
+ * OPT, SRC, A_B_CNT, DST, SRC_DST_BIDX, LINK_BCNTRLD, SRC_DST_CIDX
+ * and CCNT
+ */
+#define EDMACC_PARAM_ENTRY_FIELDS		(0x8)
+
+#define SOC_EDMA_NUM_DMACH		64
+#define SOC_EDMA_NUM_QDMACH		8
+
+/**
+ * @brief EDMA Parameter RAM Set in User Configurable format
+ *
+ * This is a mapping of the EDMA PaRAM set provided to the user
+ * for ease of modification of the individual fields
+ */
+struct edma_param_entry {
+	/** OPT field of PaRAM Set */
+	u32 opt;
+
+	/**
+	 * @brief Starting byte address of Source
+	 * For FIFO mode, src_addr must be a 256-bit aligned address.
+	 */
+	u32 src_addr;
+
+	/**
+	 * @brief Number of bytes in each Array (ACNT)
+	 */
+	u16 a_cnt;
+
+	/**
+	 * @brief Number of Arrays in each Frame (BCNT)
+	 */
+	u16 b_cnt;
+
+	/**
+	 * @brief Starting byte address of destination
+	 * For FIFO mode, dest_addr must be a 256-bit aligned address.
+	 * i.e. 5 LSBs should be 0.
+	 */
+	u32 dest_addr;
+
+	/**
+	 * @brief Index between consec. arrays of a Source Frame (SRCBIDX)
+	 */
+	s16 src_bidx;
+
+	/**
+	 * @brief Index between consec. arrays of a Destination Frame (DSTBIDX)
+	 */
+	s16 dest_bidx;
+
+	/**
+	 * @brief Address for linking (AutoReloading of a PaRAM Set)
+	 * This must point to a valid aligned 32-byte PaRAM set
+	 * A value of 0xFFFF means no linking
+	 */
+	u16 link_addr;
+
+	/**
+	 * @brief Reload value of the numArrInFrame (BCNT)
+	 * Relevant only for A-sync transfers
+	 */
+	u16 b_cnt_reload;
+
+	/**
+	 * @brief Index between consecutive frames of a Source Block (SRCCIDX)
+	 */
+	s16 src_cidx;
+
+	/**
+	 * @brief Index between consecutive frames of a Dest Block (DSTCIDX)
+	 */
+	s16 dest_cidx;
+
+	/**
+	 * @brief Number of Frames in a block (CCNT)
+	 */
+	u16 c_cnt;
+} __packed;
+
+void edma_init(u32 que_num);
+bool edma_request_channel(u32 ch_num, u32 tcc_num, u32 evt_qnum);
+void edma_set_param(u32 param_id, struct edma_param_entry* new_param);
+bool edma_enable_transfer(u32 ch_num);
+u32 edma_get_intr_status(void);
+void edma_clr_intr(u32 value);
diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h
index 8d0a0eb..f86ec38 100644
--- a/include/configs/dra7xx_evm.h
+++ b/include/configs/dra7xx_evm.h
@@ -113,6 +113,10 @@
 
 /* SPI SPL */
 #define CONFIG_SPL_SPI_SUPPORT
+#define CONFIG_SPL_DMA_SUPPORT
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_TI_EDMA
+#endif
 #define CONFIG_SPL_SPI_LOAD
 #define CONFIG_SPL_SPI_FLASH_SUPPORT
 #define CONFIG_SPL_SPI_BUS             0
-- 
1.7.9.5



More information about the U-Boot mailing list