[PATCH 123/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00093265 Add ASRC script and ASRC p2p script support in SDMA driver

Brad Figg brad.figg at canonical.com
Thu Jul 9 16:49:53 UTC 2009


1. SSI15 has dividual entry for ASRC
2. SSI15 sdma scripts have supported p2p feature
3. SDMA driver needs changes to support p2p feature.
4. Enhance the mxc_dma_request interface to transfer parameter to dma driver.
   It is just for ASRC to set data channle number now. The enhanced interface
   named mxc_dma_request_ext.

Signed-off-by: Fred Fan <r01011 at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 arch/arm/plat-mxc/include/mach/dma.h             |   23 +++++-
 arch/arm/plat-mxc/include/mach/sdma.h            |   57 +++++++++++++-
 arch/arm/plat-mxc/sdma/dma_sdma.c                |   19 ++++-
 arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h |    3 +-
 arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c     |    4 +-
 arch/arm/plat-mxc/sdma/sdma.c                    |   94 ++++++++++++++++++++-
 6 files changed, 186 insertions(+), 14 deletions(-)

diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h
index b52b2fc..46128d2 100644
--- a/arch/arm/plat-mxc/include/mach/dma.h
+++ b/arch/arm/plat-mxc/include/mach/dma.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -133,6 +133,16 @@ typedef struct mxc_dma_requestbuf {
 	int num_of_bytes;	/*!< the length of this transfer : bytes */
 } mxc_dma_requestbuf_t;
 
+/*! This struct contains the information for asrc special*/
+struct dma_channel_asrc_info {
+	u32 channs;		/*!< data channels in asrc */
+};
+
+/*! This struct contains  the information for device special*/
+struct dma_channel_info {
+	struct dma_channel_asrc_info asrc;	/*!< asrc special information */
+};
+
 #if defined(CONFIG_ARCH_MX27) || defined(CONFIG_ARCH_MX21)
 #include <mach/mx2_dma.h>
 #else
@@ -152,10 +162,17 @@ typedef struct mxc_dma_requestbuf {
  *                     The DMA driver could use static or dynamic DMA channel
  *                     allocation.
  * @param dev_name     module name or device name
+ * @param data         the customized parameter for special channel.
  * @return returns a negative number on error if request for a DMA channel did not
  *         succeed, returns the channel number to be used on success.
  */
-extern int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name);
+extern int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name,
+			       struct dma_channel_info *info);
+
+static inline int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name)
+{
+	return mxc_dma_request_ext(channel_id, dev_name, NULL);
+}
 
 /*!
  * This function is generally called by the driver at close time. The DMA
@@ -185,7 +202,7 @@ extern int mxc_dma_free(int channel_num);
  * @return This function returns a negative number on error if buffer could not be
  *         added with DMA for transfer. On Success, it returns 0
  */
-extern int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf,
+extern int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t *dma_buf,
 			  int num_buf, mxc_dma_mode_t mode);
 
 /*!
diff --git a/arch/arm/plat-mxc/include/mach/sdma.h b/arch/arm/plat-mxc/include/mach/sdma.h
index 453cf65..1b145e8 100644
--- a/arch/arm/plat-mxc/include/mach/sdma.h
+++ b/arch/arm/plat-mxc/include/mach/sdma.h
@@ -55,6 +55,28 @@
 
 #define MXC_FIFO_MEM_DEST_FIXED   0x1
 #define MXC_FIFO_MEM_SRC_FIXED    0x2
+
+#define SDMA_ASRC_INFO_WML_OFF	0
+#define SDMA_ASRC_INFO_WML_MASK ((1 << 10) - 1)
+#define SDMA_ASRC_INFO_PS	(1 << 10)
+#define SDMA_ASRC_INFO_PA	(1 << 11)
+#define SDMA_ASRC_INFO_TXFR_DIR	(1 << 14)
+#define SDMA_ASRC_INFO_N_OFF	(24)
+#define SDMA_ASRC_INFO_N_MASK	((1 << 4) - 1)
+
+#define SDMA_ASRC_P2P_INFO_LWML_OFF 0
+#define SDMA_ASRC_P2P_INFO_LWML_MASK ((1 << 8) - 1)
+#define SDMA_ASRC_P2P_INFO_PS	(1 << 8)
+#define SDMA_ASRC_P2P_INFO_PA	(1 << 9)
+#define SDMA_ASRC_P2P_INFO_SPDIF (1 << 10)
+#define SDMA_ASRC_P2P_INFO_SP (1 << 11)
+#define SDMA_ASRC_P2P_INFO_DP (1 << 12)
+#define SDMA_ASRC_P2P_INFO_HWML_OFF 14
+#define SDMA_ASRC_P2P_INFO_HWML_MASK ((1 << 10) - 1)
+#define SDMA_ASRC_P2P_INFO_LWE (1 << 28)
+#define SDMA_ASRC_P2P_INFO_HWE (1 << 29)
+#define SDMA_ASRC_P2P_INFO_CONT (1 << 31)
+
 /*!
  * This enumerates  transfer types
  */
@@ -136,9 +158,11 @@ typedef void (*dma_callback_t) (void *arg);
 typedef struct {
 	__u32 watermark_level;	/*!< Lower/upper threshold that
 				 *   triggers SDMA event
+				 *   for p2p, this is event1 watermark level
 				 */
 	__u32 per_address;	/*!< Peripheral source/destination
 				 *   physical address
+				 *   for p2p, this is destination address
 				 */
 	sdma_periphT peripheral_type;	/*!< Peripheral type */
 	sdma_transferT transfer_type;	/*!< Transfer type   */
@@ -159,8 +183,29 @@ typedef struct {
 	dma_callback_t callback;	/*!   callback function            */
 	void *arg;		/*!   callback argument            */
 	unsigned long word_size:8;	/*!< SDMA data access word size    */
+	unsigned long ext:1;	/*!< 1: extend parameter structure */
 } dma_channel_params;
 
+typedef struct {
+	dma_channel_params common;
+	unsigned long p2p_dir:1;	/*!< 0: per2 to per.
+					 * the device of peripheral_type is per.
+					 * 1: per to per2
+					 * the device of peripheral_type is per2
+					 */
+	unsigned long info_bits;	/*!< info field in context */
+	unsigned long info_mask;	/*!< info field mask in context */
+	__u32 watermark_level2;	/*!< event2 threshold that
+				 *   triggers SDMA event
+				 *   just valid for p2p.
+				 */
+	__u32 per_address2;	/*!< Peripheral source
+				 *   physical address.
+				 *   just valid for p2p.
+				 */
+	struct dma_channel_info info;	/*!< the channel special parameter */
+} dma_channel_ext_params;
+
 /*!
  * Structure containing sdma request  parameters.
  */
@@ -285,13 +330,23 @@ typedef struct {
 
 /*! Structure to store the initialized dma_channel parameters */
 typedef struct mxc_sdma_channel_params {
+	/*! Channel type (static channel number or dynamic channel) */
+	unsigned int channel_num;
+	/*! Channel priority [0x1(lowest) - 0x7(highest)] */
+	unsigned int chnl_priority;
 	/*! Channel params */
 	dma_channel_params chnl_params;
+} mxc_sdma_channel_params_t;
+
+/*! Structure to store the initialized dma_channel extend parameters */
+typedef struct mxc_sdma_channel_ext_params {
 	/*! Channel type (static channel number or dynamic channel) */
 	unsigned int channel_num;
 	/*! Channel priority [0x1(lowest) - 0x7(highest)] */
 	unsigned int chnl_priority;
-} mxc_sdma_channel_params_t;
+	/*! Channel extend params */
+	dma_channel_ext_params chnl_ext_params;
+} mxc_sdma_channel_ext_params_t;
 
 /*! Private SDMA data structure */
 typedef struct mxc_dma_channel_private {
diff --git a/arch/arm/plat-mxc/sdma/dma_sdma.c b/arch/arm/plat-mxc/sdma/dma_sdma.c
index a05016d..5ca75d0 100644
--- a/arch/arm/plat-mxc/sdma/dma_sdma.c
+++ b/arch/arm/plat-mxc/sdma/dma_sdma.c
@@ -93,17 +93,27 @@ static void mxc_sdma_channeltasklet(unsigned long arg)
  * @return returns a negative number on error if request for a DMA channel did not
  *         succeed, returns the channel number to be used on success.
  */
-int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name)
+int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name,
+			struct dma_channel_info *info)
 {
 	mxc_sdma_channel_params_t *chnl;
 	mxc_dma_channel_private_t *data_priv;
 	int ret = 0, i = 0, channel_num = 0;
+	mxc_sdma_channel_ext_params_t *p;
 
 	chnl = mxc_sdma_get_channel_params(channel_id);
 	if (chnl == NULL) {
 		return -EINVAL;
 	}
 
+	if (info) {
+		if (!chnl->chnl_params.ext)
+			return -EINVAL;
+		p = (mxc_sdma_channel_ext_params_t *)chnl;
+		memcpy(&p->chnl_ext_params.info, info, sizeof(info));
+	}
+
+
 	/* Enable the SDMA clock */
 	clk_enable(mxc_sdma_ahb_clk);
 	clk_enable(mxc_sdma_ipg_clk);
@@ -333,7 +343,10 @@ int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf,
 		}
 		request_t.destAddr = (__u8 *) dma_buf->dst_addr;
 		request_t.sourceAddr = (__u8 *) dma_buf->src_addr;
-		request_t.count = dma_buf->num_of_bytes;
+		if (chnl_param.peripheral_type == ASRC)
+			request_t.count = dma_buf->num_of_bytes / 4;
+		else
+			request_t.count = dma_buf->num_of_bytes;
 		request_t.bd_cont = 1;
 		ret = mxc_dma_set_config(channel_num, &request_t,
 					 chnl_info->curr_buf);
@@ -671,7 +684,7 @@ EXPORT_SYMBOL(sdma_virt_to_phys);
 
 #endif
 
-EXPORT_SYMBOL(mxc_dma_request);
+EXPORT_SYMBOL(mxc_dma_request_ext);
 EXPORT_SYMBOL(mxc_dma_free);
 EXPORT_SYMBOL(mxc_dma_config);
 EXPORT_SYMBOL(mxc_dma_sg_config);
diff --git a/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h b/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h
index 995d215..bc42dab 100644
--- a/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h
+++ b/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  *
  * The code contained herein is licensed under the GNU General Public
@@ -408,6 +408,7 @@ typedef struct iapi_script_data {
   unsigned short load_address;/**<start address of the script*/
   unsigned long  wml;		   /**<parameters for the channel descriptor*/
   unsigned long  shp_addr;    /**<shared peripheral base address*/
+  unsigned long  per_addr;    /**<peripheral base address for p2p source*/
   unsigned long  event_mask1; /**<First Event mask */
   unsigned long  event_mask2; /**<Second Event mask */
 } script_data;
diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c
index 1d79511..886c70c 100644
--- a/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c
+++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  *
  * The code contained herein is licensed under the GNU General Public
@@ -455,6 +455,8 @@ iapi_lowAssignScript(channelDescriptor * cd_p, script_data * data_p)
    chContext->gReg[1] = data_p->event_mask1;
    chContext->gReg[6] = data_p->shp_addr;
    chContext->gReg[7] = data_p->wml;
+   if (data_p->per_addr)
+	chContext->gReg[2] = data_p->per_addr;
 
    /* Set transmited data to the CD*/
    cd_p->watermarkLevel = data_p->wml;
diff --git a/arch/arm/plat-mxc/sdma/sdma.c b/arch/arm/plat-mxc/sdma/sdma.c
index 1ec54a1..5428605 100644
--- a/arch/arm/plat-mxc/sdma/sdma.c
+++ b/arch/arm/plat-mxc/sdma/sdma.c
@@ -342,10 +342,10 @@ static unsigned short sdma_get_pc(sdma_periphT peripheral_type,
 	} else if (peripheral_type == ASRC) {
 		switch (transfer_type) {
 		case per_2_emi:
-			res = sdma_script_addrs.mxc_sdma_shp_2_mcu_addr;
+			res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr;
 			break;
 		case emi_2_per:
-			res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr;
+			res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr;
 			break;
 		case per_2_per:
 			res = sdma_script_addrs.mxc_sdma_per_2_per_addr;
@@ -401,6 +401,77 @@ static unsigned short sdma_get_pc(sdma_periphT peripheral_type,
 
 }
 
+static inline int sdma_asrc_set_info(dma_channel_params *p,
+				     script_data *pcontext, int eflags)
+{
+	dma_channel_ext_params *ep = (dma_channel_ext_params *) p;
+	unsigned int wml, tmp, wml1, wml2;
+	struct dma_channel_asrc_info *info = &(ep->info.asrc);
+	wml = 0;
+	if (p->transfer_type == per_2_per) {
+		if (!p->ext)
+			return wml;
+		wml1 = p->watermark_level;
+		wml2 = ep->watermark_level2;
+		if (info->channs) {
+			wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) <<
+			    SDMA_ASRC_INFO_N_OFF;
+			if (ep->p2p_dir)
+				wml2 *= info->channs & SDMA_ASRC_INFO_N_MASK;
+			else
+				wml1 *= info->channs & SDMA_ASRC_INFO_N_MASK;
+		}
+		if (info->channs & 1) {
+			if (ep->p2p_dir)
+				wml |= SDMA_ASRC_P2P_INFO_PS;
+			else
+				wml |= SDMA_ASRC_P2P_INFO_PA;
+		}
+		if (wml1 > wml2) {
+			tmp = wml2 & SDMA_ASRC_P2P_INFO_LWML_MASK;
+			wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF;
+			tmp = wml1 & SDMA_ASRC_P2P_INFO_HWML_MASK;
+			wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF;
+			if (eflags & (1 << 31))
+				wml |= SDMA_ASRC_P2P_INFO_LWE;
+			if (eflags & (1 << 30))
+				wml |= SDMA_ASRC_P2P_INFO_HWE;
+		} else {
+			tmp = wml1 & SDMA_ASRC_P2P_INFO_LWML_MASK;
+			wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF;
+			tmp = wml2 & SDMA_ASRC_P2P_INFO_HWML_MASK;
+			wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF;
+			wml |= eflags >> 2;
+			tmp = pcontext->event_mask2;
+			pcontext->event_mask2 = pcontext->event_mask1;
+			pcontext->event_mask1 = tmp;
+		}
+	} else {
+		if (p->ext && info->channs) {
+			wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) <<
+			    SDMA_ASRC_INFO_N_OFF;
+			tmp = (info->channs * p->watermark_level) &
+			    SDMA_ASRC_INFO_WML_MASK;
+			wml |= tmp << SDMA_ASRC_INFO_WML_OFF;
+		} else {
+			tmp = (p->watermark_level & SDMA_ASRC_INFO_WML_MASK);
+			wml |= tmp << SDMA_ASRC_INFO_WML_OFF;
+		}
+
+		if (p->transfer_type == per_2_emi)
+			wml |= SDMA_ASRC_INFO_TXFR_DIR;
+
+		if (p->ext && (info->channs & 1)) {
+			if (p->transfer_type == per_2_emi)
+				wml |= SDMA_ASRC_INFO_PS;
+			else
+				wml |= SDMA_ASRC_INFO_PA;
+		}
+		wml |= eflags;
+	}
+	return wml;
+}
+
 /*!
  * Downloads channel context according to channel parameters
  *
@@ -413,6 +484,7 @@ static int sdma_load_context(int channel, dma_channel_params * p)
 	int res;
 	int event1_greater_than_32;
 	int event2_greater_than_32;
+	dma_channel_ext_params *ep = (dma_channel_ext_params *) p;
 
 	res = 0;
 
@@ -456,13 +528,24 @@ static int sdma_load_context(int channel, dma_channel_params * p)
 					    0x1 << (p->event_id - 32);
 				}
 			}
+
+			if (p->ext)
+				context.wml = ep->info_bits;
 			/* Watermark Level */
-			context.wml =
-			    event2_greater_than_32 | event1_greater_than_32 |
-			    p->watermark_level;
+			if (p->peripheral_type == ASRC) {
+				context.wml |= sdma_asrc_set_info(p,
+								  &context,
+								  event2_greater_than_32
+								  |
+								  event1_greater_than_32);
+			} else
+				context.wml |= event2_greater_than_32 |
+				    event1_greater_than_32 | p->watermark_level;
 
 			/* Address */
 			context.shp_addr = (unsigned long)(p->per_address);
+			if (p->ext)
+				context.per_addr = ep->per_address2;
 			iapi_IoCtl(sdma_data[channel].cd,
 				   IAPI_CHANGE_PERIPHADDR, p->per_address);
 		} else {
@@ -529,6 +612,7 @@ descriptors (0x%x)\n", err);
 		case int_2_per:
 		case per_2_int:
 		case per_2_emi:
+		case per_2_per:
 			/*
 			 * Peripheral <------> Memory
 			 * evtOvr = 0 dspOvr = 1
-- 
1.6.0.4





More information about the kernel-team mailing list