Re: [RFC][PATCH 2/2] OMAP4: sDMA driver: descriptor autoloading feature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



"S, Venkatraman" <svenkatr@xxxxxx> writes:

> This patch adds the essential APIs for using the linked list mode of OMAP4 sDMA.
>
> Signed-off-by: Venkatraman S <svenkatr@xxxxxx>

Your detailed description from PATCH 0/2 would be better placed here.

In addition to dropping the #ifdef, additional comments below...

> ---
>  arch/arm/plat-omap/dma.c              |  284 +++++++++++++++++++++++++++++++++
>  arch/arm/plat-omap/include/mach/dma.h |  100 ++++++++++++
>  2 files changed, 384 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
> index 7677a4a..dd4990a 100644
> --- a/arch/arm/plat-omap/dma.c
> +++ b/arch/arm/plat-omap/dma.c
> @@ -29,6 +29,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/io.h>
> +#include <linux/dma-mapping.h>
>  
>  #include <asm/system.h>
>  #include <mach/hardware.h>
> @@ -52,8 +53,23 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED };
>  
>  #define OMAP_FUNC_MUX_ARM_BASE		(0xfffe1000 + 0xec)
>  
> +#define OMAP_DMALIST_SET_NTYPE(nod_, val_) \
> +	do { \
> +		(nod_)->num_of_elem |= ((val_) << 29); \
> +	} while (0)
> +

Use static inline function.

>  static int enable_1510_mode;
>  
> +#ifdef CONFIG_OMAP_DMA_DESCRIPTOR_LOAD
> +struct omap_dma_list_config_params {
> +	int chid;
> +	int num_elem;
> +	struct omap_dma_sglist_node *sghead;
> +	int sgheadphy;
> +	int pausenode;
> +};
> +#endif
> +
>  struct omap_dma_lch {
>  	int next_lch;
>  	int dev_id;
> @@ -72,6 +88,10 @@ struct omap_dma_lch {
>  
>  	int status;
>  #endif
> +
> +#ifdef CONFIG_OMAP_DMA_DESCRIPTOR_LOAD
> +	void *list_config;
> +#endif
>  	long flags;
>  };
>  
> @@ -1787,6 +1807,267 @@ EXPORT_SYMBOL(omap_get_dma_chain_src_pos);
>  #endif	/* ifndef CONFIG_ARCH_OMAP1 */
>  
>  /*----------------------------------------------------------------------------*/
> +#ifdef CONFIG_OMAP_DMA_DESCRIPTOR_LOAD
> +
> +int omap_request_dma_sglist(int dev_id, const char *dev_name,
> +	void (*callback) (int channel_id, u16 ch_status, void *data),
> +	int *listid, int nelem, struct omap_dma_sglist_node **elems)
> +{
> +	struct omap_dma_list_config_params *lcfg;
> +	struct omap_dma_sglist_node *desc;
> +	int dma_lch;
> +	int rc, i;
> +
> +	if (unlikely(nelem <= 2)) {
> +		printk(KERN_ERR "omap DMA: Need >2 elements in the list\n");
> +		return -EINVAL;
> +	}
> +	rc = omap_request_dma(dev_id, dev_name,
> +			  callback, NULL, &dma_lch);
> +	if (rc < 0) {
> +		printk(KERN_ERR "omap_dma_list: Request failed %d\n", rc);
> +		return rc;
> +	}
> +	*listid = dma_lch;
> +	dma_chan[dma_lch].state = DMA_CH_NOTSTARTED;
> +	lcfg = kmalloc(sizeof(*lcfg), GFP_KERNEL);
> +	if (NULL == lcfg)
> +		goto error1;
> +	dma_chan[dma_lch].list_config = lcfg;
> +
> +	lcfg->num_elem = nelem;
> +
> +	*elems = desc = lcfg->sghead = dma_alloc_coherent(NULL,
> +		sizeof(*desc), &(lcfg->sgheadphy), 0);
> +	if (NULL == desc)
> +		goto error1;
> +
> +	for (i = 1; i < nelem; i++) {
> +		desc->next = dma_alloc_coherent(NULL,
> +			sizeof(*(desc->next)), &(desc->next_desc_add_ptr), 0);
> +		if (NULL == desc->next)
> +			goto error1;
> +		desc = desc->next;
> +		desc->next = NULL;
> +	}
> +	desc->next_desc_add_ptr = 0xfffffffc;
> +
> +	/* TRM Sec 1.4.21.4.3 */

A summary of that TRM section would be preferred, followed by the
section reference.

> +	dma_write(0, CCDN(dma_lch));
> +	dma_write(0xffff, CCFN(dma_lch));
> +	dma_write(0xffffff, CCEN(dma_lch));

Some symbolic names for these constants would be preferred.

> +	return 0;
> +
> +error1:
> +	omap_release_dma_sglist(dma_lch);
> +	return -ENOMEM;
> +
> +}
> +EXPORT_SYMBOL(omap_request_dma_sglist);
> +
> +/* The client can choose to not preconfigure the DMA registers
> + * In fast mode,the DMA controller uses the first element in the list to
> + * program the registers first, and then starts the transfer
> + */
> +
> +int omap_set_dma_sglist_params(const int listid,
> +	struct omap_dma_sglist_node *sghead,
> +	struct omap_dma_channel_params *chparams)
> +{
> +	struct omap_dma_list_config_params *lcfg;
> +	struct omap_dma_sglist_node *sgitcurr, *sgitprev;
> +	int l = 0x100; /* Enable Linked list mode in CDP */

Define these fields above using BIT() and use the symbolic
names in the code.

> +	lcfg = dma_chan[listid].list_config;
> +	if (lcfg->sghead != sghead) {
> +		printk(KERN_ERR "Unknown config pointer passed\n");
> +		return -EPERM;
> +	}
> +
> +	if (NULL == chparams)
> +		l |= 0x400;  /* FAST mode bit:10 */

ditto

> +	else
> +		omap_set_dma_params(listid, chparams);
> +		/* The client can set the dma params and still use fast mode
> +		 * by using the set fast mode api
> +		 */
> +	dma_write(l, CDP(listid));
> +
> +	sgitprev = sghead;
> +	sgitcurr = sgitprev->next;
> +
> +	while (sgitcurr != NULL) {
> +		switch (sgitcurr->desc_type) {
> +		case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE1:
> +			OMAP_DMALIST_SET_NTYPE(sgitprev, 1);
> +			break;
> +
> +		case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE2a:
> +			/* intentional no break */
> +		case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE2b:
> +			OMAP_DMALIST_SET_NTYPE(sgitprev, 2);
> +			break;
> +
> +		case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE3a:
> +			/* intentional no break */
> +		case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE3b:
> +			OMAP_DMALIST_SET_NTYPE(sgitprev, 3);
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +		if (sgitcurr->flags & OMAP_DMA_LIST_SRC_VALID)
> +			sgitprev->next_desc_add_ptr |= 1<<24;

use BIT()

> +		if (sgitcurr->flags & OMAP_DMA_LIST_DST_VALID)
> +			sgitprev->next_desc_add_ptr |= 1<<26;

ditto

> +		if (sgitcurr->flags & OMAP_DMA_LIST_NOTIFY_BLOCK_END)
> +			sgitprev->next_desc_add_ptr |= 1<<28;

ditto

> +
> +		sgitprev = sgitcurr;
> +		sgitcurr = sgitcurr->next;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(omap_set_dma_sglist_params);
> +
> +int omap_start_dma_sglist_transfers(const int listid, const int pauseafter)
> +{
> +	struct omap_dma_list_config_params *lcfg;
> +	struct omap_dma_sglist_node *sgn;
> +	unsigned int l, typeid;
> +
> +	lcfg = dma_chan[listid].list_config;
> +	lcfg->pausenode = 0;
> +	sgn = lcfg->sghead;
> +	if (pauseafter > 0 && pauseafter <= lcfg->num_elem) {
> +		for (l = 0; l < pauseafter; l++)
> +			sgn = sgn->next;
> +		sgn->next_desc_add_ptr |= 0x1;
> +		lcfg->pausenode = pauseafter;
> +	}
> +
> +	switch (lcfg->sghead->desc_type) {
> +	case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE1:
> +		typeid = 1;
> +		break;
> +	case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE2a:
> +	case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE2b:
> +		typeid = 2;
> +		break;
> +	case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE3a:
> +	case OMAP_DMA_SGLIST_DESCRIPTOR_TYPE3b:
> +		typeid = 3;
> +		break;
> +	default:
> +		BUG();
> +	}
> +
> +	l = dma_read(CDP(listid));
> +	l |= (typeid << 4);

some symbolic names for the typeid values and the shift value
would be more readable.

> +	if (lcfg->sghead->flags & OMAP_DMA_LIST_SRC_VALID)
> +		l |= (1 << 2);

BIT()

> +	if (lcfg->sghead->flags & OMAP_DMA_LIST_DST_VALID)
> +		l |= 1;

BIT()

you get the picture...

> +	dma_write(l, CDP(listid));
> +	dma_write(0, CCDN(listid));
> +
> +	dma_write((lcfg->sgheadphy), CNDP(listid));
> +	printk(KERN_DEBUG "Start list transfer for list %x\n",
> +		lcfg->sgheadphy);
> +	omap_start_dma(listid);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(omap_start_dma_sglist_transfers);
> +
> +int omap_resume_dma_sglist_transfers(const int listid, const int pauseafter)
> +{
> +	struct omap_dma_list_config_params *lcfg;
> +	struct omap_dma_sglist_node *sgn;
> +	int l;
> +
> +	lcfg = dma_chan[listid].list_config;
> +	sgn = lcfg->sghead;
> +	/* Clear the previous pause, if any */
> +	lcfg->pausenode = 0;
> +
> +	if (pauseafter > 0 && pauseafter <= lcfg->num_elem) {
> +		for (l = 0; l < pauseafter; l++)
> +			sgn = sgn->next;
> +		sgn->next_desc_add_ptr |= 0x1;
> +		lcfg->pausenode = pauseafter;
> +	}
> +
> +	/* Clear pause bit in CDP */
> +	l = dma_read(CDP(listid));
> +	printk(KERN_DEBUG "Resuming after pause CDP=%x\n", l);
> +	l &= 0x77f;
> +	dma_write(l, CDP(listid));
> +	omap_start_dma(listid);
> +	return 0;
> +}
> +EXPORT_SYMBOL(omap_resume_dma_sglist_transfers);
> +
> +int omap_release_dma_sglist(const int listid)
> +{
> +	struct omap_dma_list_config_params *lcfg;
> +	struct omap_dma_sglist_node *sgn, *sgn2;
> +
> +	lcfg = dma_chan[listid].list_config;
> +	sgn = lcfg->sghead;
> +
> +	if (NULL != sgn) {
> +		sgn = sgn->next;
> +		do {
> +			sgn2 = sgn->next;
> +			dma_free_coherent(NULL, sizeof(*sgn), sgn,
> +				sgn->next_desc_add_ptr);
> +			sgn = sgn2;
> +		} while (sgn2 != NULL);
> +
> +		dma_free_coherent(NULL, sizeof(*(lcfg->sghead)),
> +			lcfg->sghead, lcfg->sgheadphy);
> +	}
> +	if (NULL != dma_chan[listid].list_config)
> +		kfree(dma_chan[listid].list_config);
> +	dma_chan[listid].list_config = NULL;
> +	omap_free_dma(listid);
> +	return 0;
> +}
> +EXPORT_SYMBOL(omap_release_dma_sglist);
> +
> +int omap_get_completed_sglist_nodes(const int listid)
> +{
> +	int list_count;
> +
> +	list_count = dma_read(CCDN(listid));
> +	return list_count & 0xffff;
> +}
> +EXPORT_SYMBOL(omap_get_completed_sglist_nodes);
> +
> +int omap_dma_sglist_is_paused(const int listid)
> +{
> +	int list_state;
> +
> +	list_state = dma_read(CDP(listid));
> +	return (list_state & 0x80) ? 1 : 0;

BIT()

> +}
> +EXPORT_SYMBOL(omap_dma_sglist_is_paused);
> +
> +void omap_dma_set_sglist_fastmode(const int listid, const int fastmode)
> +{
> +	int l = dma_read(CDP(listid));
> +
> +	if (fastmode)
> +		l |= 0x400;

BIT()

> +	else
> +		l &= 0xffffffdf;
> +	dma_write(l, CDP(listid));
> +}
> +EXPORT_SYMBOL(omap_dma_set_sglist_fastmode);
> +#endif
>  
>  #ifdef CONFIG_ARCH_OMAP1
>  
> @@ -2418,6 +2699,9 @@ static int __init omap_init_dma(void)
>  		omap_clear_dma(ch);
>  		dma_chan[ch].dev_id = -1;
>  		dma_chan[ch].next_lch = -1;
> +#ifdef CONFIG_OMAP_DMA_DESCRIPTOR_LOAD
> +		dma_chan[ch].list_config = NULL;
> +#endif
>  
>  		if (ch >= 6 && enable_1510_mode)
>  			continue;
> diff --git a/arch/arm/plat-omap/include/mach/dma.h b/arch/arm/plat-omap/include/mach/dma.h
> index 72f680b..df4a7b8 100644
> --- a/arch/arm/plat-omap/include/mach/dma.h
> +++ b/arch/arm/plat-omap/include/mach/dma.h
> @@ -112,8 +112,12 @@
>  #define OMAP1_DMA_COLOR_U(n)		(0x40 * (n) + 0x22)
>  #define OMAP1_DMA_CCR2(n)		(0x40 * (n) + 0x24)
>  #define OMAP1_DMA_LCH_CTRL(n)		(0x40 * (n) + 0x2a)	/* not on 15xx */
> +#define OMAP1_DMA_COLOR(n)		0
>  #define OMAP1_DMA_CCEN(n)		0
>  #define OMAP1_DMA_CCFN(n)		0
> +#define OMAP1_DMA_CDP(n)		0
> +#define OMAP1_DMA_CNDP(n)		0
> +#define OMAP1_DMA_CCDN(n)		0
>  
>  /* Channel specific registers only on omap2 */
>  #define OMAP_DMA4_CSSA(n)		(0x60 * (n) + 0x9c)
> @@ -576,6 +580,86 @@ struct omap_dma_channel_params {
>  #endif
>  };
>  
> +#ifdef CONFIG_OMAP_DMA_DESCRIPTOR_LOAD
> +struct omap_dma_sglist_type1_params {
> +	u32 src_addr;
> +	u32 dst_addr;
> +	u16 cfn_fn;
> +	u16 cicr;
> +	u16 dst_elem_idx;
> +	u16 src_elem_idx;
> +	u32 dst_frame_idx_or_pkt_size;
> +	u32 src_frame_idx_or_pkt_size;
> +	u32 color;
> +	u32 csdp;
> +	u32 clnk_ctrl;
> +	u32 ccr;
> +};
> +
> +struct omap_dma_sglist_type2a_params {
> +	u32 src_addr;
> +	u32 dst_addr;
> +	u16 cfn_fn;
> +	u16 cicr;
> +	u16 dst_elem_idx;
> +	u16 src_elem_idx;
> +	u32 dst_frame_idx_or_pkt_size;
> +	u32 src_frame_idx_or_pkt_size;
> +};
> +
> +struct omap_dma_sglist_type2b_params {
> +	u32 src_or_dest_addr;
> +	u16 cfn_fn;
> +	u16 cicr;
> +	u16 dst_elem_idx;
> +	u16 src_elem_idx;
> +	u32 dst_frame_idx_or_pkt_size;
> +	u32 src_frame_idx_or_pkt_size;
> +};
> +
> +struct omap_dma_sglist_type3a_params {
> +	u32 src_addr;
> +	u32 dst_addr;
> +};
> +
> +struct omap_dma_sglist_type3b_params {
> +	u32 src_or_dest_addr;
> +};
> +
> +enum omap_dma_sglist_descriptor_select {
> +	OMAP_DMA_SGLIST_DESCRIPTOR_TYPE1,
> +	OMAP_DMA_SGLIST_DESCRIPTOR_TYPE2a,
> +	OMAP_DMA_SGLIST_DESCRIPTOR_TYPE2b,
> +	OMAP_DMA_SGLIST_DESCRIPTOR_TYPE3a,
> +	OMAP_DMA_SGLIST_DESCRIPTOR_TYPE3b,
> +};
> +
> +union omap_dma_sglist_node_type{
> +	struct omap_dma_sglist_type1_params t1;
> +	struct omap_dma_sglist_type2a_params t2a;
> +	struct omap_dma_sglist_type2b_params t2b;
> +	struct omap_dma_sglist_type3a_params t3a;
> +	struct omap_dma_sglist_type3b_params t3b;
> +};
> +
> +struct omap_dma_sglist_node {
> +
> +	/* Common elements for all descriptors */
> +	u32 next_desc_add_ptr;
> +	u32 num_of_elem;
> +	/* Type specific elements */
> +	union omap_dma_sglist_node_type sg_node;
> +	/* Control fields */
> +	int flags;
> +	/* Fields that can be set in flags variable */
> +	#define OMAP_DMA_LIST_SRC_VALID		(1)
> +	#define OMAP_DMA_LIST_DST_VALID		(2)
> +	#define OMAP_DMA_LIST_NOTIFY_BLOCK_END	(4)
> +	u32 desc_type;
> +	struct omap_dma_sglist_node *next;
> +};
> +
> +#endif
>  
>  extern void omap_set_dma_priority(int lch, int dst_port, int priority);
>  extern int omap_request_dma(int dev_id, const char *dev_name,
> @@ -656,6 +740,22 @@ extern int omap_modify_dma_chain_params(int chain_id,
>  extern int omap_dma_chain_status(int chain_id);
>  #endif
>  
> +#ifdef CONFIG_OMAP_DMA_DESCRIPTOR_LOAD
> +extern int omap_request_dma_sglist(int dev_id, const char *dev_name,
> +		void (*callback) (int channel_id, u16 ch_status, void *data),
> +		int *listid, int nelem, struct omap_dma_sglist_node **elems);
> +extern int omap_set_dma_sglist_params(const int listid,
> +				      struct omap_dma_sglist_node *sghead,
> +				      struct omap_dma_channel_params *chparams);
> +extern int omap_start_dma_sglist_transfers(const int listid,
> +					   const int pauseafter);
> +extern int omap_resume_dma_sglist_transfers(const int listid,
> +					    const int pauseafter);
> +extern int omap_release_dma_sglist(const int listid);
> +int omap_get_completed_sglist_nodes(const int listid);
> +int omap_dma_sglist_is_paused(const int listid);
> +void omap_dma_set_sglist_fastmode(const int listid, const int fastmode);
> +#endif
>  /* LCD DMA functions */
>  extern int omap_request_lcd_dma(void (*callback)(u16 status, void *data),
>  				void *data);
> ---
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux