1e165b1d3SKhoronzhuk, Ivan /* 2e165b1d3SKhoronzhuk, Ivan * Enhanced Direct Memory Access (EDMA3) Controller 3e165b1d3SKhoronzhuk, Ivan * 4e165b1d3SKhoronzhuk, Ivan * (C) Copyright 2014 5e165b1d3SKhoronzhuk, Ivan * Texas Instruments Incorporated, <www.ti.com> 6e165b1d3SKhoronzhuk, Ivan * 7e165b1d3SKhoronzhuk, Ivan * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> 8e165b1d3SKhoronzhuk, Ivan * 9e165b1d3SKhoronzhuk, Ivan * SPDX-License-Identifier: GPL-2.0+ 10e165b1d3SKhoronzhuk, Ivan */ 11e165b1d3SKhoronzhuk, Ivan 12e165b1d3SKhoronzhuk, Ivan #include <asm/io.h> 13e165b1d3SKhoronzhuk, Ivan #include <common.h> 14e165b1d3SKhoronzhuk, Ivan #include <asm/ti-common/ti-edma3.h> 15e165b1d3SKhoronzhuk, Ivan 16e165b1d3SKhoronzhuk, Ivan #define EDMA3_SL_BASE(slot) (0x4000 + ((slot) << 5)) 17e165b1d3SKhoronzhuk, Ivan #define EDMA3_SL_MAX_NUM 512 18e165b1d3SKhoronzhuk, Ivan #define EDMA3_SLOPT_FIFO_WIDTH_MASK (0x7 << 8) 19e165b1d3SKhoronzhuk, Ivan 20e165b1d3SKhoronzhuk, Ivan #define EDMA3_QCHMAP(ch) 0x0200 + ((ch) << 2) 21e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_PARSET_MASK 0x1ff 22e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_PARSET_SHIFT 0x5 23e165b1d3SKhoronzhuk, Ivan #define EDMA3_CHMAP_TRIGWORD_SHIFT 0x2 24e165b1d3SKhoronzhuk, Ivan 25e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEMCR 0x314 26e165b1d3SKhoronzhuk, Ivan #define EDMA3_IPR 0x1068 27e165b1d3SKhoronzhuk, Ivan #define EDMA3_IPRH 0x106c 28e165b1d3SKhoronzhuk, Ivan #define EDMA3_ICR 0x1070 29e165b1d3SKhoronzhuk, Ivan #define EDMA3_ICRH 0x1074 30e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEECR 0x1088 31e165b1d3SKhoronzhuk, Ivan #define EDMA3_QEESR 0x108c 32e165b1d3SKhoronzhuk, Ivan #define EDMA3_QSECR 0x1094 33e165b1d3SKhoronzhuk, Ivan 34e165b1d3SKhoronzhuk, Ivan /** 35e165b1d3SKhoronzhuk, Ivan * qedma3_start - start qdma on a channel 36e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 37e165b1d3SKhoronzhuk, Ivan * @cfg: pinter to struct edma3_channel_config where you can set 38e165b1d3SKhoronzhuk, Ivan * the slot number to associate with, the chnum, which corresponds 39e165b1d3SKhoronzhuk, Ivan * your quick channel number 0-7, complete code - transfer complete code 40e165b1d3SKhoronzhuk, Ivan * and trigger slot word - which has to correspond to the word number in 41e165b1d3SKhoronzhuk, Ivan * edma3_slot_layout struct for generating event. 42e165b1d3SKhoronzhuk, Ivan * 43e165b1d3SKhoronzhuk, Ivan */ 44e165b1d3SKhoronzhuk, Ivan void qedma3_start(u32 base, struct edma3_channel_config *cfg) 45e165b1d3SKhoronzhuk, Ivan { 46e165b1d3SKhoronzhuk, Ivan u32 qchmap; 47e165b1d3SKhoronzhuk, Ivan 48e165b1d3SKhoronzhuk, Ivan /* Clear the pending int bit */ 49e165b1d3SKhoronzhuk, Ivan if (cfg->complete_code < 32) 50e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->complete_code, base + EDMA3_ICR); 51e165b1d3SKhoronzhuk, Ivan else 52e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH); 53e165b1d3SKhoronzhuk, Ivan 54e165b1d3SKhoronzhuk, Ivan /* Map parameter set and trigger word 7 to quick channel */ 55e165b1d3SKhoronzhuk, Ivan qchmap = ((EDMA3_CHMAP_PARSET_MASK & cfg->slot) 56e165b1d3SKhoronzhuk, Ivan << EDMA3_CHMAP_PARSET_SHIFT) | 57e165b1d3SKhoronzhuk, Ivan (cfg->trigger_slot_word << EDMA3_CHMAP_TRIGWORD_SHIFT); 58e165b1d3SKhoronzhuk, Ivan 59e165b1d3SKhoronzhuk, Ivan __raw_writel(qchmap, base + EDMA3_QCHMAP(cfg->chnum)); 60e165b1d3SKhoronzhuk, Ivan 61e165b1d3SKhoronzhuk, Ivan /* Clear missed event if set*/ 62e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->chnum, base + EDMA3_QSECR); 63e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR); 64e165b1d3SKhoronzhuk, Ivan 65e165b1d3SKhoronzhuk, Ivan /* Enable qdma channel event */ 66e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->chnum, base + EDMA3_QEESR); 67e165b1d3SKhoronzhuk, Ivan } 68e165b1d3SKhoronzhuk, Ivan 69e165b1d3SKhoronzhuk, Ivan /** 70e165b1d3SKhoronzhuk, Ivan * edma3_set_dest - set initial DMA destination address in parameter RAM slot 71e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 72e165b1d3SKhoronzhuk, Ivan * @slot: parameter RAM slot being configured 73e165b1d3SKhoronzhuk, Ivan * @dst: physical address of destination (memory, controller FIFO, etc) 74e165b1d3SKhoronzhuk, Ivan * @addressMode: INCR, except in very rare cases 75e165b1d3SKhoronzhuk, Ivan * @width: ignored unless @addressMode is FIFO, else specifies the 76e165b1d3SKhoronzhuk, Ivan * width to use when addressing the fifo (e.g. W8BIT, W32BIT) 77e165b1d3SKhoronzhuk, Ivan * 78e165b1d3SKhoronzhuk, Ivan * Note that the destination address is modified during the DMA transfer 79e165b1d3SKhoronzhuk, Ivan * according to edma3_set_dest_index(). 80e165b1d3SKhoronzhuk, Ivan */ 81e165b1d3SKhoronzhuk, Ivan void edma3_set_dest(u32 base, int slot, u32 dst, enum edma3_address_mode mode, 82e165b1d3SKhoronzhuk, Ivan enum edma3_fifo_width width) 83e165b1d3SKhoronzhuk, Ivan { 84e165b1d3SKhoronzhuk, Ivan u32 opt; 85e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 86e165b1d3SKhoronzhuk, Ivan 87e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 88e165b1d3SKhoronzhuk, Ivan 89e165b1d3SKhoronzhuk, Ivan opt = __raw_readl(&rg->opt); 90e165b1d3SKhoronzhuk, Ivan if (mode == FIFO) 91e165b1d3SKhoronzhuk, Ivan opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) | 92e165b1d3SKhoronzhuk, Ivan (EDMA3_SLOPT_DST_ADDR_CONST_MODE | 93e165b1d3SKhoronzhuk, Ivan EDMA3_SLOPT_FIFO_WIDTH_SET(width)); 94e165b1d3SKhoronzhuk, Ivan else 95e165b1d3SKhoronzhuk, Ivan opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE; 96e165b1d3SKhoronzhuk, Ivan 97e165b1d3SKhoronzhuk, Ivan __raw_writel(opt, &rg->opt); 98e165b1d3SKhoronzhuk, Ivan __raw_writel(dst, &rg->dst); 99e165b1d3SKhoronzhuk, Ivan } 100e165b1d3SKhoronzhuk, Ivan 101e165b1d3SKhoronzhuk, Ivan /** 102e165b1d3SKhoronzhuk, Ivan * edma3_set_dest_index - configure DMA destination address indexing 103e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 104e165b1d3SKhoronzhuk, Ivan * @slot: parameter RAM slot being configured 105e165b1d3SKhoronzhuk, Ivan * @bidx: byte offset between destination arrays in a frame 106e165b1d3SKhoronzhuk, Ivan * @cidx: byte offset between destination frames in a block 107e165b1d3SKhoronzhuk, Ivan * 108e165b1d3SKhoronzhuk, Ivan * Offsets are specified to support either contiguous or discontiguous 109e165b1d3SKhoronzhuk, Ivan * memory transfers, or repeated access to a hardware register, as needed. 110e165b1d3SKhoronzhuk, Ivan * When accessing hardware registers, both offsets are normally zero. 111e165b1d3SKhoronzhuk, Ivan */ 112e165b1d3SKhoronzhuk, Ivan void edma3_set_dest_index(u32 base, unsigned slot, int bidx, int cidx) 113e165b1d3SKhoronzhuk, Ivan { 114e165b1d3SKhoronzhuk, Ivan u32 src_dst_bidx; 115e165b1d3SKhoronzhuk, Ivan u32 src_dst_cidx; 116e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 117e165b1d3SKhoronzhuk, Ivan 118e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 119e165b1d3SKhoronzhuk, Ivan 120e165b1d3SKhoronzhuk, Ivan src_dst_bidx = __raw_readl(&rg->src_dst_bidx); 121e165b1d3SKhoronzhuk, Ivan src_dst_cidx = __raw_readl(&rg->src_dst_cidx); 122e165b1d3SKhoronzhuk, Ivan 123e165b1d3SKhoronzhuk, Ivan __raw_writel((src_dst_bidx & 0x0000ffff) | (bidx << 16), 124e165b1d3SKhoronzhuk, Ivan &rg->src_dst_bidx); 125e165b1d3SKhoronzhuk, Ivan __raw_writel((src_dst_cidx & 0x0000ffff) | (cidx << 16), 126e165b1d3SKhoronzhuk, Ivan &rg->src_dst_cidx); 127e165b1d3SKhoronzhuk, Ivan } 128e165b1d3SKhoronzhuk, Ivan 129e165b1d3SKhoronzhuk, Ivan /** 130e165b1d3SKhoronzhuk, Ivan * edma3_set_dest_addr - set destination address for slot only 131e165b1d3SKhoronzhuk, Ivan */ 132e165b1d3SKhoronzhuk, Ivan void edma3_set_dest_addr(u32 base, int slot, u32 dst) 133e165b1d3SKhoronzhuk, Ivan { 134e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 135e165b1d3SKhoronzhuk, Ivan 136e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 137e165b1d3SKhoronzhuk, Ivan __raw_writel(dst, &rg->dst); 138e165b1d3SKhoronzhuk, Ivan } 139e165b1d3SKhoronzhuk, Ivan 140e165b1d3SKhoronzhuk, Ivan /** 141e165b1d3SKhoronzhuk, Ivan * edma3_set_src - set initial DMA source address in parameter RAM slot 142e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 143e165b1d3SKhoronzhuk, Ivan * @slot: parameter RAM slot being configured 144e165b1d3SKhoronzhuk, Ivan * @src_port: physical address of source (memory, controller FIFO, etc) 145e165b1d3SKhoronzhuk, Ivan * @mode: INCR, except in very rare cases 146e165b1d3SKhoronzhuk, Ivan * @width: ignored unless @addressMode is FIFO, else specifies the 147e165b1d3SKhoronzhuk, Ivan * width to use when addressing the fifo (e.g. W8BIT, W32BIT) 148e165b1d3SKhoronzhuk, Ivan * 149e165b1d3SKhoronzhuk, Ivan * Note that the source address is modified during the DMA transfer 150e165b1d3SKhoronzhuk, Ivan * according to edma3_set_src_index(). 151e165b1d3SKhoronzhuk, Ivan */ 152e165b1d3SKhoronzhuk, Ivan void edma3_set_src(u32 base, int slot, u32 src, enum edma3_address_mode mode, 153e165b1d3SKhoronzhuk, Ivan enum edma3_fifo_width width) 154e165b1d3SKhoronzhuk, Ivan { 155e165b1d3SKhoronzhuk, Ivan u32 opt; 156e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 157e165b1d3SKhoronzhuk, Ivan 158e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 159e165b1d3SKhoronzhuk, Ivan 160e165b1d3SKhoronzhuk, Ivan opt = __raw_readl(&rg->opt); 161e165b1d3SKhoronzhuk, Ivan if (mode == FIFO) 162e165b1d3SKhoronzhuk, Ivan opt = (opt & EDMA3_SLOPT_FIFO_WIDTH_MASK) | 163e165b1d3SKhoronzhuk, Ivan (EDMA3_SLOPT_DST_ADDR_CONST_MODE | 164e165b1d3SKhoronzhuk, Ivan EDMA3_SLOPT_FIFO_WIDTH_SET(width)); 165e165b1d3SKhoronzhuk, Ivan else 166e165b1d3SKhoronzhuk, Ivan opt &= ~EDMA3_SLOPT_DST_ADDR_CONST_MODE; 167e165b1d3SKhoronzhuk, Ivan 168e165b1d3SKhoronzhuk, Ivan __raw_writel(opt, &rg->opt); 169e165b1d3SKhoronzhuk, Ivan __raw_writel(src, &rg->src); 170e165b1d3SKhoronzhuk, Ivan } 171e165b1d3SKhoronzhuk, Ivan 172e165b1d3SKhoronzhuk, Ivan /** 173e165b1d3SKhoronzhuk, Ivan * edma3_set_src_index - configure DMA source address indexing 174e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 175e165b1d3SKhoronzhuk, Ivan * @slot: parameter RAM slot being configured 176e165b1d3SKhoronzhuk, Ivan * @bidx: byte offset between source arrays in a frame 177e165b1d3SKhoronzhuk, Ivan * @cidx: byte offset between source frames in a block 178e165b1d3SKhoronzhuk, Ivan * 179e165b1d3SKhoronzhuk, Ivan * Offsets are specified to support either contiguous or discontiguous 180e165b1d3SKhoronzhuk, Ivan * memory transfers, or repeated access to a hardware register, as needed. 181e165b1d3SKhoronzhuk, Ivan * When accessing hardware registers, both offsets are normally zero. 182e165b1d3SKhoronzhuk, Ivan */ 183e165b1d3SKhoronzhuk, Ivan void edma3_set_src_index(u32 base, unsigned slot, int bidx, int cidx) 184e165b1d3SKhoronzhuk, Ivan { 185e165b1d3SKhoronzhuk, Ivan u32 src_dst_bidx; 186e165b1d3SKhoronzhuk, Ivan u32 src_dst_cidx; 187e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 188e165b1d3SKhoronzhuk, Ivan 189e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 190e165b1d3SKhoronzhuk, Ivan 191e165b1d3SKhoronzhuk, Ivan src_dst_bidx = __raw_readl(&rg->src_dst_bidx); 192e165b1d3SKhoronzhuk, Ivan src_dst_cidx = __raw_readl(&rg->src_dst_cidx); 193e165b1d3SKhoronzhuk, Ivan 194e165b1d3SKhoronzhuk, Ivan __raw_writel((src_dst_bidx & 0xffff0000) | bidx, 195e165b1d3SKhoronzhuk, Ivan &rg->src_dst_bidx); 196e165b1d3SKhoronzhuk, Ivan __raw_writel((src_dst_cidx & 0xffff0000) | cidx, 197e165b1d3SKhoronzhuk, Ivan &rg->src_dst_cidx); 198e165b1d3SKhoronzhuk, Ivan } 199e165b1d3SKhoronzhuk, Ivan 200e165b1d3SKhoronzhuk, Ivan /** 201e165b1d3SKhoronzhuk, Ivan * edma3_set_src_addr - set source address for slot only 202e165b1d3SKhoronzhuk, Ivan */ 203e165b1d3SKhoronzhuk, Ivan void edma3_set_src_addr(u32 base, int slot, u32 src) 204e165b1d3SKhoronzhuk, Ivan { 205e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 206e165b1d3SKhoronzhuk, Ivan 207e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 208e165b1d3SKhoronzhuk, Ivan __raw_writel(src, &rg->src); 209e165b1d3SKhoronzhuk, Ivan } 210e165b1d3SKhoronzhuk, Ivan 211e165b1d3SKhoronzhuk, Ivan /** 212e165b1d3SKhoronzhuk, Ivan * edma3_set_transfer_params - configure DMA transfer parameters 213e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 214e165b1d3SKhoronzhuk, Ivan * @slot: parameter RAM slot being configured 215e165b1d3SKhoronzhuk, Ivan * @acnt: how many bytes per array (at least one) 216e165b1d3SKhoronzhuk, Ivan * @bcnt: how many arrays per frame (at least one) 217e165b1d3SKhoronzhuk, Ivan * @ccnt: how many frames per block (at least one) 218e165b1d3SKhoronzhuk, Ivan * @bcnt_rld: used only for A-Synchronized transfers; this specifies 219e165b1d3SKhoronzhuk, Ivan * the value to reload into bcnt when it decrements to zero 220e165b1d3SKhoronzhuk, Ivan * @sync_mode: ASYNC or ABSYNC 221e165b1d3SKhoronzhuk, Ivan * 222e165b1d3SKhoronzhuk, Ivan * See the EDMA3 documentation to understand how to configure and link 223e165b1d3SKhoronzhuk, Ivan * transfers using the fields in PaRAM slots. If you are not doing it 224e165b1d3SKhoronzhuk, Ivan * all at once with edma3_write_slot(), you will use this routine 225e165b1d3SKhoronzhuk, Ivan * plus two calls each for source and destination, setting the initial 226e165b1d3SKhoronzhuk, Ivan * address and saying how to index that address. 227e165b1d3SKhoronzhuk, Ivan * 228e165b1d3SKhoronzhuk, Ivan * An example of an A-Synchronized transfer is a serial link using a 229e165b1d3SKhoronzhuk, Ivan * single word shift register. In that case, @acnt would be equal to 230e165b1d3SKhoronzhuk, Ivan * that word size; the serial controller issues a DMA synchronization 231e165b1d3SKhoronzhuk, Ivan * event to transfer each word, and memory access by the DMA transfer 232e165b1d3SKhoronzhuk, Ivan * controller will be word-at-a-time. 233e165b1d3SKhoronzhuk, Ivan * 234e165b1d3SKhoronzhuk, Ivan * An example of an AB-Synchronized transfer is a device using a FIFO. 235e165b1d3SKhoronzhuk, Ivan * In that case, @acnt equals the FIFO width and @bcnt equals its depth. 236e165b1d3SKhoronzhuk, Ivan * The controller with the FIFO issues DMA synchronization events when 237e165b1d3SKhoronzhuk, Ivan * the FIFO threshold is reached, and the DMA transfer controller will 238e165b1d3SKhoronzhuk, Ivan * transfer one frame to (or from) the FIFO. It will probably use 239e165b1d3SKhoronzhuk, Ivan * efficient burst modes to access memory. 240e165b1d3SKhoronzhuk, Ivan */ 241e165b1d3SKhoronzhuk, Ivan void edma3_set_transfer_params(u32 base, int slot, int acnt, 242e165b1d3SKhoronzhuk, Ivan int bcnt, int ccnt, u16 bcnt_rld, 243e165b1d3SKhoronzhuk, Ivan enum edma3_sync_dimension sync_mode) 244e165b1d3SKhoronzhuk, Ivan { 245e165b1d3SKhoronzhuk, Ivan u32 opt; 246e165b1d3SKhoronzhuk, Ivan u32 link_bcntrld; 247e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 248e165b1d3SKhoronzhuk, Ivan 249e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 250e165b1d3SKhoronzhuk, Ivan 251e165b1d3SKhoronzhuk, Ivan link_bcntrld = __raw_readl(&rg->link_bcntrld); 252e165b1d3SKhoronzhuk, Ivan 253e165b1d3SKhoronzhuk, Ivan __raw_writel((bcnt_rld << 16) | (0x0000ffff & link_bcntrld), 254e165b1d3SKhoronzhuk, Ivan &rg->link_bcntrld); 255e165b1d3SKhoronzhuk, Ivan 256e165b1d3SKhoronzhuk, Ivan opt = __raw_readl(&rg->opt); 257e165b1d3SKhoronzhuk, Ivan if (sync_mode == ASYNC) 258e165b1d3SKhoronzhuk, Ivan __raw_writel(opt & ~EDMA3_SLOPT_AB_SYNC, &rg->opt); 259e165b1d3SKhoronzhuk, Ivan else 260e165b1d3SKhoronzhuk, Ivan __raw_writel(opt | EDMA3_SLOPT_AB_SYNC, &rg->opt); 261e165b1d3SKhoronzhuk, Ivan 262e165b1d3SKhoronzhuk, Ivan /* Set the acount, bcount, ccount registers */ 263e165b1d3SKhoronzhuk, Ivan __raw_writel((bcnt << 16) | (acnt & 0xffff), &rg->a_b_cnt); 264e165b1d3SKhoronzhuk, Ivan __raw_writel(0xffff & ccnt, &rg->ccnt); 265e165b1d3SKhoronzhuk, Ivan } 266e165b1d3SKhoronzhuk, Ivan 267e165b1d3SKhoronzhuk, Ivan /** 268e165b1d3SKhoronzhuk, Ivan * edma3_write_slot - write parameter RAM data for slot 269e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 270e165b1d3SKhoronzhuk, Ivan * @slot: number of parameter RAM slot being modified 271e165b1d3SKhoronzhuk, Ivan * @param: data to be written into parameter RAM slot 272e165b1d3SKhoronzhuk, Ivan * 273e165b1d3SKhoronzhuk, Ivan * Use this to assign all parameters of a transfer at once. This 274e165b1d3SKhoronzhuk, Ivan * allows more efficient setup of transfers than issuing multiple 275e165b1d3SKhoronzhuk, Ivan * calls to set up those parameters in small pieces, and provides 276e165b1d3SKhoronzhuk, Ivan * complete control over all transfer options. 277e165b1d3SKhoronzhuk, Ivan */ 278e165b1d3SKhoronzhuk, Ivan void edma3_write_slot(u32 base, int slot, struct edma3_slot_layout *param) 279e165b1d3SKhoronzhuk, Ivan { 280e165b1d3SKhoronzhuk, Ivan int i; 281e165b1d3SKhoronzhuk, Ivan u32 *p = (u32 *)param; 282e165b1d3SKhoronzhuk, Ivan u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot)); 283e165b1d3SKhoronzhuk, Ivan 284e165b1d3SKhoronzhuk, Ivan for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4) 285e165b1d3SKhoronzhuk, Ivan __raw_writel(*p++, addr++); 286e165b1d3SKhoronzhuk, Ivan } 287e165b1d3SKhoronzhuk, Ivan 288e165b1d3SKhoronzhuk, Ivan /** 289e165b1d3SKhoronzhuk, Ivan * edma3_read_slot - read parameter RAM data from slot 290e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 291e165b1d3SKhoronzhuk, Ivan * @slot: number of parameter RAM slot being copied 292e165b1d3SKhoronzhuk, Ivan * @param: where to store copy of parameter RAM data 293e165b1d3SKhoronzhuk, Ivan * 294e165b1d3SKhoronzhuk, Ivan * Use this to read data from a parameter RAM slot, perhaps to 295e165b1d3SKhoronzhuk, Ivan * save them as a template for later reuse. 296e165b1d3SKhoronzhuk, Ivan */ 297e165b1d3SKhoronzhuk, Ivan void edma3_read_slot(u32 base, int slot, struct edma3_slot_layout *param) 298e165b1d3SKhoronzhuk, Ivan { 299e165b1d3SKhoronzhuk, Ivan int i; 300e165b1d3SKhoronzhuk, Ivan u32 *p = (u32 *)param; 301e165b1d3SKhoronzhuk, Ivan u32 *addr = (u32 *)(base + EDMA3_SL_BASE(slot)); 302e165b1d3SKhoronzhuk, Ivan 303e165b1d3SKhoronzhuk, Ivan for (i = 0; i < sizeof(struct edma3_slot_layout)/4; i += 4) 304e165b1d3SKhoronzhuk, Ivan *p++ = __raw_readl(addr++); 305e165b1d3SKhoronzhuk, Ivan } 306e165b1d3SKhoronzhuk, Ivan 307e165b1d3SKhoronzhuk, Ivan void edma3_slot_configure(u32 base, int slot, struct edma3_slot_config *cfg) 308e165b1d3SKhoronzhuk, Ivan { 309e165b1d3SKhoronzhuk, Ivan struct edma3_slot_layout *rg; 310e165b1d3SKhoronzhuk, Ivan 311e165b1d3SKhoronzhuk, Ivan rg = (struct edma3_slot_layout *)(base + EDMA3_SL_BASE(slot)); 312e165b1d3SKhoronzhuk, Ivan 313e165b1d3SKhoronzhuk, Ivan __raw_writel(cfg->opt, &rg->opt); 314e165b1d3SKhoronzhuk, Ivan __raw_writel(cfg->src, &rg->src); 315e165b1d3SKhoronzhuk, Ivan __raw_writel((cfg->bcnt << 16) | (cfg->acnt & 0xffff), &rg->a_b_cnt); 316e165b1d3SKhoronzhuk, Ivan __raw_writel(cfg->dst, &rg->dst); 317e165b1d3SKhoronzhuk, Ivan __raw_writel((cfg->dst_bidx << 16) | 318e165b1d3SKhoronzhuk, Ivan (cfg->src_bidx & 0xffff), &rg->src_dst_bidx); 319e165b1d3SKhoronzhuk, Ivan __raw_writel((cfg->bcntrld << 16) | 320e165b1d3SKhoronzhuk, Ivan (cfg->link & 0xffff), &rg->link_bcntrld); 321e165b1d3SKhoronzhuk, Ivan __raw_writel((cfg->dst_cidx << 16) | 322e165b1d3SKhoronzhuk, Ivan (cfg->src_cidx & 0xffff), &rg->src_dst_cidx); 323e165b1d3SKhoronzhuk, Ivan __raw_writel(0xffff & cfg->ccnt, &rg->ccnt); 324e165b1d3SKhoronzhuk, Ivan } 325e165b1d3SKhoronzhuk, Ivan 326e165b1d3SKhoronzhuk, Ivan /** 327e165b1d3SKhoronzhuk, Ivan * edma3_check_for_transfer - check if transfer coplete by checking 328e165b1d3SKhoronzhuk, Ivan * interrupt pending bit. Clear interrupt pending bit if complete. 329e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 330e165b1d3SKhoronzhuk, Ivan * @cfg: pinter to struct edma3_channel_config which was passed 331e165b1d3SKhoronzhuk, Ivan * to qedma3_start when you started qdma channel 332e165b1d3SKhoronzhuk, Ivan * 333e165b1d3SKhoronzhuk, Ivan * Return 0 if complete, 1 if not. 334e165b1d3SKhoronzhuk, Ivan */ 335e165b1d3SKhoronzhuk, Ivan int edma3_check_for_transfer(u32 base, struct edma3_channel_config *cfg) 336e165b1d3SKhoronzhuk, Ivan { 337e165b1d3SKhoronzhuk, Ivan u32 inum; 338e165b1d3SKhoronzhuk, Ivan u32 ipr_base; 339e165b1d3SKhoronzhuk, Ivan u32 icr_base; 340e165b1d3SKhoronzhuk, Ivan 341e165b1d3SKhoronzhuk, Ivan if (cfg->complete_code < 32) { 342e165b1d3SKhoronzhuk, Ivan ipr_base = base + EDMA3_IPR; 343e165b1d3SKhoronzhuk, Ivan icr_base = base + EDMA3_ICR; 344e165b1d3SKhoronzhuk, Ivan inum = 1 << cfg->complete_code; 345e165b1d3SKhoronzhuk, Ivan } else { 346e165b1d3SKhoronzhuk, Ivan ipr_base = base + EDMA3_IPRH; 347e165b1d3SKhoronzhuk, Ivan icr_base = base + EDMA3_ICRH; 348e165b1d3SKhoronzhuk, Ivan inum = 1 << (cfg->complete_code - 32); 349e165b1d3SKhoronzhuk, Ivan } 350e165b1d3SKhoronzhuk, Ivan 351e165b1d3SKhoronzhuk, Ivan /* check complete interrupt */ 352e165b1d3SKhoronzhuk, Ivan if (!(__raw_readl(ipr_base) & inum)) 353e165b1d3SKhoronzhuk, Ivan return 1; 354e165b1d3SKhoronzhuk, Ivan 355e165b1d3SKhoronzhuk, Ivan /* clean up the pending int bit */ 356e165b1d3SKhoronzhuk, Ivan __raw_writel(inum, icr_base); 357e165b1d3SKhoronzhuk, Ivan 358e165b1d3SKhoronzhuk, Ivan return 0; 359e165b1d3SKhoronzhuk, Ivan } 360e165b1d3SKhoronzhuk, Ivan 361e165b1d3SKhoronzhuk, Ivan /** 362e165b1d3SKhoronzhuk, Ivan * qedma3_stop - stops dma on the channel passed 363e165b1d3SKhoronzhuk, Ivan * @base: base address of edma 364e165b1d3SKhoronzhuk, Ivan * @cfg: pinter to struct edma3_channel_config which was passed 365e165b1d3SKhoronzhuk, Ivan * to qedma3_start when you started qdma channel 366e165b1d3SKhoronzhuk, Ivan */ 367e165b1d3SKhoronzhuk, Ivan void qedma3_stop(u32 base, struct edma3_channel_config *cfg) 368e165b1d3SKhoronzhuk, Ivan { 369e165b1d3SKhoronzhuk, Ivan /* Disable qdma channel event */ 370e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->chnum, base + EDMA3_QEECR); 371e165b1d3SKhoronzhuk, Ivan 372e165b1d3SKhoronzhuk, Ivan /* clean up the interrupt indication */ 373e165b1d3SKhoronzhuk, Ivan if (cfg->complete_code < 32) 374e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->complete_code, base + EDMA3_ICR); 375e165b1d3SKhoronzhuk, Ivan else 376e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->complete_code, base + EDMA3_ICRH); 377e165b1d3SKhoronzhuk, Ivan 378e165b1d3SKhoronzhuk, Ivan /* Clear missed event if set*/ 379e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->chnum, base + EDMA3_QSECR); 380e165b1d3SKhoronzhuk, Ivan __raw_writel(1 << cfg->chnum, base + EDMA3_QEMCR); 381e165b1d3SKhoronzhuk, Ivan 382e165b1d3SKhoronzhuk, Ivan /* Clear the channel map */ 383e165b1d3SKhoronzhuk, Ivan __raw_writel(0, base + EDMA3_QCHMAP(cfg->chnum)); 384e165b1d3SKhoronzhuk, Ivan } 385*664ab2c9SVignesh R 386*664ab2c9SVignesh R void edma3_transfer(unsigned long edma3_base_addr, unsigned int 387*664ab2c9SVignesh R edma_slot_num, void *dst, void *src, size_t len) 388*664ab2c9SVignesh R { 389*664ab2c9SVignesh R struct edma3_slot_config slot; 390*664ab2c9SVignesh R struct edma3_channel_config edma_channel; 391*664ab2c9SVignesh R int b_cnt_value = 1; 392*664ab2c9SVignesh R int rem_bytes = 0; 393*664ab2c9SVignesh R int a_cnt_value = len; 394*664ab2c9SVignesh R unsigned int addr = (unsigned int) (dst); 395*664ab2c9SVignesh R unsigned int max_acnt = 0x7FFFU; 396*664ab2c9SVignesh R 397*664ab2c9SVignesh R if (len > max_acnt) { 398*664ab2c9SVignesh R b_cnt_value = (len / max_acnt); 399*664ab2c9SVignesh R rem_bytes = (len % max_acnt); 400*664ab2c9SVignesh R a_cnt_value = max_acnt; 401*664ab2c9SVignesh R } 402*664ab2c9SVignesh R 403*664ab2c9SVignesh R slot.opt = 0; 404*664ab2c9SVignesh R slot.src = ((unsigned int) src); 405*664ab2c9SVignesh R slot.acnt = a_cnt_value; 406*664ab2c9SVignesh R slot.bcnt = b_cnt_value; 407*664ab2c9SVignesh R slot.ccnt = 1; 408*664ab2c9SVignesh R slot.src_bidx = a_cnt_value; 409*664ab2c9SVignesh R slot.dst_bidx = a_cnt_value; 410*664ab2c9SVignesh R slot.src_cidx = 0; 411*664ab2c9SVignesh R slot.dst_cidx = 0; 412*664ab2c9SVignesh R slot.link = EDMA3_PARSET_NULL_LINK; 413*664ab2c9SVignesh R slot.bcntrld = 0; 414*664ab2c9SVignesh R slot.opt = EDMA3_SLOPT_TRANS_COMP_INT_ENB | 415*664ab2c9SVignesh R EDMA3_SLOPT_COMP_CODE(0) | 416*664ab2c9SVignesh R EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC; 417*664ab2c9SVignesh R 418*664ab2c9SVignesh R edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot); 419*664ab2c9SVignesh R edma_channel.slot = edma_slot_num; 420*664ab2c9SVignesh R edma_channel.chnum = 0; 421*664ab2c9SVignesh R edma_channel.complete_code = 0; 422*664ab2c9SVignesh R /* set event trigger to dst update */ 423*664ab2c9SVignesh R edma_channel.trigger_slot_word = EDMA3_TWORD(dst); 424*664ab2c9SVignesh R 425*664ab2c9SVignesh R qedma3_start(edma3_base_addr, &edma_channel); 426*664ab2c9SVignesh R edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr); 427*664ab2c9SVignesh R 428*664ab2c9SVignesh R while (edma3_check_for_transfer(edma3_base_addr, &edma_channel)) 429*664ab2c9SVignesh R ; 430*664ab2c9SVignesh R qedma3_stop(edma3_base_addr, &edma_channel); 431*664ab2c9SVignesh R 432*664ab2c9SVignesh R if (rem_bytes != 0) { 433*664ab2c9SVignesh R slot.opt = 0; 434*664ab2c9SVignesh R slot.src = 435*664ab2c9SVignesh R (b_cnt_value * max_acnt) + ((unsigned int) src); 436*664ab2c9SVignesh R slot.acnt = rem_bytes; 437*664ab2c9SVignesh R slot.bcnt = 1; 438*664ab2c9SVignesh R slot.ccnt = 1; 439*664ab2c9SVignesh R slot.src_bidx = rem_bytes; 440*664ab2c9SVignesh R slot.dst_bidx = rem_bytes; 441*664ab2c9SVignesh R slot.src_cidx = 0; 442*664ab2c9SVignesh R slot.dst_cidx = 0; 443*664ab2c9SVignesh R slot.link = EDMA3_PARSET_NULL_LINK; 444*664ab2c9SVignesh R slot.bcntrld = 0; 445*664ab2c9SVignesh R slot.opt = EDMA3_SLOPT_TRANS_COMP_INT_ENB | 446*664ab2c9SVignesh R EDMA3_SLOPT_COMP_CODE(0) | 447*664ab2c9SVignesh R EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC; 448*664ab2c9SVignesh R edma3_slot_configure(edma3_base_addr, edma_slot_num, &slot); 449*664ab2c9SVignesh R edma_channel.slot = edma_slot_num; 450*664ab2c9SVignesh R edma_channel.chnum = 0; 451*664ab2c9SVignesh R edma_channel.complete_code = 0; 452*664ab2c9SVignesh R /* set event trigger to dst update */ 453*664ab2c9SVignesh R edma_channel.trigger_slot_word = EDMA3_TWORD(dst); 454*664ab2c9SVignesh R 455*664ab2c9SVignesh R qedma3_start(edma3_base_addr, &edma_channel); 456*664ab2c9SVignesh R edma3_set_dest_addr(edma3_base_addr, edma_channel.slot, addr + 457*664ab2c9SVignesh R (max_acnt * b_cnt_value)); 458*664ab2c9SVignesh R while (edma3_check_for_transfer(edma3_base_addr, &edma_channel)) 459*664ab2c9SVignesh R ; 460*664ab2c9SVignesh R qedma3_stop(edma3_base_addr, &edma_channel); 461*664ab2c9SVignesh R } 462*664ab2c9SVignesh R } 463