1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14#include <platsupport/gen_config.h> 15 16/* This is core ARM IP, but we will limit the compile to EXYNOS5 for now */ 17#ifdef CONFIG_PLAT_EXYNOS5 18 19#include <platsupport/dma330.h> 20#include "string.h" 21 22/* Debug control */ 23#define DBGCMD_EXEC 0b00 24#define DBGINST_CHDBG BIT(0) 25#define DBGINST_CH(x) ((x) << 8) 26 27/* Manager Status */ 28#define MGRSTS_NS BIT(9) 29#define MGRSTS_STATUS(x) ((x) & 0xf) 30#define DBGSTS_BUSY BIT(0) 31 32/* Channel Status */ 33#define CHSTS_NS BIT(21) 34#define CHSTS_STATUS(x) ((x) & 0xf) 35#define CHSTS_STOPPED 0b0000 36#define CHSTS_EXECUTING 0b0001 37#define CHSTS_CACHEMISS 0b0010 38#define CHSTS_PCUPDATE 0b0011 39#define CHSTS_WFE 0b0100 40#define CHSTS_BARRIER 0b0101 41#define CHSTS_BUSY 0b0110 42#define CHSTS_WFP 0b0111 43#define CHSTS_KILLING 0b1000 44#define CHSTS_COMPLETING 0b1001 45#define CHSTS_COMPLETING_FAULT 0b1110 46#define CHSTS_FAULT 0b1111 47 48/* Channel control */ 49#define CCR_AUTO_INC BIT(0) 50#define CCR_BURST_SIZE(x) (((x) & 0x7) << 1) 51#define CCR_BURST_LEN(x) (((x) & 0xf) << 4) 52#define CCR_PROT_CTRL(x) (((x) & 0x7) << 8) 53#define CCR_CACHE_CTRL(x) (((x) & 0x7) << 11) 54#define CCR_ENDIAN_SWAP_SZ(x) (((x) & 0xf) << 28) 55#define CCR_CFG_DST(x) ((x) << 14) 56#define CCR_CFG_SRC(x) ((x) << 0) 57 58/* Fault type */ 59#define FT_UNDEFINST BIT(0) 60#define FT_OPERAND BIT(1) 61#define FTMG_DMAGO_ERR BIT(4) 62#define FT_EVENT_ERR BIT(5) 63#define FTCH_PERIPH_ERR BIT(6) 64#define FTCH_DATA_ERR BIT(7) 65#define FTCH_FIFO_ERR BIT(12) 66#define FT_PREFETCH BIT(16) 67#define FTCH_WRITE_ERR BIT(17) 68#define FTCH_READ_ERR BIT(18) 69#define FT_DBGINST BIT(30) 70#define FTMG_LOCKUP_ERR BIT(31) 71 72#define PTR64(x) (uint64_t)(uintptr_t)(x) 73 74/* DMAC instruction set */ 75#define DMAI_ADDHW_SRC(x) /* DMAADDH */ (((x) << 8) | 0x54) 76#define DMAI_ADDHW_DST(x) /* DMAADDH */ (((x) << 8) | 0x56) 77#define DMAI_END /* DMAEND */ (0x00) 78#define DMAI_FLASH_PERIPH(x) /* DMAFLUSHP */ (((x) << 11) | 0x35) 79#define DMAI_GO(ch, pc) /* DMAGO */ ((PTR64(pc) << 16) | ((ch) << 8) | 0xa0) 80#define DMAI_NS_GO(ch, pc) /* DMAGO */ (DMAI_GO(ch, pc) | BIT(1)) 81#define DMAI_LD /* DMALD[S|B] */ (0x04) 82#define DMAI_LDS /* DMALD[S|B] */ (DMAI_LD | 0x1) 83#define DMAI_LDB /* DMALD[S|B] */ (DMAI_LD | 0x3) 84#define DMAI_LDPS(p) /* DMALDP<S|B> */ (((p) << 11) | 0x25) 85#define DMAI_LDPB(p) /* DMALDP<S|B> */ (DMAI_LDPS(p) | 0x2) 86#define DMAI_LP(lc, i) /* DMALP */ (((i) << 8) | 0x20 | ((lc) << 1)) 87#define DMAI_LPFEEND(lc, jmp) /* DMALPEND[S|B] */ ((PTR64(jmp) << 8) | 0x28 | ((lc) << 2)) 88#define DMAI_LPEND(lc, jmp) /* DMALPEND[S|B] */ (DMAI_LPFEEND(lc, jmp) | BIT(4)) 89#define DMAI_LPENDS(lc, jmp) /* DMALPEND[S|B] */ (DMAI_LPEND(lc, jmp) | 0x1) 90#define DMAI_LPENDB(lc, jmp) /* DMALPEND[S|B] */ (DMAI_LPEND(lc, jmp) | 0x3) 91#define DMAI_LPFEENDS(lc, jmp) /* DMALPEND[S|B] */ (DMAI_LPFEEND(lc, jmp) | 0x1) 92#define DMAI_LPFEENDB(lc, jmp) /* DMALPEND[S|B] */ (DMAI_LPFEEND(lc, jmp) | 0x3) 93/* DMALPFE */ 94/* DMAKILL */ 95#define DMAI_MOV_SAR(a) /* DMAMOV */ ((PTR64(a) << 16) | 0xBC) 96#define DMAI_MOV_DAR(a) /* DMAMOV */ (DMAI_MOV_SAR(a) | (0x2 << 8)) 97#define DMAI_MOV_CCR(a) /* DMAMOV */ (DMAI_MOV_SAR(a) | (BIT(8))) 98#define DMAI_NOP /* DMANOP */ (0x18) 99/* DMARMB */ 100#define DMAI_SEV(e) /* DMASEV */ (((e) << 11) | 0x34) 101#define DMAI_ST /* DMAST[S|B] */ (0x08) 102#define DMAI_STS /* DMAST[S|B] */ (0x09) 103#define DMAI_STB /* DMAST[S|B] */ (0x0B) 104/* DMASTP<S|B> */ 105/* DMASTZ */ 106/* DMAWFE */ 107/* DMAWFP<S|B|P> */ 108#define DMAI_WMB /* DMAWMB */ (0x13) 109 110/* DMAC instruction sizes */ 111#define DMAISZ_ADDHW_SRC(...) 3 112#define DMAISZ_ADDHW_DST(...) 3 113#define DMAISZ_END 1 114#define DMAISZ_FLASH_PERIPH(...) 2 115#define DMAISZ_GO(...) 6 116#define DMAISZ_NS_GO(...) 6 117#define DMAISZ_LD 1 118#define DMAISZ_LDS 1 119#define DMAISZ_LDB 1 120#define DMAISZ_LDPS(...) 2 121#define DMAISZ_LDPB(...) 2 122#define DMAISZ_LP(...) 2 123#define DMAISZ_LPEND(...) 2 124#define DMAISZ_LPENDS(...) 2 125#define DMAISZ_LPENDB(...) 2 126/* DMALPFE */ 127/* DMAKILL */ 128#define DMAISZ_MOV_SAR(...) 6 129#define DMAISZ_MOV_DAR(...) 6 130#define DMAISZ_MOV_CCR(...) 6 131#define DMAISZ_NOP 1 132/* DMARMB */ 133#define DMAISZ_SEV(...) 2 134#define DMAISZ_ST 1 135#define DMAISZ_STS 1 136#define DMAISZ_STB 1 137/* DMASTP<S|B> */ 138/* DMASTZ */ 139/* DMAWFE */ 140/* DMAWFP<S|B|P> */ 141#define DMAISZ_WMB 1 142 143#define APPEND_INSTRUCTION(buf, op) \ 144 do { \ 145 uint64_t code = DMAI_##op; \ 146 int i; \ 147 /* memcpy in muslc causes alignment faults */ \ 148 for(i = 0; i < DMAISZ_##op; i++) { \ 149 *buf++ = code; \ 150 code >>= 8; \ 151 } \ 152 } while(0) 153 154typedef volatile struct dma330_map { 155 /* 0x000 */ 156 struct { 157 uint32_t dsr; /* RO */ 158 uint32_t dpc; /* RO */ 159 uint32_t reserved0[6]; 160 uint32_t inten; /* RW */ 161 uint32_t int_event_ris; /* RO */ 162 uint32_t intmis; /* RO */ 163 uint32_t intclr; /* WO */ 164 uint32_t fsm; /* RO */ 165 uint32_t fsc; /* RO */ 166 uint32_t ftm; /* RO */ 167 uint32_t reserved1[1]; 168 uint32_t ftc[8]; /* RO */ 169 uint32_t reserved2[40]; 170 } ctrl; 171 /* 0x100 */ 172 struct { 173 uint32_t csr; /* RO */ 174 uint32_t cpc; /* RO */ 175 } chstat[8]; 176 uint32_t reserved0[176]; 177 /* 0x400 */ 178 struct dma330_axi_map { 179 uint32_t sar; /* RO */ 180 uint32_t dar; /* RO */ 181 uint32_t ccr; /* RO */ 182 uint32_t lc[2]; /* RO */ 183 uint32_t reserved[3]; 184 } axi[8]; 185 uint32_t reserved1[512]; 186 /* 0xd00 */ 187 struct { 188 uint32_t dbgstatus; /* RO */ 189 uint32_t dbgcmd; /* WO */ 190 uint32_t dbginst[2]; /* WO */ 191 uint32_t reserved[60]; 192 } debug; 193 /* 0xe00 */ 194 struct { 195 uint32_t cr[5]; /* RO */ 196 uint32_t crd; /* RO */ 197 uint32_t reserved[58]; 198 } config; 199 /* 0xf00 */ 200 uint32_t reserved2[56]; 201 /* 0xfe0 */ 202 struct { 203 uint32_t periph[4]; /* RO */ 204 uint32_t pcell[4]; /* RO */ 205 } id; 206} dma330_map_t; 207 208struct channel_data { 209 dma330_signal_cb cb; 210 void* token; 211}; 212 213struct dma330_dev { 214 dma330_map_t* regs; 215 struct channel_data channel_data[8]; 216} _dma330_dev[NPL330]; 217 218static inline int 219dmac_busy(dma330_t dma330) 220{ 221 dma330_map_t* regs = dma330->regs; 222 return !!(regs->debug.dbgstatus & DBGSTS_BUSY); 223} 224 225static inline uintptr_t 226dmac_get_pc(dma330_t dma330, int channel) 227{ 228 dma330_map_t* regs = dma330->regs; 229 return regs->chstat[channel].cpc; 230} 231 232static inline uint32_t 233dmac_has_fault(dma330_t dma330, int channel) 234{ 235 dma330_map_t* regs = dma330->regs; 236 if (channel < 0) { 237 return regs->ctrl.fsm & BIT(0); 238 } else { 239 return regs->ctrl.fsc & BIT(channel); 240 } 241} 242 243static inline uint32_t 244dmac_get_status(dma330_t dma330, int channel) 245{ 246 dma330_map_t* regs = dma330->regs; 247 if (channel < 0) { 248 return regs->ctrl.dsr; 249 } else { 250 return regs->chstat[channel].csr; 251 } 252} 253 254static inline uint32_t 255dmac_get_fault_type(dma330_t dma330, int channel) 256{ 257 dma330_map_t* regs = dma330->regs; 258 if (channel < 1) { 259 return regs->ctrl.ftm; 260 } else { 261 return regs->ctrl.ftc[channel]; 262 } 263} 264 265UNUSED static void 266dmac_channel_dump(dma330_t dma330, int channel) 267{ 268 dma330_map_t* regs = dma330->regs; 269 char* sts_str; 270 char* sec_str; 271 uint32_t v, sts; 272 int i = channel; 273 if (i < 0) { 274 v = regs->ctrl.dsr; 275 sts = MGRSTS_STATUS(v); 276 sec_str = (v & MGRSTS_NS) ? "non-secure, " : "secure, "; 277 } else { 278 v = regs->chstat[i].csr; 279 sts = CHSTS_STATUS(v); 280 sec_str = (v & CHSTS_NS) ? "non-secure, " : "secure, "; 281 } 282 switch (sts) { 283 case CHSTS_STOPPED: 284 sts_str = "stopped"; 285 sec_str = ""; 286 break; 287 case CHSTS_EXECUTING: 288 sts_str = "running"; 289 break; 290 case CHSTS_CACHEMISS: 291 sts_str = "cache miss"; 292 break; 293 case CHSTS_PCUPDATE: 294 sts_str = "updating PC"; 295 break; 296 case CHSTS_WFE: 297 sts_str = "waiting for event"; 298 break; 299 case CHSTS_BARRIER: 300 sts_str = "waiting for barrier completion"; 301 break; 302 case CHSTS_BUSY: 303 sts_str = "queue busy"; 304 break; 305 case CHSTS_WFP: 306 sts_str = "waiting for peripheral"; 307 break; 308 case CHSTS_KILLING: 309 sts_str = "killing"; 310 break; 311 case CHSTS_COMPLETING: 312 sts_str = "completing"; 313 break; 314 case CHSTS_COMPLETING_FAULT: 315 sts_str = "fault complete"; 316 break; 317 case CHSTS_FAULT: 318 sts_str = "faulting"; 319 break; 320 default: 321 sts_str = "<reserved>"; 322 break; 323 } 324 325 if (i < 0) { 326 printf("[ Manager ] Status: 0x%08x (%s%s)\n", v, sec_str, sts_str); 327 printf(" MGR PC: 0x%08x\n", regs->ctrl.dpc); 328 printf(" fs: 0x%08x\n", regs->ctrl.fsm); 329 printf(" Fault: 0x%08x\n", regs->ctrl.ftm); 330 printf(" fs/ch: 0x%08x\n", regs->ctrl.fsc); 331 } else { 332 printf("[Channel %d] Status: 0x%08x (%s%s)\n", i, v, sec_str, sts_str); 333 printf(" PC: 0x%08x\n", regs->chstat[i].cpc); 334 v = regs->axi[i].sar; 335 printf(" SRC: 0x%08x\n", v); 336 v = regs->axi[i].dar; 337 printf(" DST: 0x%08x\n", v); 338 v = regs->axi[i].lc[0]; 339 printf(" LOOP0: 0x%08x\n", v); 340 v = regs->axi[i].lc[1]; 341 printf(" LOOP1: 0x%08x\n", v); 342 v = regs->axi[i].ccr; 343 printf(" Config: 0x%08x\n", v); 344 v = regs->ctrl.ftc[i]; 345 printf(" Fault: 0x%08x\n", v); 346 } 347} 348 349UNUSED static void 350dmac_dump(dma330_t dma330) 351{ 352 dma330_map_t* regs = dma330->regs; 353 uint32_t v; 354 int i; 355 printf("#### DMA330 ####\n"); 356 v = regs->debug.dbgstatus; 357 printf("dbg_sts: 0x%08x (%s)\n", v, (v & DBGSTS_BUSY) ? "busy" : "idle"); 358 v = regs->ctrl.inten; 359 printf("INT en: 0x%08x\n", v); 360 v = regs->ctrl.int_event_ris; 361 printf("INT evt: 0x%08x\n", v); 362 v = regs->ctrl.intmis; 363 printf("INT mis: 0x%08x\n", v); 364 v = regs->ctrl.intclr; 365 printf("INT clr: 0x%08x\n", v); 366 v = regs->config.cr[0]; 367 printf("Config0: 0x%08x\n", v); 368 v = regs->config.cr[1]; 369 printf("Config1: 0x%08x\n", v); 370 v = regs->config.cr[2]; 371 printf("Config2: 0x%08x\n", v); 372 v = regs->config.cr[3]; 373 printf("Config3: 0x%08x\n", v); 374 v = regs->config.cr[4]; 375 printf("Config4: 0x%08x\n", v); 376 v = regs->config.crd; 377 printf("Configd: 0x%08x\n", v); 378 printf("---------------\n"); 379 380 for (i = -1; i < 8; i++) { 381 dmac_channel_dump(dma330, i); 382 } 383 printf("################\n"); 384} 385 386UNUSED static void 387dmac_print_fault(dma330_t dma330, int channel) 388{ 389 dma330_map_t* regs = dma330->regs; 390 uint32_t ft, src, dst, pc; 391 if (channel < 0) { 392 ft = regs->ctrl.ftm; 393 pc = regs->ctrl.dpc; 394 src = dst = 0; 395 } else { 396 ft = regs->ctrl.ftc[channel]; 397 pc = regs->chstat[channel].cpc; 398 src = regs->axi[channel].sar; 399 dst = regs->axi[channel].dar; 400 } 401 if (ft & FT_DBGINST) { 402 pc = 0xdeadbeef; 403 } 404 405 printf("DMAC fault @ 0x%08x: ", pc); 406 if (ft & FT_UNDEFINST) { 407 printf("Undefined instruction. "); 408 } 409 if (ft & FT_OPERAND) { 410 printf("Inavid operand. "); 411 } 412 if (ft & FTMG_DMAGO_ERR) { 413 printf("DMAGO error. "); 414 } 415 if (ft & FT_EVENT_ERR) { 416 printf("Event error. "); 417 } 418 if (ft & FTCH_PERIPH_ERR) { 419 printf("Peripheral error. "); 420 } 421 if (ft & FTCH_DATA_ERR) { 422 printf("Data error. "); 423 } 424 if (ft & FTCH_FIFO_ERR) { 425 printf("FIFO error. "); 426 } 427 if (ft & FT_PREFETCH) { 428 printf("Prefetch error. "); 429 } 430 if (ft & FTCH_WRITE_ERR) { 431 printf("Write error to 0x%08x. ", dst); 432 } 433 if (ft & FTCH_READ_ERR) { 434 printf("Read error from 0x%08x. ", src); 435 } 436 if (ft & FTMG_LOCKUP_ERR) { 437 printf("Lockup error. "); 438 } 439 printf("\n"); 440} 441 442UNUSED static void 443program_dump(void *vbin) 444{ 445 uint8_t* bin = (uint8_t*)vbin; 446 int i = 0; 447 printf("DMAC program @ 0x%08x", (uint32_t)bin); 448 while ((bin[0] | bin[1] | bin[2] | bin[3] | bin[4] | bin[5]) != 0) { 449 if ((i % 4) == 0) { 450 printf("\n0x%03x: ", i); 451 } 452 printf("0x%02x ", *bin++); 453 i++; 454 } 455 printf("\n----\n"); 456} 457 458static void 459dmac_exec(dma330_t dma330, uint64_t instruction, int channel) 460{ 461 dma330_map_t* regs = dma330->regs; 462 uint32_t inst1, inst0; 463 inst1 = instruction >> 16; 464 inst0 = instruction << 16; 465 if (channel < 0) { 466 /* Manager thread, no extra bits to select */ 467 } else if (channel < 8) { 468 inst0 |= DBGINST_CHDBG; 469 inst0 |= DBGINST_CH(channel); 470 } else { 471 assert(!"Invalid channel"); 472 } 473 regs->debug.dbginst[0] = inst0; 474 regs->debug.dbginst[1] = inst1; 475 476 while (dmac_busy(dma330)); 477 regs->debug.dbgcmd = DBGCMD_EXEC; 478} 479 480int 481dma330_init_base(enum dma330_id id, void* dma330_base, clock_sys_t* clk_sys, dma330_t* dma330) 482{ 483 assert(sizeof(struct dma330_map) == 0x1000); 484 assert(id >= 0); 485 assert(id < NPL330); 486 assert(dma330_base); 487 assert(clk_sys); 488 assert(dma330); 489 490 if (dma330_base == NULL) { 491 return -1; 492 } else { 493 struct dma330_dev* dev; 494 uint32_t v; 495 dev = &_dma330_dev[id]; 496 *dma330 = dev; 497 memset(dev, 0, sizeof(*dev)); 498 dev->regs = dma330_base; 499 /* Check peripheral ID */ 500 v = 0; 501 v |= dev->regs->id.periph[0] << 0; 502 v |= dev->regs->id.periph[1] << 8; 503 v |= dev->regs->id.periph[2] << 16; 504 v |= dev->regs->id.periph[3] << 24; 505 if ((v & 0x000fffff) != 0x41330) { 506 LOG_ERROR("Invalid peripheral ID for DMA330\n"); 507 return -1; 508 } 509 /* Check primecell ID */ 510 v = 0; 511 v |= dev->regs->id.pcell[0] << 0; 512 v |= dev->regs->id.pcell[1] << 8; 513 v |= dev->regs->id.pcell[2] << 16; 514 v |= dev->regs->id.pcell[3] << 24; 515 if (v != 0xB105F00D) { 516 LOG_ERROR("Invalid PrimeCell ID for DMA330\n"); 517 return -1; 518 } 519 /* Success! */ 520 return 0; 521 } 522}; 523 524int 525dma330_init(enum dma330_id id, struct ps_io_ops* ops, dma330_t* dma330) 526{ 527 void* base; 528 assert(dma330); 529 assert(ops); 530 assert(id >= 0); 531 assert(id < NPL330); 532 if (_dma330_dev[id].regs == NULL) { 533 uintptr_t pbase = dma330_paddr[id]; 534 base = ps_io_map(&ops->io_mapper, pbase, DMA330_SIZE, 0, PS_MEM_NORMAL); 535 return dma330_init_base(id, base, &ops->clock_sys, dma330); 536 } else { 537 *dma330 = &_dma330_dev[id]; 538 return 0; 539 } 540}; 541 542int 543dma330_xfer(dma330_t* dma330_ptr, int ch, uintptr_t program, dma330_signal_cb cb, void* token) 544{ 545 dma330_t dma330 = *dma330_ptr; 546 if (ch < 0 || ch > 8) { 547 return -1; 548 } 549 if (dma330->channel_data[ch].cb != NULL) { 550 return -1; 551 } 552 if (CHSTS_STATUS(dmac_get_status(dma330, ch)) != CHSTS_STOPPED) { 553 return -1; 554 } 555 556 ZF_LOGD("Executing 0x%x on channel %d\n", program, ch); 557 dma330->channel_data[ch].cb = cb; 558 dma330->channel_data[ch].token = token; 559 560 dmac_exec(dma330, DMAI_NS_GO(ch, program), -1); 561 if (cb == NULL) { 562 UNUSED uint32_t status; 563 while (dmac_get_status(dma330, ch) == CHSTS_EXECUTING); 564 status = CHSTS_STATUS(dmac_get_status(dma330, ch)); 565 ZF_LOGD("Transfer @ 0x%x completed with status: 0x%x\n", program, status); 566 if (dmac_has_fault(dma330, ch)) { 567 dmac_print_fault(dma330, ch); 568 } 569 } else { 570 dma330->regs->ctrl.inten |= (0xf << (ch * 4)); 571 } 572 573 return 0; 574} 575 576int 577dma330_handle_irq(dma330_t* dma330_ptr) 578{ 579 dma330_t dma330 = *dma330_ptr; 580 uint32_t int_stat; 581 582 int_stat = dma330->regs->ctrl.intmis; 583 while (int_stat) { 584 struct channel_data *cdata; 585 int resume; 586 int sig, ch; 587 /* Search the bitfield for the next signal and determine its owner */ 588 sig = CTZ(int_stat); 589 ch = sig / 4; 590 sig &= 0x3; 591 cdata = &dma330->channel_data[ch]; 592 593 ZF_LOGD("IRQ: Channel %d.%d\n", ch, sig); 594 595 /* We should only get an IRQ if a callback is registered */ 596 assert(cdata->cb); 597 if (cdata->cb) { 598 uintptr_t pc = dma330->regs->chstat[ch].cpc; 599 uint32_t stat = dma330->regs->chstat[ch].csr; 600 /* Call the provided callback */ 601 resume = cdata->cb(dma330_ptr, sig, pc, stat, cdata->token); 602 } else { 603 resume = 0; 604 } 605 /* Clean up the transfer */ 606 if (!resume || dmac_get_status(dma330, ch) == CHSTS_STOPPED) { 607 uint32_t irq_mask = (0xf << (ch * 4)); 608 dma330->regs->ctrl.intclr = irq_mask; 609 dma330->regs->ctrl.inten &= ~irq_mask; 610 int_stat &= ~irq_mask; 611 cdata->cb = NULL; 612 cdata->token = NULL; 613 } else { 614 dma330->regs->ctrl.intclr = BIT(sig); 615 int_stat &= ~BIT(sig); 616 } 617 } 618 return 0; 619} 620 621/**************************** 622 *** Compiler and presets *** 623 ****************************/ 624 625int 626dma330_compile(char* source_code, void* bin) 627{ 628 assert(!"Not implemented"); 629 return -1; 630} 631 632void 633dma330_copy_compile(int channel, void* vbin) 634{ 635#if 0 636 /* Reserved bytes */ 637 "DMAMOV src, 0x00000000;" /* Set source */ 638 "DMAMOV dst, 0x00000000;" /* Set destination */ 639 "DMAMOV cfg, 0x00000000;" /* Set configuration */ 640 /* Program code */ 641 "DMALP cnt, 0x00;" /* Loop X times */ 642 " DMALD" /* Load from src */ 643 " DMAST" /* Store to dst */ 644 "DMALPEND" /* Loop end */ 645 "DMAWMB" /* Write barrier */ 646 "DMAEND" /* End program */ 647#endif 648 uint8_t* bin = (uint8_t*)vbin; 649 uint8_t* loop0; 650 /* Place holders for configuration */ 651 APPEND_INSTRUCTION(bin, MOV_SAR(0)); 652 APPEND_INSTRUCTION(bin, MOV_DAR(0)); 653 APPEND_INSTRUCTION(bin, MOV_CCR(0)); 654 APPEND_INSTRUCTION(bin, LP(0, 0)); 655 656 (loop0 = bin); 657 { 658 APPEND_INSTRUCTION(bin, LD); 659 APPEND_INSTRUCTION(bin, ST); 660 } 661 APPEND_INSTRUCTION(bin, LPEND(0, bin - loop0)); 662 663 APPEND_INSTRUCTION(bin, WMB); 664 APPEND_INSTRUCTION(bin, SEV(channel * 4)); 665 APPEND_INSTRUCTION(bin, END); 666} 667 668int 669dma330_copy_configure(uintptr_t pdst, uintptr_t psrc, size_t len, void* vbin) 670{ 671 ZF_LOGD("Copy configure @ 0x%x: 0x%x -> 0x%x (%d bytes)\n", 672 (uint32_t)vbin, (uint32_t)psrc, (uint32_t)pdst, len); 673 char* bin = (char*)vbin; 674 uint32_t cfg = 0; 675 cfg |= CCR_CFG_SRC(CCR_PROT_CTRL(2) | CCR_AUTO_INC); 676 cfg |= CCR_CFG_DST(CCR_PROT_CTRL(2) | CCR_AUTO_INC); 677 678 if (len > 255) { 679 return -1; 680 } else if (len <= 0) { 681 return -1; 682 } else { 683 APPEND_INSTRUCTION(bin, MOV_SAR(psrc)); 684 APPEND_INSTRUCTION(bin, MOV_DAR(pdst)); 685 APPEND_INSTRUCTION(bin, MOV_CCR(cfg)); 686 APPEND_INSTRUCTION(bin, LP(0, len - 1)); 687 } 688 689 return 0; 690} 691 692#endif 693