From 327f7a020a3037ae8ef6c94488d5e9a3aa772943 Mon Sep 17 00:00:00 2001 From: wdenk Date: Wed, 28 Nov 2001 17:49:55 +0000 Subject: Initial revision --- cpu/mpc824x/drivers/dma/Makefile | 83 ++++ cpu/mpc824x/drivers/dma/Makefile_pc | 89 ++++ cpu/mpc824x/drivers/dma/README | 102 +++++ cpu/mpc824x/drivers/dma/dma.h | 326 ++++++++++++++ cpu/mpc824x/drivers/dma/dma1.c | 801 +++++++++++++++++++++++++++++++++++ cpu/mpc824x/drivers/dma/dma2.S | 45 ++ cpu/mpc824x/drivers/dma/dma_export.h | 100 +++++ 7 files changed, 1546 insertions(+) create mode 100644 cpu/mpc824x/drivers/dma/Makefile create mode 100644 cpu/mpc824x/drivers/dma/Makefile_pc create mode 100644 cpu/mpc824x/drivers/dma/README create mode 100644 cpu/mpc824x/drivers/dma/dma.h create mode 100644 cpu/mpc824x/drivers/dma/dma1.c create mode 100644 cpu/mpc824x/drivers/dma/dma2.S create mode 100644 cpu/mpc824x/drivers/dma/dma_export.h (limited to 'cpu/mpc824x/drivers/dma') 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 -- cgit v1.1