827 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			827 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*****************************************************************************
 | |
| * Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
 | |
| *
 | |
| * Unless you and Broadcom execute a separate written software license
 | |
| * agreement governing use of this software, this software is licensed to you
 | |
| * under the terms of the GNU General Public License version 2, available at
 | |
| * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
 | |
| *
 | |
| * Notwithstanding the above, under no circumstances may you combine this
 | |
| * software in any way with any other Broadcom software provided under a
 | |
| * license other than the GPL, without Broadcom's express prior written
 | |
| * consent.
 | |
| *****************************************************************************/
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   @file   dma.h
 | |
| *
 | |
| *   @brief  API definitions for the linux DMA interface.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| #if !defined(ASM_ARM_ARCH_BCMRING_DMA_H)
 | |
| #define ASM_ARM_ARCH_BCMRING_DMA_H
 | |
| 
 | |
| /* ---- Include Files ---------------------------------------------------- */
 | |
| 
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/wait.h>
 | |
| #include <linux/semaphore.h>
 | |
| #include <csp/dmacHw.h>
 | |
| #include <mach/timer.h>
 | |
| #include <linux/scatterlist.h>
 | |
| #include <linux/dma-mapping.h>
 | |
| #include <linux/mm.h>
 | |
| #include <linux/vmalloc.h>
 | |
| #include <linux/pagemap.h>
 | |
| 
 | |
| /* ---- Constants and Types ---------------------------------------------- */
 | |
| 
 | |
| /* If DMA_DEBUG_TRACK_RESERVATION is set to a non-zero value, then the filename */
 | |
| /* and line number of the reservation request will be recorded in the channel table */
 | |
| 
 | |
| #define DMA_DEBUG_TRACK_RESERVATION   1
 | |
| 
 | |
| #define DMA_NUM_CONTROLLERS     2
 | |
| #define DMA_NUM_CHANNELS        8	/* per controller */
 | |
| 
 | |
| typedef enum {
 | |
| 	DMA_DEVICE_MEM_TO_MEM,	/* For memory to memory transfers */
 | |
| 	DMA_DEVICE_I2S0_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_I2S0_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_I2S1_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_I2S1_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_APM_CODEC_A_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_APM_CODEC_A_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_APM_CODEC_B_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_APM_CODEC_B_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_APM_CODEC_C_DEV_TO_MEM,	/* Additional mic input for beam-forming */
 | |
| 	DMA_DEVICE_APM_PCM0_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_APM_PCM0_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_APM_PCM1_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_APM_PCM1_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_SPUM_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_SPUM_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_SPIH_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_SPIH_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_UART_A_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_UART_A_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_UART_B_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_UART_B_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_PIF_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_PIF_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_ESW_DEV_TO_MEM,
 | |
| 	DMA_DEVICE_ESW_MEM_TO_DEV,
 | |
| 	DMA_DEVICE_VPM_MEM_TO_MEM,
 | |
| 	DMA_DEVICE_CLCD_MEM_TO_MEM,
 | |
| 	DMA_DEVICE_NAND_MEM_TO_MEM,
 | |
| 	DMA_DEVICE_MEM_TO_VRAM,
 | |
| 	DMA_DEVICE_VRAM_TO_MEM,
 | |
| 
 | |
| 	/* Add new entries before this line. */
 | |
| 
 | |
| 	DMA_NUM_DEVICE_ENTRIES,
 | |
| 	DMA_DEVICE_NONE = 0xff,	/* Special value to indicate that no device is currently assigned. */
 | |
| 
 | |
| } DMA_Device_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_Handle_t is the primary object used by callers of the API.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| #define DMA_INVALID_HANDLE  ((DMA_Handle_t) -1)
 | |
| 
 | |
| typedef int DMA_Handle_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_DescriptorRing_t contains a ring of descriptors which is used
 | |
| *   to point to regions of memory.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| typedef struct {
 | |
| 	void *virtAddr;		/* Virtual Address of the descriptor ring */
 | |
| 	dma_addr_t physAddr;	/* Physical address of the descriptor ring */
 | |
| 	int descriptorsAllocated;	/* Number of descriptors allocated in the descriptor ring */
 | |
| 	size_t bytesAllocated;	/* Number of bytes allocated in the descriptor ring */
 | |
| 
 | |
| } DMA_DescriptorRing_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_MemType_t and DMA_MemMap_t are helper structures used to setup
 | |
| *   DMA chains from a variety of memory sources.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| #define DMA_MEM_MAP_MIN_SIZE    4096	/* Pages less than this size are better */
 | |
| 					/* off not being DMA'd. */
 | |
| 
 | |
| typedef enum {
 | |
| 	DMA_MEM_TYPE_NONE,	/* Not a valid setting */
 | |
| 	DMA_MEM_TYPE_VMALLOC,	/* Memory came from vmalloc call */
 | |
| 	DMA_MEM_TYPE_KMALLOC,	/* Memory came from kmalloc call */
 | |
| 	DMA_MEM_TYPE_DMA,	/* Memory came from dma_alloc_xxx call */
 | |
| 	DMA_MEM_TYPE_USER,	/* Memory came from user space. */
 | |
| 
 | |
| } DMA_MemType_t;
 | |
| 
 | |
| /* A segment represents a physically and virtually contiguous chunk of memory. */
 | |
| /* i.e. each segment can be DMA'd */
 | |
| /* A user of the DMA code will add memory regions. Each region may need to be */
 | |
| /* represented by one or more segments. */
 | |
| 
 | |
| typedef struct {
 | |
| 	void *virtAddr;		/* Virtual address used for this segment */
 | |
| 	dma_addr_t physAddr;	/* Physical address this segment maps to */
 | |
| 	size_t numBytes;	/* Size of the segment, in bytes */
 | |
| 
 | |
| } DMA_Segment_t;
 | |
| 
 | |
| /* A region represents a virtually contiguous chunk of memory, which may be */
 | |
| /* made up of multiple segments. */
 | |
| 
 | |
| typedef struct {
 | |
| 	DMA_MemType_t memType;
 | |
| 	void *virtAddr;
 | |
| 	size_t numBytes;
 | |
| 
 | |
| 	/* Each region (virtually contiguous) consists of one or more segments. Each */
 | |
| 	/* segment is virtually and physically contiguous. */
 | |
| 
 | |
| 	int numSegmentsUsed;
 | |
| 	int numSegmentsAllocated;
 | |
| 	DMA_Segment_t *segment;
 | |
| 
 | |
| 	/* When a region corresponds to user memory, we need to lock all of the pages */
 | |
| 	/* down before we can figure out the physical addresses. The lockedPage array contains */
 | |
| 	/* the pages that were locked, and which subsequently need to be unlocked once the */
 | |
| 	/* memory is unmapped. */
 | |
| 
 | |
| 	unsigned numLockedPages;
 | |
| 	struct page **lockedPages;
 | |
| 
 | |
| } DMA_Region_t;
 | |
| 
 | |
| typedef struct {
 | |
| 	int inUse;		/* Is this mapping currently being used? */
 | |
| 	struct semaphore lock;	/* Acquired when using this structure */
 | |
| 	enum dma_data_direction dir;	/* Direction this transfer is intended for */
 | |
| 
 | |
| 	/* In the event that we're mapping user memory, we need to know which task */
 | |
| 	/* the memory is for, so that we can obtain the correct mm locks. */
 | |
| 
 | |
| 	struct task_struct *userTask;
 | |
| 
 | |
| 	int numRegionsUsed;
 | |
| 	int numRegionsAllocated;
 | |
| 	DMA_Region_t *region;
 | |
| 
 | |
| } DMA_MemMap_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_DeviceAttribute_t contains information which describes a
 | |
| *   particular DMA device (or peripheral).
 | |
| *
 | |
| *   It is anticipated that the arrary of DMA_DeviceAttribute_t's will be
 | |
| *   statically initialized.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| /* The device handler is called whenever a DMA operation completes. The reaon */
 | |
| /* for it to be called will be a bitmask with one or more of the following bits */
 | |
| /* set. */
 | |
| 
 | |
| #define DMA_HANDLER_REASON_BLOCK_COMPLETE       dmacHw_INTERRUPT_STATUS_BLOCK
 | |
| #define DMA_HANDLER_REASON_TRANSFER_COMPLETE    dmacHw_INTERRUPT_STATUS_TRANS
 | |
| #define DMA_HANDLER_REASON_ERROR                dmacHw_INTERRUPT_STATUS_ERROR
 | |
| 
 | |
| typedef void (*DMA_DeviceHandler_t) (DMA_Device_t dev, int reason,
 | |
| 				     void *userData);
 | |
| 
 | |
| #define DMA_DEVICE_FLAG_ON_DMA0             0x00000001
 | |
| #define DMA_DEVICE_FLAG_ON_DMA1             0x00000002
 | |
| #define DMA_DEVICE_FLAG_PORT_PER_DMAC       0x00000004	/* If set, it means that the port used on DMAC0 is different from the port used on DMAC1 */
 | |
| #define DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST    0x00000008	/* If set, allocate from DMA1 before allocating from DMA0 */
 | |
| #define DMA_DEVICE_FLAG_IS_DEDICATED        0x00000100
 | |
| #define DMA_DEVICE_FLAG_NO_ISR              0x00000200
 | |
| #define DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO    0x00000400
 | |
| #define DMA_DEVICE_FLAG_IN_USE              0x00000800	/* If set, device is in use on a channel */
 | |
| 
 | |
| /* Note: Some DMA devices can be used from multiple DMA Controllers. The bitmask is used to */
 | |
| /*       determine which DMA controllers a given device can be used from, and the interface */
 | |
| /*       array determeines the actual interface number to use for a given controller. */
 | |
| 
 | |
| typedef struct {
 | |
| 	uint32_t flags;		/* Bitmask of DMA_DEVICE_FLAG_xxx constants */
 | |
| 	uint8_t dedicatedController;	/* Controller number to use if DMA_DEVICE_FLAG_IS_DEDICATED is set. */
 | |
| 	uint8_t dedicatedChannel;	/* Channel number to use if DMA_DEVICE_FLAG_IS_DEDICATED is set. */
 | |
| 	const char *name;	/* Will show up in the /proc entry */
 | |
| 
 | |
| 	uint32_t dmacPort[DMA_NUM_CONTROLLERS];	/* Specifies the port number when DMA_DEVICE_FLAG_PORT_PER_DMAC flag is set */
 | |
| 
 | |
| 	dmacHw_CONFIG_t config;	/* Configuration to use when DMA'ing using this device */
 | |
| 
 | |
| 	void *userData;		/* Passed to the devHandler */
 | |
| 	DMA_DeviceHandler_t devHandler;	/* Called when DMA operations finish. */
 | |
| 
 | |
| 	timer_tick_count_t transferStartTime;	/* Time the current transfer was started */
 | |
| 
 | |
| 	/* The following statistical information will be collected and presented in a proc entry. */
 | |
| 	/* Note: With a contiuous bandwidth of 1 Gb/sec, it would take 584 years to overflow */
 | |
| 	/*       a 64 bit counter. */
 | |
| 
 | |
| 	uint64_t numTransfers;	/* Number of DMA transfers performed */
 | |
| 	uint64_t transferTicks;	/* Total time spent doing DMA transfers (measured in timer_tick_count_t's) */
 | |
| 	uint64_t transferBytes;	/* Total bytes transferred */
 | |
| 	uint32_t timesBlocked;	/* Number of times a channel was unavailable */
 | |
| 	uint32_t numBytes;	/* Last transfer size */
 | |
| 
 | |
| 	/* It's not possible to free memory which is allocated for the descriptors from within */
 | |
| 	/* the ISR. So make the presumption that a given device will tend to use the */
 | |
| 	/* same sized buffers over and over again, and we keep them around. */
 | |
| 
 | |
| 	DMA_DescriptorRing_t ring;	/* Ring of descriptors allocated for this device */
 | |
| 
 | |
| 	/* We stash away some of the information from the previous transfer. If back-to-back */
 | |
| 	/* transfers are performed from the same buffer, then we don't have to keep re-initializing */
 | |
| 	/* the descriptor buffers. */
 | |
| 
 | |
| 	uint32_t prevNumBytes;
 | |
| 	dma_addr_t prevSrcData;
 | |
| 	dma_addr_t prevDstData;
 | |
| 
 | |
| } DMA_DeviceAttribute_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   DMA_Channel_t, DMA_Controller_t, and DMA_State_t are really internal
 | |
| *   data structures and don't belong in this header file, but are included
 | |
| *   merely for discussion.
 | |
| *
 | |
| *   By the time this is implemented, these structures will be moved out into
 | |
| *   the appropriate C source file instead.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_Channel_t contains state information about each DMA channel. Some
 | |
| *   of the channels are dedicated. Non-dedicated channels are shared
 | |
| *   amongst the other devices.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| #define DMA_CHANNEL_FLAG_IN_USE         0x00000001
 | |
| #define DMA_CHANNEL_FLAG_IS_DEDICATED   0x00000002
 | |
| #define DMA_CHANNEL_FLAG_NO_ISR         0x00000004
 | |
| #define DMA_CHANNEL_FLAG_LARGE_FIFO     0x00000008
 | |
| 
 | |
| typedef struct {
 | |
| 	uint32_t flags;		/* bitmask of DMA_CHANNEL_FLAG_xxx constants */
 | |
| 	DMA_Device_t devType;	/* Device this channel is currently reserved for */
 | |
| 	DMA_Device_t lastDevType;	/* Device type that used this previously */
 | |
| 	char name[20];		/* Name passed onto request_irq */
 | |
| 
 | |
| #if (DMA_DEBUG_TRACK_RESERVATION)
 | |
| 	const char *fileName;	/* Place where channel reservation took place */
 | |
| 	int lineNum;		/* Place where channel reservation took place */
 | |
| #endif
 | |
| 	dmacHw_HANDLE_t dmacHwHandle;	/* low level channel handle. */
 | |
| 
 | |
| } DMA_Channel_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_Controller_t contains state information about each DMA controller.
 | |
| *
 | |
| *   The freeChannelQ is stored in the controller data structure rather than
 | |
| *   the channel data structure since several of the devices are accessible
 | |
| *   from multiple controllers, and there is no way to know which controller
 | |
| *   will become available first.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| typedef struct {
 | |
| 	DMA_Channel_t channel[DMA_NUM_CHANNELS];
 | |
| 
 | |
| } DMA_Controller_t;
 | |
| 
 | |
| /****************************************************************************
 | |
| *
 | |
| *   The DMA_Global_t contains all of the global state information used by
 | |
| *   the DMA code.
 | |
| *
 | |
| *   Callers which need to allocate a shared channel will be queued up
 | |
| *   on the freeChannelQ until a channel becomes available.
 | |
| *
 | |
| *****************************************************************************/
 | |
| 
 | |
| typedef struct {
 | |
| 	struct semaphore lock;	/* acquired when manipulating table entries */
 | |
| 	wait_queue_head_t freeChannelQ;
 | |
| 
 | |
| 	DMA_Controller_t controller[DMA_NUM_CONTROLLERS];
 | |
| 
 | |
| } DMA_Global_t;
 | |
| 
 | |
| /* ---- Variable Externs ------------------------------------------------- */
 | |
| 
 | |
| extern DMA_DeviceAttribute_t DMA_gDeviceAttribute[DMA_NUM_DEVICE_ENTRIES];
 | |
| 
 | |
| /* ---- Function Prototypes ---------------------------------------------- */
 | |
| 
 | |
| #if defined(__KERNEL__)
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initializes the DMA module.
 | |
| *
 | |
| *   @return
 | |
| *       0       - Success
 | |
| *       < 0     - Error
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_init(void);
 | |
| 
 | |
| #if (DMA_DEBUG_TRACK_RESERVATION)
 | |
| DMA_Handle_t dma_request_channel_dbg(DMA_Device_t dev, const char *fileName,
 | |
| 				     int lineNum);
 | |
| #define dma_request_channel(dev)  dma_request_channel_dbg(dev, __FILE__, __LINE__)
 | |
| #else
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Reserves a channel for use with @a dev. If the device is setup to use
 | |
| *   a shared channel, then this function will block until a free channel
 | |
| *   becomes available.
 | |
| *
 | |
| *   @return
 | |
| *       >= 0    - A valid DMA Handle.
 | |
| *       -EBUSY  - Device is currently being used.
 | |
| *       -ENODEV - Device handed in is invalid.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| DMA_Handle_t dma_request_channel(DMA_Device_t dev	/* Device to use with the allocated channel. */
 | |
|     );
 | |
| #endif
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Frees a previously allocated DMA Handle.
 | |
| *
 | |
| *   @return
 | |
| *        0      - DMA Handle was released successfully.
 | |
| *       -EINVAL - Invalid DMA handle
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_free_channel(DMA_Handle_t channel	/* DMA handle. */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Determines if a given device has been configured as using a shared
 | |
| *   channel.
 | |
| *
 | |
| *   @return boolean
 | |
| *       0           Device uses a dedicated channel
 | |
| *       non-zero    Device uses a shared channel
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_device_is_channel_shared(DMA_Device_t dev	/* Device to check. */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Allocates memory to hold a descriptor ring. The descriptor ring then
 | |
| *   needs to be populated by making one or more calls to
 | |
| *   dna_add_descriptors.
 | |
| *
 | |
| *   The returned descriptor ring will be automatically initialized.
 | |
| *
 | |
| *   @return
 | |
| *       0           Descriptor ring was allocated successfully
 | |
| *       -ENOMEM     Unable to allocate memory for the desired number of descriptors.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_alloc_descriptor_ring(DMA_DescriptorRing_t *ring,	/* Descriptor ring to populate */
 | |
| 			      int numDescriptors	/* Number of descriptors that need to be allocated. */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Releases the memory which was previously allocated for a descriptor ring.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| void dma_free_descriptor_ring(DMA_DescriptorRing_t *ring	/* Descriptor to release */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initializes a descriptor ring, so that descriptors can be added to it.
 | |
| *   Once a descriptor ring has been allocated, it may be reinitialized for
 | |
| *   use with additional/different regions of memory.
 | |
| *
 | |
| *   Note that if 7 descriptors are allocated, it's perfectly acceptable to
 | |
| *   initialize the ring with a smaller number of descriptors. The amount
 | |
| *   of memory allocated for the descriptor ring will not be reduced, and
 | |
| *   the descriptor ring may be reinitialized later
 | |
| *
 | |
| *   @return
 | |
| *       0           Descriptor ring was initialized successfully
 | |
| *       -ENOMEM     The descriptor which was passed in has insufficient space
 | |
| *                   to hold the desired number of descriptors.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_init_descriptor_ring(DMA_DescriptorRing_t *ring,	/* Descriptor ring to initialize */
 | |
| 			     int numDescriptors	/* Number of descriptors to initialize. */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Determines the number of descriptors which would be required for a
 | |
| *   transfer of the indicated memory region.
 | |
| *
 | |
| *   This function also needs to know which DMA device this transfer will
 | |
| *   be destined for, so that the appropriate DMA configuration can be retrieved.
 | |
| *   DMA parameters such as transfer width, and whether this is a memory-to-memory
 | |
| *   or memory-to-peripheral, etc can all affect the actual number of descriptors
 | |
| *   required.
 | |
| *
 | |
| *   @return
 | |
| *       > 0     Returns the number of descriptors required for the indicated transfer
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
 | |
| *       -ENOMEM Memory exhausted
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_calculate_descriptor_count(DMA_Device_t device,	/* DMA Device that this will be associated with */
 | |
| 				   dma_addr_t srcData,	/* Place to get data to write to device */
 | |
| 				   dma_addr_t dstData,	/* Pointer to device data address */
 | |
| 				   size_t numBytes	/* Number of bytes to transfer to the device */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Adds a region of memory to the descriptor ring. Note that it may take
 | |
| *   multiple descriptors for each region of memory. It is the callers
 | |
| *   responsibility to allocate a sufficiently large descriptor ring.
 | |
| *
 | |
| *   @return
 | |
| *       0       Descriptors were added successfully
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
 | |
| *       -ENOMEM Memory exhausted
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_add_descriptors(DMA_DescriptorRing_t *ring,	/* Descriptor ring to add descriptors to */
 | |
| 			DMA_Device_t device,	/* DMA Device that descriptors are for */
 | |
| 			dma_addr_t srcData,	/* Place to get data (memory or device) */
 | |
| 			dma_addr_t dstData,	/* Place to put data (memory or device) */
 | |
| 			size_t numBytes	/* Number of bytes to transfer to the device */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Sets the descriptor ring associated with a device.
 | |
| *
 | |
| *   Once set, the descriptor ring will be associated with the device, even
 | |
| *   across channel request/free calls. Passing in a NULL descriptor ring
 | |
| *   will release any descriptor ring currently associated with the device.
 | |
| *
 | |
| *   Note: If you call dma_transfer, or one of the other dma_alloc_ functions
 | |
| *         the descriptor ring may be released and reallocated.
 | |
| *
 | |
| *   Note: This function will release the descriptor memory for any current
 | |
| *         descriptor ring associated with this device.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_set_device_descriptor_ring(DMA_Device_t device,	/* Device to update the descriptor ring for. */
 | |
| 				   DMA_DescriptorRing_t *ring	/* Descriptor ring to add descriptors to */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Retrieves the descriptor ring associated with a device.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_get_device_descriptor_ring(DMA_Device_t device,	/* Device to retrieve the descriptor ring for. */
 | |
| 				   DMA_DescriptorRing_t *ring	/* Place to store retrieved ring */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Allocates buffers for the descriptors. This is normally done automatically
 | |
| *   but needs to be done explicitly when initiating a dma from interrupt
 | |
| *   context.
 | |
| *
 | |
| *   @return
 | |
| *       0       Descriptors were allocated successfully
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
 | |
| *       -ENOMEM Memory exhausted
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_alloc_descriptors(DMA_Handle_t handle,	/* DMA Handle */
 | |
| 			  dmacHw_TRANSFER_TYPE_e transferType,	/* Type of transfer being performed */
 | |
| 			  dma_addr_t srcData,	/* Place to get data to write to device */
 | |
| 			  dma_addr_t dstData,	/* Pointer to device data address */
 | |
| 			  size_t numBytes	/* Number of bytes to transfer to the device */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Allocates and sets up descriptors for a double buffered circular buffer.
 | |
| *
 | |
| *   This is primarily intended to be used for things like the ingress samples
 | |
| *   from a microphone.
 | |
| *
 | |
| *   @return
 | |
| *       > 0     Number of descriptors actually allocated.
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
 | |
| *       -ENOMEM Memory exhausted
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_alloc_double_dst_descriptors(DMA_Handle_t handle,	/* DMA Handle */
 | |
| 				     dma_addr_t srcData,	/* Physical address of source data */
 | |
| 				     dma_addr_t dstData1,	/* Physical address of first destination buffer */
 | |
| 				     dma_addr_t dstData2,	/* Physical address of second destination buffer */
 | |
| 				     size_t numBytes	/* Number of bytes in each destination buffer */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initializes a DMA_MemMap_t data structure
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_init_mem_map(DMA_MemMap_t *memMap	/* Stores state information about the map */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Releases any memory currently being held by a memory mapping structure.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_term_mem_map(DMA_MemMap_t *memMap	/* Stores state information about the map */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Looks at a memory address and categorizes it.
 | |
| *
 | |
| *   @return One of the values from the DMA_MemType_t enumeration.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| DMA_MemType_t dma_mem_type(void *addr);
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Sets the process (aka userTask) associated with a mem map. This is
 | |
| *   required if user-mode segments will be added to the mapping.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| static inline void dma_mem_map_set_user_task(DMA_MemMap_t *memMap,
 | |
| 					     struct task_struct *task)
 | |
| {
 | |
| 	memMap->userTask = task;
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Looks at a memory address and determines if we support DMA'ing to/from
 | |
| *   that type of memory.
 | |
| *
 | |
| *   @return boolean -
 | |
| *               return value != 0 means dma supported
 | |
| *               return value == 0 means dma not supported
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_mem_supports_dma(void *addr);
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initializes a memory map for use. Since this function acquires a
 | |
| *   sempaphore within the memory map, it is VERY important that dma_unmap
 | |
| *   be called when you're finished using the map.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_map_start(DMA_MemMap_t *memMap,	/* Stores state information about the map */
 | |
| 		  enum dma_data_direction dir	/* Direction that the mapping will be going */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Adds a segment of memory to a memory map.
 | |
| *
 | |
| *   @return     0 on success, error code otherwise.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_map_add_region(DMA_MemMap_t *memMap,	/* Stores state information about the map */
 | |
| 		       void *mem,	/* Virtual address that we want to get a map of */
 | |
| 		       size_t numBytes	/* Number of bytes being mapped */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Creates a descriptor ring from a memory mapping.
 | |
| *
 | |
| *   @return 0 on sucess, error code otherwise.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_map_create_descriptor_ring(DMA_Device_t dev,	/* DMA device (where the ring is stored) */
 | |
| 				   DMA_MemMap_t *memMap,	/* Memory map that will be used */
 | |
| 				   dma_addr_t devPhysAddr	/* Physical address of device */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Maps in a memory region such that it can be used for performing a DMA.
 | |
| *
 | |
| *   @return
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_map_mem(DMA_MemMap_t *memMap,	/* Stores state information about the map */
 | |
| 		void *addr,	/* Virtual address that we want to get a map of */
 | |
| 		size_t count,	/* Number of bytes being mapped */
 | |
| 		enum dma_data_direction dir	/* Direction that the mapping will be going */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Maps in a memory region such that it can be used for performing a DMA.
 | |
| *
 | |
| *   @return
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_unmap(DMA_MemMap_t *memMap,	/* Stores state information about the map */
 | |
| 	      int dirtied	/* non-zero if any of the pages were modified */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initiates a transfer when the descriptors have already been setup.
 | |
| *
 | |
| *   This is a special case, and normally, the dma_transfer_xxx functions should
 | |
| *   be used.
 | |
| *
 | |
| *   @return
 | |
| *       0       Transfer was started successfully
 | |
| *       -ENODEV Invalid handle
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_start_transfer(DMA_Handle_t handle);
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Stops a previously started DMA transfer.
 | |
| *
 | |
| *   @return
 | |
| *       0       Transfer was stopped successfully
 | |
| *       -ENODEV Invalid handle
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_stop_transfer(DMA_Handle_t handle);
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Waits for a DMA to complete by polling. This function is only intended
 | |
| *   to be used for testing. Interrupts should be used for most DMA operations.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_wait_transfer_done(DMA_Handle_t handle);
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initiates a DMA transfer
 | |
| *
 | |
| *   @return
 | |
| *       0       Transfer was started successfully
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_transfer(DMA_Handle_t handle,	/* DMA Handle */
 | |
| 		 dmacHw_TRANSFER_TYPE_e transferType,	/* Type of transfer being performed */
 | |
| 		 dma_addr_t srcData,	/* Place to get data to write to device */
 | |
| 		 dma_addr_t dstData,	/* Pointer to device data address */
 | |
| 		 size_t numBytes	/* Number of bytes to transfer to the device */
 | |
|     );
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initiates a transfer from memory to a device.
 | |
| *
 | |
| *   @return
 | |
| *       0       Transfer was started successfully
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _DEV_TO_MEM and not _MEM_TO_DEV)
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| static inline int dma_transfer_to_device(DMA_Handle_t handle,	/* DMA Handle */
 | |
| 					 dma_addr_t srcData,	/* Place to get data to write to device (physical address) */
 | |
| 					 dma_addr_t dstData,	/* Pointer to device data address (physical address) */
 | |
| 					 size_t numBytes	/* Number of bytes to transfer to the device */
 | |
|     ) {
 | |
| 	return dma_transfer(handle,
 | |
| 			    dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL,
 | |
| 			    srcData, dstData, numBytes);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initiates a transfer from a device to memory.
 | |
| *
 | |
| *   @return
 | |
| *       0       Transfer was started successfully
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM)
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| static inline int dma_transfer_from_device(DMA_Handle_t handle,	/* DMA Handle */
 | |
| 					   dma_addr_t srcData,	/* Pointer to the device data address (physical address) */
 | |
| 					   dma_addr_t dstData,	/* Place to store data retrieved from the device (physical address) */
 | |
| 					   size_t numBytes	/* Number of bytes to retrieve from the device */
 | |
|     ) {
 | |
| 	return dma_transfer(handle,
 | |
| 			    dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM,
 | |
| 			    srcData, dstData, numBytes);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Initiates a memory to memory transfer.
 | |
| *
 | |
| *   @return
 | |
| *       0       Transfer was started successfully
 | |
| *       -EINVAL Invalid device type for this kind of transfer
 | |
| *               (i.e. the device wasn't DMA_DEVICE_MEM_TO_MEM)
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| static inline int dma_transfer_mem_to_mem(DMA_Handle_t handle,	/* DMA Handle */
 | |
| 					  dma_addr_t srcData,	/* Place to transfer data from (physical address) */
 | |
| 					  dma_addr_t dstData,	/* Place to transfer data to (physical address) */
 | |
| 					  size_t numBytes	/* Number of bytes to transfer */
 | |
|     ) {
 | |
| 	return dma_transfer(handle,
 | |
| 			    dmacHw_TRANSFER_TYPE_MEM_TO_MEM,
 | |
| 			    srcData, dstData, numBytes);
 | |
| }
 | |
| 
 | |
| /****************************************************************************/
 | |
| /**
 | |
| *   Set the callback function which will be called when a transfer completes.
 | |
| *   If a NULL callback function is set, then no callback will occur.
 | |
| *
 | |
| *   @note   @a devHandler will be called from IRQ context.
 | |
| *
 | |
| *   @return
 | |
| *       0       - Success
 | |
| *       -ENODEV - Device handed in is invalid.
 | |
| */
 | |
| /****************************************************************************/
 | |
| 
 | |
| int dma_set_device_handler(DMA_Device_t dev,	/* Device to set the callback for. */
 | |
| 			   DMA_DeviceHandler_t devHandler,	/* Function to call when the DMA completes */
 | |
| 			   void *userData	/* Pointer which will be passed to devHandler. */
 | |
|     );
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #endif /* ASM_ARM_ARCH_BCMRING_DMA_H */
 |