Initial revision
diff --git a/cpu/mpc824x/drivers/dma/Makefile b/cpu/mpc824x/drivers/dma/Makefile
new file mode 100644
index 0000000..59e2fac
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/Makefile
@@ -0,0 +1,83 @@
+##########################################################################
+#
+#       Copyright Motorola, Inc. 1997
+#       ALL RIGHTS RESERVED
+#
+#       You are hereby granted a copyright license to use, modify, and
+#       distribute the SOFTWARE so long as this entire notice is retained
+#       without alteration in any modified and/or redistributed versions,
+#       and that such modified versions are clearly identified as such.
+#       No licenses are granted by implication, estoppel or otherwise under
+#       any patents or trademarks of Motorola, Inc.
+#
+#       The SOFTWARE is provided on an "AS IS" basis and without warranty.
+#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS
+#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED
+#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
+#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS
+#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS.
+#
+#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL
+#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF
+#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
+#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR
+#       INABILITY TO USE THE SOFTWARE.
+#
+############################################################################
+TARGET = libdma.a
+
+DEBUG   = -DDMADBG
+LST     = -Hanno -S
+OPTIM   =
+CC      = /risc/tools/pkgs/metaware/bin/hcppc
+CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc
+CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM)
+PREP    = $(CC) $(CFLAGS) -P
+
+# Assembler used to build the .s files (for the board version)
+
+ASOPT   = -big_si -c
+ASDEBUG = -l -fm
+AS      = /risc/tools/pkgs/metaware/bin/asppc
+
+# Linker to bring .o files together into an executable.
+
+LKOPT	=  -Bbase=0 -q -r -Qn
+LKCMD   =
+LINK    =  /risc/tools/pkgs/metaware/bin/ldppc $(LKCMD) $(LKOPT)
+
+# DOS Utilities
+
+DEL     = rm
+COPY    = cp
+LIST    = ls
+
+OBJECTS = dma1.o dma2.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+	$(LINK) $(OBJECTS) -o $@
+
+objects: dma1.o
+
+clean:
+	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS)
+
+.s.o:
+	$(DEL) -f $*.i
+	$(PREP) -Hasmcpp $<
+	$(AS) $(ASOPT) $*.i
+#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst
+
+.c.o:
+	$(CCobj) $<
+
+.c.s:
+	$(CCobj) $(LST) $<
+
+dma1.o: dma_export.h dma.h dma1.c
+
+dma2.o: dma.h dma2.s
diff --git a/cpu/mpc824x/drivers/dma/Makefile_pc b/cpu/mpc824x/drivers/dma/Makefile_pc
new file mode 100644
index 0000000..8df2a3c
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/Makefile_pc
@@ -0,0 +1,89 @@
+##########################################################################
+#
+#   makefile_pc  for use with mksnt tools   drivers/dma
+#
+#       Copyright Motorola, Inc. 1997
+#       ALL RIGHTS RESERVED
+#
+#       You are hereby granted a copyright license to use, modify, and
+#       distribute the SOFTWARE so long as this entire notice is retained
+#       without alteration in any modified and/or redistributed versions,
+#       and that such modified versions are clearly identified as such.
+#       No licenses are granted by implication, estoppel or otherwise under
+#       any patents or trademarks of Motorola, Inc.
+#
+#       The SOFTWARE is provided on an "AS IS" basis and without warranty.
+#       To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS
+#       ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED
+#       WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+#       PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
+#       REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS
+#       THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS.
+#
+#       To the maximum extent permitted by applicable law, IN NO EVENT SHALL
+#       MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
+#       (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF
+#       BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
+#       INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR
+#       INABILITY TO USE THE SOFTWARE.
+#
+############################################################################
+TARGET = libdma.a
+
+DEBUG   = -DDMADBG
+LST     = -Hanno -S
+OPTIM   =
+CC      = m:/old_tools/tools/hcppc/bin/hcppc
+CFLAGS  = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc
+CCobj   = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM)
+PREP    = $(CC) $(CFLAGS) -P
+
+# Assembler used to build the .s files (for the board version)
+
+ASOPT   = -big_si -c
+ASDEBUG = -l -fm
+AS      = m:/old_tools/tools/hcppc/bin/asppc
+
+# Linker to bring .o files together into an executable.
+
+LKOPT	=  -Bbase=0 -q -r -Qn
+LKCMD   =
+LINK    = m:/old_tools/tools/hcppc/bin/ldppc $(LKCMD) $(LKOPT)
+
+# DOS Utilities
+
+DEL     = rm
+COPY    = cp
+LIST    = ls
+
+OBJECTS = dma1.o dma2.o
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+	$(LINK) $(OBJECTS) -o $@
+
+objects: dma1.o
+
+clean:
+	$(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS)
+
+.s.o:
+	$(DEL) -f $*.i
+	$(PREP) -Hasmcpp $<
+	$(AS) $(ASOPT) $*.i
+#	$(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst
+
+.c.o:
+	$(CCobj) $<
+
+.c.s:
+	$(CCobj) $(LST) $<
+
+dma1.o: dma_export.h dma.h dma1.c
+	$(CCobj) $<
+
+dma2.o: dma.h dma2.s
+	$(DEL) -f $*.i
+	$(PREP) -Hasmcpp $<
+	$(AS) $(ASOPT) $*.i
diff --git a/cpu/mpc824x/drivers/dma/README b/cpu/mpc824x/drivers/dma/README
new file mode 100644
index 0000000..ab4b68b
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/README
@@ -0,0 +1,102 @@
+CONTENT:
+
+   dma.h
+   dma1.c
+   dma2.s
+
+WHAT ARE THESE FILES:
+
+These files contain MPC8240 (Kahlua) DMA controller
+driver routines. The driver routines are not
+written for any specific operating system.
+They serves the purpose of code sample, and
+jump-start for using the MPC8240 DMA controller.
+
+For the reason of correctness of C language
+syntax, these files are compiled by Metaware
+C compiler and assembler.
+
+ENDIAN NOTATION:
+
+The algorithm is designed for big-endian mode,
+software is responsible for byte swapping.
+
+USAGE:
+
+1. The host system that is running on MPC8240
+   or using MPC8240 as I/O device shall link
+   the files listed here. The memory location
+   of driver routines shall take into account of
+   that driver routines need to run in supervisor
+   mode and they process DMA controller interrupt.
+
+2. The host system is responsible for configuring
+   the MPC8240 including Embedded Utilities Memory
+   Block. Since the DMA controller on MPC8240 can
+   be accessed by either local 603e core or the host
+   that MPC8240 serves as I/O processor through host
+   PCI configuration, it is important that the local
+   processor uses EUMBBAR to access its local DMA
+   controller while the PCI master uses I/O
+   processor's PCSRBAR to access the DMA controller
+   on I/O device.
+
+   To qualify whether is EUMBBAR or PCSRBAR, one
+   additional parameter is requied from the host
+   system, LOCAL or REMOTE so that the base value
+   can be correctly interpreted.
+
+3. If the host system is also using the EPIC unit
+   on MPC8240, the system can register the
+   DMA_ISR with the EPIC including other
+   desired resources.
+
+   If the host system does not using the EPIC unit
+   on MPC8240, DMA_ISR function can be called for
+   each desired time interval.
+
+   In both cases, the host system is free to
+   provide its own interrupt service routine.
+
+4. To start a direct mode DMA transaction,
+   use DMA_Bld_Curr with the start parameter
+   set to 1.
+
+   To start a chaining mode DMA transaction,
+   the application shall build descriptors
+   in memory first, next, use DMA_Bld_Desp
+   with the start parameter set to 1.
+
+5. DMA_Start function clears, then sets the CS
+   bit of DMA mode register.
+
+   DMA_Halt function clears the CS bit of DMA
+   mode register.
+
+   These functions can be used to start and
+   halt the DMA transaction.
+
+   If the chaining descriptors has been
+   modified since the last time a DMA
+   transaction started, use DMA_Chn_Cnt
+   function to let DMA controller process
+   the modified descriptor chain without
+   stopping or disturbing the current DMA
+   transaction.
+
+   It is the host system's responsibility of
+   setting up the correct DMA transfer mode
+   and pass the correct memory address parameters.
+
+6. It is the host system's responsibility of
+   queueing the DMA I/O request. The host
+   system can call the DMA_ISR with its own
+   desired interrupt service subroutines to
+   handle each individual interrupt and queued
+   DMA I/O requests.
+
+7. The DMA driver routines contains a set
+   of utilities, Set and Get, for host system
+   to query and modify the desired DMA registers.
+
+
diff --git a/cpu/mpc824x/drivers/dma/dma.h b/cpu/mpc824x/drivers/dma/dma.h
new file mode 100644
index 0000000..a21be74
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/dma.h
@@ -0,0 +1,326 @@
+#ifndef DMA_H
+#define DMA_H
+/*******************************************************
+ *
+ * copyright @ Motorola 1999
+ *
+ *******************************************************/
+#define NUM_DMA_REG   7
+#define DMA_MR_REG    0
+#define DMA_SR_REG    1
+#define DMA_CDAR_REG  2
+#define DMA_SAR_REG   3
+#define DMA_DAR_REG   4
+#define DMA_BCR_REG   5
+#define DMA_NDAR_REG  6
+
+typedef enum _dmastatus
+{
+	DMASUCCESS = 0x1000,
+	DMALMERROR,
+	DMAPERROR,
+	DMACHNBUSY,
+	DMAEOSINT,
+	DMAEOCAINT,
+	DMAINVALID,
+	DMANOEVENT,
+} DMAStatus;
+
+typedef enum _location
+{
+	LOCAL = 0,     /* local processor accesses on board DMA,
+			          local processor's eumbbar is required */
+	REMOTE = 1,    /* PCI master accesses DMA on I/O board,
+			          I/O processor's pcsrbar is required */
+} LOCATION;
+
+typedef enum dma_mr_bit
+{
+	IRQS    = 0x00080000,
+    PDE     = 0x00040000,
+	DAHTS   = 0x00030000,
+	SAHTS   = 0x0000c000,
+	DAHE    = 0x00002000,
+	SAHE    = 0x00001000,
+	PRC     = 0x00000c00,
+	EIE     = 0x00000080,
+	EOTIE   = 0x00000040,
+	DL      = 0x00000008,
+	CTM     = 0x00000004,
+	CC      = 0x00000002,
+	CS      = 0x00000001,
+} DMA_MR_BIT;
+
+typedef enum dma_sr_bit
+{
+	LME     = 0x00000080,
+	PE      = 0x00000010,
+	CB      = 0x00000004,
+	EOSI    = 0x00000002,
+	EOCAI   = 0x00000001,
+} DMA_SR_BIT;
+
+/* structure for DMA Mode Register */
+typedef struct _dma_mr
+{
+	unsigned int  reserved0 : 12;
+	unsigned int  irqs      : 1;
+	unsigned int  pde       : 1;
+	unsigned int  dahts     : 2;
+    unsigned int  sahts     : 2;
+	unsigned int  dahe      : 1;
+	unsigned int  sahe      : 1;
+	unsigned int  prc       : 2;
+	unsigned int  reserved1 : 1;
+	unsigned int  eie       : 1;
+	unsigned int  eotie     : 1;
+	unsigned int  reserved2 : 3;
+	unsigned int  dl        : 1;
+	unsigned int  ctm       : 1;
+	/* if chaining mode is enabled, any time, user can modify the
+	 * descriptor and does not need to halt the current DMA transaction.
+	 * Set CC bit, enable DMA to process the modified descriptors
+	 * Hardware will clear this bit each time, DMA starts.
+	 */
+	unsigned int  cc        : 1;
+	/* cs bit has dua role, halt the current DMA transaction and
+	 * (re)start DMA transaction. In chaining mode, if the descriptor
+	 * needs modification, cs bit shall be used not the cc bit.
+	 * Hardware will not set/clear this bit each time DMA transaction
+	 * stops or starts. Software shall do it.
+	 *
+	 * cs bit shall not be used to halt chaining DMA transaction for
+	 * modifying the descriptor. That is the role of CC bit.
+	 */
+	unsigned int  cs        : 1;
+} DMA_MR;
+
+/* structure for DMA Status register */
+typedef struct _dma_sr
+{
+	unsigned int  reserved0 : 24;
+	unsigned int  lme       : 1;
+	unsigned int  reserved1 : 2;
+	unsigned int  pe        : 1;
+	unsigned int  reserved2 : 1;
+	unsigned int  cb        : 1;
+	unsigned int  eosi      : 1;
+	unsigned int  eocai     : 1;
+} DMA_SR;
+
+/* structure for DMA current descriptor address register */
+typedef struct _dma_cdar
+{
+	unsigned int  cda    : 27;
+	unsigned int snen    : 1;
+	unsigned int eosie   : 1;
+	unsigned int ctt     : 2;
+	unsigned int eotd    : 1;
+} DMA_CDAR;
+
+/* structure for DMA byte count register */
+typedef struct _dma_bcr
+{
+	unsigned int reserved : 6;
+	unsigned int  bcr      : 26;
+} DMA_BCR;
+
+/* structure for DMA Next Descriptor Address register */
+typedef struct _dma_ndar
+{
+	unsigned int nda    : 27;
+	unsigned int ndsnen : 1;
+	unsigned int ndeosie: 1;
+	unsigned int ndctt  : 2;
+	unsigned int eotd   : 1;
+} DMA_NDAR;
+
+/* structure for DMA current transaction info */
+typedef struct _dma_curr
+{
+	unsigned int src_addr;
+	unsigned int dest_addr;
+	unsigned int byte_cnt;
+} DMA_CURR;
+
+/************************* Kernel API********************
+ * Kernel APIs are used to interface with O.S. kernel.
+ * They are the functions required by O.S. kernel to
+ * provide I/O service.
+ ********************************************************/
+
+/**************DMA Device Control Functions ********/
+
+/**
+ * Note:
+ *
+ * In all following functions, the host (KAHLUA) processor has a
+ * choice of accessing on board local DMA (LOCAL),
+ * or DMA on a distributed KAHLUA (REMOTE). In either case,
+ * the caller shall pass the configured embedded utility memory
+ * block base address relative to the DMA. If LOCAL DMA is used,
+ * this parameter shall be EUMBBAR, if REMOTE is used, the
+ * parameter shall be the corresponding PCSRBAR.
+ **/
+
+/**************************************************************
+ * function: DMA_Get_Stat
+ *
+ * description: return the content of status register of
+ *              the given DMA channel
+ *              if error, return DMAINVALID. Otherwise return
+ *              DMASUCCESS.
+ *
+ **************************************************************/
+static DMAStatus DMA_Get_Stat( LOCATION, unsigned int eumbbar, unsigned int channel, DMA_SR * );
+
+/**************************************************************
+ * function: DMA_Get_Mode
+ *
+ * description: return the content of mode register of the
+ *              given DMA channel
+ *              if error, return DMAINVALID. Otherwise return DMASUCCESS.
+ *
+ **************************************************************/
+static DMAStatus DMA_Get_Mode( LOCATION, unsigned int eumbbar, unsigned int channel, DMA_MR * );
+
+/**************************************************************
+ * function: DMA_Set_Mode
+ *
+ * description: Set a new mode to a given DMA channel
+ *              return DMASUCCESS if success, otherwise return DMACHNINVALID
+ *
+ * note: It is not a good idea of changing the DMA mode during
+ *       the middle of a transaction.
+ **************************************************************/
+static DMAStatus DMA_Set_Mode( LOCATION, unsigned int eumbbar, unsigned int channel, DMA_MR mode );
+
+/*************************************************************
+ * function: DMA_ISR
+ *
+ * description: DMA interrupt service routine
+ *              return DMAStatus based on the status
+ *
+ *************************************************************/
+static DMAStatus    DMA_ISR( unsigned int eumbbar,
+							 unsigned int channel,
+						     DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ),
+					         DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ),
+					         DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ),
+					         DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus ));
+
+static DMAStatus dma_error_func( unsigned int, unsigned int, DMAStatus );
+
+/********************* DMA I/O function ********************/
+
+/************************************************************
+ * function: DMA_Start
+ *
+ * description: start a given DMA channel transaction
+ *              return DMASUCCESS if success, otherwise return DMACHNINVALID
+ *
+ * note: this function will clear DMA_MR(CC) first, then
+ *       set DMA_MR(CC).
+ ***********************************************************/
+static DMAStatus DMA_Start( LOCATION, unsigned int eumbbar,unsigned int channel );
+
+/***********************************************************
+ * function: DMA_Halt
+ *
+ * description: halt the current dma transaction on the specified
+ *              channel.
+ *              return DMASUCCESS if success, otherwise return DMACHNINVALID
+ *
+ * note: if the specified DMA channel is idle, nothing happens
+ *************************************************************/
+static DMAStatus DMA_Halt( LOCATION, unsigned int eumbbar,unsigned int channel );
+
+/*************************************************************
+ * function: DMA_Chn_Cnt
+ *
+ * description: set the DMA_MR(CC) bit for a given channel
+ *              that is in chaining mode.
+ *              return DMASUCCESS if successfule, otherwise return DMACHNINVALID
+ *
+ * note: if the given channel is not in chaining mode, nothing
+ *       happen.
+ *
+ *************************************************************/
+static DMAStatus DMA_Chn_Cnt( LOCATION, unsigned int eumbbar,unsigned int channel );
+
+/*********************** App. API ***************************
+ * App. API are the APIs Kernel provides for the application
+ * level program
+ ************************************************************/
+/**************************************************************
+ * function: DMA_Bld_Curr
+ *
+ * description: set current src, dest, byte count registers
+ *              according to the desp for a given channel
+ *
+ *              if the given channel is busy,  no change made,
+ *              return DMACHNBUSY.
+ *
+ *              otherwise return DMASUCCESS.
+ *
+ * note:
+ **************************************************************/
+static DMAStatus DMA_Bld_Curr( LOCATION,
+								  unsigned int eumbbar,
+								  unsigned int channel,
+							      DMA_CURR     desp );
+
+/**************************************************************
+ * function: DMA_Poke_Curr
+ *
+ * description: poke the current src, dest, byte count registers
+ *              for a given channel.
+ *
+ *              return DMASUCCESS if no error otherwise return DMACHNERROR
+ *
+ * note:        Due to the undeterministic parallelism, in chaining
+ *              mode, the value returned by this function shall
+ *              be taken as reference when the query is made rather
+ *              than the absolute snapshot when the value is returned.
+ **************************************************************/
+static DMAStatus DMA_Poke_Curr( LOCATION,
+							   unsigned int eumbbar,
+							   unsigned int channel,
+						       DMA_CURR*    desp );
+
+/**************************************************************
+ * function: DMA_Bld_Desp
+ *
+ * description: set current descriptor address register
+ *              according to the desp for a given channel
+ *
+ *              if the given channel is busy return DMACHNBUSY
+ *              and no change made, otherwise return DMASUCCESS.
+ *
+ * note:
+ **************************************************************/
+static DMAStatus DMA_Bld_Desp( LOCATION host,
+					          unsigned int eumbbar,
+					          unsigned int channel,
+					          DMA_CDAR     desp );
+
+/**************************************************************
+ * function: DMA_Poke_Desp
+ *
+ * description: poke the current descriptor address register
+ *              for a given channel
+ *
+ *              return DMASUCCESS if no error otherwise return
+ *              DMAINVALID
+ *
+ * note: Due to the undeterministic parallellism of DMA operation,
+ *       the value returned by this function shall be taken as
+ *       the most recently used descriptor when the last time
+ *       DMA starts a chaining mode operation.
+ **************************************************************/
+static DMAStatus DMA_Poke_Desp( LOCATION,
+							   unsigned int eumbbar,
+							   unsigned int channel,
+						       DMA_CDAR     *desp );
+
+#endif
diff --git a/cpu/mpc824x/drivers/dma/dma1.c b/cpu/mpc824x/drivers/dma/dma1.c
new file mode 100644
index 0000000..8c3834e
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/dma1.c
@@ -0,0 +1,801 @@
+/************************************************************
+ *
+ * copyright @ Motorola, 1999
+ *
+ * App. API
+ *
+ * App. API are the APIs Kernel provides for the application
+ * level program
+ *
+ ************************************************************/
+#include "dma_export.h"
+#include "dma.h"
+
+/* Define a macro to use an optional application-layer print function, if
+ * one was passed to the library during initialization.  If there was no
+ * function pointer passed, this protects against referencing a NULL pointer.
+ * Also define The global variable that holds the passed pointer.
+ */
+#define PRINT if ( app_print ) app_print
+static int (*app_print)(char *,...);
+
+/* Set by call to get_eumbbar during DMA_Initialize.
+ * This could be globally available to the library, but there is
+ * an advantage to passing it as a parameter: it is already in a register
+ * and doesn't have to be loaded from memory.  Also, that is the way the
+ * library was already implemented and I don't want to change it without
+ * a more detailed analysis.
+ * It is being set as a global variable during initialization to hide it from
+ * the DINK application layer, because it is Kahlua-specific.  I think that
+ * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in
+ * a Kahlua-specific library dealing with the embedded utilities memory block.
+ * Right now, get_eumbbar is defined in dink32/kahlua.s.  The other two are
+ * defined in dink32/drivers/i2c/i2c2.s, drivers/dma/dma2.s, etc.
+ */
+static unsigned int Global_eumbbar = 0;
+extern unsigned int get_eumbbar();
+
+
+extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg );
+#pragma Alias( load_runtime_reg, "load_runtime_reg" );
+
+extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val );
+#pragma Alias( store_runtime_reg, "store_runtime_reg" );
+
+unsigned int dma_reg_tb[][14] = {
+	/* local DMA registers */
+	{
+      /* DMA_0_MR   */  0x00001100,
+      /* DMA_0_SR   */  0x00001104,
+      /* DMA_0_CDAR */  0x00001108,
+      /* DMA_0_SAR  */  0x00001110,
+      /* DMA_0_DAR  */  0x00001118,
+      /* DMA_0_BCR  */  0x00001120,
+      /* DMA_0_NDAR */  0x00001124,
+      /* DMA_1_MR   */  0x00001200,
+      /* DMA_1_SR   */  0x00001204,
+      /* DMA_1_CDAR */  0x00001208,
+      /* DMA_1_SAR  */  0x00001210,
+      /* DMA_1_DAR  */  0x00001218,
+      /* DMA_1_BCR  */  0x00001220,
+      /* DMA_1_NDAR */  0x00001224,
+	},
+	/* remote DMA registers */
+	{
+      /* DMA_0_MR   */  0x00000100,
+      /* DMA_0_SR   */  0x00000104,
+      /* DMA_0_CDAR */  0x00000108,
+      /* DMA_0_SAR  */  0x00000110,
+      /* DMA_0_DAR  */  0x00000118,
+      /* DMA_0_BCR  */  0x00000120,
+      /* DMA_0_NDAR */  0x00000124,
+      /* DMA_1_MR   */  0x00000200,
+      /* DMA_1_SR   */  0x00000204,
+      /* DMA_1_CDAR */  0x00000208,
+      /* DMA_1_SAR  */  0x00000210,
+      /* DMA_1_DAR  */  0x00000218,
+      /* DMA_1_BCR  */  0x00000220,
+      /* DMA_1_NDAR */  0x00000224,
+	},
+};
+
+/* API functions */
+
+/*  Initialize DMA unit with the following:
+ *  optional pointer to application layer print function
+ *
+ *  These parameters may be added:
+ *  ???
+ *  Interrupt enables, modes, etc. are set for each transfer.
+ *
+ *  This function must be called before DMA unit can be used.
+ */
+extern
+DMA_Status DMA_Initialize( int (*p)(char *,...))
+{
+  DMAStatus status;
+  /* establish the pointer, if there is one, to the application's "printf" */
+  app_print = p;
+
+  /* If this is the first call, get the embedded utilities memory block
+   * base address.  I'm not sure what to do about error handling here:
+   * if a non-zero value is returned, accept it.
+   */
+  if ( Global_eumbbar == 0)
+     Global_eumbbar = get_eumbbar();
+  if ( Global_eumbbar == 0)
+  {
+    PRINT( "DMA_Initialize: can't find EUMBBAR\n" );
+    return DMA_ERROR;
+  }
+
+  return DMA_SUCCESS;
+}
+
+
+/* Perform the DMA transfer, only direct mode is currently implemented.
+ * At this point, I think it would be better to define a different
+ * function for chaining mode.
+ * Also, I'm not sure if it is appropriate to have the "generic" API
+ * accept snoop and int_steer parameters.  The DINK user interface allows
+ * them, so for now I'll leave them.
+ *
+ * int_steer controls DMA interrupt steering to PCI or local processor
+ * type is the type of transfer: M2M, M2P, P2M, P2P
+ * source is the source address of the data
+ * dest is the destination address of the data
+ * len is the length of data to transfer
+ * channel is the DMA channel to use for the transfer
+ * snoop is the snoop enable control
+ */
+extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer,
+                                       DMA_TRANSFER_TYPE type,
+                                       unsigned int source,
+                                       unsigned int dest,
+                                       unsigned int len,
+                                       DMA_CHANNEL channel,
+                                       DMA_SNOOP_MODE snoop)
+{
+    DMA_MR md;
+    DMA_CDAR cdar;
+    /* it's inappropriate for curr to be a struct, but I'll leave it */
+    DMA_CURR curr;
+
+    DMAStatus stat;
+
+	/* The rest of this code was moved from device.c test_dma to here.
+	 * It needs to be cleaned up and validated, but at least it is removed
+	 * from the application and API.  Most of the mode is left hard coded.
+	 * This should be changed after the final API is defined and the user
+	 * application has a way to control the transfer.
+	 *
+	 */
+
+	if ( DMA_Get_Mode( LOCAL, Global_eumbbar, channel, &md ) != DMASUCCESS )
+	{
+		return DMA_ERROR;
+	}
+
+	md.irqs = int_steer;
+	md.pde = 0;
+	md.dahts = 3; /* 8 - byte */
+	md.sahts = 3; /* 8 - byte */
+	md.dahe = 0;
+	md.sahe = 0;
+	md.prc = 0;
+	/* if steering interrupts to local processor, use polling mode */
+	if ( int_steer == DMA_INT_STEER_PCI )
+	{
+		md.eie = 1;
+		md.eotie = 1;
+	} else {
+		md.eie = 0;
+		md.eotie = 0;
+	}
+	md.dl = 0;
+	md.ctm = 1;   /* direct mode */
+    md.cc = 0;
+
+	/* validate the length range */
+	if (len > 0x3ffffff )
+	{
+		PRINT( "dev DMA: length of transfer too large: %d\n", len );
+		return DMA_ERROR;
+	}
+
+	/* inappropriate to use a struct, but leave as is for now */
+	curr.src_addr = source;
+	curr.dest_addr = dest;
+	curr.byte_cnt = len;
+
+	(void)DMA_Poke_Desp( LOCAL, Global_eumbbar, channel, &cdar );
+	cdar.snen = snoop;
+	cdar.ctt = type;
+
+	if ( ( stat = DMA_Bld_Desp( LOCAL, Global_eumbbar, channel, cdar ))
+			!= DMASUCCESS ||
+		 ( stat = DMA_Bld_Curr( LOCAL, Global_eumbbar, channel, curr ))
+			!= DMASUCCESS ||
+	     ( stat = DMA_Set_Mode( LOCAL, Global_eumbbar, channel, md ))
+			!= DMASUCCESS ||
+		 ( stat = DMA_Start( LOCAL, Global_eumbbar, channel ))
+			!= DMASUCCESS )
+	{
+		if ( stat == DMACHNBUSY )
+		{
+			PRINT( "dev DMA: channel %d busy.\n", channel );
+		}
+		else
+		{
+			PRINT( "dev DMA: invalid channel request.\n", channel );
+		}
+
+		return DMA_ERROR;
+	}
+
+/* Since we are interested at the DMA performace right now,
+   we are going to do as less as possible to burden the
+   603e core.
+
+   if you have epic enabled or don't care the return from
+   DMA operation, you can just return SUCCESS.
+
+   if you don't have epic enabled and care the DMA result,
+   you can use the polling method below.
+
+   Note: I'll attempt to activate the code for handling polling.
+ */
+
+#if 0
+	/* if steering interrupt to local processor, let it handle results */
+	if ( int_steer == DMA_INT_STEER_LOCAL )
+	{
+	    return DMA_SUCCESS;
+	}
+
+	/* polling since interrupt goes to PCI */
+	do
+	{
+		stat = DMA_ISR( Global_eumbbar, channel, dma_error_func,
+			dma_error_func, dma_error_func, dma_error_func );
+	}
+	while ( stat == DMANOEVENT );
+#endif
+
+    return DMA_SUCCESS;
+}
+
+/* DMA library internal functions */
+
+/**
+ * Note:
+ *
+ * In all following functions, the host (KAHLUA) processor has a
+ * choice of accessing on board local DMA (LOCAL),
+ * or DMA on a distributed KAHLUA (REMOTE). In either case,
+ * the caller shall pass the configured embedded utility memory
+ * block base address relative to the DMA. If LOCAL DMA is used,
+ * this parameter shall be EUMBBAR, if REMOTE is used, the
+ * parameter shall be the corresponding PCSRBAR.
+ **/
+
+/**************************************************************
+ * function: DMA_Get_Stat
+ *
+ * description: return the content of status register of
+ *              the given DMA channel
+ *
+ *              if error, reserved0 field all 1s.
+ **************************************************************/
+static
+DMAStatus DMA_Get_Stat( LOCATION host, unsigned int eumbbar, unsigned int channel, DMA_SR *stat )
+{
+    unsigned int tmp;
+
+   if ( channel != 0 && channel != 1 || stat == 0 )
+   {
+       return DMAINVALID;
+   }
+
+    tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG] );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) stat = 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG], tmp );
+#endif
+
+	 stat->reserved0 = ( tmp & 0xffffff00 ) >> 8;
+	 stat->lme       = ( tmp & 0x00000080 ) >> 7;
+	 stat->reserved1 = ( tmp & 0x00000060 ) >> 5;
+	 stat->pe        = ( tmp & 0x00000010 ) >> 4;
+	 stat->reserved2 = ( tmp & 0x00000008 ) >> 3;
+	 stat->cb        = ( tmp & 0x00000004 ) >> 2;
+	 stat->eosi      = ( tmp & 0x00000002 ) >> 1;
+	 stat->eocai     = ( tmp & 0x00000001 );
+
+   return DMASUCCESS;
+}
+
+/**************************************************************
+ * function: DMA_Get_Mode
+ *
+ * description: return the content of mode register of the
+ *              given DMA channel
+ *
+ *              if error, return DMAINVALID, otherwise return
+ *              DMASUCCESS
+ **************************************************************/
+static
+DMAStatus DMA_Get_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR *mode )
+{
+    unsigned int tmp;
+   if ( channel != 0 && channel != 1 || mode == 0 )
+   {
+     return DMAINVALID;
+   }
+
+    tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG] );
+
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) mode = 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG], tmp );
+#endif
+
+	 mode->reserved0 = (tmp & 0xfff00000) >> 20;
+	 mode->irqs      = (tmp & 0x00080000) >> 19;
+	 mode->pde       = (tmp & 0x00040000) >> 18;
+	 mode->dahts     = (tmp & 0x00030000) >> 16;
+     mode->sahts     = (tmp & 0x0000c000) >> 14;
+	 mode->dahe      = (tmp & 0x00002000) >> 13;
+	 mode->sahe      = (tmp & 0x00001000) >> 12;
+	 mode->prc       = (tmp & 0x00000c00) >> 10;
+	 mode->reserved1 = (tmp & 0x00000200) >> 9;
+	 mode->eie       = (tmp & 0x00000100) >> 8;
+	 mode->eotie     = (tmp & 0x00000080) >> 7;
+	 mode->reserved2 = (tmp & 0x00000070) >> 4;
+	 mode->dl        = (tmp & 0x00000008) >> 3;
+	 mode->ctm       = (tmp & 0x00000004) >> 2;
+	 mode->cc        = (tmp & 0x00000002) >> 1;
+	 mode->cs        = (tmp & 0x00000001);
+
+   return DMASUCCESS;
+}
+
+/**************************************************************
+ * function: DMA_Set_Mode
+ *
+ * description: Set a new mode to a given DMA channel
+ *
+ * note: It is not a good idea of changing the DMA mode during
+ *       the middle of a transaction.
+ **************************************************************/
+static
+DMAStatus DMA_Set_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR mode )
+{
+    unsigned int tmp;
+   if ( channel != 0 && channel != 1 )
+   {
+	   return DMAINVALID;
+   }
+
+   tmp = ( mode.reserved0 & 0xfff ) << 20;
+   tmp |= ( ( mode.irqs  & 0x1 ) << 19);
+   tmp |= ( ( mode.pde   & 0x1 ) << 18 );
+   tmp |= ( ( mode.dahts & 0x3 ) << 16 );
+   tmp |= ( ( mode.sahts & 0x3 ) << 14 );
+   tmp |= ( ( mode.dahe  & 0x1 ) << 13 );
+   tmp |= ( ( mode.sahe  & 0x1 ) << 12 );
+   tmp |= ( ( mode.prc   & 0x3 ) << 10 );
+   tmp |= ( ( mode.reserved1 & 0x1 ) << 9 );
+   tmp |= ( ( mode.eie   & 0x1 ) << 8 );
+   tmp |= ( ( mode.eotie & 0x1 ) << 7 );
+   tmp |= ( ( mode.reserved2 & 0x7 ) << 4 );
+   tmp |= ( ( mode.dl    & 0x1 ) << 3 );
+   tmp |= ( ( mode.ctm   & 0x1 ) << 2 );
+   tmp |= ( ( mode.cc    & 0x1 ) << 1 ) ;
+   tmp |= ( mode.cs    & 0x1 );
+
+   store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], tmp );
+   return DMASUCCESS;
+}
+
+/************************************************************
+ * function: DMA_Start
+ *
+ * description: start a given DMA channel transaction
+ *              return DMASUCCESS if success otherwise return
+ *              DMAStatus value
+ *
+ * note: this function will clear DMA_MR(CC) first, then
+ *       set DMA_MR(CC).
+ ***********************************************************/
+static
+DMAStatus DMA_Start( LOCATION host, unsigned int eumbbar, unsigned int channel )
+{
+   DMA_SR stat;
+   unsigned int mode;
+
+   if ( channel != 0 && channel != 1 )
+   {
+	   return DMAINVALID;
+   }
+
+   if ( DMA_Get_Stat( host, eumbbar, channel, &stat ) != DMASUCCESS )
+   {
+		   return DMAINVALID;
+   }
+
+   if ( stat.cb == 1 )
+   {
+	   /* DMA is not free */
+	   return DMACHNBUSY;
+   }
+
+   mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG] );
+   /* clear DMA_MR(CS) */
+   mode &= 0xfffffffe;
+   store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
+
+   /* set DMA_MR(CS) */
+   mode |= CS;
+   store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
+   return DMASUCCESS;
+}
+
+/***********************************************************
+ * function: DMA_Halt
+ *
+ * description: halt the current dma transaction on the specified
+ *              channel.
+ *              return DMASUCCESS if success otherwise return DMAINVALID
+ *
+ * note: if the specified DMA channel is idle, nothing happens
+ *************************************************************/
+static
+DMAStatus DMA_Halt( LOCATION host, unsigned int eumbbar, unsigned int channel )
+{
+   unsigned int mode;
+   if ( channel != 0 && channel != 1 )
+   {
+	   return DMAINVALID;
+   }
+
+   mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG]);
+
+   /* clear DMA_MR(CS) */
+   mode &= 0xfffffffe;
+   store_runtime_reg(eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
+   return DMASUCCESS;
+}
+
+/*************************************************************
+ * function: DMA_Chn_Cnt
+ *
+ * description: set the DMA_MR(CC) bit for a given channel
+ *              that is in chaining mode.
+ *              return DMASUCCESS if successfule, otherwise return
+ *              DMAINVALID.
+ *
+ * note: if the given channel is not in chaining mode, nothing
+ *       happen.
+ *
+ *************************************************************/
+static
+DMAStatus DMA_Chn_Cnt( LOCATION host, unsigned int eumbbar, unsigned int channel )
+{
+	DMA_MR mode;
+	if ( channel != 0 && channel != 1 )
+	{
+		return DMAINVALID;
+	}
+
+	if ( DMA_Get_Mode( host, eumbbar, channel, &mode ) != DMASUCCESS )
+	{
+			return DMAINVALID;
+	}
+
+	if ( mode.ctm == 0 )
+	{
+		/* either illegal mode or not chaining mode */
+		return DMAINVALID;
+	}
+
+	mode.cc = 1;
+	return DMA_Set_Mode( host, eumbbar, channel, mode );
+}
+
+/**************************************************************
+ * function: DMA_Bld_Desp
+ *
+ * description: set current descriptor address register
+ *              according to the desp for a given channel
+ *
+ *              if the given channel is busy return DMACHNBUSY
+ *              and no change made, otherwise return DMASUCCESS.
+ *
+ * note:
+ **************************************************************/
+static
+DMAStatus DMA_Bld_Desp( LOCATION host,
+						   unsigned int eumbbar,
+						   unsigned int channel,
+						   DMA_CDAR     desp )
+{
+	DMA_SR status;
+	unsigned int temp;
+
+	if ( channel != 0 && channel != 1 )
+	{
+		/* channel number out of range */
+		return DMAINVALID;
+	}
+
+	if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS )
+	{
+			return DMAINVALID;
+	}
+
+	if ( status.cb == 1 )
+	{
+		/* channel busy */
+		return DMACHNBUSY;
+	}
+
+	temp = ( desp.cda & 0x7ffffff ) << 5;
+	temp |= (( desp.snen & 0x1 ) << 4 );
+	temp |= (( desp.eosie & 0x1 ) << 3 );
+	temp |= (( desp.ctt   & 0x3 ) << 1 );
+    temp |= ( desp.eotd  & 0x1 );
+
+    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp );
+
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) cdar := 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp );
+#endif
+
+	return DMASUCCESS;
+}
+
+/**************************************************************
+ * function: DMA_Poke_Desp
+ *
+ * description: poke the current descriptor address register
+ *              for a given channel
+ *
+ *              return DMASUCCESS if no error
+ *
+ * note: Due to the undeterministic parallellism of DMA operation,
+ *       the value returned by this function shall be taken as
+ *       the most recently used descriptor when the last time
+ *       DMA starts a chaining mode operation.
+ **************************************************************/
+static
+DMAStatus DMA_Poke_Desp( LOCATION host,
+						    unsigned int eumbbar,
+						    unsigned int channel,
+						    DMA_CDAR     *desp )
+{
+	unsigned int cdar;
+	if ( channel != 0 && channel != 1 || desp == 0 )
+	{
+			return DMAINVALID;
+	}
+
+    cdar = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG] );
+
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) cdar : 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], cdar );
+#endif
+
+
+	desp->cda   = ( cdar & 0xffffffe0 ) >> 5;
+	desp->snen  = ( cdar & 0x00000010 ) >> 4;
+	desp->eosie = ( cdar & 0x00000008 ) >> 3;
+	desp->ctt   = ( cdar & 0x00000006 ) >> 1;
+	desp->eotd  = ( cdar & 0x00000001 );
+
+	return DMASUCCESS;
+}
+
+/**************************************************************
+ * function: DMA_Bld_Curr
+ *
+ * description: set current src, dest, byte count registers
+ *              according to the desp for a given channel
+ *              return DMASUCCESS if no error.
+ *
+ * note:
+ **************************************************************/
+static
+DMAStatus DMA_Bld_Curr( LOCATION host,
+					   unsigned int eumbbar,
+					   unsigned int channel,
+					   DMA_CURR     desp )
+{
+	DMA_SR status;
+	if ( channel != 0 && channel != 1 )
+	{
+		/* channel number out of range */
+		return DMAINVALID;
+	}
+
+	if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS )
+	{
+		 return DMAINVALID;
+	}
+
+	if ( status.cb == 1  )
+	{
+		/* channel busy */
+		return DMACHNBUSY;
+	}
+
+	desp.byte_cnt &= 0x03ffffff; /* upper 6-bits are 0s */
+
+    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG], desp.src_addr );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) src := 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.src_addr );
+#endif
+
+    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG], desp.dest_addr );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) dest := 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.dest_addr );
+#endif
+
+    store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG], desp.byte_cnt );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) count := 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.byte_cnt );
+#endif
+
+
+	return DMASUCCESS;
+
+}
+
+/**************************************************************
+ * function: DMA_Poke_Curr
+ *
+ * description: poke the current src, dest, byte count registers
+ *              for a given channel.
+ *
+ *              return DMASUCCESS if no error
+ *
+ * note:        Due to the undeterministic parallelism, in chaining
+ *              mode, the value returned by this function shall
+ *              be taken as reference when the query is made rather
+ *              than the absolute snapshot when the value is returned.
+ **************************************************************/
+static
+DMAStatus DMA_Poke_Curr( LOCATION host,
+					    unsigned int eumbbar,
+					    unsigned int channel,
+					    DMA_CURR*    desp )
+{
+	if ( channel != 0 && channel != 1 || desp == 0 )
+	{
+			return DMAINVALID;
+	}
+
+	desp->src_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG] );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) src : 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->src_addr );
+#endif
+
+	desp->dest_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG] );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) dest : 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->dest_addr );
+#endif
+
+    desp->byte_cnt = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG] );
+#ifdef DMADBG0
+   PRINT( "%s(%d): %s DMA %d (0x%08x) count : 0x%08x\n", __FILE__, __LINE__,
+		  ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->byte_cnt );
+#endif
+
+
+	return DMASUCCESS;
+}
+
+/*****************************************************************
+ * function: dma_error_func
+ *
+ * description: display the error information
+ *
+ * note: This seems like a highly convoluted way to handle messages,
+ * but I'll leave it as it was in device.c when I moved it into the
+ * DMA library source.
+ ****************************************************************/
+static
+DMAStatus dma_error_func( unsigned int eumbbar, unsigned int chn, DMAStatus err)
+{
+	unsigned char *msg[] =
+		{
+			"Local Memory Error",
+			"PCI Error",
+			"Channel Busy",
+			"End-of-Segment Interrupt",
+			"End-of-Chain/Direct Interrupt",
+		};
+
+	   if ( err >= DMALMERROR && err <= DMAEOCAINT )
+	   {
+	     PRINT( "DMA Status: channel %d  %s\n", chn, msg[err-DMASUCCESS-1] );
+	   }
+
+	   return err;
+
+}
+
+/*************************************************************
+ * function: DMA_ISR
+ *
+ * description: DMA interrupt service routine
+ *              return DMAStatus value based on
+ *              the status
+ *
+ *************************************************************/
+static
+DMAStatus DMA_ISR( unsigned int eumbbar,
+				  unsigned int channel,
+				  DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ),
+				  DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ),
+				  DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ),
+				  DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus ))
+{
+
+	DMA_SR stat;
+	DMAStatus rval = DMANOEVENT;
+    unsigned int temp;
+
+	if ( channel != 0 && channel != 1 )
+	{
+		return DMAINVALID;
+	}
+
+	if ( DMA_Get_Stat( LOCAL, eumbbar, channel, &stat ) != DMASUCCESS )
+	{
+			return DMAINVALID;
+	}
+
+	if ( stat.lme == 1 )
+	{
+		/* local memory error */
+		rval = DMALMERROR;
+		if ( lme_func != 0 )
+		{
+		  rval = (*lme_func)(eumbbar, channel, DMALMERROR );
+	    }
+
+	}
+	else if ( stat.pe == 1 )
+	{
+        /* PCI error */
+		rval = DMAPERROR;
+		if ( pe_func != 0 )
+		{
+		  rval = (*pe_func)(eumbbar, channel, DMAPERROR );
+	    }
+
+	}
+	else if ( stat.eosi == 1 )
+	{
+		/* end-of-segment interrupt */
+		rval = DMAEOSINT;
+		if ( eosi_func != 0 )
+		{
+		  rval = (*eosi_func)(eumbbar, channel, DMAEOSINT );
+	    }
+	}
+	else
+	{
+		/* End-of-chain/direct interrupt */
+		rval = DMAEOCAINT;
+		if ( eocai_func != 0 )
+		{
+		  rval = (*eocai_func)(eumbbar, channel, DMAEOCAINT );
+	    }
+	}
+
+    temp = ( stat.reserved0 & 0xffffff ) << 8;
+   	temp |= ( ( stat.lme       & 0x1 ) << 7 );  /* write one to clear */
+	temp |= ( ( stat.reserved1 & 0x3 ) << 5 );
+    temp |= ( ( stat.pe        & 0x1 ) << 4 );  /* write one to clear */
+    temp |= ( ( stat.reserved2 & 0x1 ) << 3 );
+	temp |= ( ( stat.cb        & 0x1 ) << 2 );  /* write one to clear */
+    temp |= ( ( stat.eosi      & 0x1 ) << 1 );  /* write one to clear */
+    temp |= ( stat.eocai & 0x1 );               /* write one to clear */
+
+    store_runtime_reg( eumbbar, dma_reg_tb[LOCAL][channel*NUM_DMA_REG + DMA_SR_REG], temp );
+
+#ifdef DMADBG0
+	PRINT( "%s(%d): DMA channel %d SR := 0x%08x\n", __FILE__, __LINE__, channel, temp );
+#endif
+
+	return rval;
+}
diff --git a/cpu/mpc824x/drivers/dma/dma2.S b/cpu/mpc824x/drivers/dma/dma2.S
new file mode 100644
index 0000000..dab1de3
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/dma2.S
@@ -0,0 +1,45 @@
+/**************************************
+ *
+ * copyright @ Motorola, 1999
+ *
+ **************************************/
+
+/**********************************************************
+ * function: load_runtime_reg
+ *
+ * input:  r3 - value of eumbbar
+ *         r4 - register offset in embedded utility space
+ *
+ * output: r3 - register content
+ **********************************************************/
+      .text
+      .align 2
+      .global load_runtime_reg
+
+load_runtime_reg:
+
+	      lwbrx	r3,r4,r3
+	      sync
+
+ 	      bclr 20, 0
+
+/****************************************************************
+ * function: store_runtime_reg
+ *
+ * input: r3 - value of eumbbar
+ *        r4 - register offset in embedded utility space
+ *        r5 - new value to be stored
+ *
+ ****************************************************************/
+           .text
+           .align 2
+           .global store_runtime_reg
+store_runtime_reg:
+
+	      stwbrx r5,  r4, r3
+	      sync
+
+		  bclr   20,0
+
+
+
diff --git a/cpu/mpc824x/drivers/dma/dma_export.h b/cpu/mpc824x/drivers/dma/dma_export.h
new file mode 100644
index 0000000..cb750dd
--- /dev/null
+++ b/cpu/mpc824x/drivers/dma/dma_export.h
@@ -0,0 +1,100 @@
+#ifndef DMA_EXPORT_H
+#define DMA_EXPORT_H
+
+/****************************************************
+ * $Id:
+ *
+ * Copyright Motorola 1999
+ *
+ * $Log:
+ *
+ ****************************************************/
+
+/* These are the defined return values for the DMA_* functions.
+ * Any non-zero value indicates failure.  Failure modes can be added for
+ * more detailed error reporting.
+ */
+typedef enum _dma_status
+{
+ DMA_SUCCESS     = 0,
+ DMA_ERROR,
+} DMA_Status;
+
+/* These are the defined channel transfer types.  */
+typedef enum _dma_transfer_types
+{
+	DMA_M2M =  0,	/* local memory to local memory */
+	DMA_M2P =  1,	/* local memory to PCI */
+	DMA_P2M =  2,	/* PCI to local memory */
+	DMA_P2P =  3,	/* PCI to PCI */
+} DMA_TRANSFER_TYPE;
+
+typedef enum _dma_interrupt_steer
+{
+	DMA_INT_STEER_LOCAL =  0, /* steer DMA int to local processor */
+	DMA_INT_STEER_PCI = 1,    /* steer DMA int to PCI bus through INTA_ */
+} DMA_INTERRUPT_STEER;
+
+typedef enum _dma_channel
+{
+	DMA_CHN_0 =  0, /* kahlua has two dma channels: 0 and 1 */
+	DMA_CHN_1 =  1,
+} DMA_CHANNEL;
+
+typedef enum _dma_snoop_mode
+{
+	DMA_SNOOP_DISABLE =  0,
+	DMA_SNOOP_ENABLE = 1,
+} DMA_SNOOP_MODE;
+
+/******************** App. API ********************
+ * The application API is for user level application
+ * to use the functionality provided by DMA driver.
+ * This is a "generic" DMA interface, it should contain
+ * nothing specific to the Kahlua implementation.
+ * Only the generic functions are exported by the library.
+ *
+ * Note: Its App.s responsibility to swap the data
+ *       byte. In our API, we currently transfer whatever
+ *       we are given - Big/Little Endian.  This could
+ *       become part of the DMA config, though.
+ **************************************************/
+
+
+/*  Initialize DMA unit with the following:
+ *  optional pointer to application layer print function
+ *
+ *  These parameters may be added:
+ *  ???
+ *  Interrupt enables, modes, etc. are set for each transfer.
+ *
+ *  This function must be called before DMA unit can be used.
+ */
+extern DMA_Status DMA_Initialize(
+        int (*app_print_function)(char *,...)); /* pointer to optional "printf"
+                                                 * provided by application
+                                                 */
+
+/* Perform the DMA transfer, only direct mode is currently implemented.
+ * At this point, I think it would be better to define a different
+ * function for chaining mode.
+ * Also, I'm not sure if it is appropriate to have the "generic" API
+ * accept snoop and int_steer parameters.  The DINK user interface allows
+ * them, so for now I'll leave them.
+ *
+ * int_steer controls DMA interrupt steering to PCI or local processor
+ * type is the type of transfer: M2M, M2P, P2M, P2P
+ * source is the source address of the data
+ * dest is the destination address of the data
+ * len is the length of data to transfer
+ * channel is the DMA channel to use for the transfer
+ * snoop is the snoop enable control
+ */
+extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer,
+                                       DMA_TRANSFER_TYPE type,
+                                       unsigned int source,
+                                       unsigned int dest,
+                                       unsigned int len,
+                                       DMA_CHANNEL channel,
+                                       DMA_SNOOP_MODE snoop);
+#endif