qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 03/18] hw: add QEMU model for Faraday AHB DMA


From: Dante
Subject: [Qemu-devel] [PATCH 03/18] hw: add QEMU model for Faraday AHB DMA
Date: Fri, 18 Jan 2013 14:28:11 +0800

Signed-off-by: Kuo-Jung Su <address@hidden>
---
 hw/ftdmac020.c |  625 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ftdmac020.h |  117 +++++++++++
 2 files changed, 742 insertions(+)
 create mode 100644 hw/ftdmac020.c
 create mode 100644 hw/ftdmac020.h

diff --git a/hw/ftdmac020.c b/hw/ftdmac020.c
new file mode 100644
index 0000000..2841455
--- /dev/null
+++ b/hw/ftdmac020.c
@@ -0,0 +1,625 @@
+/*
+ * QEMU model of the FTDMAC020 DMA Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Copyright (C) 2012 Dante Su <address@hidden>
+ *
+ * Note: The FTDMAC020 decreasing address mode is not implemented.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
+
+#include "ftdmac020.h"
+
+#ifndef min
+#define min(a, b)    ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)    ((a) > (b) ? (a) : (b))
+#endif
+
+typedef struct _ftdmac020_state ftdmac020_state;
+
+/**
+ * struct ftdmac020_lld - 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 _ftdmac020_lld {
+    uint32_t src;
+    uint32_t dst;
+    uint32_t next;
+    uint32_t ctrl;
+    uint32_t size;
+} ftdmac020_lld;
+
+typedef struct _ftdmac020_chan {
+    ftdmac020_state *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;
+} ftdmac020_chan;
+
+typedef struct _ftdmac020_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    
+    ftdmac020_chan chan[8];
+    qemu_irq       ack[16];
+    uint32_t       req;
+
+    int busy;    /* Busy Channel ID */
+    QEMUTimer *qtimer;
+    
+    /* 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;
+} ftdmac020_state;
+
+static inline uint32_t
+ftdmac020_get_isr(ftdmac020_state *s)
+{
+    uint32_t isr = 0;
+
+    /* 1. Checking TC interrupts */
+    isr |= s->tcisr & 0xff;
+    /* 2. Checking Error interrupts */
+    isr |= s->eaisr & 0xff;
+    /* 3. Checking Abort interrupts */
+    isr |= (s->eaisr >> 16) & 0xff;
+    
+    return isr;
+}
+
+static inline void 
+ftdmac020_update_irq(ftdmac020_state *s)
+{
+    uint32_t isr = ftdmac020_get_isr(s);
+    
+    if (isr)
+        qemu_set_irq(s->irq, 1);
+    else
+        qemu_set_irq(s->irq, 0);
+}
+
+static void 
+ftdmac020_chan_ccr_decode(ftdmac020_chan *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(ftdmac020_chan *c)
+{
+    ftdmac020_state *s = c->chip;
+    hwaddr src, dst, src_len, dst_len;
+    int src_hs, dst_hs;
+    uint8_t *src_map = NULL, *dst_map = NULL;
+    uint8_t *src_ptr = NULL, *dst_ptr = NULL;
+    uint8_t buf[4096];
+    ftdmac020_lld desc;
+    int len = 0;
+
+    if (!(c->ccr & 0x01))
+        return;
+
+    s->busy = c->id;
+    
+    src = c->src;
+    dst = c->dst;
+    src_hs = (c->cfg & 0x0080) ? ((c->cfg >> 3) & 0x0f) : -1;
+    dst_hs = (c->cfg & 0x2000) ? ((c->cfg >> 9) & 0x0f) : -1;
+    src_len = c->src_stride ? (c->len * (c->src_bw >> 3)) : (c->src_bw >> 3);
+    dst_len = c->dst_stride ? (c->len * (c->dst_bw >> 3)) : (c->dst_bw >> 3);
+    if (!cpu_physical_memory_is_io(c->src))
+        src_map = src_ptr = cpu_physical_memory_map(c->src, &src_len, 0);
+    if (!cpu_physical_memory_is_io(c->dst))
+        dst_map = dst_ptr = cpu_physical_memory_map(c->dst, &dst_len, 1);
+
+    while (c->len > 0) {
+        
+        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 (src_ptr) {
+            if (c->src_stride) {
+                memcpy(buf, src_ptr, len);
+                src += len;
+                src_ptr += len;
+            } else {
+                int i;
+                switch(c->src_bw) {
+                case 8:
+                    for (i = 0; i < len; i += 1)
+                        *(uint8_t *)(buf + i) = *(uint8_t *)src_ptr;
+                    break;
+                case 16:
+                    for (i = 0; i < len; i += 2)
+                        *(uint16_t *)(buf + i) = *(uint16_t *)src_ptr;
+                    break;
+                case 32:
+                    for (i = 0; i < len; i += 4)
+                        *(uint32_t *)(buf + i) = *(uint32_t *)src_ptr;
+                    break;
+                default:
+                    for (i = 0; i < len; i += 8)
+                        *(uint64_t *)(buf + i) = *(uint64_t *)src_ptr;
+                    break;
+                }
+            }
+        } else {
+            uint32_t rl, stride = c->src_bw >> 3;
+            for (rl = 0; rl < len; rl += stride, src += c->src_stride)
+                cpu_physical_memory_read(src, (uint64_t *)(buf + rl), stride);
+        }
+
+        /* DMA Hardware Handshake */
+        if (src_hs >= 0) {
+            qemu_set_irq(s->ack[src_hs], 1);
+        }
+
+        /* store data into destination from local buffer */
+        if (dst_ptr) {
+            if (c->dst_stride) {
+                memcpy(dst_ptr, buf, len);
+                dst += len;
+                dst_ptr += len;
+            } else {
+                int i;
+                switch(c->dst_bw) {
+                case 8:
+                    for (i = 0; i < len; i += 1)
+                        *(uint8_t *)dst_ptr = *(uint8_t *)(buf + i);
+                    break;
+                case 16:
+                    for (i = 0; i < len; i += 2)
+                        *(uint16_t *)dst_ptr = *(uint16_t *)(buf + i);
+                    break;
+                case 32:
+                    for (i = 0; i < len; i += 4)
+                        *(uint32_t *)dst_ptr = *(uint32_t *)(buf + i);
+                    break;
+                default:
+                    for (i = 0; i < len; i += 8)
+                        *(uint64_t *)dst_ptr = *(uint64_t *)(buf + i);
+                    break;
+                }
+            }
+        } else {
+            uint32_t wl, stride = c->dst_bw >> 3;
+            for (wl = 0; wl < len; wl += stride, dst += c->dst_stride)
+                cpu_physical_memory_write(dst, (uint64_t *)(buf + wl), 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) {
+            /* release the memory mappings */
+            if (src_map) {
+                cpu_physical_memory_unmap(src_map, src_len, 0, 
(hwaddr)(src_ptr - src_map));
+                src_map = src_ptr = NULL;
+            }
+            if (dst_map) {
+                cpu_physical_memory_unmap(dst_map, dst_len, 1, 
(hwaddr)(dst_ptr - dst_map));
+                dst_map = dst_ptr = NULL;
+            }
+            /* update the channel transfer status */
+            if (!(c->ccr & (1 << 31))) {
+                s->tcsr |= (1 << c->id);
+                if (!(c->cfg & 0x01))
+                    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));
+                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;
+                src_len = c->src_stride ? (c->len * (c->src_bw >> 3)) : 
(c->src_bw >> 3);
+                dst_len = c->dst_stride ? (c->len * (c->dst_bw >> 3)) : 
(c->dst_bw >> 3);
+                if (!cpu_physical_memory_is_io(c->src))
+                    src_map = src_ptr = cpu_physical_memory_map(c->src, 
&src_len, 0);
+                if (!cpu_physical_memory_is_io(c->dst))
+                    dst_map = dst_ptr = cpu_physical_memory_map(c->dst, 
&dst_len, 1);
+            } else {
+                /* clear dma start bit */
+                c->ccr &= 0xfffffffe;
+            }
+        }
+    }
+    
+    /* release the memory mappings */
+    if (src_map)
+        cpu_physical_memory_unmap(src_map, src_len, 0, (hwaddr)(src_ptr - 
src_map));
+    if (dst_map)
+        cpu_physical_memory_unmap(dst_map, dst_len, 1, (hwaddr)(dst_ptr - 
dst_map));
+
+    /* update dma src/dst address */
+    c->src = src;
+    c->dst = dst;
+    
+    s->busy = -1;
+}
+
+static void 
+ftdmac020_chan_reset(ftdmac020_chan *c)
+{
+    c->ccr = 0;
+    c->cfg = 0;
+    c->src = 0;
+    c->dst = 0;
+    c->llp = 0;
+    c->len = 0;
+}
+
+static void 
+ftdmac020_timer_tick(void *opaque)
+{
+    ftdmac020_state *s = (ftdmac020_state *)opaque;
+    ftdmac020_chan *c = NULL;
+    int i, jobs, done;
+    
+    jobs = 0;
+    done = 0;
+    for (i = 0; i < 8; ++i) {
+        c = s->chan + i;
+        if (c->ccr & 0x01) {
+            ++jobs;
+            ftdmac020_chan_start(c);
+            if (!(c->ccr & 0x01))
+                ++done;
+        }
+    }
+
+    /* ToDo: Use mutex to skip this periodic checker */
+    if (jobs - done > 0) {
+        qemu_mod_timer(s->qtimer, qemu_get_clock_ns(vm_clock) + 1);
+    } else {
+        qemu_mod_timer(s->qtimer, qemu_get_clock_ns(vm_clock) + 
(get_ticks_per_sec() >> 2));
+    }
+}
+
+static void 
+ftdmac020_handle_req(void *opaque, int line, int level)
+{
+    ftdmac020_state *s = (ftdmac020_state *)opaque;
+
+    if (level) {
+        s->req |= (1 << line);
+    } else {
+        s->req &= ~(1 << line);
+        qemu_set_irq(s->ack[line], 0);
+    }
+}
+
+static void ftdmac020_chip_reset(ftdmac020_state *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 int size)
+{
+    ftdmac020_state *s = opaque;
+    ftdmac020_chan  *c = NULL;
+    uint32_t i, ret = 0;
+    
+    if (addr < 0x100) {
+        switch(addr) {
+        case REG_ISR:
+            return ftdmac020_get_isr(s);
+        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 int size)
+{
+    ftdmac020_state *s = opaque;
+    ftdmac020_chan  *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 & 0x01) && (val & 0x01)) {
+                c->llp_cnt = 0;
+            }
+            c->ccr = (uint32_t)val & 0x87FFBFFF;
+            if (c->ccr & 0x01) {
+                ftdmac020_chan_ccr_decode(c);
+                /* kick-off DMA engine */
+                qemu_mod_timer(s->qtimer, qemu_get_clock_ns(vm_clock) + 1);
+            }
+            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_mem_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 *d)
+{
+    ftdmac020_state *s = DO_UPCAST(ftdmac020_state, busdev.qdev, d);
+    ftdmac020_chip_reset(s);
+}
+
+static int ftdmac020_init(SysBusDevice *dev)
+{
+    ftdmac020_state *s = FROM_SYSBUS(typeof(*s), dev);
+    int i;
+
+    memory_region_init_io(&s->iomem, &ftdmac020_mem_ops, s, "ftdmac020", 
0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    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->qtimer = qemu_new_timer_ns(vm_clock, ftdmac020_timer_tick, s);
+    for (i = 0; i < 8; ++i) {
+        ftdmac020_chan *c = s->chan + i;
+        c->id   = i;
+        c->chip = s;
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_ftdmac020 = {
+    .name = "ftdmac020",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(tcisr, ftdmac020_state),
+        VMSTATE_UINT32(eaisr, ftdmac020_state),
+        VMSTATE_UINT32(tcsr, ftdmac020_state),
+        VMSTATE_UINT32(easr, ftdmac020_state),
+        VMSTATE_UINT32(cesr, ftdmac020_state),
+        VMSTATE_UINT32(cbsr, ftdmac020_state),
+        VMSTATE_UINT32(csr, ftdmac020_state),
+        VMSTATE_UINT32(sync, ftdmac020_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ftdmac020_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    sdc->init  = ftdmac020_init;
+    k->vmsd    = &vmstate_ftdmac020;
+    k->reset   = ftdmac020_reset;
+    k->no_user = 1;
+}
+
+static TypeInfo ftdmac020_info = {
+    .name           = "ftdmac020",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(ftdmac020_state),
+    .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/ftdmac020.h b/hw/ftdmac020.h
new file mode 100644
index 0000000..75df3bc
--- /dev/null
+++ b/hw/ftdmac020.h
@@ -0,0 +1,117 @@
+/*
+ *  arch/arm/mach-faraday/drivers/ftdmac020.h
+ *
+ *  Faraday FTDMAC020 DMA controller
+ *
+ *  Copyright (C) 2010 Faraday Technology
+ *  Copyright (C) 2011 Dante Su <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __FTDMAC020_H
+#define __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_ENABLE                (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 tc interrupt */
+#define CFG_MASK_EI                (1 << 1)    /* mask error interrupt */
+#define CFG_MASK_AI                (1 << 2)    /* mask 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 */
-- 
1.7.9.5


********************* Confidentiality Notice ************************
This electronic message and any attachments may contain
confidential and legally privileged information or
information which is otherwise protected from disclosure.
If you are not the intended recipient,please do not disclose
the contents, either in whole or in part, to anyone,and
immediately delete the message and any attachments from
your computer system and destroy all hard copies.
Thank you for your cooperation.
***********************************************************************




reply via email to

[Prev in Thread] Current Thread [Next in Thread]