aboutsummaryrefslogtreecommitdiff
path: root/sim
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2011-06-03 01:13:45 -0400
committerMike Frysinger <vapier@gentoo.org>2024-01-01 18:23:26 -0500
commitcba5f2973b1db4d3ee176c4459a735f281b9dd58 (patch)
tree147c72b9b071bb88bc2cbb81eef2962c77efbbbb /sim
parentb444dcd4b1abad6e39719bef21467d2b764c0edb (diff)
downloadgdb-cba5f2973b1db4d3ee176c4459a735f281b9dd58.zip
gdb-cba5f2973b1db4d3ee176c4459a735f281b9dd58.tar.gz
gdb-cba5f2973b1db4d3ee176c4459a735f281b9dd58.tar.bz2
sim: bfin: add new DDE (distributed DMA engine) model (bf60x)
This models the new DMA controller found on BF60x processors.
Diffstat (limited to 'sim')
-rw-r--r--sim/bfin/dv-bfin_dde.c595
-rw-r--r--sim/bfin/dv-bfin_dde.h109
-rw-r--r--sim/bfin/local.mk1
-rw-r--r--sim/bfin/machs.c66
-rw-r--r--sim/bfin/machs.h1
5 files changed, 772 insertions, 0 deletions
diff --git a/sim/bfin/dv-bfin_dde.c b/sim/bfin/dv-bfin_dde.c
new file mode 100644
index 0000000..3b4aecc
--- /dev/null
+++ b/sim/bfin/dv-bfin_dde.c
@@ -0,0 +1,595 @@
+/* Blackfin Distributed DMA Engine (DDE) model.
+
+ Copyright (C) 2010-2016 Free Software Foundation, Inc.
+ Contributed by Analog Devices, Inc.
+
+ This file is part of simulators.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+
+#include "sim-main.h"
+#include "devices.h"
+#include "hw-device.h"
+#include "dv-bfin_dde.h"
+
+/* Note: This DMA implementation requires the producer to be the master when
+ the peer is MDMA. The source is always a slave. This way we don't
+ have the two DMA devices thrashing each other with one trying to
+ write and the other trying to read. */
+
+struct bfin_dde
+{
+ /* This top portion matches common dv_bfin struct. */
+ bu32 base;
+ struct hw *dma_master;
+ bool acked;
+
+ struct hw_event *handler;
+ unsigned psize, msize;
+ struct hw *peer;
+
+ /* Order after here is important -- matches hardware MMR layout. */
+ bu32 descpnext;
+ bu32 addrstart;
+ bu32 config;
+ bu32 xcount;
+ bu32 xmodify;
+ bu32 ycount;
+ bu32 ymodify;
+ bu32 _pad0[2];
+ bu32 descpcurr;
+ bu32 descpprev;
+ bu32 addrcurr;
+ bu32 status;
+ bu32 xcountcurr;
+ bu32 ycountcurr;
+ bu32 _pad1;
+ bu32 bwlcount;
+ bu32 bwlcountcur;
+ bu32 bwmcount;
+ bu32 bwmcountcur;
+};
+#define mmr_base() offsetof(struct bfin_dde, descpnext)
+#define mmr_offset(mmr) (offsetof(struct bfin_dde, mmr) - mmr_base())
+#define mmr_idx(mmr) (mmr_offset (mmr) / 4)
+
+static const char * const mmr_names[] =
+{
+ "DESCPNEXT", "ADDRSTART", "CONFIG", "XCOUNT", "XMODIFY", "YCOUNT", "YMODIFY",
+ [mmr_idx (descpcurr)] = "DESCPCURR", "DESCPPREV", "ADDRCURR", "STATUS",
+ "XCOUNTCURR", "YCOUNTCURR",
+ [mmr_idx (bwlcount)] = "BWLCOUNT", "BWLCOUNTCUR", "BWMCOUNT", "BWMCOUNTCUR",
+};
+#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
+
+static bool
+bfin_dde_enabled (struct bfin_dde *dde)
+{
+ return (dde->config & DMAEN);
+}
+
+static bool
+bfin_dde_running (struct bfin_dde *dde)
+{
+ return (dde->status & DMA_RUN);
+}
+
+static void
+bfin_dde_process_desc (struct hw *me, struct bfin_dde *dde)
+{
+ unsigned psize, msize;
+ bu8 ndsize = (dde->config & NDSIZE) >> NDSIZE_P;
+ bu16 _flows[9], *flows = _flows;
+
+ HW_TRACE ((me, "dma starting up %#x", dde->config));
+
+ /* Figure out transfer size to memory. */
+ dde->msize = (dde->config & MSIZE) >> MSIZE_P;
+ if (dde->msize > DDE_MSIZE_MAX)
+ hw_abort (me, "DMA config error: invalid MSIZE %#x", dde->msize);
+ msize = (dde->status & DMA_MBWIDTH) >> DMA_MBWIDTH_P;
+ if (dde->msize > msize)
+ hw_abort (me, "DMA config error: MSIZE %#x is larger than hw %#x",
+ dde->msize, msize);
+ dde->msize = 1 << dde->msize;
+
+ /* Figure out transfer size to peripheral peer. */
+ dde->psize = (dde->config & PSIZE) >> PSIZE_P;
+ if (dde->psize > DDE_PSIZE_MAX)
+ hw_abort (me, "DMA config error: invalid PSIZE %#x", dde->psize);
+ psize = (dde->status & DMA_PBWIDTH) >> DMA_PBWIDTH_P;
+ if (dde->psize > psize)
+ hw_abort (me, "DMA config error: PSIZE %#x is larger than hw %#x",
+ dde->psize, psize);
+ dde->psize = 1 << dde->psize;
+
+ /* Address has to be mutiple of transfer size. */
+ if (dde->addrstart & (dde->msize - 1))
+ dde->status |= DMA_ERR;
+
+ /* Verify 2D sanity. */
+ if ((dde->config & TWOD) && dde->ycount == 0)
+ hw_abort (me, "DMA config error: 2D dma requires non-zero ycount");
+
+ if (dde->msize != (unsigned) abs (dde->xmodify))
+ hw_abort (me, "DMA config (striding) %#x not supported (xmodify: %d)",
+ dde->config, dde->xmodify);
+
+ switch (dde->config & FLOW)
+ {
+ case FLOW_AUTO:
+ case FLOW_STOP:
+ if (ndsize)
+ hw_abort (me, "DMA config error: FLOW_{AUTO,STOP} requires NDSIZE_0");
+ break;
+ case FLOW_DSCL:
+ case FLOW_DSCA:
+ case FLOW_DSDL:
+ case FLOW_DSDA:
+ hw_abort (me, "DMA flow (%#x) not supported yet", dde->config & FLOW);
+ break;
+ default:
+ hw_abort (me, "DMA config error: invalid FLOW %#x", dde->config);
+ }
+
+ if (ndsize)
+ {
+#if 0
+ bu8 idx;
+ bu16 *stores[] = {
+ &dde->sal,
+ &dde->sah,
+ &dde->config,
+ &dde->xcount,
+ (void *) &dde->xmodify,
+ &dde->ycount,
+ (void *) &dde->ymodify,
+ };
+
+ switch (dde->config & FLOW)
+ {
+ case DMAFLOW_LARGE:
+ dde->ndph = _flows[1];
+ --ndsize;
+ ++flows;
+ case DMAFLOW_SMALL:
+ dde->ndpl = _flows[0];
+ --ndsize;
+ ++flows;
+ break;
+ }
+
+ for (idx = 0; idx < ndsize; ++idx)
+ *stores[idx] = flows[idx];
+#endif
+ }
+
+ dde->descpcurr = dde->descpnext;
+ dde->addrcurr = dde->addrstart;
+ dde->xcountcurr = dde->xcount;
+ dde->ycountcurr = dde->ycount;
+}
+
+static int
+bfin_dde_finish_x (struct hw *me, struct bfin_dde *dde)
+{
+ /* XXX: This would be the time to process the next descriptor. */
+ /* XXX: Should this toggle Enable in dde->config ? */
+
+ if ((dde->config & INT) == INT_X)
+ hw_port_event (me, 0, 1);
+
+ if (dde->config & TWOD)
+ {
+ if (dde->ycountcurr > 1)
+ {
+ dde->ycountcurr -= 1;
+ dde->xcountcurr = dde->xcount;
+
+ /* With 2D, last X transfer does not modify addrcurr. */
+ dde->addrcurr = dde->addrcurr - dde->xmodify + dde->ymodify;
+
+ return 1;
+ }
+ else if ((dde->config & INT) == INT_Y)
+ hw_port_event (me, 0, 1);
+ }
+
+ switch (dde->config & FLOW)
+ {
+ case FLOW_STOP:
+ HW_TRACE ((me, "dma is complete"));
+ dde->status = (dde->status & ~DMA_RUN) | DMA_DONE;
+ return 0;
+ default:
+ bfin_dde_process_desc (me, dde);
+ return 1;
+ }
+}
+
+static void bfin_dde_hw_event_callback (struct hw *, void *);
+
+static void
+bfin_dde_reschedule (struct hw *me, unsigned delay)
+{
+ struct bfin_dde *dde = hw_data (me);
+ if (dde->handler)
+ {
+ hw_event_queue_deschedule (me, dde->handler);
+ dde->handler = NULL;
+ }
+ if (!delay)
+ return;
+ HW_TRACE ((me, "scheduling next process in %u", delay));
+ dde->handler = hw_event_queue_schedule (me, delay,
+ bfin_dde_hw_event_callback, dde);
+}
+
+/* Chew through the DMA over and over. */
+static void
+bfin_dde_hw_event_callback (struct hw *me, void *data)
+{
+ struct bfin_dde *dde = data;
+ struct hw *peer;
+ struct dv_bfin *bfin_peer;
+ bu8 buf[4096];
+ unsigned ret, nr_bytes, ele_count, ele_size;
+
+ dde->handler = NULL;
+ ret = 0;
+
+ peer = dde->peer;
+ if (!peer)
+ hw_abort (me, "unable to locate peer");
+ bfin_peer = hw_data (peer);
+
+ /* XXX: This isn't exactly right, but close enough. */
+ ele_size = (dde->config & WNR) ? dde->psize : dde->msize;
+ if (dde->xmodify < 0)
+ /* XXX: This sucks performance wise. */
+ nr_bytes = ele_size;
+ else
+ nr_bytes = min (sizeof (buf), dde->xcountcurr * ele_size);
+
+ /* Pumping a chunk! */
+ bfin_peer->dma_master = me;
+ bfin_peer->acked = false;
+ if (dde->config & WNR)
+ {
+ HW_TRACE ((me, "dma transfer to 0x%08lx length %u",
+ (unsigned long) dde->addrcurr, nr_bytes));
+
+ ret = hw_dma_read_buffer (peer, buf, 0, dde->addrcurr, nr_bytes);
+ /* Has the DMA stalled ? abort for now. */
+ if (ret == 0)
+ goto reschedule;
+ /* XXX: How to handle partial DMA transfers ? */
+ if (ret % ele_size)
+ goto error;
+ ret = sim_write (hw_system (me), dde->addrcurr, buf, ret);
+ }
+ else
+ {
+ HW_TRACE ((me, "dma transfer from 0x%08lx length %u",
+ (unsigned long) dde->addrcurr, nr_bytes));
+
+ ret = sim_read (hw_system (me), dde->addrcurr, buf, nr_bytes);
+ if (ret == 0)
+ goto reschedule;
+ /* XXX: How to handle partial DMA transfers ? */
+ if (ret % ele_size)
+ goto error;
+ ret = hw_dma_write_buffer (peer, buf, 0, dde->addrcurr, ret, 0);
+ if (ret == 0)
+ goto reschedule;
+ }
+
+ /* Ignore partial writes. */
+ ele_count = ret / ele_size;
+ dde->addrcurr += ele_count * dde->xmodify;
+ dde->xcountcurr -= ele_count;
+
+ if ((!dde->acked && dde->xcountcurr) || bfin_dde_finish_x (me, dde))
+ /* Still got work to do, so schedule again. */
+ reschedule:
+ bfin_dde_reschedule (me, ret ? 1 : 5000);
+
+ return;
+
+ error:
+ /* Don't reschedule on errors ... */
+ dde->status |= DMA_ERR;
+}
+
+static unsigned
+bfin_dde_io_write_buffer (struct hw *me, const void *source, int space,
+ address_word addr, unsigned nr_bytes)
+{
+ struct bfin_dde *dde = hw_data (me);
+ bu32 mmr_off;
+ bu32 value;
+ bu32 *valuep;
+
+ value = dv_load_4 (source);
+ mmr_off = addr % dde->base;
+ valuep = (void *)((unsigned long)dde + mmr_base() + mmr_off);
+
+ HW_TRACE_WRITE ();
+
+ dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
+
+ /* XXX: All registers are RO when DMA is enabled (except IRQ_STATUS).
+ But does the HW discard writes or send up IVGHW ? The sim
+ simply discards atm ... */
+ switch (mmr_off)
+ {
+ case mmr_offset(descpnext):
+ case mmr_offset(addrstart):
+ case mmr_offset(descpcurr):
+ case mmr_offset(addrcurr):
+ if (!bfin_dde_running (dde))
+ *valuep = value;
+ else
+ HW_TRACE ((me, "discarding write while dma running"));
+ break;
+ case mmr_offset(xcount):
+ case mmr_offset(xmodify):
+ case mmr_offset(ycount):
+ case mmr_offset(ymodify):
+ if (!bfin_dde_running (dde))
+ *valuep = value;
+ break;
+ case mmr_offset(config):
+ /* XXX: How to handle updating CONFIG of a running channel ? */
+ *valuep = value;
+
+ if (bfin_dde_enabled (dde))
+ {
+ dde->status |= DMA_RUN;
+ bfin_dde_process_desc (me, dde);
+ /* The writer is the master. */
+ if (dde->config & WNR)
+ bfin_dde_reschedule (me, 1);
+ }
+ else
+ {
+ dde->status &= ~DMA_RUN;
+ bfin_dde_reschedule (me, 0);
+ }
+ break;
+ case mmr_offset(status):
+ dv_w1c_4 (valuep, value, DMA_DONE | DMA_ERR | DMA_PIRQ);
+ break;
+ case mmr_offset(xcountcurr):
+ case mmr_offset(ycountcurr):
+ if (!bfin_dde_running (dde))
+ *valuep = value;
+ else
+ HW_TRACE ((me, "discarding write while dma running"));
+ break;
+ default:
+ /* XXX: The HW lets the pad regions be read/written ... */
+ dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
+ break;
+ }
+
+ return nr_bytes;
+}
+
+static unsigned
+bfin_dde_io_read_buffer (struct hw *me, void *dest, int space,
+ address_word addr, unsigned nr_bytes)
+{
+ struct bfin_dde *dde = hw_data (me);
+ bu32 mmr_off;
+ bu32 *valuep;
+
+ mmr_off = addr % dde->base;
+ valuep = (void *)((unsigned long)dde + mmr_base() + mmr_off);
+
+ HW_TRACE_READ ();
+
+ dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
+
+ switch (mmr_off)
+ {
+ case mmr_offset(descpnext):
+ case mmr_offset(addrstart):
+ case mmr_offset(config):
+ case mmr_offset(xcount):
+ case mmr_offset(xmodify):
+ case mmr_offset(ycount):
+ case mmr_offset(ymodify):
+ case mmr_offset(descpcurr):
+ case mmr_offset(descpprev):
+ case mmr_offset(addrcurr):
+ case mmr_offset(status):
+ case mmr_offset(xcountcurr):
+ case mmr_offset(ycountcurr):
+ case mmr_offset(bwlcount):
+ case mmr_offset(bwlcountcur):
+ case mmr_offset(bwmcount):
+ case mmr_offset(bwmcountcur):
+ dv_store_4 (dest, *valuep);
+ break;
+ default:
+ /* XXX: The HW lets the pad regions be read/written ... */
+ dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
+ break;
+ }
+
+ return nr_bytes;
+}
+
+static unsigned
+bfin_dde_dma_read_buffer (struct hw *me, void *dest, int space,
+ unsigned_word addr, unsigned nr_bytes)
+{
+ struct bfin_dde *dde = hw_data (me);
+ unsigned ret, ele_count;
+
+ HW_TRACE_DMA_READ ();
+
+ /* If someone is trying to read from me, I have to be enabled. */
+ if (!bfin_dde_enabled (dde) && !bfin_dde_running (dde))
+ return 0;
+
+ /* XXX: handle xmodify ... */
+ ret = sim_read (hw_system (me), dde->addrcurr, dest, nr_bytes);
+ /* Ignore partial writes. */
+ ele_count = ret / dde->msize;
+ /* Has the DMA stalled ? abort for now. */
+ if (!ele_count)
+ return 0;
+
+ dde->addrcurr += ele_count * dde->xmodify;
+ dde->xcountcurr -= ele_count;
+
+ if (dde->xcountcurr == 0)
+ bfin_dde_finish_x (me, dde);
+
+ return ret;
+}
+
+static unsigned
+bfin_dde_dma_write_buffer (struct hw *me, const void *source,
+ int space, unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ struct bfin_dde *dde = hw_data (me);
+ unsigned ret, ele_count;
+
+ HW_TRACE_DMA_WRITE ();
+
+ /* If someone is trying to write to me, I have to be enabled. */
+ if (!bfin_dde_enabled (dde) && !bfin_dde_running (dde))
+ return 0;
+
+ /* XXX: handle xmodify ... */
+ ret = sim_write (hw_system (me), dde->addrcurr, source, nr_bytes);
+ /* Ignore partial writes. */
+ ele_count = ret / dde->psize;
+ /* Has the DMA stalled ? abort for now. */
+ if (!ele_count)
+ return 0;
+
+ dde->addrcurr += ele_count * dde->xmodify;
+ dde->xcountcurr -= ele_count;
+
+ if (dde->xcountcurr == 0)
+ bfin_dde_finish_x (me, dde);
+
+ return ret;
+}
+
+static const struct hw_port_descriptor bfin_dde_ports[] =
+{
+ { "di", 0, 0, output_port, }, /* DMA Interrupt */
+ { "pi", 0, 0, input_port, }, /* Peripheral Interrupt */
+ { NULL, 0, 0, 0, },
+};
+
+static void
+bfin_dde_port_event (struct hw *me, int my_port, struct hw *source,
+ int source_port, int level)
+{
+ struct bfin_dde *dde = hw_data (me);
+
+ /* Have the DMA channel raise its interrupt to the SEC. */
+ if ((dde->config & INT) == INT_PER)
+ hw_port_event (me, 0, 1);
+}
+
+static void
+attach_bfin_dde_regs (struct hw *me, struct bfin_dde *dde)
+{
+ address_word attach_address;
+ int attach_space;
+ unsigned attach_size;
+ reg_property_spec reg;
+ const char *peer;
+ char path[100];
+ unsigned mwidth, pwidth;
+
+ if (hw_find_property (me, "reg") == NULL)
+ hw_abort (me, "Missing \"reg\" property");
+
+ if (hw_find_property (me, "peer") == NULL)
+ hw_abort (me, "Missing \"peer\" property");
+
+ if (hw_find_property (me, "mwidth") == NULL)
+ hw_abort (me, "Missing \"mwidth\" property");
+
+ if (hw_find_property (me, "pwidth") == NULL)
+ hw_abort (me, "Missing \"pwidth\" property");
+
+ if (!hw_find_reg_array_property (me, "reg", 0, &reg))
+ hw_abort (me, "\"reg\" property must contain three addr/size entries");
+
+ hw_unit_address_to_attach_address (hw_parent (me),
+ &reg.address,
+ &attach_space, &attach_address, me);
+ hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
+
+ if (attach_size != BFIN_MMR_DDE_SIZE)
+ hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_DDE_SIZE);
+
+ hw_attach_address (hw_parent (me),
+ 0, attach_space, attach_address, attach_size, me);
+
+ dde->base = attach_address;
+
+ peer = hw_find_string_property (me, "peer");
+ sprintf (path, "/core/%s", peer);
+ dde->peer = hw_tree_find_device (me, path);
+
+ mwidth = hw_find_integer_property (me, "mwidth");
+ if (mwidth > DDE_MWIDTH_MAX)
+ hw_abort (me, "\"mwidth\" must be between 0 and %i inclusive",
+ DDE_MWIDTH_MAX);
+ dde->status |= mwidth << DMA_MBWIDTH_P;
+
+ pwidth = hw_find_integer_property (me, "pwidth");
+ if (pwidth > DDE_PWIDTH_MAX)
+ hw_abort (me, "\"pwidth\" must be between 0 and %i inclusive",
+ DDE_PWIDTH_MAX);
+ dde->status |= pwidth << DMA_PBWIDTH_P;
+}
+
+static void
+bfin_dde_finish (struct hw *me)
+{
+ struct bfin_dde *dde;
+
+ dde = HW_ZALLOC (me, struct bfin_dde);
+
+ set_hw_data (me, dde);
+ set_hw_io_read_buffer (me, bfin_dde_io_read_buffer);
+ set_hw_io_write_buffer (me, bfin_dde_io_write_buffer);
+ set_hw_dma_read_buffer (me, bfin_dde_dma_read_buffer);
+ set_hw_dma_write_buffer (me, bfin_dde_dma_write_buffer);
+ set_hw_ports (me, bfin_dde_ports);
+ set_hw_port_event (me, bfin_dde_port_event);
+
+ attach_bfin_dde_regs (me, dde);
+}
+
+const struct hw_descriptor dv_bfin_dde_descriptor[] =
+{
+ {"bfin_dde", bfin_dde_finish,},
+ {NULL, NULL},
+};
diff --git a/sim/bfin/dv-bfin_dde.h b/sim/bfin/dv-bfin_dde.h
new file mode 100644
index 0000000..f7bf8a5
--- /dev/null
+++ b/sim/bfin/dv-bfin_dde.h
@@ -0,0 +1,109 @@
+/* Blackfin Distributed DMA Engine (DDE) model.
+
+ Copyright (C) 2010-2016 Free Software Foundation, Inc.
+ Contributed by Analog Devices, Inc.
+
+ This file is part of simulators.
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef DV_BFIN_DDE_H
+#define DV_BFIN_DDE_H
+
+#define DDE_PSIZE_MAX 3
+#define DDE_MSIZE_MAX 5
+#define DDE_PWIDTH_MAX 3
+#define DDE_MWIDTH_MAX 3
+
+/* DMA_CONFIG Masks */
+#define DMAEN (1 << DMAEN_P) /* DMA Channel Enable */
+#define WNR (1 << WNR_P) /* Channel Direction (W/R*) */
+#define SYNC (1 << SYNC_P) /* Synchronize Work Unit Transitions */
+#define CADDR (1 << CADDR_P) /* Use Current Address */
+#define PSIZE (7 << PSIZE_P) /* Peripheral Word Size */
+#define PSIZE_1 (0 << PSIZE_P)
+#define PSIZE_2 (1 << PSIZE_P)
+#define PSIZE_4 (2 << PSIZE_P)
+#define PSIZE_8 (3 << PSIZE_P)
+#define MSIZE (7 << MSIZE_P) /* Memory Transfer Size */
+#define MSIZE_1 (0 << MSIZE_P)
+#define MSIZE_2 (1 << MSIZE_P)
+#define MSIZE_4 (2 << MSIZE_P)
+#define MSIZE_8 (3 << MSIZE_P)
+#define MSIZE_16 (4 << MSIZE_P)
+#define MSIZE_32 (5 << MSIZE_P)
+#define FLOW (7 << FLOW_P) /* Next Operation */
+#define FLOW_STOP (0 << FLOW_P) /* Stop Mode */
+#define FLOW_AUTO (1 << FLOW_P) /* Autobuffer Mode */
+#define FLOW_DSCL (4 << FLOW_P) /* Descriptor List */
+#define FLOW_DSCA (5 << FLOW_P) /* Descriptor Array */
+#define FLOW_DSDL (6 << FLOW_P) /* Descriptor On Demand List */
+#define FLOW_DSDA (7 << FLOW_P) /* Descriptor On Demand Array */
+#define NDSIZE (7 << NDSIZE_P) /* Next Descriptor Set Size */
+#define NDSIZE_1 (0 << NDSIZE_P)
+#define NDSIZE_2 (1 << NDSIZE_P)
+#define NDSIZE_3 (2 << NDSIZE_P)
+#define NDSIZE_4 (3 << NDSIZE_P)
+#define NDSIZE_5 (4 << NDSIZE_P)
+#define NDSIZE_6 (5 << NDSIZE_P)
+#define NDSIZE_7 (6 << NDSIZE_P)
+#define INT (3 << INT_P) /* Generate Interrupt */
+#define INT_NEVER (0 << INT_P) /* ... never */
+#define INT_X (1 << INT_P) /* ... when xcount is 0 */
+#define INT_Y (2 << INT_P) /* ... when ycount is 0 */
+#define INT_PER (3 << INT_P) /* ... forwarding peripherals */
+#define TRIG (3 << TRIG_P) /* Generate Trigger */
+#define TOVEN (1 << TOVEN_P)
+#define DESCIDCPY (1 << DESCIDCPY_P)
+#define TWOD (1 << TWOD_P)
+#define PDRF (1 << PDRF_P)
+
+#define DMAEN_P 0
+#define WNR_P 1
+#define SYNC_P 2
+#define CADDR_P 3
+#define PSIZE_P 4
+#define MSIZE_P 8
+#define FLOW_P 12
+#define TWAIT_P 15
+#define NDSIZE_P 16
+#define INT_P 20
+#define TRIG_P 22
+#define TOVEN_P 24
+#define DESCIDCPY_P 25
+#define TWOD_P 26
+#define PDRF_P 28
+
+/* DMA_STATUS Masks */
+#define DMA_DONE (1 << DMA_DONE_P) /* Work Unit/Row Done Interrupt */
+#define DMA_ERR (1 << DMA_ERR_P) /* Error Interrupt */
+#define DMA_PIRQ (1 << DMA_PIRQ_P) /* Peripheral Interrupt Request */
+#define DMA_ERRC (7 << DMA_ERRC_P) /* Error Cause */
+#define DMA_RUN (7 << DMA_RUN_P) /* Run Status */
+#define DMA_PBWIDTH (3 << DMA_PBWIDTH_P) /* Peripheral Bus Width */
+#define DMA_MBWIDTH (3 << DMA_MBWIDTH_P) /* Memory Bus Width */
+#define DMA_FIFOFILL (7 << DMA_FIFOFILL_P) /* FIFO Fill Status */
+#define DMA_TWAIT (1 << DMA_TWAIT_P) /* Trigger Wait Status */
+
+#define DMA_DONE_P 0
+#define DMA_ERR_P 1
+#define DMA_PIRQ_P 2
+#define DMA_ERRC_P 4
+#define DMA_RUN_P 8
+#define DMA_PBWIDTH_P 12
+#define DMA_MBWIDTH_P 14
+#define DMA_FIFOFILL_P 16
+#define DMA_TWAIT_P 20
+
+#endif
diff --git a/sim/bfin/local.mk b/sim/bfin/local.mk
index 4c0b661..820eabf 100644
--- a/sim/bfin/local.mk
+++ b/sim/bfin/local.mk
@@ -54,6 +54,7 @@ noinst_PROGRAMS += %D%/run
bfin_cec \
bfin_cgu \
bfin_ctimer \
+ bfin_dde \
bfin_dma \
bfin_dmac \
bfin_ebiu_amc \
diff --git a/sim/bfin/machs.c b/sim/bfin/machs.c
index 92ce85a..6c3b784 100644
--- a/sim/bfin/machs.c
+++ b/sim/bfin/machs.c
@@ -50,6 +50,11 @@ struct bfin_dmac_layout {
address_word base;
unsigned int dma_count;
};
+struct bfin_dde_layout {
+ address_word base;
+ const char *dev, *peer, *port;
+ unsigned int mwidth, pwidth;
+};
struct bfin_port_layout {
/* Which device this routes to (name/port). */
const char *dst, *dst_port;
@@ -65,6 +70,8 @@ struct bfin_model_data {
size_t dev_count;
const struct bfin_dmac_layout *dmac;
size_t dmac_count;
+ const struct bfin_dde_layout *dde;
+ size_t dde_count;
const struct bfin_port_layout *port;
size_t port_count;
};
@@ -72,6 +79,15 @@ struct bfin_model_data {
#define LAYOUT(_addr, _len, _mask) { .addr = _addr, .len = _len, .mask = access_##_mask, }
#define _DEVICE(_base, _len, _dev, _dmac) { .base = _base, .len = _len, .dev = _dev, .dmac = _dmac, }
#define DEVICE(_base, _len, _dev) _DEVICE(_base, _len, _dev, 0)
+#define DDE(_base, _dev, _peer, _port) \
+ { \
+ .base = _base, \
+ .dev = "bfin_dde@"#_dev, \
+ .peer = _peer, \
+ .port = _port, \
+ .mwidth = 3, \
+ .pwidth = 3, \
+ }
#define PORT(_dst, _dst_port, _src, _src_port) \
{ \
.dst = _dst, \
@@ -88,6 +104,7 @@ struct bfin_model_data {
static const struct bfin_memory_layout bf000_mem[] = {};
static const struct bfin_dev_layout bf000_dev[] = {};
static const struct bfin_dmac_layout bf000_dmac[] = {};
+static const struct bfin_dde_layout bf000_dde[] = {};
static const struct bfin_port_layout bf000_port[] = {};
#define bf50x_chipid 0x2800
@@ -137,6 +154,8 @@ static const struct bfin_dmac_layout bf50x_dmac[] =
};
#define bf504_dmac bf50x_dmac
#define bf506_dmac bf50x_dmac
+#define bf504_dde bf000_dde
+#define bf506_dde bf000_dde
static const struct bfin_port_layout bf50x_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -283,6 +302,10 @@ static const struct bfin_dev_layout bf516_dev[] =
#define bf514_dmac bf50x_dmac
#define bf516_dmac bf50x_dmac
#define bf518_dmac bf50x_dmac
+#define bf512_dde bf000_dde
+#define bf514_dde bf000_dde
+#define bf516_dde bf000_dde
+#define bf518_dde bf000_dde
static const struct bfin_port_layout bf51x_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -438,6 +461,12 @@ static const struct bfin_dev_layout bf526_dev[] =
#define bf525_dmac bf50x_dmac
#define bf526_dmac bf50x_dmac
#define bf527_dmac bf50x_dmac
+#define bf522_dde bf000_dde
+#define bf523_dde bf000_dde
+#define bf524_dde bf000_dde
+#define bf525_dde bf000_dde
+#define bf526_dde bf000_dde
+#define bf527_dde bf000_dde
static const struct bfin_port_layout bf52x_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -563,6 +592,9 @@ static const struct bfin_dmac_layout bf533_dmac[] =
};
#define bf531_dmac bf533_dmac
#define bf532_dmac bf533_dmac
+#define bf531_dde bf000_dde
+#define bf532_dde bf000_dde
+#define bf533_dde bf000_dde
static const struct bfin_port_layout bf533_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -714,6 +746,9 @@ static const struct bfin_dev_layout bf537_dev[] =
#define bf534_dmac bf50x_dmac
#define bf536_dmac bf50x_dmac
#define bf537_dmac bf50x_dmac
+#define bf534_dde bf000_dde
+#define bf536_dde bf000_dde
+#define bf537_dde bf000_dde
static const struct bfin_port_layout bf537_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -821,6 +856,8 @@ static const struct bfin_dmac_layout bf538_dmac[] =
{ BFIN_MMR_DMAC1_BASE, 12, },
};
#define bf539_dmac bf538_dmac
+#define bf538_dde bf000_dde
+#define bf539_dde bf000_dde
static const struct bfin_port_layout bf538_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -1052,6 +1089,11 @@ static const struct bfin_dmac_layout bf54x_dmac[] =
#define bf547_dmac bf54x_dmac
#define bf548_dmac bf54x_dmac
#define bf549_dmac bf54x_dmac
+#define bf542_dde bf000_dde
+#define bf544_dde bf000_dde
+#define bf547_dde bf000_dde
+#define bf548_dde bf000_dde
+#define bf549_dde bf000_dde
#define PINT_PIQS(p, b, g) \
PORT (p, "piq0@"#b, g, "p0"), \
PORT (p, "piq1@"#b, g, "p1"), \
@@ -1247,6 +1289,7 @@ static const struct bfin_dmac_layout bf561_dmac[] =
{ BFIN_MMR_DMAC1_BASE, 12, },
/* XXX: IMDMA: { 0xFFC01800, 4, }, */
};
+#define bf561_dde bf000_dde
static const struct bfin_port_layout bf561_port[] =
{
/* SIC0 */
@@ -1350,6 +1393,7 @@ static const struct bfin_dmac_layout bf592_dmac[] =
start right after the dma channels ... */
{ BFIN_MMR_DMAC0_BASE, 12, },
};
+#define bf592_dde bf000_dde
static const struct bfin_port_layout bf592_port[] =
{
SIC (0, 0, "bfin_pll", "pll"),
@@ -1401,6 +1445,7 @@ static const struct bfin_model_data bfin_model_data[] =
bf##n##_mem , ARRAY_SIZE (bf##n##_mem ), \
bf##n##_dev , ARRAY_SIZE (bf##n##_dev ), \
bf##n##_dmac, ARRAY_SIZE (bf##n##_dmac), \
+ bf##n##_dde , ARRAY_SIZE (bf##n##_dde ), \
bf##n##_port, ARRAY_SIZE (bf##n##_port), \
},
#include "proc_list.def"
@@ -1514,6 +1559,17 @@ bfin_model_hw_tree_init (SIM_DESC sd, SIM_CPU *cpu)
}
}
+ for (i = 0; i < mdata->dde_count; ++i)
+ {
+ const struct bfin_dde_layout *dde = &mdata->dde[i];
+
+ sim_hw_parse (sd, "/core/%s/reg %#x %i", dde->dev,
+ dde->base, BFIN_MMR_DDE_SIZE);
+ sim_hw_parse (sd, "/core/%s/mwidth %i", dde->dev, dde->mwidth);
+ sim_hw_parse (sd, "/core/%s/pwidth %i", dde->dev, dde->pwidth);
+ sim_hw_parse (sd, "/core/%s/peer %s", dde->dev, dde->peer);
+ }
+
for (i = 0; i < mdata->dev_count; ++i)
{
const struct bfin_dev_layout *dev = &mdata->dev[i];
@@ -1547,6 +1603,16 @@ bfin_model_hw_tree_init (SIM_DESC sd, SIM_CPU *cpu)
}
}
+ for (i = 0; i < mdata->dde_count; ++i)
+ {
+ const struct bfin_dde_layout *dde = &mdata->dde[i];
+
+ /* Must run after we've declared all of our devices to avoid loops. */
+ if (dde->port[0])
+ sim_hw_parse (sd, "/core/%s > %s pi /core/%s", dde->peer,
+ dde->port, dde->dev);
+ }
+
done:
/* Add any additional user board content. */
if (board->hw_file)
diff --git a/sim/bfin/machs.h b/sim/bfin/machs.h
index a621190..4e8a8ba 100644
--- a/sim/bfin/machs.h
+++ b/sim/bfin/machs.h
@@ -52,6 +52,7 @@ extern const SIM_MACH * const bfin_sim_machs[];
#define BFIN_COREMMR_WP_SIZE 0x204
#define BFIN_MMR_CGU_SIZE (4 * 5)
+#define BFIN_MMR_DDE_SIZE 0x50
#define BFIN_MMR_DMA_SIZE (4 * 16)
#define BFIN_MMR_DMAC0_BASE 0xFFC00C00
#define BFIN_MMR_DMAC1_BASE 0xFFC01C00