diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 8e106ff..497c474 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -42,3 +42,4 @@ obj-y += fttmr010.o
 obj-y += ftpwmtmr010.o
 obj-y += ftwdt010.o
 obj-y += ftrtc011.o
+obj-y += ftdmac020.o
diff --git a/hw/arm/faraday_a360.c b/hw/arm/faraday_a360.c
index 3652876..98e5cc0 100644
--- a/hw/arm/faraday_a360.c
+++ b/hw/arm/faraday_a360.c
@@ -69,6 +69,14 @@ a360_device_init(A360State *s)
 
     /* ftwdt010 */
     sysbus_create_simple("ftwdt010", 0x98500000, pic[16]);
+
+    /* ftdmac020 */
+    s->hdma[0] = sysbus_create_varargs("ftdmac020",
+                                       0x90400000,
+                                       pic[21], /* ALL */
+                                       pic[40], /* TC */
+                                       pic[41], /* ERR */
+                                       NULL);
 }
 
 static void
diff --git a/hw/arm/faraday_a369.c b/hw/arm/faraday_a369.c
index f8471b4..406aee0 100644
--- a/hw/arm/faraday_a369.c
+++ b/hw/arm/faraday_a369.c
@@ -107,6 +107,20 @@ a369_device_init(A369State *s)
                           pic[44],    /* Minute (Edge) */
                           pic[45],    /* Hour (Edge) */
                           NULL);
+
+    /* ftdmac020 */
+    s->hdma[0] = sysbus_create_varargs("ftdmac020",
+                                       0x90300000,
+                                       pic[0],  /* ALL (NC in A369) */
+                                       pic[15], /* TC */
+                                       pic[16], /* ERR */
+                                       NULL);
+    s->hdma[1] = sysbus_create_varargs("ftdmac020",
+                                       0x96100000,
+                                       pic[0],  /* ALL (NC in A369) */
+                                       pic[17], /* TC */
+                                       pic[18], /* ERR */
+                                       NULL);
 }
 
 static void
diff --git a/hw/arm/ftdmac020.c b/hw/arm/ftdmac020.c
new file mode 100644
index 0000000..7870254
--- /dev/null
+++ b/hw/arm/ftdmac020.c
@@ -0,0 +1,581 @@
+/*
+ * QEMU model of the FTDMAC020 DMA Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ *
+ * Note: The FTDMAC020 decreasing address mode is not implemented.
+ */
+
+#include <hw/sysbus.h>
+#include <sysemu/sysemu.h>
+#include <sysemu/blockdev.h>
+
+#include "ftdmac020.h"
+
+#define TYPE_FTDMAC020    "ftdmac020"
+
+enum ftdmac020_irqpin {
+    IRQ_ALL = 0,
+    IRQ_TC,
+    IRQ_ERR,
+};
+
+typedef struct Ftdmac020State Ftdmac020State;
+
+/**
+ * struct Ftdmac020LLD - hardware link list descriptor.
+ * @src: source physical address
+ * @dst: destination physical addr
+ * @next: phsical address to the next link list descriptor
+ * @ctrl: control field
+ * @size: transfer size
+ *
+ * should be word aligned
+ */
+typedef struct Ftdmac020LLD {
+    uint32_t src;
+    uint32_t dst;
+    uint32_t next;
+    uint32_t ctrl;
+    uint32_t size;
+} Ftdmac020LLD;
+
+typedef struct Ftdmac020Chan {
+    Ftdmac020State *chip;
+
+    int id;
+    int burst;
+    int llp_cnt;
+    int src_bw;
+    int src_stride;
+    int dst_bw;
+    int dst_stride;
+
+    /* HW register cache */
+    uint32_t ccr;
+    uint32_t cfg;
+    uint32_t src;
+    uint32_t dst;
+    uint32_t llp;
+    uint32_t len;
+} Ftdmac020Chan;
+
+typedef struct Ftdmac020State {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq[3];
+
+    Ftdmac020Chan chan[8];
+    qemu_irq       ack[16];
+    uint32_t       req;
+
+    int busy;    /* Busy Channel ID */
+    int bh_owner;
+    QEMUBH *bh;
+
+    /* HW register cache */
+    uint32_t tcisr;
+    uint32_t eaisr;
+    uint32_t tcsr;
+    uint32_t easr;
+    uint32_t cesr;
+    uint32_t cbsr;
+    uint32_t csr;
+    uint32_t sync;
+} Ftdmac020State;
+
+#define FTDMAC020(obj) \
+    OBJECT_CHECK(Ftdmac020State, obj, TYPE_FTDMAC020)
+
+static void ftdmac020_update_irq(Ftdmac020State *s)
+{
+    uint32_t tc, err;
+
+    /* 1. Checking TC interrupts */
+    tc = s->tcisr & 0xff;
+    qemu_set_irq(s->irq[IRQ_TC], tc ? 1 : 0);
+
+    /* 2. Checking Error/Abort interrupts */
+    err = s->eaisr & 0x00ff00ff;
+    qemu_set_irq(s->irq[IRQ_ERR], err ? 1 : 0);
+
+    /* 3. Checking interrupt summary (TC | Error | Abort) */
+    qemu_set_irq(s->irq[IRQ_ALL], (tc || err) ? 1 : 0);
+}
+
+static void ftdmac020_chan_ccr_decode(Ftdmac020Chan *c)
+{
+    uint32_t tmp;
+
+    /* 1. decode burst size */
+    tmp = (c->ccr >> 16) & 0x07;
+    c->burst  = 1 << (tmp ? tmp + 1 : 0);
+
+    /* 2. decode source width */
+    tmp = (c->ccr >> 11) & 0x03;
+    c->src_bw = 8 << tmp;
+
+    /* 3. decode destination width */
+    tmp = (c->ccr >> 8) & 0x03;
+    c->dst_bw = 8 << tmp;
+
+    /* 4. decode source address stride */
+    tmp = (c->ccr >> 5) & 0x03;
+    if (tmp == 2) {
+        c->src_stride = 0;
+    } else {
+        c->src_stride = c->src_bw >> 3;
+    }
+
+    /* 5. decode destination address stride */
+    tmp = (c->ccr >> 3) & 0x03;
+    if (tmp == 2) {
+        c->dst_stride = 0;
+    } else {
+        c->dst_stride = c->dst_bw >> 3;
+    }
+}
+
+static void ftdmac020_chan_start(Ftdmac020Chan *c)
+{
+    Ftdmac020State *s = c->chip;
+    Ftdmac020LLD desc;
+    hwaddr src, dst;
+    uint8_t buf[4096] __attribute__ ((aligned (8)));
+    int i, len, stride, src_hs, dst_hs;
+
+    if (!(c->ccr & 0x01)) {
+        return;
+    }
+
+    s->busy = c->id;
+
+    /* DMA src/dst address */
+    src = c->src;
+    dst = c->dst;
+    /* DMA hardware handshake id */
+    src_hs = (c->cfg & 0x0080) ? ((c->cfg >> 3) & 0x0f) : -1;
+    dst_hs = (c->cfg & 0x2000) ? ((c->cfg >> 9) & 0x0f) : -1;
+    /* DMA src/dst sanity check */
+    if (cpu_physical_memory_is_io(src) && c->src_stride) {
+        hw_error("ftdmac020: src is an I/O device with non-fixed address?\n");
+        exit(1);
+    }
+    if (cpu_physical_memory_is_io(dst) && c->dst_stride) {
+        hw_error("ftdmac020: dst is an I/O device with non-fixed address?\n");
+        exit(1);
+    }
+
+    while (c->len > 0) {
+        /*
+         * Postpone this DMA action
+         * if the corresponding dma request is not asserted
+         */
+        if ((src_hs >= 0) && !(s->req & (1 << src_hs))) {
+            break;
+        }
+        if ((dst_hs >= 0) && !(s->req & (1 << dst_hs))) {
+            break;
+        }
+
+        len = MIN(sizeof(buf), c->burst * (c->src_bw >> 3));
+
+        /* load data from source into local buffer */
+        if (c->src_stride) {
+            cpu_physical_memory_read(src, buf, len);
+            src += len;
+        } else {
+            stride = c->src_bw >> 3;
+            for (i = 0; i < len; i += stride) {
+                cpu_physical_memory_read(src, buf + i, stride);
+            }
+        }
+
+        /* DMA Hardware Handshake */
+        if (src_hs >= 0) {
+            qemu_set_irq(s->ack[src_hs], 1);
+        }
+
+        /* store data into destination from local buffer */
+        if (c->dst_stride) {
+            cpu_physical_memory_write(dst, buf, len);
+            dst += len;
+        } else {
+            stride = c->dst_bw >> 3;
+            for (i = 0; i < len; i += stride) {
+                cpu_physical_memory_write(dst, buf + i, stride);
+            }
+        }
+
+        /* DMA Hardware Handshake */
+        if (dst_hs >= 0) {
+            qemu_set_irq(s->ack[dst_hs], 1);
+        }
+
+        /* update the channel transfer size */
+        c->len -= len / (c->src_bw >> 3);
+
+        if (c->len == 0) {
+            /* update the channel transfer status */
+            if (!(c->ccr & CCR_MASK_TC)) {
+                s->tcsr |= (1 << c->id);
+                if (!(c->cfg & CFG_MASK_TCI)) {
+                    s->tcisr |= (1 << c->id);
+                }
+                ftdmac020_update_irq(s);
+            }
+            /* try to load next lld */
+            if (c->llp) {
+                c->llp_cnt += 1;
+                cpu_physical_memory_read(c->llp, &desc, sizeof(desc));
+
+                desc.src  = le32_to_cpu(desc.src);
+                desc.dst  = le32_to_cpu(desc.dst);
+                desc.next = le32_to_cpu(desc.next);
+                desc.size = le32_to_cpu(desc.size);
+                desc.ctrl = le32_to_cpu(desc.ctrl);
+
+                c->src = desc.src;
+                c->dst = desc.dst;
+                c->llp = desc.next & 0xfffffffc;
+                c->len = desc.size & 0x003fffff;
+                c->ccr = (c->ccr & 0x78f8c081)
+                       | (((desc.ctrl >> 29) & 0x07) << 24)
+                       | ((desc.ctrl & (1 << 28)) ? (1 << 31) : 0)
+                       | (((desc.ctrl >> 25) & 0x07) << 11)
+                       | (((desc.ctrl >> 22) & 0x07) << 8)
+                       | (((desc.ctrl >> 20) & 0x03) << 5)
+                       | (((desc.ctrl >> 18) & 0x03) << 3)
+                       | (((desc.ctrl >> 16) & 0x03) << 1);
+                ftdmac020_chan_ccr_decode(c);
+
+                src = c->src;
+                dst = c->dst;
+            } else {
+                /* clear dma start bit */
+                c->ccr &= 0xfffffffe;
+            }
+        }
+    }
+
+    /* update dma src/dst address */
+    c->src = src;
+    c->dst = dst;
+
+    s->busy = -1;
+}
+
+static void ftdmac020_chan_reset(Ftdmac020Chan *c)
+{
+    c->ccr = 0;
+    c->cfg = 0;
+    c->src = 0;
+    c->dst = 0;
+    c->llp = 0;
+    c->len = 0;
+}
+
+static void ftdmac020_bh(void *opaque)
+{
+    Ftdmac020State *s = FTDMAC020(opaque);
+    Ftdmac020Chan  *c = NULL;
+    int i, jobs, done;
+
+    ++s->bh_owner;
+    jobs = 0;
+    done = 0;
+    for (i = 0; i < 8; ++i) {
+        c = s->chan + i;
+        if (c->ccr & CCR_START) {
+            ++jobs;
+            ftdmac020_chan_start(c);
+            if (!(c->ccr & CCR_START)) {
+                ++done;
+            }
+        }
+    }
+    --s->bh_owner;
+
+    /*
+     * Devices those with an infinite FIFO (always ready for R/W)
+     * would trigger a new DMA handshake transaction here.
+     * (i.e. ftnandc021, ftsdc010)
+     */
+    if ((jobs - done) && s->req) {
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static void ftdmac020_handle_req(void *opaque, int line, int level)
+{
+    Ftdmac020State *s = FTDMAC020(opaque);
+
+    if (level) {
+        /*
+         * Devices those wait for data from externaI/O
+         * would trigger a new DMA handshake transaction here.
+         * (i.e. ftssp010)
+         */
+        if (!(s->req & (1 << line))) {
+            /* a simple workaround for BH reentry issue */
+            if (!s->bh_owner) {
+                qemu_bh_schedule(s->bh);
+            }
+        }
+        s->req |= (1 << line);
+    } else {
+        s->req &= ~(1 << line);
+        qemu_set_irq(s->ack[line], 0);
+    }
+}
+
+static void ftdmac020_chip_reset(Ftdmac020State *s)
+{
+    int i;
+
+    s->tcisr = 0;
+    s->eaisr = 0;
+    s->tcsr = 0;
+    s->easr = 0;
+    s->cesr = 0;
+    s->cbsr = 0;
+    s->csr  = 0;
+    s->sync = 0;
+
+    for (i = 0; i < 8; ++i) {
+        ftdmac020_chan_reset(s->chan + i);
+    }
+
+    /* We can assume our GPIO have been wired up now */
+    for (i = 0; i < 16; ++i) {
+        qemu_set_irq(s->ack[i], 0);
+    }
+    s->req = 0;
+}
+
+static uint64_t ftdmac020_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    Ftdmac020State *s = FTDMAC020(opaque);
+    Ftdmac020Chan  *c = NULL;
+    uint32_t i, ret = 0;
+
+    if (addr < 0x100) {
+        switch (addr) {
+        case REG_ISR:
+            /* 1. Checking TC interrupts */
+            ret |= s->tcisr & 0xff;
+            /* 2. Checking Error interrupts */
+            ret |= s->eaisr & 0xff;
+            /* 3. Checking Abort interrupts */
+            ret |= (s->eaisr >> 16) & 0xff;
+            break;
+        case REG_TCISR:
+            return s->tcisr;
+        case REG_EAISR:
+            return s->eaisr;
+        case REG_TCSR:
+            return s->tcsr;
+        case REG_EASR:
+            return s->easr;
+        case REG_CESR:
+            ret = 0;
+            for (i = 0; i < 8; ++i) {
+                c = s->chan + i;
+                ret |= (c->ccr & 0x01) ? (1 << i) : 0;
+            }
+            break;
+        case REG_CBSR:
+            return (s->busy > 0) ? (1 << s->busy) : 0;
+        case REG_CSR:
+            return s->csr;
+        case REG_SYNC:
+            return s->sync;
+        case REG_REVISION:
+            return 0x00011300;
+        case REG_FEATURE:
+            return 0x00008105;
+        default:
+            break;
+        }
+    } else if (addr < 0x1f8) {
+        c = s->chan + REG_CHAN_ID(addr);
+        switch (addr & 0x1f) {
+        case REG_CHAN_CCR:
+            return c->ccr;
+        case REG_CHAN_CFG:
+            ret = c->cfg;
+            ret |= (s->busy == c->id) ? (1 << 8) : 0;
+            ret |= (c->llp_cnt & 0x0f) << 16;
+            break;
+        case REG_CHAN_SRC:
+            return c->src;
+        case REG_CHAN_DST:
+            return c->dst;
+        case REG_CHAN_LLP:
+            return c->llp;
+        case REG_CHAN_LEN:
+            return c->len;
+        }
+    }
+
+    return ret;
+}
+
+static void ftdmac020_mem_write(void    *opaque,
+                                hwaddr   addr,
+                                uint64_t val,
+                                unsigned size)
+{
+    Ftdmac020State *s = FTDMAC020(opaque);
+    Ftdmac020Chan  *c = NULL;
+
+    if (addr < 0x100) {
+        switch (addr) {
+        case REG_TCCLR:
+            s->tcisr &= ~((uint32_t)val);
+            s->tcsr &= ~((uint32_t)val);
+            ftdmac020_update_irq(s);
+            break;
+        case REG_EACLR:
+            s->eaisr &= ~((uint32_t)val);
+            s->easr &= ~((uint32_t)val);
+            ftdmac020_update_irq(s);
+            break;
+        case REG_CSR:
+            s->csr = (uint32_t)val;
+            break;
+        case REG_SYNC:
+            /* In QEMU, devices are all in the same clock domain
+             * so there is nothing needs to be done.
+             */
+            s->sync = (uint32_t)val;
+            break;
+        default:
+            break;
+        }
+    } else if (addr < 0x1f8) {
+        c = s->chan + REG_CHAN_ID(addr);
+        switch (addr & 0x1f) {
+        case REG_CHAN_CCR:
+            if (!(c->ccr & CCR_START) && (val & CCR_START)) {
+                c->llp_cnt = 0;
+            }
+            c->ccr = (uint32_t)val & 0x87FFBFFF;
+            if (c->ccr & CCR_START) {
+                ftdmac020_chan_ccr_decode(c);
+                /* kick-off DMA engine */
+                qemu_bh_schedule(s->bh);
+            }
+            break;
+        case REG_CHAN_CFG:
+            c->cfg = (uint32_t)val & 0x3eff;
+            break;
+        case REG_CHAN_SRC:
+            c->src = (uint32_t)val;
+            break;
+        case REG_CHAN_DST:
+            c->dst = (uint32_t)val;
+            break;
+        case REG_CHAN_LLP:
+            c->llp = (uint32_t)val & 0xfffffffc;
+            break;
+        case REG_CHAN_LEN:
+            c->len = (uint32_t)val & 0x003fffff;
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+static const MemoryRegionOps ftdmac020_ops = {
+    .read  = ftdmac020_mem_read,
+    .write = ftdmac020_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void ftdmac020_reset(DeviceState *ds)
+{
+    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
+    Ftdmac020State *s = FTDMAC020(FROM_SYSBUS(Ftdmac020State, busdev));
+
+    ftdmac020_chip_reset(s);
+}
+
+static int ftdmac020_init(SysBusDevice *dev)
+{
+    Ftdmac020State *s = FTDMAC020(FROM_SYSBUS(Ftdmac020State, dev));
+    int i;
+
+    memory_region_init_io(&s->iomem,
+                          &ftdmac020_ops,
+                          s,
+                          TYPE_FTDMAC020,
+                          0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    for (i = 0; i < 3; ++i) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+    qdev_init_gpio_in(&s->busdev.qdev, ftdmac020_handle_req, 16);
+    qdev_init_gpio_out(&s->busdev.qdev, s->ack, 16);
+
+    s->busy = -1;
+    s->bh = qemu_bh_new(ftdmac020_bh, s);
+    for (i = 0; i < 8; ++i) {
+        Ftdmac020Chan *c = s->chan + i;
+        c->id   = i;
+        c->chip = s;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_ftdmac020 = {
+    .name = TYPE_FTDMAC020,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(tcisr, Ftdmac020State),
+        VMSTATE_UINT32(eaisr, Ftdmac020State),
+        VMSTATE_UINT32(tcsr, Ftdmac020State),
+        VMSTATE_UINT32(easr, Ftdmac020State),
+        VMSTATE_UINT32(cesr, Ftdmac020State),
+        VMSTATE_UINT32(cbsr, Ftdmac020State),
+        VMSTATE_UINT32(csr, Ftdmac020State),
+        VMSTATE_UINT32(sync, Ftdmac020State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ftdmac020_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init     = ftdmac020_init;
+    dc->vmsd    = &vmstate_ftdmac020;
+    dc->reset   = ftdmac020_reset;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftdmac020_info = {
+    .name           = TYPE_FTDMAC020,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(Ftdmac020State),
+    .class_init     = ftdmac020_class_init,
+};
+
+static void ftdmac020_register_types(void)
+{
+    type_register_static(&ftdmac020_info);
+}
+
+type_init(ftdmac020_register_types)
diff --git a/hw/arm/ftdmac020.h b/hw/arm/ftdmac020.h
new file mode 100644
index 0000000..d9d0431
--- /dev/null
+++ b/hw/arm/ftdmac020.h
@@ -0,0 +1,105 @@
+/*
+ * QEMU model of the FTDMAC020 DMA Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2+.
+ *
+ * Note: The FTDMAC020 decreasing address mode is not implemented.
+ */
+
+#ifndef HW_ARM_FTDMAC020_H
+#define HW_ARM_FTDMAC020_H
+
+#define REG_ISR         0x00    /* Interrupt Status Register */
+#define REG_TCISR       0x04    /* Terminal Count Interrupt Status Register */
+#define REG_TCCLR       0x08    /* Terminal Count Status Clear Register */
+#define REG_EAISR       0x0c    /* Error/Abort Interrupt Status Register */
+#define REG_EACLR       0x10    /* Error/Abort Status Clear Register */
+#define REG_TCSR        0x14    /* Terminal Count Status Register */
+#define REG_EASR        0x18    /* Error/Abort Status Register */
+#define REG_CESR        0x1c    /* Channel Enable Status Register */
+#define REG_CBSR        0x20    /* Channel Busy Status Register */
+#define REG_CSR         0x24    /* Configuration Status Register */
+#define REG_SYNC        0x28    /* Synchronization Register */
+#define REG_REVISION    0x30
+#define REG_FEATURE     0x34
+
+#define REG_CHAN_ID(addr)   (((addr) - 0x100) >> 5)
+#define REG_CHAN_BASE(ch)   (0x100 + ((ch) << 5))
+
+#define REG_CHAN_CCR        0x00
+#define REG_CHAN_CFG        0x04
+#define REG_CHAN_SRC        0x08
+#define REG_CHAN_DST        0x0C
+#define REG_CHAN_LLP        0x10
+#define REG_CHAN_LEN        0x14
+
+/*
+ * Feature register
+ */
+#define FEATURE_NCHAN(f)    (((f) >> 12) & 0xF)
+#define FEATURE_BRIDGE(f)   ((f) & (1 << 10))
+#define FEATURE_DUALBUS(f)  ((f) & (1 << 9))
+#define FEATURE_LLP(f)      ((f) & (1 << 8))
+#define FEATURE_FIFOAW(f)   ((f) & 0xF)
+
+/*
+ * Channel control register
+ */
+#define CCR_START           (1 << 0)
+#define CCR_DST_M1          (1 << 1)
+#define CCR_SRC_M1          (1 << 2)
+#define CCR_DST_INC         (0 << 3)
+#define CCR_DST_DEC         (1 << 3)
+#define CCR_DST_FIXED       (2 << 3)
+#define CCR_SRC_INC         (0 << 5)
+#define CCR_SRC_DEC         (1 << 5)
+#define CCR_SRC_FIXED       (2 << 5)
+#define CCR_HANDSHAKE       (1 << 7)
+#define CCR_DST_WIDTH_8     (0 << 8)
+#define CCR_DST_WIDTH_16    (1 << 8)
+#define CCR_DST_WIDTH_32    (2 << 8)
+#define CCR_DST_WIDTH_64    (3 << 8)
+#define CCR_SRC_WIDTH_8     (0 << 11)
+#define CCR_SRC_WIDTH_16    (1 << 11)
+#define CCR_SRC_WIDTH_32    (2 << 11)
+#define CCR_SRC_WIDTH_64    (3 << 11)
+#define CCR_ABORT           (1 << 15)
+#define CCR_BURST_1         (0 << 16)
+#define CCR_BURST_4         (1 << 16)
+#define CCR_BURST_8         (2 << 16)
+#define CCR_BURST_16        (3 << 16)
+#define CCR_BURST_32        (4 << 16)
+#define CCR_BURST_64        (5 << 16)
+#define CCR_BURST_128       (6 << 16)
+#define CCR_BURST_256       (7 << 16)
+#define CCR_PRIVILEGED      (1 << 19)
+#define CCR_BUFFERABLE      (1 << 20)
+#define CCR_CACHEABLE       (1 << 21)
+#define CCR_PRIO_0          (0 << 22)
+#define CCR_PRIO_1          (1 << 22)
+#define CCR_PRIO_2          (2 << 22)
+#define CCR_PRIO_3          (3 << 22)
+#define CCR_FIFOTH_1        (0 << 24)
+#define CCR_FIFOTH_2        (1 << 24)
+#define CCR_FIFOTH_4        (2 << 24)
+#define CCR_FIFOTH_8        (3 << 24)
+#define CCR_FIFOTH_16       (4 << 24)
+#define CCR_MASK_TC         (1 << 31)
+
+/*
+ * Channel configuration register
+ */
+#define CFG_MASK_TCI            (1 << 0)    /* mask(disable) tc interrupt */
+#define CFG_MASK_EI             (1 << 1)    /* mask(disable) error interrupt */
+#define CFG_MASK_AI             (1 << 2)    /* mask(disable) abort interrupt */
+#define CFG_SRC_HANDSHAKE(x)    (((x) & 0xf) << 3)
+#define CFG_SRC_HANDSHAKE_EN    (1 << 7)
+#define CFG_BUSY                (1 << 8)
+#define CFG_DST_HANDSHAKE(x)    (((x) & 0xf) << 9)
+#define CFG_DST_HANDSHAKE_EN    (1 << 13)
+#define CFG_LLP_CNT(cfg)        (((cfg) >> 16) & 0xf)
+
+#endif    /* __FTDMAC020_H */
