Leo Chen | 7c4c295 | 2009-08-07 20:00:39 +0100 | [diff] [blame] | 1 | /***************************************************************************** |
| 2 | * Copyright 2004 - 2008 Broadcom Corporation. All rights reserved. |
| 3 | * |
| 4 | * Unless you and Broadcom execute a separate written software license |
| 5 | * agreement governing use of this software, this software is licensed to you |
| 6 | * under the terms of the GNU General Public License version 2, available at |
| 7 | * http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). |
| 8 | * |
| 9 | * Notwithstanding the above, under no circumstances may you combine this |
| 10 | * software in any way with any other Broadcom software provided under a |
| 11 | * license other than the GPL, without Broadcom's express prior written |
| 12 | * consent. |
| 13 | *****************************************************************************/ |
| 14 | |
| 15 | /****************************************************************************/ |
| 16 | /** |
| 17 | * @file dma.h |
| 18 | * |
| 19 | * @brief API definitions for the linux DMA interface. |
| 20 | */ |
| 21 | /****************************************************************************/ |
| 22 | |
| 23 | #if !defined(ASM_ARM_ARCH_BCMRING_DMA_H) |
| 24 | #define ASM_ARM_ARCH_BCMRING_DMA_H |
| 25 | |
| 26 | /* ---- Include Files ---------------------------------------------------- */ |
| 27 | |
| 28 | #include <linux/kernel.h> |
| 29 | #include <linux/wait.h> |
| 30 | #include <linux/semaphore.h> |
| 31 | #include <csp/dmacHw.h> |
| 32 | #include <mach/timer.h> |
| 33 | #include <linux/scatterlist.h> |
| 34 | #include <linux/dma-mapping.h> |
| 35 | #include <linux/mm.h> |
| 36 | #include <linux/vmalloc.h> |
| 37 | #include <linux/pagemap.h> |
| 38 | |
| 39 | /* ---- Constants and Types ---------------------------------------------- */ |
| 40 | |
| 41 | /* If DMA_DEBUG_TRACK_RESERVATION is set to a non-zero value, then the filename */ |
| 42 | /* and line number of the reservation request will be recorded in the channel table */ |
| 43 | |
| 44 | #define DMA_DEBUG_TRACK_RESERVATION 1 |
| 45 | |
| 46 | #define DMA_NUM_CONTROLLERS 2 |
| 47 | #define DMA_NUM_CHANNELS 8 /* per controller */ |
| 48 | |
| 49 | typedef enum { |
| 50 | DMA_DEVICE_MEM_TO_MEM, /* For memory to memory transfers */ |
| 51 | DMA_DEVICE_I2S0_DEV_TO_MEM, |
| 52 | DMA_DEVICE_I2S0_MEM_TO_DEV, |
| 53 | DMA_DEVICE_I2S1_DEV_TO_MEM, |
| 54 | DMA_DEVICE_I2S1_MEM_TO_DEV, |
| 55 | DMA_DEVICE_APM_CODEC_A_DEV_TO_MEM, |
| 56 | DMA_DEVICE_APM_CODEC_A_MEM_TO_DEV, |
| 57 | DMA_DEVICE_APM_CODEC_B_DEV_TO_MEM, |
| 58 | DMA_DEVICE_APM_CODEC_B_MEM_TO_DEV, |
| 59 | DMA_DEVICE_APM_CODEC_C_DEV_TO_MEM, /* Additional mic input for beam-forming */ |
| 60 | DMA_DEVICE_APM_PCM0_DEV_TO_MEM, |
| 61 | DMA_DEVICE_APM_PCM0_MEM_TO_DEV, |
| 62 | DMA_DEVICE_APM_PCM1_DEV_TO_MEM, |
| 63 | DMA_DEVICE_APM_PCM1_MEM_TO_DEV, |
| 64 | DMA_DEVICE_SPUM_DEV_TO_MEM, |
| 65 | DMA_DEVICE_SPUM_MEM_TO_DEV, |
| 66 | DMA_DEVICE_SPIH_DEV_TO_MEM, |
| 67 | DMA_DEVICE_SPIH_MEM_TO_DEV, |
| 68 | DMA_DEVICE_UART_A_DEV_TO_MEM, |
| 69 | DMA_DEVICE_UART_A_MEM_TO_DEV, |
| 70 | DMA_DEVICE_UART_B_DEV_TO_MEM, |
| 71 | DMA_DEVICE_UART_B_MEM_TO_DEV, |
| 72 | DMA_DEVICE_PIF_MEM_TO_DEV, |
| 73 | DMA_DEVICE_PIF_DEV_TO_MEM, |
| 74 | DMA_DEVICE_ESW_DEV_TO_MEM, |
| 75 | DMA_DEVICE_ESW_MEM_TO_DEV, |
| 76 | DMA_DEVICE_VPM_MEM_TO_MEM, |
| 77 | DMA_DEVICE_CLCD_MEM_TO_MEM, |
| 78 | DMA_DEVICE_NAND_MEM_TO_MEM, |
| 79 | DMA_DEVICE_MEM_TO_VRAM, |
| 80 | DMA_DEVICE_VRAM_TO_MEM, |
| 81 | |
| 82 | /* Add new entries before this line. */ |
| 83 | |
| 84 | DMA_NUM_DEVICE_ENTRIES, |
| 85 | DMA_DEVICE_NONE = 0xff, /* Special value to indicate that no device is currently assigned. */ |
| 86 | |
| 87 | } DMA_Device_t; |
| 88 | |
| 89 | /**************************************************************************** |
| 90 | * |
| 91 | * The DMA_Handle_t is the primary object used by callers of the API. |
| 92 | * |
| 93 | *****************************************************************************/ |
| 94 | |
| 95 | #define DMA_INVALID_HANDLE ((DMA_Handle_t) -1) |
| 96 | |
| 97 | typedef int DMA_Handle_t; |
| 98 | |
| 99 | /**************************************************************************** |
| 100 | * |
| 101 | * The DMA_DescriptorRing_t contains a ring of descriptors which is used |
| 102 | * to point to regions of memory. |
| 103 | * |
| 104 | *****************************************************************************/ |
| 105 | |
| 106 | typedef struct { |
| 107 | void *virtAddr; /* Virtual Address of the descriptor ring */ |
| 108 | dma_addr_t physAddr; /* Physical address of the descriptor ring */ |
| 109 | int descriptorsAllocated; /* Number of descriptors allocated in the descriptor ring */ |
| 110 | size_t bytesAllocated; /* Number of bytes allocated in the descriptor ring */ |
| 111 | |
| 112 | } DMA_DescriptorRing_t; |
| 113 | |
| 114 | /**************************************************************************** |
| 115 | * |
| 116 | * The DMA_MemType_t and DMA_MemMap_t are helper structures used to setup |
| 117 | * DMA chains from a variety of memory sources. |
| 118 | * |
| 119 | *****************************************************************************/ |
| 120 | |
| 121 | #define DMA_MEM_MAP_MIN_SIZE 4096 /* Pages less than this size are better */ |
| 122 | /* off not being DMA'd. */ |
| 123 | |
| 124 | typedef enum { |
| 125 | DMA_MEM_TYPE_NONE, /* Not a valid setting */ |
| 126 | DMA_MEM_TYPE_VMALLOC, /* Memory came from vmalloc call */ |
| 127 | DMA_MEM_TYPE_KMALLOC, /* Memory came from kmalloc call */ |
| 128 | DMA_MEM_TYPE_DMA, /* Memory came from dma_alloc_xxx call */ |
| 129 | DMA_MEM_TYPE_USER, /* Memory came from user space. */ |
| 130 | |
| 131 | } DMA_MemType_t; |
| 132 | |
| 133 | /* A segment represents a physically and virtually contiguous chunk of memory. */ |
| 134 | /* i.e. each segment can be DMA'd */ |
| 135 | /* A user of the DMA code will add memory regions. Each region may need to be */ |
| 136 | /* represented by one or more segments. */ |
| 137 | |
| 138 | typedef struct { |
| 139 | void *virtAddr; /* Virtual address used for this segment */ |
| 140 | dma_addr_t physAddr; /* Physical address this segment maps to */ |
| 141 | size_t numBytes; /* Size of the segment, in bytes */ |
| 142 | |
| 143 | } DMA_Segment_t; |
| 144 | |
| 145 | /* A region represents a virtually contiguous chunk of memory, which may be */ |
| 146 | /* made up of multiple segments. */ |
| 147 | |
| 148 | typedef struct { |
| 149 | DMA_MemType_t memType; |
| 150 | void *virtAddr; |
| 151 | size_t numBytes; |
| 152 | |
| 153 | /* Each region (virtually contiguous) consists of one or more segments. Each */ |
| 154 | /* segment is virtually and physically contiguous. */ |
| 155 | |
| 156 | int numSegmentsUsed; |
| 157 | int numSegmentsAllocated; |
| 158 | DMA_Segment_t *segment; |
| 159 | |
| 160 | /* When a region corresponds to user memory, we need to lock all of the pages */ |
| 161 | /* down before we can figure out the physical addresses. The lockedPage array contains */ |
| 162 | /* the pages that were locked, and which subsequently need to be unlocked once the */ |
| 163 | /* memory is unmapped. */ |
| 164 | |
| 165 | unsigned numLockedPages; |
| 166 | struct page **lockedPages; |
| 167 | |
| 168 | } DMA_Region_t; |
| 169 | |
| 170 | typedef struct { |
| 171 | int inUse; /* Is this mapping currently being used? */ |
| 172 | struct semaphore lock; /* Acquired when using this structure */ |
| 173 | enum dma_data_direction dir; /* Direction this transfer is intended for */ |
| 174 | |
| 175 | /* In the event that we're mapping user memory, we need to know which task */ |
| 176 | /* the memory is for, so that we can obtain the correct mm locks. */ |
| 177 | |
| 178 | struct task_struct *userTask; |
| 179 | |
| 180 | int numRegionsUsed; |
| 181 | int numRegionsAllocated; |
| 182 | DMA_Region_t *region; |
| 183 | |
| 184 | } DMA_MemMap_t; |
| 185 | |
| 186 | /**************************************************************************** |
| 187 | * |
| 188 | * The DMA_DeviceAttribute_t contains information which describes a |
| 189 | * particular DMA device (or peripheral). |
| 190 | * |
| 191 | * It is anticipated that the arrary of DMA_DeviceAttribute_t's will be |
| 192 | * statically initialized. |
| 193 | * |
| 194 | *****************************************************************************/ |
| 195 | |
| 196 | /* The device handler is called whenever a DMA operation completes. The reaon */ |
| 197 | /* for it to be called will be a bitmask with one or more of the following bits */ |
| 198 | /* set. */ |
| 199 | |
| 200 | #define DMA_HANDLER_REASON_BLOCK_COMPLETE dmacHw_INTERRUPT_STATUS_BLOCK |
| 201 | #define DMA_HANDLER_REASON_TRANSFER_COMPLETE dmacHw_INTERRUPT_STATUS_TRANS |
| 202 | #define DMA_HANDLER_REASON_ERROR dmacHw_INTERRUPT_STATUS_ERROR |
| 203 | |
| 204 | typedef void (*DMA_DeviceHandler_t) (DMA_Device_t dev, int reason, |
| 205 | void *userData); |
| 206 | |
| 207 | #define DMA_DEVICE_FLAG_ON_DMA0 0x00000001 |
| 208 | #define DMA_DEVICE_FLAG_ON_DMA1 0x00000002 |
| 209 | #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 */ |
| 210 | #define DMA_DEVICE_FLAG_ALLOC_DMA1_FIRST 0x00000008 /* If set, allocate from DMA1 before allocating from DMA0 */ |
| 211 | #define DMA_DEVICE_FLAG_IS_DEDICATED 0x00000100 |
| 212 | #define DMA_DEVICE_FLAG_NO_ISR 0x00000200 |
| 213 | #define DMA_DEVICE_FLAG_ALLOW_LARGE_FIFO 0x00000400 |
| 214 | #define DMA_DEVICE_FLAG_IN_USE 0x00000800 /* If set, device is in use on a channel */ |
| 215 | |
| 216 | /* Note: Some DMA devices can be used from multiple DMA Controllers. The bitmask is used to */ |
| 217 | /* determine which DMA controllers a given device can be used from, and the interface */ |
| 218 | /* array determeines the actual interface number to use for a given controller. */ |
| 219 | |
| 220 | typedef struct { |
| 221 | uint32_t flags; /* Bitmask of DMA_DEVICE_FLAG_xxx constants */ |
| 222 | uint8_t dedicatedController; /* Controller number to use if DMA_DEVICE_FLAG_IS_DEDICATED is set. */ |
| 223 | uint8_t dedicatedChannel; /* Channel number to use if DMA_DEVICE_FLAG_IS_DEDICATED is set. */ |
| 224 | const char *name; /* Will show up in the /proc entry */ |
| 225 | |
| 226 | uint32_t dmacPort[DMA_NUM_CONTROLLERS]; /* Specifies the port number when DMA_DEVICE_FLAG_PORT_PER_DMAC flag is set */ |
| 227 | |
| 228 | dmacHw_CONFIG_t config; /* Configuration to use when DMA'ing using this device */ |
| 229 | |
| 230 | void *userData; /* Passed to the devHandler */ |
| 231 | DMA_DeviceHandler_t devHandler; /* Called when DMA operations finish. */ |
| 232 | |
| 233 | timer_tick_count_t transferStartTime; /* Time the current transfer was started */ |
| 234 | |
| 235 | /* The following statistical information will be collected and presented in a proc entry. */ |
| 236 | /* Note: With a contiuous bandwidth of 1 Gb/sec, it would take 584 years to overflow */ |
| 237 | /* a 64 bit counter. */ |
| 238 | |
| 239 | uint64_t numTransfers; /* Number of DMA transfers performed */ |
| 240 | uint64_t transferTicks; /* Total time spent doing DMA transfers (measured in timer_tick_count_t's) */ |
| 241 | uint64_t transferBytes; /* Total bytes transferred */ |
| 242 | uint32_t timesBlocked; /* Number of times a channel was unavailable */ |
| 243 | uint32_t numBytes; /* Last transfer size */ |
| 244 | |
| 245 | /* It's not possible to free memory which is allocated for the descriptors from within */ |
| 246 | /* the ISR. So make the presumption that a given device will tend to use the */ |
| 247 | /* same sized buffers over and over again, and we keep them around. */ |
| 248 | |
| 249 | DMA_DescriptorRing_t ring; /* Ring of descriptors allocated for this device */ |
| 250 | |
| 251 | /* We stash away some of the information from the previous transfer. If back-to-back */ |
| 252 | /* transfers are performed from the same buffer, then we don't have to keep re-initializing */ |
| 253 | /* the descriptor buffers. */ |
| 254 | |
| 255 | uint32_t prevNumBytes; |
| 256 | dma_addr_t prevSrcData; |
| 257 | dma_addr_t prevDstData; |
| 258 | |
| 259 | } DMA_DeviceAttribute_t; |
| 260 | |
| 261 | /**************************************************************************** |
| 262 | * |
| 263 | * DMA_Channel_t, DMA_Controller_t, and DMA_State_t are really internal |
| 264 | * data structures and don't belong in this header file, but are included |
| 265 | * merely for discussion. |
| 266 | * |
| 267 | * By the time this is implemented, these structures will be moved out into |
| 268 | * the appropriate C source file instead. |
| 269 | * |
| 270 | *****************************************************************************/ |
| 271 | |
| 272 | /**************************************************************************** |
| 273 | * |
| 274 | * The DMA_Channel_t contains state information about each DMA channel. Some |
| 275 | * of the channels are dedicated. Non-dedicated channels are shared |
| 276 | * amongst the other devices. |
| 277 | * |
| 278 | *****************************************************************************/ |
| 279 | |
| 280 | #define DMA_CHANNEL_FLAG_IN_USE 0x00000001 |
| 281 | #define DMA_CHANNEL_FLAG_IS_DEDICATED 0x00000002 |
| 282 | #define DMA_CHANNEL_FLAG_NO_ISR 0x00000004 |
| 283 | #define DMA_CHANNEL_FLAG_LARGE_FIFO 0x00000008 |
| 284 | |
| 285 | typedef struct { |
| 286 | uint32_t flags; /* bitmask of DMA_CHANNEL_FLAG_xxx constants */ |
| 287 | DMA_Device_t devType; /* Device this channel is currently reserved for */ |
| 288 | DMA_Device_t lastDevType; /* Device type that used this previously */ |
| 289 | char name[20]; /* Name passed onto request_irq */ |
| 290 | |
| 291 | #if (DMA_DEBUG_TRACK_RESERVATION) |
| 292 | const char *fileName; /* Place where channel reservation took place */ |
| 293 | int lineNum; /* Place where channel reservation took place */ |
| 294 | #endif |
| 295 | dmacHw_HANDLE_t dmacHwHandle; /* low level channel handle. */ |
| 296 | |
| 297 | } DMA_Channel_t; |
| 298 | |
| 299 | /**************************************************************************** |
| 300 | * |
| 301 | * The DMA_Controller_t contains state information about each DMA controller. |
| 302 | * |
| 303 | * The freeChannelQ is stored in the controller data structure rather than |
| 304 | * the channel data structure since several of the devices are accessible |
| 305 | * from multiple controllers, and there is no way to know which controller |
| 306 | * will become available first. |
| 307 | * |
| 308 | *****************************************************************************/ |
| 309 | |
| 310 | typedef struct { |
| 311 | DMA_Channel_t channel[DMA_NUM_CHANNELS]; |
| 312 | |
| 313 | } DMA_Controller_t; |
| 314 | |
| 315 | /**************************************************************************** |
| 316 | * |
| 317 | * The DMA_Global_t contains all of the global state information used by |
| 318 | * the DMA code. |
| 319 | * |
| 320 | * Callers which need to allocate a shared channel will be queued up |
| 321 | * on the freeChannelQ until a channel becomes available. |
| 322 | * |
| 323 | *****************************************************************************/ |
| 324 | |
| 325 | typedef struct { |
| 326 | struct semaphore lock; /* acquired when manipulating table entries */ |
| 327 | wait_queue_head_t freeChannelQ; |
| 328 | |
| 329 | DMA_Controller_t controller[DMA_NUM_CONTROLLERS]; |
| 330 | |
| 331 | } DMA_Global_t; |
| 332 | |
| 333 | /* ---- Variable Externs ------------------------------------------------- */ |
| 334 | |
| 335 | extern DMA_DeviceAttribute_t DMA_gDeviceAttribute[DMA_NUM_DEVICE_ENTRIES]; |
| 336 | |
| 337 | /* ---- Function Prototypes ---------------------------------------------- */ |
| 338 | |
| 339 | #if defined(__KERNEL__) |
| 340 | |
| 341 | /****************************************************************************/ |
| 342 | /** |
| 343 | * Initializes the DMA module. |
| 344 | * |
| 345 | * @return |
| 346 | * 0 - Success |
| 347 | * < 0 - Error |
| 348 | */ |
| 349 | /****************************************************************************/ |
| 350 | |
| 351 | int dma_init(void); |
| 352 | |
| 353 | #if (DMA_DEBUG_TRACK_RESERVATION) |
| 354 | DMA_Handle_t dma_request_channel_dbg(DMA_Device_t dev, const char *fileName, |
| 355 | int lineNum); |
| 356 | #define dma_request_channel(dev) dma_request_channel_dbg(dev, __FILE__, __LINE__) |
| 357 | #else |
| 358 | |
| 359 | /****************************************************************************/ |
| 360 | /** |
| 361 | * Reserves a channel for use with @a dev. If the device is setup to use |
| 362 | * a shared channel, then this function will block until a free channel |
| 363 | * becomes available. |
| 364 | * |
| 365 | * @return |
| 366 | * >= 0 - A valid DMA Handle. |
| 367 | * -EBUSY - Device is currently being used. |
| 368 | * -ENODEV - Device handed in is invalid. |
| 369 | */ |
| 370 | /****************************************************************************/ |
| 371 | |
| 372 | DMA_Handle_t dma_request_channel(DMA_Device_t dev /* Device to use with the allocated channel. */ |
| 373 | ); |
| 374 | #endif |
| 375 | |
| 376 | /****************************************************************************/ |
| 377 | /** |
| 378 | * Frees a previously allocated DMA Handle. |
| 379 | * |
| 380 | * @return |
| 381 | * 0 - DMA Handle was released successfully. |
| 382 | * -EINVAL - Invalid DMA handle |
| 383 | */ |
| 384 | /****************************************************************************/ |
| 385 | |
| 386 | int dma_free_channel(DMA_Handle_t channel /* DMA handle. */ |
| 387 | ); |
| 388 | |
| 389 | /****************************************************************************/ |
| 390 | /** |
| 391 | * Determines if a given device has been configured as using a shared |
| 392 | * channel. |
| 393 | * |
| 394 | * @return boolean |
| 395 | * 0 Device uses a dedicated channel |
| 396 | * non-zero Device uses a shared channel |
| 397 | */ |
| 398 | /****************************************************************************/ |
| 399 | |
| 400 | int dma_device_is_channel_shared(DMA_Device_t dev /* Device to check. */ |
| 401 | ); |
| 402 | |
| 403 | /****************************************************************************/ |
| 404 | /** |
| 405 | * Allocates memory to hold a descriptor ring. The descriptor ring then |
| 406 | * needs to be populated by making one or more calls to |
| 407 | * dna_add_descriptors. |
| 408 | * |
| 409 | * The returned descriptor ring will be automatically initialized. |
| 410 | * |
| 411 | * @return |
| 412 | * 0 Descriptor ring was allocated successfully |
| 413 | * -ENOMEM Unable to allocate memory for the desired number of descriptors. |
| 414 | */ |
| 415 | /****************************************************************************/ |
| 416 | |
| 417 | int dma_alloc_descriptor_ring(DMA_DescriptorRing_t *ring, /* Descriptor ring to populate */ |
| 418 | int numDescriptors /* Number of descriptors that need to be allocated. */ |
| 419 | ); |
| 420 | |
| 421 | /****************************************************************************/ |
| 422 | /** |
| 423 | * Releases the memory which was previously allocated for a descriptor ring. |
| 424 | */ |
| 425 | /****************************************************************************/ |
| 426 | |
| 427 | void dma_free_descriptor_ring(DMA_DescriptorRing_t *ring /* Descriptor to release */ |
| 428 | ); |
| 429 | |
| 430 | /****************************************************************************/ |
| 431 | /** |
| 432 | * Initializes a descriptor ring, so that descriptors can be added to it. |
| 433 | * Once a descriptor ring has been allocated, it may be reinitialized for |
| 434 | * use with additional/different regions of memory. |
| 435 | * |
| 436 | * Note that if 7 descriptors are allocated, it's perfectly acceptable to |
| 437 | * initialize the ring with a smaller number of descriptors. The amount |
| 438 | * of memory allocated for the descriptor ring will not be reduced, and |
| 439 | * the descriptor ring may be reinitialized later |
| 440 | * |
| 441 | * @return |
| 442 | * 0 Descriptor ring was initialized successfully |
| 443 | * -ENOMEM The descriptor which was passed in has insufficient space |
| 444 | * to hold the desired number of descriptors. |
| 445 | */ |
| 446 | /****************************************************************************/ |
| 447 | |
| 448 | int dma_init_descriptor_ring(DMA_DescriptorRing_t *ring, /* Descriptor ring to initialize */ |
| 449 | int numDescriptors /* Number of descriptors to initialize. */ |
| 450 | ); |
| 451 | |
| 452 | /****************************************************************************/ |
| 453 | /** |
| 454 | * Determines the number of descriptors which would be required for a |
| 455 | * transfer of the indicated memory region. |
| 456 | * |
| 457 | * This function also needs to know which DMA device this transfer will |
| 458 | * be destined for, so that the appropriate DMA configuration can be retrieved. |
| 459 | * DMA parameters such as transfer width, and whether this is a memory-to-memory |
| 460 | * or memory-to-peripheral, etc can all affect the actual number of descriptors |
| 461 | * required. |
| 462 | * |
| 463 | * @return |
| 464 | * > 0 Returns the number of descriptors required for the indicated transfer |
| 465 | * -EINVAL Invalid device type for this kind of transfer |
| 466 | * (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM) |
| 467 | * -ENOMEM Memory exhausted |
| 468 | */ |
| 469 | /****************************************************************************/ |
| 470 | |
| 471 | int dma_calculate_descriptor_count(DMA_Device_t device, /* DMA Device that this will be associated with */ |
| 472 | dma_addr_t srcData, /* Place to get data to write to device */ |
| 473 | dma_addr_t dstData, /* Pointer to device data address */ |
| 474 | size_t numBytes /* Number of bytes to transfer to the device */ |
| 475 | ); |
| 476 | |
| 477 | /****************************************************************************/ |
| 478 | /** |
| 479 | * Adds a region of memory to the descriptor ring. Note that it may take |
| 480 | * multiple descriptors for each region of memory. It is the callers |
| 481 | * responsibility to allocate a sufficiently large descriptor ring. |
| 482 | * |
| 483 | * @return |
| 484 | * 0 Descriptors were added successfully |
| 485 | * -EINVAL Invalid device type for this kind of transfer |
| 486 | * (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM) |
| 487 | * -ENOMEM Memory exhausted |
| 488 | */ |
| 489 | /****************************************************************************/ |
| 490 | |
| 491 | int dma_add_descriptors(DMA_DescriptorRing_t *ring, /* Descriptor ring to add descriptors to */ |
| 492 | DMA_Device_t device, /* DMA Device that descriptors are for */ |
| 493 | dma_addr_t srcData, /* Place to get data (memory or device) */ |
| 494 | dma_addr_t dstData, /* Place to put data (memory or device) */ |
| 495 | size_t numBytes /* Number of bytes to transfer to the device */ |
| 496 | ); |
| 497 | |
| 498 | /****************************************************************************/ |
| 499 | /** |
| 500 | * Sets the descriptor ring associated with a device. |
| 501 | * |
| 502 | * Once set, the descriptor ring will be associated with the device, even |
| 503 | * across channel request/free calls. Passing in a NULL descriptor ring |
| 504 | * will release any descriptor ring currently associated with the device. |
| 505 | * |
| 506 | * Note: If you call dma_transfer, or one of the other dma_alloc_ functions |
| 507 | * the descriptor ring may be released and reallocated. |
| 508 | * |
| 509 | * Note: This function will release the descriptor memory for any current |
| 510 | * descriptor ring associated with this device. |
| 511 | */ |
| 512 | /****************************************************************************/ |
| 513 | |
| 514 | int dma_set_device_descriptor_ring(DMA_Device_t device, /* Device to update the descriptor ring for. */ |
| 515 | DMA_DescriptorRing_t *ring /* Descriptor ring to add descriptors to */ |
| 516 | ); |
| 517 | |
| 518 | /****************************************************************************/ |
| 519 | /** |
| 520 | * Retrieves the descriptor ring associated with a device. |
| 521 | */ |
| 522 | /****************************************************************************/ |
| 523 | |
| 524 | int dma_get_device_descriptor_ring(DMA_Device_t device, /* Device to retrieve the descriptor ring for. */ |
| 525 | DMA_DescriptorRing_t *ring /* Place to store retrieved ring */ |
| 526 | ); |
| 527 | |
| 528 | /****************************************************************************/ |
| 529 | /** |
| 530 | * Allocates buffers for the descriptors. This is normally done automatically |
| 531 | * but needs to be done explicitly when initiating a dma from interrupt |
| 532 | * context. |
| 533 | * |
| 534 | * @return |
| 535 | * 0 Descriptors were allocated successfully |
| 536 | * -EINVAL Invalid device type for this kind of transfer |
| 537 | * (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM) |
| 538 | * -ENOMEM Memory exhausted |
| 539 | */ |
| 540 | /****************************************************************************/ |
| 541 | |
| 542 | int dma_alloc_descriptors(DMA_Handle_t handle, /* DMA Handle */ |
| 543 | dmacHw_TRANSFER_TYPE_e transferType, /* Type of transfer being performed */ |
| 544 | dma_addr_t srcData, /* Place to get data to write to device */ |
| 545 | dma_addr_t dstData, /* Pointer to device data address */ |
| 546 | size_t numBytes /* Number of bytes to transfer to the device */ |
| 547 | ); |
| 548 | |
| 549 | /****************************************************************************/ |
| 550 | /** |
| 551 | * Allocates and sets up descriptors for a double buffered circular buffer. |
| 552 | * |
| 553 | * This is primarily intended to be used for things like the ingress samples |
| 554 | * from a microphone. |
| 555 | * |
| 556 | * @return |
| 557 | * > 0 Number of descriptors actually allocated. |
| 558 | * -EINVAL Invalid device type for this kind of transfer |
| 559 | * (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM) |
| 560 | * -ENOMEM Memory exhausted |
| 561 | */ |
| 562 | /****************************************************************************/ |
| 563 | |
| 564 | int dma_alloc_double_dst_descriptors(DMA_Handle_t handle, /* DMA Handle */ |
| 565 | dma_addr_t srcData, /* Physical address of source data */ |
| 566 | dma_addr_t dstData1, /* Physical address of first destination buffer */ |
| 567 | dma_addr_t dstData2, /* Physical address of second destination buffer */ |
| 568 | size_t numBytes /* Number of bytes in each destination buffer */ |
| 569 | ); |
| 570 | |
| 571 | /****************************************************************************/ |
| 572 | /** |
| 573 | * Initializes a DMA_MemMap_t data structure |
| 574 | */ |
| 575 | /****************************************************************************/ |
| 576 | |
| 577 | int dma_init_mem_map(DMA_MemMap_t *memMap /* Stores state information about the map */ |
| 578 | ); |
| 579 | |
| 580 | /****************************************************************************/ |
| 581 | /** |
| 582 | * Releases any memory currently being held by a memory mapping structure. |
| 583 | */ |
| 584 | /****************************************************************************/ |
| 585 | |
| 586 | int dma_term_mem_map(DMA_MemMap_t *memMap /* Stores state information about the map */ |
| 587 | ); |
| 588 | |
| 589 | /****************************************************************************/ |
| 590 | /** |
| 591 | * Looks at a memory address and categorizes it. |
| 592 | * |
| 593 | * @return One of the values from the DMA_MemType_t enumeration. |
| 594 | */ |
| 595 | /****************************************************************************/ |
| 596 | |
| 597 | DMA_MemType_t dma_mem_type(void *addr); |
| 598 | |
| 599 | /****************************************************************************/ |
| 600 | /** |
| 601 | * Sets the process (aka userTask) associated with a mem map. This is |
| 602 | * required if user-mode segments will be added to the mapping. |
| 603 | */ |
| 604 | /****************************************************************************/ |
| 605 | |
| 606 | static inline void dma_mem_map_set_user_task(DMA_MemMap_t *memMap, |
| 607 | struct task_struct *task) |
| 608 | { |
| 609 | memMap->userTask = task; |
| 610 | } |
| 611 | |
| 612 | /****************************************************************************/ |
| 613 | /** |
| 614 | * Looks at a memory address and determines if we support DMA'ing to/from |
| 615 | * that type of memory. |
| 616 | * |
| 617 | * @return boolean - |
| 618 | * return value != 0 means dma supported |
| 619 | * return value == 0 means dma not supported |
| 620 | */ |
| 621 | /****************************************************************************/ |
| 622 | |
| 623 | int dma_mem_supports_dma(void *addr); |
| 624 | |
| 625 | /****************************************************************************/ |
| 626 | /** |
| 627 | * Initializes a memory map for use. Since this function acquires a |
| 628 | * sempaphore within the memory map, it is VERY important that dma_unmap |
| 629 | * be called when you're finished using the map. |
| 630 | */ |
| 631 | /****************************************************************************/ |
| 632 | |
| 633 | int dma_map_start(DMA_MemMap_t *memMap, /* Stores state information about the map */ |
| 634 | enum dma_data_direction dir /* Direction that the mapping will be going */ |
| 635 | ); |
| 636 | |
| 637 | /****************************************************************************/ |
| 638 | /** |
| 639 | * Adds a segment of memory to a memory map. |
| 640 | * |
| 641 | * @return 0 on success, error code otherwise. |
| 642 | */ |
| 643 | /****************************************************************************/ |
| 644 | |
| 645 | int dma_map_add_region(DMA_MemMap_t *memMap, /* Stores state information about the map */ |
| 646 | void *mem, /* Virtual address that we want to get a map of */ |
| 647 | size_t numBytes /* Number of bytes being mapped */ |
| 648 | ); |
| 649 | |
| 650 | /****************************************************************************/ |
| 651 | /** |
| 652 | * Creates a descriptor ring from a memory mapping. |
| 653 | * |
| 654 | * @return 0 on sucess, error code otherwise. |
| 655 | */ |
| 656 | /****************************************************************************/ |
| 657 | |
| 658 | int dma_map_create_descriptor_ring(DMA_Device_t dev, /* DMA device (where the ring is stored) */ |
| 659 | DMA_MemMap_t *memMap, /* Memory map that will be used */ |
| 660 | dma_addr_t devPhysAddr /* Physical address of device */ |
| 661 | ); |
| 662 | |
| 663 | /****************************************************************************/ |
| 664 | /** |
| 665 | * Maps in a memory region such that it can be used for performing a DMA. |
| 666 | * |
| 667 | * @return |
| 668 | */ |
| 669 | /****************************************************************************/ |
| 670 | |
| 671 | int dma_map_mem(DMA_MemMap_t *memMap, /* Stores state information about the map */ |
| 672 | void *addr, /* Virtual address that we want to get a map of */ |
| 673 | size_t count, /* Number of bytes being mapped */ |
| 674 | enum dma_data_direction dir /* Direction that the mapping will be going */ |
| 675 | ); |
| 676 | |
| 677 | /****************************************************************************/ |
| 678 | /** |
| 679 | * Maps in a memory region such that it can be used for performing a DMA. |
| 680 | * |
| 681 | * @return |
| 682 | */ |
| 683 | /****************************************************************************/ |
| 684 | |
| 685 | int dma_unmap(DMA_MemMap_t *memMap, /* Stores state information about the map */ |
| 686 | int dirtied /* non-zero if any of the pages were modified */ |
| 687 | ); |
| 688 | |
| 689 | /****************************************************************************/ |
| 690 | /** |
| 691 | * Initiates a transfer when the descriptors have already been setup. |
| 692 | * |
| 693 | * This is a special case, and normally, the dma_transfer_xxx functions should |
| 694 | * be used. |
| 695 | * |
| 696 | * @return |
| 697 | * 0 Transfer was started successfully |
| 698 | * -ENODEV Invalid handle |
| 699 | */ |
| 700 | /****************************************************************************/ |
| 701 | |
| 702 | int dma_start_transfer(DMA_Handle_t handle); |
| 703 | |
| 704 | /****************************************************************************/ |
| 705 | /** |
| 706 | * Stops a previously started DMA transfer. |
| 707 | * |
| 708 | * @return |
| 709 | * 0 Transfer was stopped successfully |
| 710 | * -ENODEV Invalid handle |
| 711 | */ |
| 712 | /****************************************************************************/ |
| 713 | |
| 714 | int dma_stop_transfer(DMA_Handle_t handle); |
| 715 | |
| 716 | /****************************************************************************/ |
| 717 | /** |
| 718 | * Waits for a DMA to complete by polling. This function is only intended |
| 719 | * to be used for testing. Interrupts should be used for most DMA operations. |
| 720 | */ |
| 721 | /****************************************************************************/ |
| 722 | |
| 723 | int dma_wait_transfer_done(DMA_Handle_t handle); |
| 724 | |
| 725 | /****************************************************************************/ |
| 726 | /** |
| 727 | * Initiates a DMA transfer |
| 728 | * |
| 729 | * @return |
| 730 | * 0 Transfer was started successfully |
| 731 | * -EINVAL Invalid device type for this kind of transfer |
| 732 | * (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM) |
| 733 | */ |
| 734 | /****************************************************************************/ |
| 735 | |
| 736 | int dma_transfer(DMA_Handle_t handle, /* DMA Handle */ |
| 737 | dmacHw_TRANSFER_TYPE_e transferType, /* Type of transfer being performed */ |
| 738 | dma_addr_t srcData, /* Place to get data to write to device */ |
| 739 | dma_addr_t dstData, /* Pointer to device data address */ |
| 740 | size_t numBytes /* Number of bytes to transfer to the device */ |
| 741 | ); |
| 742 | |
| 743 | /****************************************************************************/ |
| 744 | /** |
| 745 | * Initiates a transfer from memory to a device. |
| 746 | * |
| 747 | * @return |
| 748 | * 0 Transfer was started successfully |
| 749 | * -EINVAL Invalid device type for this kind of transfer |
| 750 | * (i.e. the device is _DEV_TO_MEM and not _MEM_TO_DEV) |
| 751 | */ |
| 752 | /****************************************************************************/ |
| 753 | |
| 754 | static inline int dma_transfer_to_device(DMA_Handle_t handle, /* DMA Handle */ |
| 755 | dma_addr_t srcData, /* Place to get data to write to device (physical address) */ |
| 756 | dma_addr_t dstData, /* Pointer to device data address (physical address) */ |
| 757 | size_t numBytes /* Number of bytes to transfer to the device */ |
| 758 | ) { |
| 759 | return dma_transfer(handle, |
| 760 | dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL, |
| 761 | srcData, dstData, numBytes); |
| 762 | } |
| 763 | |
| 764 | /****************************************************************************/ |
| 765 | /** |
| 766 | * Initiates a transfer from a device to memory. |
| 767 | * |
| 768 | * @return |
| 769 | * 0 Transfer was started successfully |
| 770 | * -EINVAL Invalid device type for this kind of transfer |
| 771 | * (i.e. the device is _MEM_TO_DEV and not _DEV_TO_MEM) |
| 772 | */ |
| 773 | /****************************************************************************/ |
| 774 | |
| 775 | static inline int dma_transfer_from_device(DMA_Handle_t handle, /* DMA Handle */ |
| 776 | dma_addr_t srcData, /* Pointer to the device data address (physical address) */ |
| 777 | dma_addr_t dstData, /* Place to store data retrieved from the device (physical address) */ |
| 778 | size_t numBytes /* Number of bytes to retrieve from the device */ |
| 779 | ) { |
| 780 | return dma_transfer(handle, |
| 781 | dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM, |
| 782 | srcData, dstData, numBytes); |
| 783 | } |
| 784 | |
| 785 | /****************************************************************************/ |
| 786 | /** |
| 787 | * Initiates a memory to memory transfer. |
| 788 | * |
| 789 | * @return |
| 790 | * 0 Transfer was started successfully |
| 791 | * -EINVAL Invalid device type for this kind of transfer |
| 792 | * (i.e. the device wasn't DMA_DEVICE_MEM_TO_MEM) |
| 793 | */ |
| 794 | /****************************************************************************/ |
| 795 | |
| 796 | static inline int dma_transfer_mem_to_mem(DMA_Handle_t handle, /* DMA Handle */ |
| 797 | dma_addr_t srcData, /* Place to transfer data from (physical address) */ |
| 798 | dma_addr_t dstData, /* Place to transfer data to (physical address) */ |
| 799 | size_t numBytes /* Number of bytes to transfer */ |
| 800 | ) { |
| 801 | return dma_transfer(handle, |
| 802 | dmacHw_TRANSFER_TYPE_MEM_TO_MEM, |
| 803 | srcData, dstData, numBytes); |
| 804 | } |
| 805 | |
| 806 | /****************************************************************************/ |
| 807 | /** |
| 808 | * Set the callback function which will be called when a transfer completes. |
| 809 | * If a NULL callback function is set, then no callback will occur. |
| 810 | * |
| 811 | * @note @a devHandler will be called from IRQ context. |
| 812 | * |
| 813 | * @return |
| 814 | * 0 - Success |
| 815 | * -ENODEV - Device handed in is invalid. |
| 816 | */ |
| 817 | /****************************************************************************/ |
| 818 | |
| 819 | int dma_set_device_handler(DMA_Device_t dev, /* Device to set the callback for. */ |
| 820 | DMA_DeviceHandler_t devHandler, /* Function to call when the DMA completes */ |
| 821 | void *userData /* Pointer which will be passed to devHandler. */ |
| 822 | ); |
| 823 | |
| 824 | #endif |
| 825 | |
| 826 | #endif /* ASM_ARM_ARCH_BCMRING_DMA_H */ |