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