OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uC-libc/] [include/] [asm/] [dma.h] - Rev 1765

Compare with Previous | Blame | View Log

#ifndef _OR1K_DMA_H
#define _OR1K_DMA_H 1
 
#include <linux/config.h>
 
#ifdef CONFIG_COLDFIRE
/*
 * ColdFire DMA Model:
 *   ColdFire DMA supports two forms of DMA: Single and Dual address. Single
 * address mode emits a source address, and expects that the device will either
 * pick up the data (DMA READ) or source data (DMA WRITE). This implies that
 * the device will place data on the correct byte(s) of the data bus, as the
 * memory transactions are always 32 bits. This implies that only 32 bit
 * devices will find single mode transfers useful. Dual address DMA mode
 * performs two cycles: source read and destination write. ColdFire will
 * align the data so that the device will always get the correct bytes, thus
 * is useful for 8 and 16 bit devices. This is the mode that is supported
 * below.
 */
 
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfdma.h>
 
/*
 * Set number of channels of DMA on ColdFire for different implementations
 */
#if defined(CONFIG_M5307)
#define MAX_DMA_CHANNELS 4
#else
#define MAX_DMA_CHANNELS 2
#endif
 
extern unsigned int dma_base_addr[];
 
/* Storage for where to write/read DMA data to/from */
unsigned int dma_device_address[MAX_DMA_CHANNELS];
 
#define DMA_MODE_WRITE_BIT 0x01  /* Memory/IO to IO/Memory select */
#define DMA_MODE_WORD_BIT  0x02  /* 8 or 16 bit transfers */
 
/* I/O to memory, 8 bits, mode */
#define DMA_MODE_READ	         0
/* memory to I/O, 8 bits, mode */
#define DMA_MODE_WRITE	         1
/* I/O to memory, 16 bits, mode */
#define DMA_MODE_READ_WORD       2
/* memory to I/O, 16 bits, mode */
#define DMA_MODE_WRITE_WORD      3
 
/* enable/disable a specific DMA channel */
static __inline__ void enable_dma(unsigned int dmanr)
{
  volatile unsigned short *dmawp;
 
  dmawp = (unsigned short *) dma_base_addr[dmanr];
  dmawp[MCFDMA_DCR] |= MCFDMA_DCR_EEXT;
 
}
 
static __inline__ void disable_dma(unsigned int dmanr)
{
  volatile unsigned short *dmawp;
  volatile unsigned char  *dmapb;
 
  dmawp = (unsigned short *) dma_base_addr[dmanr];
  dmapb = (unsigned char *) dma_base_addr[dmanr];
 
  /* Turn off external requests, and stop any DMA in progress */
  dmawp[MCFDMA_DCR] &= ~MCFDMA_DCR_EEXT;
  dmapb[MCFDMA_DSR] = MCFDMA_DSR_DONE;
}
 
/* Clear the 'DMA Pointer Flip Flop'.
 * Write 0 for LSB/MSB, 1 for MSB/LSB access.
 * Use this once to initialize the FF to a known state.
 * After that, keep track of it. :-)
 * --- In order to do that, the DMA routines below should ---
 * --- only be used while interrupts are disabled! ---
 *
 * This is a NOP for ColdFire. Provide a stub for compatibility.
 */
 
static __inline__ void clear_dma_ff(unsigned int dmanr)
{
}
 
/* set mode (above) for a specific DMA channel */
static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
{
  volatile unsigned char  *dmabp;
  volatile unsigned short *dmawp;
 
  dmabp = (unsigned char *) dma_base_addr[dmanr];
  dmawp = (unsigned short *) dma_base_addr[dmanr];
 
  // Clear config errors
  dmabp[MCFDMA_DSR] = MCFDMA_DSR_DONE; 
 
  // Set command register
  dmawp[MCFDMA_DCR] =
    MCFDMA_DCR_INT |         // Enable completion irq
    MCFDMA_DCR_CS |          // Force one xfer per request
    MCFDMA_DCR_AA |          // Enable auto alignment
    // Memory to I/O or I/O to Memory
    ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_SINC : MCFDMA_DCR_DINC) |
    // 16 bit or 8 bit transfers
    ((mode & DMA_MODE_WORD_BIT)  ? MCFDMA_DCR_SSIZE_WORD :
                                   MCFDMA_DCR_SSIZE_BYTE) |
    ((mode & DMA_MODE_WORD_BIT)  ? MCFDMA_DCR_DSIZE_WORD : 
                                   MCFDMA_DCR_DSIZE_BYTE) ;
 
#ifdef DMA_DEBUG
  printk("%s: Setting stat %x: %x ctrl %x: %x regs for chan %d\n",
         __FUNCTION__, 
	 &dmabp[MCFDMA_DSR], dmabp[MCFDMA_DSR],
	 &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR],
	 dmanr);
#endif
}
/* Set transfer address for specific DMA channel */
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) {
  volatile unsigned short *dmawp;
  volatile unsigned int   *dmalp;
 
  dmawp = (unsigned short *) dma_base_addr[dmanr];
  dmalp = (unsigned int *) dma_base_addr[dmanr];
 
  // Determine which address registers are used for memory/device accesses
  if (dmawp[MCFDMA_DCR] & MCFDMA_DCR_SINC) {
    // Source incrementing, must be memory
    dmalp[MCFDMA_SAR] = a;
    // Set dest address, must be device
    dmalp[MCFDMA_DAR] = dma_device_address[dmanr];
  }
  else {
    // Destination incrementing, must be memory
    dmalp[MCFDMA_DAR] = a;
    // Set source address, must be device
    dmalp[MCFDMA_SAR] = dma_device_address[dmanr];
  }
 
#ifdef DMA_DEBUG
  printk("%s: Setting src %x dest %x addr for chan %d\n",
         __FUNCTION__, dmalp[MCFDMA_SAR], dmalp[MCFDMA_DAR], dmanr);
#endif
}
 
/*
 * Specific for Coldfire - sets device address.
 * Should be called after the mode set call, and before set DMA address.
 */
static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a) {
  dma_device_address[dmanr] = a;
#ifdef DMA_DEBUG
  printk("%s: Setting device addr %x for chan %d\n",
         __FUNCTION__, dma_device_address[dmanr], dmanr);
#endif DMA_DEBUG
}
 
/*
 * NOTE 2: "count" represents _bytes_.
 */
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
{
  volatile unsigned short *dmawp;
 
  dmawp = (unsigned short *) dma_base_addr[dmanr];
  dmawp[MCFDMA_BCR] = (unsigned short)count;
 
#ifdef DMA_DEBUG
  printk("%s: Setting count %x for chan %d\n",
         __FUNCTION__, (unsigned short)count , dmanr);
#endif DMA_DEBUG
 
}
 
/* Get DMA residue count. After a DMA transfer, this
 * should return zero. Reading this while a DMA transfer is
 * still in progress will return unpredictable results.
 * Otherwise, it returns the number of _bytes_ left to transfer.
 *
 */
static __inline__ int get_dma_residue(unsigned int dmanr)
{
  volatile unsigned short *dmawp;
  unsigned short count;
 
  dmawp = (unsigned short *) dma_base_addr[dmanr];
  count = dmawp[MCFDMA_BCR];
  return((int) count);
}
 
#else
 
 #define MAX_DMA_CHANNELS 8
 
#endif /* CONFIG_COLDFIRE */
 
/* Don't define MAX_DMA_ADDRESS; it's useless on the m68k/coldfire and any
   occurrence should be flagged as an error.  */
 
/* These are in kernel/dma.c: */
 extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
 extern void free_dma(unsigned int dmanr);	/* release it again */
 
#endif /* _OR1K_DMA_H */
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.