diff options
author | Mike Frysinger <vapier@gentoo.org> | 2011-03-06 00:20:21 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2011-03-06 00:20:21 +0000 |
commit | ef016f835f292f01f065412fcfd84c50bfff1fea (patch) | |
tree | fe72facf7bcdc58af74f3a37d30f0f25d501f6a0 /sim/bfin/dv-bfin_dmac.c | |
parent | 7dcf22fd41de725f3280c80a1274bcef309d6891 (diff) | |
download | fsf-binutils-gdb-ef016f835f292f01f065412fcfd84c50bfff1fea.zip fsf-binutils-gdb-ef016f835f292f01f065412fcfd84c50bfff1fea.tar.gz fsf-binutils-gdb-ef016f835f292f01f065412fcfd84c50bfff1fea.tar.bz2 |
sim: bfin: new port
This can boot Das U-Boot and a Linux kernel. It also supports Linux
userspace FLAT and FDPIC (dynamic and static) ELFs.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'sim/bfin/dv-bfin_dmac.c')
-rw-r--r-- | sim/bfin/dv-bfin_dmac.c | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/sim/bfin/dv-bfin_dmac.c b/sim/bfin/dv-bfin_dmac.c new file mode 100644 index 0000000..f0f3c8c --- /dev/null +++ b/sim/bfin/dv-bfin_dmac.c @@ -0,0 +1,469 @@ +/* Blackfin Direct Memory Access (DMA) Controller model. + + Copyright (C) 2010-2011 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 "sim-hw.h" +#include "devices.h" +#include "hw-device.h" +#include "dv-bfin_dma.h" +#include "dv-bfin_dmac.h" + +struct bfin_dmac +{ + /* This top portion matches common dv_bfin struct. */ + bu32 base; + struct hw *dma_master; + bool acked; + + const char **pmap; + unsigned int pmap_count; +}; + +struct hw * +bfin_dmac_get_peer (struct hw *dma, bu16 pmap) +{ + struct hw *ret, *me; + struct bfin_dmac *dmac; + char peer[100]; + + me = hw_parent (dma); + dmac = hw_data (me); + if (pmap & CTYPE) + { + /* MDMA channel. */ + unsigned int chan_num = dv_get_bus_num (dma); + if (chan_num & 1) + chan_num &= ~1; + else + chan_num |= 1; + sprintf (peer, "%s/bfin_dma@%u", hw_path (me), chan_num); + } + else + { + unsigned int idx = pmap >> 12; + if (idx >= dmac->pmap_count) + hw_abort (me, "Invalid DMA peripheral_map %#x", pmap); + else + sprintf (peer, "/core/bfin_%s", dmac->pmap[idx]); + } + + ret = hw_tree_find_device (me, peer); + if (!ret) + hw_abort (me, "Unable to locate peer for %s (pmap:%#x %s)", + hw_name (dma), pmap, peer); + return ret; +} + +bu16 +bfin_dmac_default_pmap (struct hw *dma) +{ + unsigned int chan_num = dv_get_bus_num (dma); + + if (chan_num < BFIN_DMAC_MDMA_BASE) + return (chan_num % 12) << 12; + else + return CTYPE; /* MDMA */ +} + +static const char *bfin_dmac_50x_pmap[] = { + "ppi@0", "rsi", "sport@0", "sport@0", "sport@1", "sport@1", + "spi@0", "spi@1", "uart2@0", "uart2@0", "uart2@1", "uart2@1", +}; + +/* XXX: Need to figure out how to handle portmuxed DMA channels. */ +static const struct hw_port_descriptor bfin_dmac_50x_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "rsi", 1, 0, input_port, }, + { "sport@0_rx", 2, 0, input_port, }, + { "sport@0_tx", 3, 0, input_port, }, + { "sport@1_tx", 4, 0, input_port, }, + { "sport@1_rx", 5, 0, input_port, }, + { "spi@0", 6, 0, input_port, }, + { "spi@1", 7, 0, input_port, }, + { "uart2@0_rx", 8, 0, input_port, }, + { "uart2@0_tx", 9, 0, input_port, }, + { "uart2@1_rx", 10, 0, input_port, }, + { "uart2@1_tx", 11, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac_51x_pmap[] = { + "ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1", + "sport@1", "spi@0", "uart@0", "uart@0", "uart@1", "uart@1", +}; + +/* XXX: Need to figure out how to handle portmuxed DMA channels. */ +static const struct hw_port_descriptor bfin_dmac_51x_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "emac_rx", 1, 0, input_port, }, + { "emac_tx", 2, 0, input_port, }, + { "sport@0_rx", 3, 0, input_port, }, + { "sport@0_tx", 4, 0, input_port, }, +/*{ "rsi", 4, 0, input_port, },*/ + { "sport@1_tx", 5, 0, input_port, }, +/*{ "spi@1", 5, 0, input_port, },*/ + { "sport@1_rx", 6, 0, input_port, }, + { "spi@0", 7, 0, input_port, }, + { "uart@0_rx", 8, 0, input_port, }, + { "uart@0_tx", 9, 0, input_port, }, + { "uart@1_rx", 10, 0, input_port, }, + { "uart@1_tx", 11, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac_52x_pmap[] = { + "ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1", + "sport@1", "spi", "uart@0", "uart@0", "uart@1", "uart@1", +}; + +/* XXX: Need to figure out how to handle portmuxed DMA channels + like PPI/NFC here which share DMA0. */ +static const struct hw_port_descriptor bfin_dmac_52x_ports[] = { + { "ppi@0", 0, 0, input_port, }, +/*{ "nfc", 0, 0, input_port, },*/ + { "emac_rx", 1, 0, input_port, }, +/*{ "hostdp", 1, 0, input_port, },*/ + { "emac_tx", 2, 0, input_port, }, +/*{ "nfc", 2, 0, input_port, },*/ + { "sport@0_tx", 3, 0, input_port, }, + { "sport@0_rx", 4, 0, input_port, }, + { "sport@1_tx", 5, 0, input_port, }, + { "sport@1_rx", 6, 0, input_port, }, + { "spi", 7, 0, input_port, }, + { "uart@0_tx", 8, 0, input_port, }, + { "uart@0_rx", 9, 0, input_port, }, + { "uart@1_tx", 10, 0, input_port, }, + { "uart@1_rx", 11, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac_533_pmap[] = { + "ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi", + "uart@0", "uart@0", +}; + +static const struct hw_port_descriptor bfin_dmac_533_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "sport@0_tx", 1, 0, input_port, }, + { "sport@0_rx", 2, 0, input_port, }, + { "sport@1_tx", 3, 0, input_port, }, + { "sport@1_rx", 4, 0, input_port, }, + { "spi", 5, 0, input_port, }, + { "uart@0_tx", 6, 0, input_port, }, + { "uart@0_rx", 7, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac_537_pmap[] = { + "ppi@0", "emac", "emac", "sport@0", "sport@0", "sport@1", + "sport@1", "spi", "uart@0", "uart@0", "uart@1", "uart@1", +}; + +static const struct hw_port_descriptor bfin_dmac_537_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "emac_rx", 1, 0, input_port, }, + { "emac_tx", 2, 0, input_port, }, + { "sport@0_tx", 3, 0, input_port, }, + { "sport@0_rx", 4, 0, input_port, }, + { "sport@1_tx", 5, 0, input_port, }, + { "sport@1_rx", 6, 0, input_port, }, + { "spi", 7, 0, input_port, }, + { "uart@0_tx", 8, 0, input_port, }, + { "uart@0_rx", 9, 0, input_port, }, + { "uart@1_tx", 10, 0, input_port, }, + { "uart@1_rx", 11, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac0_538_pmap[] = { + "ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi@0", + "uart@0", "uart@0", +}; + +static const struct hw_port_descriptor bfin_dmac0_538_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "sport@0_rx", 1, 0, input_port, }, + { "sport@0_tx", 2, 0, input_port, }, + { "sport@1_rx", 3, 0, input_port, }, + { "sport@1_tx", 4, 0, input_port, }, + { "spi@0", 5, 0, input_port, }, + { "uart@0_rx", 6, 0, input_port, }, + { "uart@0_tx", 7, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac1_538_pmap[] = { + "sport@2", "sport@2", "sport@3", "sport@3", NULL, NULL, + "spi@1", "spi@2", "uart@1", "uart@1", "uart@2", "uart@2", +}; + +static const struct hw_port_descriptor bfin_dmac1_538_ports[] = { + { "sport@2_rx", 0, 0, input_port, }, + { "sport@2_tx", 1, 0, input_port, }, + { "sport@3_rx", 2, 0, input_port, }, + { "sport@3_tx", 3, 0, input_port, }, + { "spi@1", 6, 0, input_port, }, + { "spi@2", 7, 0, input_port, }, + { "uart@1_rx", 8, 0, input_port, }, + { "uart@1_tx", 9, 0, input_port, }, + { "uart@2_rx", 10, 0, input_port, }, + { "uart@2_tx", 11, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac0_54x_pmap[] = { + "sport@0", "sport@0", "sport@1", "sport@1", "spi@0", "spi@1", + "uart2@0", "uart2@0", "uart2@1", "uart2@1", "atapi", "atapi", +}; + +static const struct hw_port_descriptor bfin_dmac0_54x_ports[] = { + { "sport@0_rx", 0, 0, input_port, }, + { "sport@0_tx", 1, 0, input_port, }, + { "sport@1_rx", 2, 0, input_port, }, + { "sport@1_tx", 3, 0, input_port, }, + { "spi@0", 4, 0, input_port, }, + { "spi@1", 5, 0, input_port, }, + { "uart2@0_rx", 6, 0, input_port, }, + { "uart2@0_tx", 7, 0, input_port, }, + { "uart2@1_rx", 8, 0, input_port, }, + { "uart2@1_tx", 9, 0, input_port, }, + { "atapi", 10, 0, input_port, }, + { "atapi", 11, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac1_54x_pmap[] = { + "eppi@0", "eppi@1", "eppi@2", "pixc", "pixc", "pixc", + "sport@2", "sport@2", "sport@3", "sport@3", "sdh", + "spi@2", "uart2@2", "uart2@2", "uart2@3", "uart2@3", +}; + +static const struct hw_port_descriptor bfin_dmac1_54x_ports[] = { + { "eppi@0", 0, 0, input_port, }, + { "eppi@1", 1, 0, input_port, }, + { "eppi@2", 2, 0, input_port, }, + { "pixc", 3, 0, input_port, }, + { "pixc", 4, 0, input_port, }, + { "pixc", 5, 0, input_port, }, + { "sport@2_rx", 6, 0, input_port, }, + { "sport@2_tx", 7, 0, input_port, }, + { "sport@3_rx", 8, 0, input_port, }, + { "sport@3_tx", 9, 0, input_port, }, + { "sdh", 10, 0, input_port, }, +/*{ "nfc", 10, 0, input_port, },*/ + { "spi@2", 11, 0, input_port, }, + { "uart2@2_rx", 12, 0, input_port, }, + { "uart2@2_tx", 13, 0, input_port, }, + { "uart2@3_rx", 14, 0, input_port, }, + { "uart2@3_tx", 15, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac0_561_pmap[] = { + "sport@0", "sport@0", "sport@1", "sport@1", "spi", "uart@0", "uart@0", +}; + +static const struct hw_port_descriptor bfin_dmac0_561_ports[] = { + { "sport@0_rx", 0, 0, input_port, }, + { "sport@0_tx", 1, 0, input_port, }, + { "sport@1_rx", 2, 0, input_port, }, + { "sport@1_tx", 3, 0, input_port, }, + { "spi@0", 4, 0, input_port, }, + { "uart@0_rx", 5, 0, input_port, }, + { "uart@0_tx", 6, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac1_561_pmap[] = { + "ppi@0", "ppi@1", +}; + +static const struct hw_port_descriptor bfin_dmac1_561_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "ppi@1", 1, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static const char *bfin_dmac_59x_pmap[] = { + "ppi@0", "sport@0", "sport@0", "sport@1", "sport@1", "spi@0", + "spi@1", "uart@0", "uart@0", +}; + +static const struct hw_port_descriptor bfin_dmac_59x_ports[] = { + { "ppi@0", 0, 0, input_port, }, + { "sport@0_tx", 1, 0, input_port, }, + { "sport@0_rx", 2, 0, input_port, }, + { "sport@1_tx", 3, 0, input_port, }, + { "sport@1_rx", 4, 0, input_port, }, + { "spi@0", 5, 0, input_port, }, + { "spi@1", 6, 0, input_port, }, + { "uart@0_rx", 7, 0, input_port, }, + { "uart@0_tx", 8, 0, input_port, }, + { NULL, 0, 0, 0, }, +}; + +static void +bfin_dmac_port_event (struct hw *me, int my_port, struct hw *source, + int source_port, int level) +{ + SIM_DESC sd = hw_system (me); + struct bfin_dmac *dmac = hw_data (me); + struct hw *dma = hw_child (me); + + while (dma) + { + bu16 pmap; + sim_hw_io_read_buffer (sd, dma, &pmap, 0, 0x2c, sizeof (pmap)); + pmap >>= 12; + if (pmap == my_port) + break; + dma = hw_sibling (dma); + } + + if (!dma) + hw_abort (me, "no valid dma mapping found for %s", dmac->pmap[my_port]); + + /* Have the DMA channel raise its interrupt to the SIC. */ + hw_port_event (dma, 0, 1); +} + +static void +bfin_dmac_finish (struct hw *me) +{ + struct bfin_dmac *dmac; + unsigned int dmac_num = dv_get_bus_num (me); + + dmac = HW_ZALLOC (me, struct bfin_dmac); + + set_hw_data (me, dmac); + set_hw_port_event (me, bfin_dmac_port_event); + + /* Initialize the DMA Controller. */ + if (hw_find_property (me, "type") == NULL) + hw_abort (me, "Missing \"type\" property"); + + switch (hw_find_integer_property (me, "type")) + { + case 500 ... 509: + if (dmac_num != 0) + hw_abort (me, "this Blackfin only has a DMAC0"); + dmac->pmap = bfin_dmac_50x_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac_50x_pmap); + set_hw_ports (me, bfin_dmac_50x_ports); + break; + case 510 ... 519: + if (dmac_num != 0) + hw_abort (me, "this Blackfin only has a DMAC0"); + dmac->pmap = bfin_dmac_51x_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac_51x_pmap); + set_hw_ports (me, bfin_dmac_51x_ports); + break; + case 522 ... 527: + if (dmac_num != 0) + hw_abort (me, "this Blackfin only has a DMAC0"); + dmac->pmap = bfin_dmac_52x_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac_52x_pmap); + set_hw_ports (me, bfin_dmac_52x_ports); + break; + case 531 ... 533: + if (dmac_num != 0) + hw_abort (me, "this Blackfin only has a DMAC0"); + dmac->pmap = bfin_dmac_533_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac_533_pmap); + set_hw_ports (me, bfin_dmac_533_ports); + break; + case 534: + case 536: + case 537: + if (dmac_num != 0) + hw_abort (me, "this Blackfin only has a DMAC0"); + dmac->pmap = bfin_dmac_537_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac_537_pmap); + set_hw_ports (me, bfin_dmac_537_ports); + break; + case 538 ... 539: + switch (dmac_num) + { + case 0: + dmac->pmap = bfin_dmac0_538_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_538_pmap); + set_hw_ports (me, bfin_dmac0_538_ports); + break; + case 1: + dmac->pmap = bfin_dmac1_538_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_538_pmap); + set_hw_ports (me, bfin_dmac1_538_ports); + break; + default: + hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1"); + } + break; + case 540 ... 549: + switch (dmac_num) + { + case 0: + dmac->pmap = bfin_dmac0_54x_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_54x_pmap); + set_hw_ports (me, bfin_dmac0_54x_ports); + break; + case 1: + dmac->pmap = bfin_dmac1_54x_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_54x_pmap); + set_hw_ports (me, bfin_dmac1_54x_ports); + break; + default: + hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1"); + } + break; + case 561: + switch (dmac_num) + { + case 0: + dmac->pmap = bfin_dmac0_561_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac0_561_pmap); + set_hw_ports (me, bfin_dmac0_561_ports); + break; + case 1: + dmac->pmap = bfin_dmac1_561_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac1_561_pmap); + set_hw_ports (me, bfin_dmac1_561_ports); + break; + default: + hw_abort (me, "this Blackfin only has a DMAC0 & DMAC1"); + } + break; + case 590 ... 599: + if (dmac_num != 0) + hw_abort (me, "this Blackfin only has a DMAC0"); + dmac->pmap = bfin_dmac_59x_pmap; + dmac->pmap_count = ARRAY_SIZE (bfin_dmac_59x_pmap); + set_hw_ports (me, bfin_dmac_59x_ports); + break; + default: + hw_abort (me, "no support for DMAC on this Blackfin model yet"); + } +} + +const struct hw_descriptor dv_bfin_dmac_descriptor[] = { + {"bfin_dmac", bfin_dmac_finish,}, + {NULL, NULL}, +}; |