summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/Makefile2
-rw-r--r--drivers/dma/keystone_nav.c332
-rw-r--r--drivers/dma/keystone_nav_cfg.c27
-rw-r--r--drivers/dma/ti-edma3.c384
4 files changed, 745 insertions, 0 deletions
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a79c391..4c8fcc2 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -8,3 +8,5 @@
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_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
+obj-$(CONFIG_TI_EDMA3) += ti-edma3.o
diff --git a/drivers/dma/keystone_nav.c b/drivers/dma/keystone_nav.c
new file mode 100644
index 0000000..77707c2
--- /dev/null
+++ b/drivers/dma/keystone_nav.c
@@ -0,0 +1,332 @@
+/*
+ * Multicore Navigator driver for TI Keystone 2 devices.
+ *
+ * (C) Copyright 2012-2014
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/ti-common/keystone_nav.h>
+
+struct qm_config qm_memmap = {
+ .stat_cfg = CONFIG_KSNAV_QM_QUEUE_STATUS_BASE,
+ .queue = (void *)CONFIG_KSNAV_QM_MANAGER_QUEUES_BASE,
+ .mngr_vbusm = CONFIG_KSNAV_QM_BASE_ADDRESS,
+ .i_lram = CONFIG_KSNAV_QM_LINK_RAM_BASE,
+ .proxy = (void *)CONFIG_KSNAV_QM_MANAGER_Q_PROXY_BASE,
+ .status_ram = CONFIG_KSNAV_QM_STATUS_RAM_BASE,
+ .mngr_cfg = (void *)CONFIG_KSNAV_QM_CONF_BASE,
+ .intd_cfg = CONFIG_KSNAV_QM_INTD_CONF_BASE,
+ .desc_mem = (void *)CONFIG_KSNAV_QM_DESC_SETUP_BASE,
+ .region_num = CONFIG_KSNAV_QM_REGION_NUM,
+ .pdsp_cmd = CONFIG_KSNAV_QM_PDSP1_CMD_BASE,
+ .pdsp_ctl = CONFIG_KSNAV_QM_PDSP1_CTRL_BASE,
+ .pdsp_iram = CONFIG_KSNAV_QM_PDSP1_IRAM_BASE,
+ .qpool_num = CONFIG_KSNAV_QM_QPOOL_NUM,
+};
+
+/*
+ * We are going to use only one type of descriptors - host packet
+ * descriptors. We staticaly allocate memory for them here
+ */
+struct qm_host_desc desc_pool[HDESC_NUM] __aligned(sizeof(struct qm_host_desc));
+
+static struct qm_config *qm_cfg;
+
+inline int num_of_desc_to_reg(int num_descr)
+{
+ int j, num;
+
+ for (j = 0, num = 32; j < 15; j++, num *= 2) {
+ if (num_descr <= num)
+ return j;
+ }
+
+ return 15;
+}
+
+int _qm_init(struct qm_config *cfg)
+{
+ u32 j;
+
+ qm_cfg = cfg;
+
+ qm_cfg->mngr_cfg->link_ram_base0 = qm_cfg->i_lram;
+ qm_cfg->mngr_cfg->link_ram_size0 = HDESC_NUM * 8;
+ qm_cfg->mngr_cfg->link_ram_base1 = 0;
+ qm_cfg->mngr_cfg->link_ram_size1 = 0;
+ qm_cfg->mngr_cfg->link_ram_base2 = 0;
+
+ qm_cfg->desc_mem[0].base_addr = (u32)desc_pool;
+ qm_cfg->desc_mem[0].start_idx = 0;
+ qm_cfg->desc_mem[0].desc_reg_size =
+ (((sizeof(struct qm_host_desc) >> 4) - 1) << 16) |
+ num_of_desc_to_reg(HDESC_NUM);
+
+ memset(desc_pool, 0, sizeof(desc_pool));
+ for (j = 0; j < HDESC_NUM; j++)
+ qm_push(&desc_pool[j], qm_cfg->qpool_num);
+
+ return QM_OK;
+}
+
+int qm_init(void)
+{
+ return _qm_init(&qm_memmap);
+}
+
+void qm_close(void)
+{
+ u32 j;
+
+ if (qm_cfg == NULL)
+ return;
+
+ queue_close(qm_cfg->qpool_num);
+
+ qm_cfg->mngr_cfg->link_ram_base0 = 0;
+ qm_cfg->mngr_cfg->link_ram_size0 = 0;
+ qm_cfg->mngr_cfg->link_ram_base1 = 0;
+ qm_cfg->mngr_cfg->link_ram_size1 = 0;
+ qm_cfg->mngr_cfg->link_ram_base2 = 0;
+
+ for (j = 0; j < qm_cfg->region_num; j++) {
+ qm_cfg->desc_mem[j].base_addr = 0;
+ qm_cfg->desc_mem[j].start_idx = 0;
+ qm_cfg->desc_mem[j].desc_reg_size = 0;
+ }
+
+ qm_cfg = NULL;
+}
+
+void qm_push(struct qm_host_desc *hd, u32 qnum)
+{
+ u32 regd;
+
+ if (!qm_cfg)
+ return;
+
+ cpu_to_bus((u32 *)hd, sizeof(struct qm_host_desc)/4);
+ regd = (u32)hd | ((sizeof(struct qm_host_desc) >> 4) - 1);
+ writel(regd, &qm_cfg->queue[qnum].ptr_size_thresh);
+}
+
+void qm_buff_push(struct qm_host_desc *hd, u32 qnum,
+ void *buff_ptr, u32 buff_len)
+{
+ hd->orig_buff_len = buff_len;
+ hd->buff_len = buff_len;
+ hd->orig_buff_ptr = (u32)buff_ptr;
+ hd->buff_ptr = (u32)buff_ptr;
+ qm_push(hd, qnum);
+}
+
+struct qm_host_desc *qm_pop(u32 qnum)
+{
+ u32 uhd;
+
+ if (!qm_cfg)
+ return NULL;
+
+ uhd = readl(&qm_cfg->queue[qnum].ptr_size_thresh) & ~0xf;
+ if (uhd)
+ cpu_to_bus((u32 *)uhd, sizeof(struct qm_host_desc)/4);
+
+ return (struct qm_host_desc *)uhd;
+}
+
+struct qm_host_desc *qm_pop_from_free_pool(void)
+{
+ if (!qm_cfg)
+ return NULL;
+
+ return qm_pop(qm_cfg->qpool_num);
+}
+
+void queue_close(u32 qnum)
+{
+ struct qm_host_desc *hd;
+
+ while ((hd = qm_pop(qnum)))
+ ;
+}
+
+/**
+ * DMA API
+ */
+
+static int ksnav_rx_disable(struct pktdma_cfg *pktdma)
+{
+ u32 j, v, k;
+
+ for (j = 0; j < pktdma->rx_ch_num; j++) {
+ v = readl(&pktdma->rx_ch[j].cfg_a);
+ if (!(v & CPDMA_CHAN_A_ENABLE))
+ continue;
+
+ writel(v | CPDMA_CHAN_A_TDOWN, &pktdma->rx_ch[j].cfg_a);
+ for (k = 0; k < TDOWN_TIMEOUT_COUNT; k++) {
+ udelay(100);
+ v = readl(&pktdma->rx_ch[j].cfg_a);
+ if (!(v & CPDMA_CHAN_A_ENABLE))
+ continue;
+ }
+ /* TODO: teardown error on if TDOWN_TIMEOUT_COUNT is reached */
+ }
+
+ /* Clear all of the flow registers */
+ for (j = 0; j < pktdma->rx_flow_num; j++) {
+ writel(0, &pktdma->rx_flows[j].control);
+ writel(0, &pktdma->rx_flows[j].tags);
+ writel(0, &pktdma->rx_flows[j].tag_sel);
+ writel(0, &pktdma->rx_flows[j].fdq_sel[0]);
+ writel(0, &pktdma->rx_flows[j].fdq_sel[1]);
+ writel(0, &pktdma->rx_flows[j].thresh[0]);
+ writel(0, &pktdma->rx_flows[j].thresh[1]);
+ writel(0, &pktdma->rx_flows[j].thresh[2]);
+ }
+
+ return QM_OK;
+}
+
+static int ksnav_tx_disable(struct pktdma_cfg *pktdma)
+{
+ u32 j, v, k;
+
+ for (j = 0; j < pktdma->tx_ch_num; j++) {
+ v = readl(&pktdma->tx_ch[j].cfg_a);
+ if (!(v & CPDMA_CHAN_A_ENABLE))
+ continue;
+
+ writel(v | CPDMA_CHAN_A_TDOWN, &pktdma->tx_ch[j].cfg_a);
+ for (k = 0; k < TDOWN_TIMEOUT_COUNT; k++) {
+ udelay(100);
+ v = readl(&pktdma->tx_ch[j].cfg_a);
+ if (!(v & CPDMA_CHAN_A_ENABLE))
+ continue;
+ }
+ /* TODO: teardown error on if TDOWN_TIMEOUT_COUNT is reached */
+ }
+
+ return QM_OK;
+}
+
+int ksnav_init(struct pktdma_cfg *pktdma, struct rx_buff_desc *rx_buffers)
+{
+ u32 j, v;
+ struct qm_host_desc *hd;
+ u8 *rx_ptr;
+
+ if (pktdma == NULL || rx_buffers == NULL ||
+ rx_buffers->buff_ptr == NULL || qm_cfg == NULL)
+ return QM_ERR;
+
+ pktdma->rx_flow = rx_buffers->rx_flow;
+
+ /* init rx queue */
+ rx_ptr = rx_buffers->buff_ptr;
+
+ for (j = 0; j < rx_buffers->num_buffs; j++) {
+ hd = qm_pop(qm_cfg->qpool_num);
+ if (hd == NULL)
+ return QM_ERR;
+
+ qm_buff_push(hd, pktdma->rx_free_q,
+ rx_ptr, rx_buffers->buff_len);
+
+ rx_ptr += rx_buffers->buff_len;
+ }
+
+ ksnav_rx_disable(pktdma);
+
+ /* configure rx channels */
+ v = CPDMA_REG_VAL_MAKE_RX_FLOW_A(1, 1, 0, 0, 0, 0, 0, pktdma->rx_rcv_q);
+ writel(v, &pktdma->rx_flows[pktdma->rx_flow].control);
+ writel(0, &pktdma->rx_flows[pktdma->rx_flow].tags);
+ writel(0, &pktdma->rx_flows[pktdma->rx_flow].tag_sel);
+
+ v = CPDMA_REG_VAL_MAKE_RX_FLOW_D(0, pktdma->rx_free_q, 0,
+ pktdma->rx_free_q);
+
+ writel(v, &pktdma->rx_flows[pktdma->rx_flow].fdq_sel[0]);
+ writel(v, &pktdma->rx_flows[pktdma->rx_flow].fdq_sel[1]);
+ writel(0, &pktdma->rx_flows[pktdma->rx_flow].thresh[0]);
+ writel(0, &pktdma->rx_flows[pktdma->rx_flow].thresh[1]);
+ writel(0, &pktdma->rx_flows[pktdma->rx_flow].thresh[2]);
+
+ for (j = 0; j < pktdma->rx_ch_num; j++)
+ writel(CPDMA_CHAN_A_ENABLE, &pktdma->rx_ch[j].cfg_a);
+
+ /* configure tx channels */
+ /* Disable loopback in the tx direction */
+ writel(0, &pktdma->global->emulation_control);
+
+ /* Set QM base address, only for K2x devices */
+ writel(CONFIG_KSNAV_QM_BASE_ADDRESS, &pktdma->global->qm_base_addr[0]);
+
+ /* Enable all channels. The current state isn't important */
+ for (j = 0; j < pktdma->tx_ch_num; j++) {
+ writel(0, &pktdma->tx_ch[j].cfg_b);
+ writel(CPDMA_CHAN_A_ENABLE, &pktdma->tx_ch[j].cfg_a);
+ }
+
+ return QM_OK;
+}
+
+int ksnav_close(struct pktdma_cfg *pktdma)
+{
+ if (!pktdma)
+ return QM_ERR;
+
+ ksnav_tx_disable(pktdma);
+ ksnav_rx_disable(pktdma);
+
+ queue_close(pktdma->rx_free_q);
+ queue_close(pktdma->rx_rcv_q);
+ queue_close(pktdma->tx_snd_q);
+
+ return QM_OK;
+}
+
+int ksnav_send(struct pktdma_cfg *pktdma, u32 *pkt, int num_bytes, u32 swinfo2)
+{
+ struct qm_host_desc *hd;
+
+ hd = qm_pop(qm_cfg->qpool_num);
+ if (hd == NULL)
+ return QM_ERR;
+
+ hd->desc_info = num_bytes;
+ hd->swinfo[2] = swinfo2;
+ hd->packet_info = qm_cfg->qpool_num;
+
+ qm_buff_push(hd, pktdma->tx_snd_q, pkt, num_bytes);
+
+ return QM_OK;
+}
+
+void *ksnav_recv(struct pktdma_cfg *pktdma, u32 **pkt, int *num_bytes)
+{
+ struct qm_host_desc *hd;
+
+ hd = qm_pop(pktdma->rx_rcv_q);
+ if (!hd)
+ return NULL;
+
+ *pkt = (u32 *)hd->buff_ptr;
+ *num_bytes = hd->desc_info & 0x3fffff;
+
+ return hd;
+}
+
+void ksnav_release_rxhd(struct pktdma_cfg *pktdma, void *hd)
+{
+ struct qm_host_desc *_hd = (struct qm_host_desc *)hd;
+
+ _hd->buff_len = _hd->orig_buff_len;
+ _hd->buff_ptr = _hd->orig_buff_ptr;
+
+ qm_push(_hd, pktdma->rx_free_q);
+}
diff --git a/drivers/dma/keystone_nav_cfg.c b/drivers/dma/keystone_nav_cfg.c
new file mode 100644
index 0000000..bdd30a0
--- /dev/null
+++ b/drivers/dma/keystone_nav_cfg.c
@@ -0,0 +1,27 @@
+/*
+ * Multicore Navigator driver for TI Keystone 2 devices.
+ *
+ * (C) Copyright 2012-2014
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <asm/ti-common/keystone_nav.h>
+
+#ifdef CONFIG_KSNAV_PKTDMA_NETCP
+/* NETCP Pktdma */
+struct pktdma_cfg netcp_pktdma = {
+ .global = (void *)CONFIG_KSNAV_NETCP_PDMA_CTRL_BASE,
+ .tx_ch = (void *)CONFIG_KSNAV_NETCP_PDMA_TX_BASE,
+ .tx_ch_num = CONFIG_KSNAV_NETCP_PDMA_TX_CH_NUM,
+ .rx_ch = (void *)CONFIG_KSNAV_NETCP_PDMA_RX_BASE,
+ .rx_ch_num = CONFIG_KSNAV_NETCP_PDMA_RX_CH_NUM,
+ .tx_sched = (u32 *)CONFIG_KSNAV_NETCP_PDMA_SCHED_BASE,
+ .rx_flows = (void *)CONFIG_KSNAV_NETCP_PDMA_RX_FLOW_BASE,
+ .rx_flow_num = CONFIG_KSNAV_NETCP_PDMA_RX_FLOW_NUM,
+ .rx_free_q = CONFIG_KSNAV_NETCP_PDMA_RX_FREE_QUEUE,
+ .rx_rcv_q = CONFIG_KSNAV_NETCP_PDMA_RX_RCV_QUEUE,
+ .tx_snd_q = CONFIG_KSNAV_NETCP_PDMA_TX_SND_QUEUE,
+};
+#endif
diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c
new file mode 100644
index 0000000..8184ded
--- /dev/null
+++ b/drivers/dma/ti-edma3.c
@@ -0,0 +1,384 @@
+/*
+ * 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 <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
+
+/**
+ * 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));
+}