| /* Blackfin Direct Memory Access (DMA) Controller model. | 
 |  | 
 |    Copyright (C) 2010-2023 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/>.  */ | 
 |  | 
 | /* This must come before any other includes.  */ | 
 | #include "defs.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 * const *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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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 * const 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}, | 
 | }; |