541 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			541 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Enhanced Direct Memory Access (EDMA3) Controller
 | 
						|
 *
 | 
						|
 * (C) Copyright 2014
 | 
						|
 *     Texas Instruments Incorporated, <www.ti.com>
 | 
						|
 *
 | 
						|
 * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier:     GPL-2.0+
 | 
						|
 */
 | 
						|
 | 
						|
#include <asm/io.h>
 | 
						|
#include <common.h>
 | 
						|
#include <dma.h>
 | 
						|
#include <dm/device.h>
 | 
						|
#include <asm/omap_common.h>
 | 
						|
#include <asm/ti-common/ti-edma3.h>
 | 
						|
 | 
						|
#define EDMA3_SL_BASE(slot)			(0x4000 + ((slot) << 5))
 | 
						|
#define EDMA3_SL_MAX_NUM			512
 | 
						|
#define EDMA3_SLOPT_FIFO_WIDTH_MASK		(0x7 << 8)
 | 
						|
 | 
						|
#define EDMA3_QCHMAP(ch)			0x0200 + ((ch) << 2)
 | 
						|
#define EDMA3_CHMAP_PARSET_MASK			0x1ff
 | 
						|
#define EDMA3_CHMAP_PARSET_SHIFT		0x5
 | 
						|
#define EDMA3_CHMAP_TRIGWORD_SHIFT		0x2
 | 
						|
 | 
						|
#define EDMA3_QEMCR				0x314
 | 
						|
#define EDMA3_IPR				0x1068
 | 
						|
#define EDMA3_IPRH				0x106c
 | 
						|
#define EDMA3_ICR				0x1070
 | 
						|
#define EDMA3_ICRH				0x1074
 | 
						|
#define EDMA3_QEECR				0x1088
 | 
						|
#define EDMA3_QEESR				0x108c
 | 
						|
#define EDMA3_QSECR				0x1094
 | 
						|
 | 
						|
struct ti_edma3_priv {
 | 
						|
	u32 base;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * qedma3_start - start qdma on a channel
 | 
						|
 * @base: base address of edma
 | 
						|
 * @cfg: pinter to struct edma3_channel_config where you can set
 | 
						|
 * the slot number to associate with, the chnum, which corresponds
 | 
						|
 * your quick channel number 0-7, complete code - transfer complete code
 | 
						|
 * and trigger slot word - which has to correspond to the word number in
 | 
						|
 * edma3_slot_layout struct for generating event.
 | 
						|
 *
 | 
						|
 */
 | 
						|
void qedma3_start(u32 base, struct edma3_channel_config *cfg)
 | 
						|
{
 | 
						|
	u32 qchmap;
 | 
						|
 | 
						|
	/* Clear the pending int bit */
 | 
						|
	if (cfg->complete_code < 32)
 | 
						|
		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
 | 
						|
	else
 | 
						|
		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
 | 
						|
 | 
						|
	/* Map parameter set and trigger word 7 to quick channel */
 | 
						|
	qchmap = ((EDMA3_CHMAP_PARSET_MASK & cfg->slot)
 | 
						|
		  << EDMA3_CHMAP_PARSET_SHIFT) |
 | 
						|
		  (cfg->trigger_slot_word << EDMA3_CHMAP_TRIGWORD_SHIFT);
 | 
						|
 | 
						|
	__raw_writel(qchmap, base + EDMA3_QCHMAP(cfg->chnum));
 | 
						|
 | 
						|
	/* Clear missed event if set*/
 | 
						|
	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
 | 
						|
	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
 | 
						|
 | 
						|
	/* Enable qdma channel event */
 | 
						|
	__raw_writel(1 << cfg->chnum, base + EDMA3_QEESR);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_dest - set initial DMA destination address in parameter RAM slot
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: parameter RAM slot being configured
 | 
						|
 * @dst: physical address of destination (memory, controller FIFO, etc)
 | 
						|
 * @addressMode: INCR, except in very rare cases
 | 
						|
 * @width: ignored unless @addressMode is FIFO, else specifies the
 | 
						|
 *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
 | 
						|
 *
 | 
						|
 * Note that the destination address is modified during the DMA transfer
 | 
						|
 * according to edma3_set_dest_index().
 | 
						|
 */
 | 
						|
void edma3_set_dest(u32 base, int slot, u32 dst, enum edma3_address_mode mode,
 | 
						|
		    enum edma3_fifo_width width)
 | 
						|
{
 | 
						|
	u32 opt;
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	opt = __raw_readl(&rg->opt);
 | 
						|
	if (mode == FIFO)
 | 
						|
		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
 | 
						|
		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
 | 
						|
			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
 | 
						|
	else
 | 
						|
		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
 | 
						|
 | 
						|
	__raw_writel(opt, &rg->opt);
 | 
						|
	__raw_writel(dst, &rg->dst);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_dest_index - configure DMA destination address indexing
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: parameter RAM slot being configured
 | 
						|
 * @bidx: byte offset between destination arrays in a frame
 | 
						|
 * @cidx: byte offset between destination frames in a block
 | 
						|
 *
 | 
						|
 * Offsets are specified to support either contiguous or discontiguous
 | 
						|
 * memory transfers, or repeated access to a hardware register, as needed.
 | 
						|
 * When accessing hardware registers, both offsets are normally zero.
 | 
						|
 */
 | 
						|
void edma3_set_dest_index(u32 base, unsigned slot, int bidx, int cidx)
 | 
						|
{
 | 
						|
	u32 src_dst_bidx;
 | 
						|
	u32 src_dst_cidx;
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
 | 
						|
	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
 | 
						|
 | 
						|
	__raw_writel((src_dst_bidx & 0x0000ffff) | (bidx << 16),
 | 
						|
		     &rg->src_dst_bidx);
 | 
						|
	__raw_writel((src_dst_cidx & 0x0000ffff) | (cidx << 16),
 | 
						|
		     &rg->src_dst_cidx);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_dest_addr - set destination address for slot only
 | 
						|
 */
 | 
						|
void edma3_set_dest_addr(u32 base, int slot, u32 dst)
 | 
						|
{
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
	__raw_writel(dst, &rg->dst);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_src - set initial DMA source address in parameter RAM slot
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: parameter RAM slot being configured
 | 
						|
 * @src_port: physical address of source (memory, controller FIFO, etc)
 | 
						|
 * @mode: INCR, except in very rare cases
 | 
						|
 * @width: ignored unless @addressMode is FIFO, else specifies the
 | 
						|
 *	width to use when addressing the fifo (e.g. W8BIT, W32BIT)
 | 
						|
 *
 | 
						|
 * Note that the source address is modified during the DMA transfer
 | 
						|
 * according to edma3_set_src_index().
 | 
						|
 */
 | 
						|
void edma3_set_src(u32 base, int slot, u32 src, enum edma3_address_mode mode,
 | 
						|
		   enum edma3_fifo_width width)
 | 
						|
{
 | 
						|
	u32 opt;
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	opt = __raw_readl(&rg->opt);
 | 
						|
	if (mode == FIFO)
 | 
						|
		opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) |
 | 
						|
		       (EDMA3_SLOPT_DST_ADDR_CONST_MODE |
 | 
						|
			EDMA3_SLOPT_FIFO_WIDTH_SET(width));
 | 
						|
	else
 | 
						|
		opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE;
 | 
						|
 | 
						|
	__raw_writel(opt, &rg->opt);
 | 
						|
	__raw_writel(src, &rg->src);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_src_index - configure DMA source address indexing
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: parameter RAM slot being configured
 | 
						|
 * @bidx: byte offset between source arrays in a frame
 | 
						|
 * @cidx: byte offset between source frames in a block
 | 
						|
 *
 | 
						|
 * Offsets are specified to support either contiguous or discontiguous
 | 
						|
 * memory transfers, or repeated access to a hardware register, as needed.
 | 
						|
 * When accessing hardware registers, both offsets are normally zero.
 | 
						|
 */
 | 
						|
void edma3_set_src_index(u32 base, unsigned slot, int bidx, int cidx)
 | 
						|
{
 | 
						|
	u32 src_dst_bidx;
 | 
						|
	u32 src_dst_cidx;
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	src_dst_bidx = __raw_readl(&rg->src_dst_bidx);
 | 
						|
	src_dst_cidx = __raw_readl(&rg->src_dst_cidx);
 | 
						|
 | 
						|
	__raw_writel((src_dst_bidx & 0xffff0000) | bidx,
 | 
						|
		     &rg->src_dst_bidx);
 | 
						|
	__raw_writel((src_dst_cidx & 0xffff0000) | cidx,
 | 
						|
		     &rg->src_dst_cidx);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_src_addr - set source address for slot only
 | 
						|
 */
 | 
						|
void edma3_set_src_addr(u32 base, int slot, u32 src)
 | 
						|
{
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
	__raw_writel(src, &rg->src);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_set_transfer_params - configure DMA transfer parameters
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: parameter RAM slot being configured
 | 
						|
 * @acnt: how many bytes per array (at least one)
 | 
						|
 * @bcnt: how many arrays per frame (at least one)
 | 
						|
 * @ccnt: how many frames per block (at least one)
 | 
						|
 * @bcnt_rld: used only for A-Synchronized transfers; this specifies
 | 
						|
 *	the value to reload into bcnt when it decrements to zero
 | 
						|
 * @sync_mode: ASYNC or ABSYNC
 | 
						|
 *
 | 
						|
 * See the EDMA3 documentation to understand how to configure and link
 | 
						|
 * transfers using the fields in PaRAM slots.  If you are not doing it
 | 
						|
 * all at once with edma3_write_slot(), you will use this routine
 | 
						|
 * plus two calls each for source and destination, setting the initial
 | 
						|
 * address and saying how to index that address.
 | 
						|
 *
 | 
						|
 * An example of an A-Synchronized transfer is a serial link using a
 | 
						|
 * single word shift register.  In that case, @acnt would be equal to
 | 
						|
 * that word size; the serial controller issues a DMA synchronization
 | 
						|
 * event to transfer each word, and memory access by the DMA transfer
 | 
						|
 * controller will be word-at-a-time.
 | 
						|
 *
 | 
						|
 * An example of an AB-Synchronized transfer is a device using a FIFO.
 | 
						|
 * In that case, @acnt equals the FIFO width and @bcnt equals its depth.
 | 
						|
 * The controller with the FIFO issues DMA synchronization events when
 | 
						|
 * the FIFO threshold is reached, and the DMA transfer controller will
 | 
						|
 * transfer one frame to (or from) the FIFO.  It will probably use
 | 
						|
 * efficient burst modes to access memory.
 | 
						|
 */
 | 
						|
void edma3_set_transfer_params(u32 base, int slot, int acnt,
 | 
						|
			       int bcnt, int ccnt, u16 bcnt_rld,
 | 
						|
			       enum edma3_sync_dimension sync_mode)
 | 
						|
{
 | 
						|
	u32 opt;
 | 
						|
	u32 link_bcntrld;
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	link_bcntrld = __raw_readl(&rg->link_bcntrld);
 | 
						|
 | 
						|
	__raw_writel((bcnt_rld << 16) | (0x0000ffff & link_bcntrld),
 | 
						|
		     &rg->link_bcntrld);
 | 
						|
 | 
						|
	opt = __raw_readl(&rg->opt);
 | 
						|
	if (sync_mode == ASYNC)
 | 
						|
		__raw_writel(opt & ~EDMA3_SLOPT_AB_SYNC, &rg->opt);
 | 
						|
	else
 | 
						|
		__raw_writel(opt | EDMA3_SLOPT_AB_SYNC, &rg->opt);
 | 
						|
 | 
						|
	/* Set the acount, bcount, ccount registers */
 | 
						|
	__raw_writel((bcnt << 16) | (acnt & 0xffff), &rg->a_b_cnt);
 | 
						|
	__raw_writel(0xffff & ccnt, &rg->ccnt);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_write_slot - write parameter RAM data for slot
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: number of parameter RAM slot being modified
 | 
						|
 * @param: data to be written into parameter RAM slot
 | 
						|
 *
 | 
						|
 * Use this to assign all parameters of a transfer at once.  This
 | 
						|
 * allows more efficient setup of transfers than issuing multiple
 | 
						|
 * calls to set up those parameters in small pieces, and provides
 | 
						|
 * complete control over all transfer options.
 | 
						|
 */
 | 
						|
void edma3_write_slot(u32 base, int slot, struct edma3_slot_layout *param)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	u32 *p = (u32 *)param;
 | 
						|
	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
 | 
						|
		__raw_writel(*p++, addr++);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_read_slot - read parameter RAM data from slot
 | 
						|
 * @base: base address of edma
 | 
						|
 * @slot: number of parameter RAM slot being copied
 | 
						|
 * @param: where to store copy of parameter RAM data
 | 
						|
 *
 | 
						|
 * Use this to read data from a parameter RAM slot, perhaps to
 | 
						|
 * save them as a template for later reuse.
 | 
						|
 */
 | 
						|
void edma3_read_slot(u32 base, int slot, struct edma3_slot_layout *param)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	u32 *p = (u32 *)param;
 | 
						|
	u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4)
 | 
						|
		*p++ = __raw_readl(addr++);
 | 
						|
}
 | 
						|
 | 
						|
void edma3_slot_configure(u32 base, int slot, struct edma3_slot_config *cfg)
 | 
						|
{
 | 
						|
	struct edma3_slot_layout *rg;
 | 
						|
 | 
						|
	rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot));
 | 
						|
 | 
						|
	__raw_writel(cfg->opt, &rg->opt);
 | 
						|
	__raw_writel(cfg->src, &rg->src);
 | 
						|
	__raw_writel((cfg->bcnt << 16) | (cfg->acnt & 0xffff), &rg->a_b_cnt);
 | 
						|
	__raw_writel(cfg->dst, &rg->dst);
 | 
						|
	__raw_writel((cfg->dst_bidx << 16) |
 | 
						|
		     (cfg->src_bidx & 0xffff), &rg->src_dst_bidx);
 | 
						|
	__raw_writel((cfg->bcntrld << 16) |
 | 
						|
		     (cfg->link & 0xffff), &rg->link_bcntrld);
 | 
						|
	__raw_writel((cfg->dst_cidx << 16) |
 | 
						|
		     (cfg->src_cidx & 0xffff), &rg->src_dst_cidx);
 | 
						|
	__raw_writel(0xffff & cfg->ccnt, &rg->ccnt);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * edma3_check_for_transfer - check if transfer coplete by checking
 | 
						|
 * interrupt pending bit. Clear interrupt pending bit if complete.
 | 
						|
 * @base: base address of edma
 | 
						|
 * @cfg: pinter to struct edma3_channel_config which was passed
 | 
						|
 * to qedma3_start when you started qdma channel
 | 
						|
 *
 | 
						|
 * Return 0 if complete, 1 if not.
 | 
						|
 */
 | 
						|
int edma3_check_for_transfer(u32 base, struct edma3_channel_config *cfg)
 | 
						|
{
 | 
						|
	u32 inum;
 | 
						|
	u32 ipr_base;
 | 
						|
	u32 icr_base;
 | 
						|
 | 
						|
	if (cfg->complete_code < 32) {
 | 
						|
		ipr_base = base + EDMA3_IPR;
 | 
						|
		icr_base = base + EDMA3_ICR;
 | 
						|
		inum = 1 << cfg->complete_code;
 | 
						|
	} else {
 | 
						|
		ipr_base = base + EDMA3_IPRH;
 | 
						|
		icr_base = base + EDMA3_ICRH;
 | 
						|
		inum = 1 << (cfg->complete_code - 32);
 | 
						|
	}
 | 
						|
 | 
						|
	/* check complete interrupt */
 | 
						|
	if (!(__raw_readl(ipr_base) & inum))
 | 
						|
		return 1;
 | 
						|
 | 
						|
	/* clean up the pending int bit */
 | 
						|
	__raw_writel(inum, icr_base);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * qedma3_stop - stops dma on the channel passed
 | 
						|
 * @base: base address of edma
 | 
						|
 * @cfg: pinter to struct edma3_channel_config which was passed
 | 
						|
 * to qedma3_start when you started qdma channel
 | 
						|
 */
 | 
						|
void qedma3_stop(u32 base, struct edma3_channel_config *cfg)
 | 
						|
{
 | 
						|
	/* Disable qdma channel event */
 | 
						|
	__raw_writel(1 << cfg->chnum, base + EDMA3_QEECR);
 | 
						|
 | 
						|
	/* clean up the interrupt indication */
 | 
						|
	if (cfg->complete_code < 32)
 | 
						|
		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICR);
 | 
						|
	else
 | 
						|
		__raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH);
 | 
						|
 | 
						|
	/* Clear missed event if set*/
 | 
						|
	__raw_writel(1 << cfg->chnum, base + EDMA3_QSECR);
 | 
						|
	__raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR);
 | 
						|
 | 
						|
	/* Clear the channel map */
 | 
						|
	__raw_writel(0, base + EDMA3_QCHMAP(cfg->chnum));
 | 
						|
}
 | 
						|
 | 
						|
void __edma3_transfer(unsigned long edma3_base_addr, unsigned int edma_slot_num,
 | 
						|
		      void *dst, void *src, size_t len)
 | 
						|
{
 | 
						|
	struct edma3_slot_config        slot;
 | 
						|
	struct edma3_channel_config     edma_channel;
 | 
						|
	int                             b_cnt_value = 1;
 | 
						|
	int                             rem_bytes  = 0;
 | 
						|
	int                             a_cnt_value = len;
 | 
						|
	unsigned int                    addr = (unsigned int) (dst);
 | 
						|
	unsigned int                    max_acnt  = 0x7FFFU;
 | 
						|
 | 
						|
	if (len > max_acnt) {
 | 
						|
		b_cnt_value = (len / max_acnt);
 | 
						|
		rem_bytes  = (len % max_acnt);
 | 
						|
		a_cnt_value = max_acnt;
 | 
						|
	}
 | 
						|
 | 
						|
	slot.opt        = 0;
 | 
						|
	slot.src        = ((unsigned int) src);
 | 
						|
	slot.acnt       = a_cnt_value;
 | 
						|
	slot.bcnt       = b_cnt_value;
 | 
						|
	slot.ccnt       = 1;
 | 
						|
	slot.src_bidx   = a_cnt_value;
 | 
						|
	slot.dst_bidx   = a_cnt_value;
 | 
						|
	slot.src_cidx   = 0;
 | 
						|
	slot.dst_cidx   = 0;
 | 
						|
	slot.link       = EDMA3_PARSET_NULL_LINK;
 | 
						|
	slot.bcntrld    = 0;
 | 
						|
	slot.opt        = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
 | 
						|
			  EDMA3_SLOPT_COMP_CODE(0) |
 | 
						|
			  EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
 | 
						|
 | 
						|
	edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot);
 | 
						|
	edma_channel.slot = edma_slot_num;
 | 
						|
	edma_channel.chnum = 0;
 | 
						|
	edma_channel.complete_code = 0;
 | 
						|
	 /* set event trigger to dst update */
 | 
						|
	edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
 | 
						|
 | 
						|
	qedma3_start(edma3_base_addr, &edma_channel);
 | 
						|
	edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr);
 | 
						|
 | 
						|
	while (edma3_check_for_transfer(edma3_base_addr, &edma_channel))
 | 
						|
		;
 | 
						|
	qedma3_stop(edma3_base_addr, &edma_channel);
 | 
						|
 | 
						|
	if (rem_bytes != 0) {
 | 
						|
		slot.opt        = 0;
 | 
						|
		slot.src        =
 | 
						|
			(b_cnt_value * max_acnt) + ((unsigned int) src);
 | 
						|
		slot.acnt       = rem_bytes;
 | 
						|
		slot.bcnt       = 1;
 | 
						|
		slot.ccnt       = 1;
 | 
						|
		slot.src_bidx   = rem_bytes;
 | 
						|
		slot.dst_bidx   = rem_bytes;
 | 
						|
		slot.src_cidx   = 0;
 | 
						|
		slot.dst_cidx   = 0;
 | 
						|
		slot.link       = EDMA3_PARSET_NULL_LINK;
 | 
						|
		slot.bcntrld    = 0;
 | 
						|
		slot.opt        = EDMA3_SLOPT_TRANS_COMP_INT_ENB |
 | 
						|
				  EDMA3_SLOPT_COMP_CODE(0) |
 | 
						|
				  EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC;
 | 
						|
		edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot);
 | 
						|
		edma_channel.slot = edma_slot_num;
 | 
						|
		edma_channel.chnum = 0;
 | 
						|
		edma_channel.complete_code = 0;
 | 
						|
		/* set event trigger to dst update */
 | 
						|
		edma_channel.trigger_slot_word = EDMA3_TWORD(dst);
 | 
						|
 | 
						|
		qedma3_start(edma3_base_addr, &edma_channel);
 | 
						|
		edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr +
 | 
						|
				    (max_acnt * b_cnt_value));
 | 
						|
		while (edma3_check_for_transfer(edma3_base_addr, &edma_channel))
 | 
						|
			;
 | 
						|
		qedma3_stop(edma3_base_addr, &edma_channel);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#ifndef CONFIG_DMA
 | 
						|
 | 
						|
void edma3_transfer(unsigned long edma3_base_addr, unsigned int edma_slot_num,
 | 
						|
		    void *dst, void *src, size_t len)
 | 
						|
{
 | 
						|
	__edma3_transfer(edma3_base_addr, edma_slot_num, dst, src, len);
 | 
						|
}
 | 
						|
 | 
						|
#else
 | 
						|
 | 
						|
static int ti_edma3_transfer(struct udevice *dev, int direction, void *dst,
 | 
						|
			     void *src, size_t len)
 | 
						|
{
 | 
						|
	struct ti_edma3_priv *priv = dev_get_priv(dev);
 | 
						|
 | 
						|
	/* enable edma3 clocks */
 | 
						|
	enable_edma3_clocks();
 | 
						|
 | 
						|
	switch (direction) {
 | 
						|
	case DMA_MEM_TO_MEM:
 | 
						|
		__edma3_transfer(priv->base, 1, dst, src, len);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		error("Transfer type not implemented in DMA driver\n");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* disable edma3 clocks */
 | 
						|
	disable_edma3_clocks();
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int ti_edma3_ofdata_to_platdata(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct ti_edma3_priv *priv = dev_get_priv(dev);
 | 
						|
 | 
						|
	priv->base = dev_get_addr(dev);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int ti_edma3_probe(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 | 
						|
 | 
						|
	uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct dma_ops ti_edma3_ops = {
 | 
						|
	.transfer	= ti_edma3_transfer,
 | 
						|
};
 | 
						|
 | 
						|
static const struct udevice_id ti_edma3_ids[] = {
 | 
						|
	{ .compatible = "ti,edma3" },
 | 
						|
	{ }
 | 
						|
};
 | 
						|
 | 
						|
U_BOOT_DRIVER(ti_edma3) = {
 | 
						|
	.name	= "ti_edma3",
 | 
						|
	.id	= UCLASS_DMA,
 | 
						|
	.of_match = ti_edma3_ids,
 | 
						|
	.ops	= &ti_edma3_ops,
 | 
						|
	.ofdata_to_platdata = ti_edma3_ofdata_to_platdata,
 | 
						|
	.probe	= ti_edma3_probe,
 | 
						|
	.priv_auto_alloc_size = sizeof(struct ti_edma3_priv),
 | 
						|
};
 | 
						|
#endif /* CONFIG_DMA */
 |