|
|
@@ -27,6 +27,7 @@
|
|
|
|
|
|
static struct dma_chan dma_ch[DMA_CH_NUM] = {0};
|
|
|
static SemaphoreHandle_t dma_mutex;
|
|
|
+static QueueHandle_t dma_m2m_done = NULL;
|
|
|
|
|
|
|
|
|
struct dma_chan *dma_request_channel(int favorite_ch)
|
|
|
@@ -148,7 +149,7 @@ int dma_config_channel(struct dma_chan *chan, struct dma_config *config)
|
|
|
int lli_num;
|
|
|
int i;
|
|
|
|
|
|
- lli_num = (blk_size + DMA_BLOCK_SIZE - 1) / DMA_BLOCK_SIZE;
|
|
|
+ lli_num = (blk_size + DMA_BLOCK_SIZE - 1) / DMA_BLOCK_SIZE - 1;
|
|
|
if (chan->lli) {
|
|
|
vPortFree(chan->lli);
|
|
|
chan->lli = NULL;
|
|
|
@@ -157,24 +158,24 @@ int dma_config_channel(struct dma_chan *chan, struct dma_config *config)
|
|
|
if (!chan->lli)
|
|
|
return -ENOMEM;
|
|
|
for (i = 0; i < lli_num - 1; i++) {
|
|
|
- chan->lli[i].src_addr = config->src_addr + (si ? i : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
- chan->lli[i].dst_addr = config->dst_addr + (di ? i : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
+ chan->lli[i].src_addr = config->src_addr + (si ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
+ chan->lli[i].dst_addr = config->dst_addr + (di ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
chan->lli[i].next_lli = (unsigned int)&chan->lli[i + 1];
|
|
|
chan->lli[i].control = ctl | DMA_BLOCK_SIZE;
|
|
|
if (!config->blkint_en)
|
|
|
chan->lli[i].control &= ~(1 << 31);
|
|
|
}
|
|
|
- chan->lli[i].src_addr = config->src_addr + (si ? i : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
- chan->lli[i].dst_addr = config->dst_addr + (di ? i : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
+ chan->lli[i].src_addr = config->src_addr + (si ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
+ chan->lli[i].dst_addr = config->dst_addr + (di ? (i + 1) : 0) * (DMA_BLOCK_SIZE << src_width);
|
|
|
chan->lli[i].next_lli = 0;
|
|
|
- chan->lli[i].control = ctl | (blk_size - DMA_BLOCK_SIZE * (lli_num - 1));
|
|
|
+ chan->lli[i].control = ctl | (blk_size - DMA_BLOCK_SIZE * lli_num);
|
|
|
CP15_clean_dcache_for_dma((unsigned int)chan->lli,
|
|
|
(unsigned int)chan->lli + sizeof(struct dma_lli) * lli_num);
|
|
|
|
|
|
- rDMACCxSrcAddr(chan->chan_id) = 0;
|
|
|
- rDMACCxDestAddr(chan->chan_id) = 0;
|
|
|
+ rDMACCxSrcAddr(chan->chan_id) = config->src_addr;
|
|
|
+ rDMACCxDestAddr(chan->chan_id) = config->dst_addr;
|
|
|
rDMACCxLLI(chan->chan_id) = (unsigned int)chan->lli | 1;
|
|
|
- rDMACCxControl(chan->chan_id) = ctl & ~(1 << 31) | 1;
|
|
|
+ rDMACCxControl(chan->chan_id) = ctl & ~(1 << 31) | DMA_BLOCK_SIZE;
|
|
|
rDMACCxConfiguration(chan->chan_id) = cfg;
|
|
|
} else {
|
|
|
rDMACCxSrcAddr(chan->chan_id) = config->src_addr;
|
|
|
@@ -187,88 +188,6 @@ int dma_config_channel(struct dma_chan *chan, struct dma_config *config)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int dma_config_cylic_channel(struct dma_chan *chan, struct dma_config *config, int num)
|
|
|
-{
|
|
|
- unsigned int ctl;
|
|
|
- unsigned int cfg;
|
|
|
- unsigned int src_width, dst_width;
|
|
|
- unsigned int src_id = 0, dst_id = 0;
|
|
|
- unsigned int di = 0, si = 0;
|
|
|
- unsigned int data_width = (1 << DMA_BUSWIDTH_4_BYTES);
|
|
|
- int i;
|
|
|
-
|
|
|
- if (chan->lli) {
|
|
|
- vPortFree(chan->lli);
|
|
|
- chan->lli = NULL;
|
|
|
- }
|
|
|
- chan->lli = pvPortMalloc(sizeof(struct dma_lli) * num);
|
|
|
- if (!chan->lli)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- for (i = 0; i < num; i++) {
|
|
|
- convert_burst(&config->src_maxburst);
|
|
|
- convert_burst(&config->dst_maxburst);
|
|
|
-
|
|
|
- if (config->direction == DMA_MEM_TO_DEV) {
|
|
|
- src_width = __ffs(data_width | config->src_addr | config->transfer_size);
|
|
|
- dst_width = config->dst_addr_width;
|
|
|
- dst_id = config->dst_id;
|
|
|
- si = 1;
|
|
|
- } else if (config->direction == DMA_DEV_TO_MEM) {
|
|
|
- src_width = config->src_addr_width;
|
|
|
- dst_width = __ffs(data_width | config->dst_addr | config->transfer_size);
|
|
|
- src_id = config->src_id;
|
|
|
- di = 1;
|
|
|
- } else if (config->direction == DMA_MEM_TO_MEM) {
|
|
|
- src_width = __ffs(data_width | config->src_addr | config->transfer_size);
|
|
|
- dst_width = __ffs(data_width | config->dst_addr | config->transfer_size);
|
|
|
- si = 1;
|
|
|
- di = 1;
|
|
|
- }
|
|
|
-
|
|
|
- ctl = (1 << 31) | /* [31] I Read/write Terminal count interrupt enable bit */
|
|
|
- (0 << 28) | /* [30:28] Prot Read/write Protection */
|
|
|
- (di << 27) | /* [27] DI Read/write Destination increment */
|
|
|
- (si << 26) | /* [26] SI Read/write Source increment */
|
|
|
- (0 << 25) | /* [25] D Read/write Destination AHB master select */
|
|
|
- (1 << 24) | /* [24] S Read/write Source AHB master select */
|
|
|
- (dst_width << 21) | /* [23:21] DWidth Read/write Destination transfer width */
|
|
|
- (src_width << 18) | /* [20:18] SWidth Read/write Source transfer width */
|
|
|
- (config->dst_maxburst << 15) | /* [17:15] DBSize Read/write Destination burst size */
|
|
|
- (config->src_maxburst << 12) | /* [14:12] SBSize Read/write Source burst size */
|
|
|
- 0; /* [11:0] TransferSize Read/write Transfer size */
|
|
|
-
|
|
|
- cfg = (0 << 18) | /* [18] H Read/write Halt */
|
|
|
- (0 << 16) | /* [16] L Read/write Lock */
|
|
|
- (1 << 15) | /* [15] ITC Read/write Terminal count interrupt mask */
|
|
|
- (1 << 14) | /* [14] IE Read/write Interrupt error mask */
|
|
|
- (config->direction << 11) | /* [13:11] FlowCntrl Read/write Flow control and transfer type */
|
|
|
- (dst_id << 6) | /* [9:6] DestPeripheral Read/write Destination peripheral */
|
|
|
- (src_id << 1) | /* [4:1] SrcPeripheral Read/write Source peripheral */
|
|
|
- 0; /* [0] Channel enable */
|
|
|
-
|
|
|
- chan->lli[i].src_addr = config->src_addr;
|
|
|
- chan->lli[i].dst_addr = config->dst_addr;
|
|
|
- chan->lli[i].next_lli = (unsigned int)&chan->lli[i + 1];
|
|
|
- chan->lli[i].control = ctl | (config->transfer_size >> src_width);
|
|
|
- if (!config->blkint_en)
|
|
|
- chan->lli[i].control &= ~(1 << 31);
|
|
|
- config++;
|
|
|
- }
|
|
|
- chan->lli[i - 1].next_lli = (unsigned int)&chan->lli[0];
|
|
|
- CP15_clean_dcache_for_dma((unsigned int)chan->lli,
|
|
|
- (unsigned int)chan->lli + sizeof(struct dma_lli) * num);
|
|
|
-
|
|
|
- rDMACCxSrcAddr(chan->chan_id) = 0;
|
|
|
- rDMACCxDestAddr(chan->chan_id) = 0;
|
|
|
- rDMACCxLLI(chan->chan_id) = (unsigned int)chan->lli | 1;
|
|
|
- rDMACCxControl(chan->chan_id) = ctl & ~(1 << 31) | 1;
|
|
|
- rDMACCxConfiguration(chan->chan_id) = cfg;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
int dma_register_complete_callback(struct dma_chan *chan,
|
|
|
void (*callback)(void *param, unsigned int mask),
|
|
|
void *callback_param)
|
|
|
@@ -302,7 +221,7 @@ int dma_stop_channel(struct dma_chan *chan)
|
|
|
}
|
|
|
|
|
|
// A channel can be disabled by clearing the Enable bit.
|
|
|
- rDMACCxConfiguration(chan->chan_id) &= ~(1 << chan->chan_id);
|
|
|
+ rDMACCxConfiguration(chan->chan_id) &= ~1;
|
|
|
|
|
|
// waiting
|
|
|
while(rDMACEnbldChns & (1 << chan->chan_id)) {
|
|
|
@@ -323,6 +242,61 @@ int dma_stop_channel(struct dma_chan *chan)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void dma_m2m_callback(void *param, unsigned int mask)
|
|
|
+{
|
|
|
+ if(dma_m2m_done)
|
|
|
+ xQueueSendFromISR(dma_m2m_done, NULL, 0);
|
|
|
+}
|
|
|
+
|
|
|
+int dma_m2mcpy(unsigned int dst_addr, unsigned int src_addr, int size)
|
|
|
+{
|
|
|
+ struct dma_config cfg = {0};
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ struct dma_chan *dma_ch = dma_request_channel(0);
|
|
|
+ if (!dma_ch) {
|
|
|
+ printf("%s() dma_request_channel fail.\n", __func__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ cfg.dst_addr_width = DMA_BUSWIDTH_4_BYTES;
|
|
|
+ cfg.dst_maxburst = 256;
|
|
|
+ cfg.src_addr_width = DMA_BUSWIDTH_4_BYTES;
|
|
|
+ cfg.src_maxburst = 256;
|
|
|
+ cfg.transfer_size = size;
|
|
|
+ cfg.src_addr = src_addr;
|
|
|
+ cfg.dst_addr = dst_addr;
|
|
|
+ cfg.direction = DMA_MEM_TO_MEM;
|
|
|
+
|
|
|
+ dma_clean_range(src_addr, src_addr + size);
|
|
|
+ dma_inv_range(dst_addr, dst_addr + size);
|
|
|
+
|
|
|
+ ret = dma_config_channel(dma_ch, &cfg);
|
|
|
+ if (ret) {
|
|
|
+ printf("%s, dma_config_channel failed.\n", __func__);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ dma_register_complete_callback(dma_ch, dma_m2m_callback, NULL);
|
|
|
+
|
|
|
+ xQueueReset(dma_m2m_done);
|
|
|
+
|
|
|
+ dma_start_channel(dma_ch);
|
|
|
+ if (xQueueReceive(dma_m2m_done, NULL, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
|
|
+ printf("dma_m2mcpy wait timeout.\n");
|
|
|
+ ret = -ETIMEDOUT;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ dma_stop_channel(dma_ch);
|
|
|
+ ret = 0;
|
|
|
+exit:
|
|
|
+ if(dma_ch)
|
|
|
+ dma_release_channel(dma_ch);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static void dma_int_handler(void *param)
|
|
|
{
|
|
|
unsigned int err_status, tfr_status;
|
|
|
@@ -359,6 +333,7 @@ static void dma_int_handler(void *param)
|
|
|
int dma_init(void)
|
|
|
{
|
|
|
dma_mutex = xSemaphoreCreateMutex();
|
|
|
+ dma_m2m_done = xQueueCreate(1, 0);
|
|
|
|
|
|
sys_soft_reset(softreset_dma);
|
|
|
|