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