| /** |
| * @file |
| * |
| * @brief Public APIs for the DMA drivers. |
| */ |
| |
| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef _DMA_H_ |
| #define _DMA_H_ |
| |
| #include <kernel.h> |
| #include <device.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| |
| /** |
| * @brief DMA Interface |
| * @defgroup DMA_interface DMA Interface |
| * @ingroup io_interfaces |
| * @{ |
| */ |
| |
| enum dma_handshake_polarity { |
| HANDSHAKE_POLARITY_HIGH = 0x0, |
| HANDSHAKE_POLARITY_LOW |
| }; |
| |
| enum dma_burst_length { |
| BURST_TRANS_LENGTH_1 = 0x0, |
| BURST_TRANS_LENGTH_4, |
| BURST_TRANS_LENGTH_8, |
| BURST_TRANS_LENGTH_16, |
| BURST_TRANS_LENGTH_32, |
| BURST_TRANS_LENGTH_64, |
| BURST_TRANS_LENGTH_128, |
| BURST_TRANS_LENGTH_256 |
| }; |
| |
| enum dma_transfer_width { |
| TRANS_WIDTH_8 = 0x0, |
| TRANS_WIDTH_16, |
| TRANS_WIDTH_32, |
| TRANS_WIDTH_64, |
| TRANS_WIDTH_128, |
| TRANS_WIDTH_256 |
| }; |
| |
| enum dma_channel_direction { |
| MEMORY_TO_MEMORY = 0x0, |
| MEMORY_TO_PERIPHERAL, |
| PERIPHERAL_TO_MEMORY |
| }; |
| |
| /** |
| * @brief DMA Channel Configuration. |
| * |
| * This defines a single channel configuration on the DMA controller. |
| */ |
| struct dma_channel_config { |
| /* Hardware Interface handshake for peripheral (I2C, SPI, etc) */ |
| u32_t handshake_interface; |
| /* Select active polarity for handshake (low/high) */ |
| enum dma_handshake_polarity handshake_polarity; |
| /* DMA transfer direction from mem/peripheral to mem/peripheral */ |
| enum dma_channel_direction channel_direction; |
| /* Data item size read from source */ |
| enum dma_transfer_width source_transfer_width; |
| /* Data item size written to destination */ |
| enum dma_transfer_width destination_transfer_width; |
| /* Number of data items read */ |
| enum dma_burst_length source_burst_length; |
| /* Number of data items written */ |
| enum dma_burst_length destination_burst_length; |
| |
| /* Completed transaction callback */ |
| void (*dma_transfer)(struct device *dev, void *data); |
| /* Error callback */ |
| void (*dma_error)(struct device *dev, void *data); |
| /* Client callback private data */ |
| void *callback_data; |
| }; |
| |
| /** |
| * @brief DMA transfer Configuration. |
| * |
| * This defines a single transfer on configured channel of the DMA controller. |
| */ |
| struct dma_transfer_config { |
| /* Total amount of data in bytes to transfer */ |
| u32_t block_size; |
| /* Source address for the transaction */ |
| u32_t *source_address; |
| /* Destination address */ |
| u32_t *destination_address; |
| }; |
| |
| /** |
| * @brief DMA block configuration structure. |
| * |
| * source_address is block starting address at source |
| * source_gather_interval is the address adjustment at gather boundary |
| * dest_address is block starting address at destination |
| * dest_scatter_interval is the address adjustment at scatter boundary |
| * dest_scatter_count is the continuous transfer count between scatter |
| * boundaries |
| * source_gather_count is the continuous transfer count between gather |
| * boundaries |
| * block_size is the number of bytes to be transferred for this block. |
| * |
| * config is a bit field with the following parts: |
| * source_gather_en [ 0 ] - 0-disable, 1-enable |
| * dest_scatter_en [ 1 ] - 0-disable, 1-enable |
| * source_addr_adj [ 2 : 3 ] - 00-increment, 01-decrement, |
| * 10-no change |
| * dest_addr_adj [ 4 : 5 ] - 00-increment, 01-decrement, |
| * 10-no change |
| * source_reload_en [ 6 ] - reload source address at the end of |
| * block transfer |
| * 0-disable, 1-enable |
| * dest_reload_en [ 7 ] - reload destination address at the end |
| * of block transfer |
| * 0-disable, 1-enable |
| * fifo_mode_control [ 8 : 11 ] - How full of the fifo before transfer |
| * start. HW specific. |
| * flow_control_mode [ 12 ] - 0-source request served upon data |
| * availability |
| * 1-source request postponed until |
| * destination request happens |
| * reserved [ 13 : 15 ] |
| */ |
| struct dma_block_config { |
| u32_t source_address; |
| u32_t source_gather_interval; |
| u32_t dest_address; |
| u32_t dest_scatter_interval; |
| u16_t dest_scatter_count; |
| u16_t source_gather_count; |
| u32_t block_size; |
| struct dma_block_config *next_block; |
| u16_t source_gather_en : 1; |
| u16_t dest_scatter_en : 1; |
| u16_t source_addr_adj : 2; |
| u16_t dest_addr_adj : 2; |
| u16_t source_reload_en : 1; |
| u16_t dest_reload_en : 1; |
| u16_t fifo_mode_control : 4; |
| u16_t flow_control_mode : 1; |
| u16_t reserved : 3; |
| }; |
| |
| /** |
| * @brief DMA configuration structure. |
| * |
| * dma_slot [ 0 : 5 ] - which peripheral and direction |
| * (HW specific) |
| * channel_direction [ 6 : 8 ] - 000-memory to memory, 001-memory to |
| * peripheral, 010-peripheral to memory, |
| * ... |
| * complete_callback_en [ 9 ] - 0-callback invoked at completion only |
| * 1-callback invoked at completion of |
| * each block |
| * error_callback_en [ 10 ] - 0-error callback enabled |
| * 1-error callback disabled |
| * source_handshake [ 11 ] - 0-HW, 1-SW |
| * dest_handshake [ 12 ] - 0-HW, 1-SW |
| * channel_priority [ 13 : 16 ] - DMA channel priority |
| * source_chaining_en [ 17 ] - enable/disable source block chaining |
| * 0-disable, 1-enable |
| * dest_chaining_en [ 18 ] - enable/disable destination block |
| * chaining. |
| * 0-disable, 1-enable |
| * reserved [ 19 : 31 ] |
| * |
| * source_data_size [ 0 : 15 ] - width of source data (in bytes) |
| * dest_data_size [ 16 : 31 ] - width of dest data (in bytes) |
| * source_burst_length [ 0 : 15 ] - number of source data units |
| * dest_burst_length [ 16 : 31 ] - number of destination data units |
| * |
| * block_count is the number of blocks used for block chaining, this |
| * depends on availability of the DMA controller. |
| * |
| * dma_callback is the callback function pointer. If enabled, callback function |
| * will be invoked at transfer completion or when error happens |
| * (error_code: zero-transfer success, non zero-error happens). |
| */ |
| struct dma_config { |
| u32_t dma_slot : 6; |
| u32_t channel_direction : 3; |
| u32_t complete_callback_en : 1; |
| u32_t error_callback_en : 1; |
| u32_t source_handshake : 1; |
| u32_t dest_handshake : 1; |
| u32_t channel_priority : 4; |
| u32_t source_chaining_en : 1; |
| u32_t dest_chaining_en : 1; |
| u32_t reserved : 13; |
| u32_t source_data_size : 16; |
| u32_t dest_data_size : 16; |
| u32_t source_burst_length : 16; |
| u32_t dest_burst_length : 16; |
| u32_t block_count; |
| struct dma_block_config *head_block; |
| void (*dma_callback)(struct device *dev, u32_t channel, |
| int error_code); |
| }; |
| |
| /** |
| * @cond INTERNAL_HIDDEN |
| * |
| * These are for internal use only, so skip these in |
| * public documentation. |
| */ |
| |
| typedef int (*dma_api_channel_config)(struct device *dev, u32_t channel, |
| struct dma_channel_config *config); |
| |
| typedef int (*dma_api_transfer_config)(struct device *dev, u32_t channel, |
| struct dma_transfer_config *config); |
| |
| typedef int (*dma_api_transfer_start)(struct device *dev, u32_t channel); |
| |
| typedef int (*dma_api_transfer_stop)(struct device *dev, u32_t channel); |
| |
| typedef int (*dma_api_config)(struct device *dev, u32_t channel, |
| struct dma_config *config); |
| |
| typedef int (*dma_api_start)(struct device *dev, u32_t channel); |
| |
| typedef int (*dma_api_stop)(struct device *dev, u32_t channel); |
| |
| struct dma_driver_api { |
| dma_api_channel_config channel_config; |
| dma_api_transfer_config transfer_config; |
| dma_api_transfer_start transfer_start; |
| dma_api_transfer_stop transfer_stop; |
| dma_api_config config; |
| dma_api_start start; |
| dma_api_stop stop; |
| }; |
| /** |
| * @endcond |
| */ |
| |
| /** |
| * @brief Configure individual channel for DMA transfer. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel to configure |
| * @param config Data structure containing the intended configuration for the |
| * selected channel |
| * |
| * @retval 0 if successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int dma_config(struct device *dev, u32_t channel, |
| struct dma_config *config) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->config(dev, channel, config); |
| } |
| |
| /** |
| * @brief Enables DMA channel and starts the transfer, the channel must be |
| * configured beforehand. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel where the transfer will |
| * be processed |
| * |
| * @retval 0 if successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int dma_start(struct device *dev, u32_t channel) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->start(dev, channel); |
| } |
| |
| /** |
| * @brief Stops the DMA transfer and disables the channel. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel where the transfer was |
| * being processed |
| * |
| * @retval 0 if successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int dma_stop(struct device *dev, u32_t channel) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->stop(dev, channel); |
| } |
| |
| /** |
| * @brief Configure individual channel for DMA transfer. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel to configure |
| * @param config Data structure containing the intended configuration for the |
| * selected channel |
| * |
| * @retval 0 If successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int __deprecated dma_channel_config(struct device *dev, |
| u32_t channel, struct dma_channel_config *config) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->channel_config(dev, channel, config); |
| } |
| |
| /** |
| * @brief Configure DMA transfer for a specific channel that has been |
| * configured. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel to configure |
| * @param config Data structure containing transfer configuration for the |
| * selected channel |
| * |
| * @retval 0 If successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int __deprecated dma_transfer_config(struct device *dev, |
| u32_t channel, struct dma_transfer_config *config) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->transfer_config(dev, channel, config); |
| } |
| |
| /** |
| * @brief Enables DMA channel and starts the transfer, the channel must be |
| * configured beforehand. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel where the transfer will |
| * be processed |
| * |
| * @retval 0 If successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int __deprecated dma_transfer_start(struct device *dev, |
| u32_t channel) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->transfer_start(dev, channel); |
| } |
| |
| /** |
| * @brief Stops the DMA transfer and disables the channel. |
| * |
| * @param dev Pointer to the device structure for the driver instance. |
| * @param channel Numeric identification of the channel where the transfer was |
| * being processed |
| * |
| * @retval 0 If successful. |
| * @retval Negative errno code if failure. |
| */ |
| static inline int __deprecated dma_transfer_stop(struct device *dev, |
| u32_t channel) |
| { |
| const struct dma_driver_api *api = dev->driver_api; |
| |
| return api->transfer_stop(dev, channel); |
| } |
| |
| /** |
| * @brief Look-up generic width index to be used in registers |
| * |
| * WARNING: This look-up works for most controllers, but *may* not work for |
| * yours. Ensure your controller expects the most common register |
| * bit values before using this convenience function. If your |
| * controller does not support these values, you will have to write |
| * your own look-up inside the controller driver. |
| * |
| * @param size: width of bus (in bytes) |
| * |
| * @retval common DMA index to be placed into registers. |
| */ |
| static inline enum dma_burst_length dma_width_index(u32_t size) |
| { |
| /* Check boundaries (max supported width is 32 Bytes) */ |
| if (size < 1 || size > 32) { |
| return 0; /* Zero is the default (8 Bytes) */ |
| } |
| |
| /* Ensure size is a power of 2 */ |
| if (!is_power_of_two(size)) { |
| return 0; /* Zero is the default (8 Bytes) */ |
| } |
| |
| /* Convert to bit pattern for writing to a register */ |
| return find_msb_set(size); |
| } |
| |
| /** |
| * @brief Look-up generic burst index to be used in registers |
| * |
| * WARNING: This look-up works for most controllers, but *may* not work for |
| * yours. Ensure your controller expects the most common register |
| * bit values before using this convenience function. If your |
| * controller does not support these values, you will have to write |
| * your own look-up inside the controller driver. |
| * |
| * @param burst: number of bytes to be sent in a single burst |
| * |
| * @retval common DMA index to be placed into registers. |
| */ |
| static inline enum dma_burst_length dma_burst_index(u32_t burst) |
| { |
| /* Check boundaries (max supported burst length is 256) */ |
| if (burst < 1 || burst > 256) { |
| return 0; /* Zero is the default (1 burst length) */ |
| } |
| |
| /* Ensure burst is a power of 2 */ |
| if (!(burst & (burst - 1))) { |
| return 0; /* Zero is the default (1 burst length) */ |
| } |
| |
| /* Convert to bit pattern for writing to a register */ |
| return find_msb_set(burst); |
| } |
| |
| /** |
| * @} |
| */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* _DMA_H_ */ |