| /***************************************************************************** |
| * 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 success, 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 */ |