• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_dma_drv.h"
9 
dma_setup_channel(DMA_Type * ptr,uint32_t ch_num,dma_channel_config_t * ch,bool start_transfer)10 hpm_stat_t dma_setup_channel(DMA_Type *ptr, uint32_t ch_num, dma_channel_config_t *ch, bool start_transfer)
11 {
12     uint32_t tmp;
13     if ((ch->dst_width > DMA_SOC_TRANSFER_WIDTH_MAX(ptr))
14             || (ch->src_width > DMA_SOC_TRANSFER_WIDTH_MAX(ptr))) {
15         return status_invalid_argument;
16     }
17     if ((ch->size_in_byte & ((1 << ch->dst_width) - 1))
18      || (ch->src_addr & ((1 << ch->src_width) - 1))
19      || (ch->dst_addr & ((1 << ch->dst_width) - 1))
20      || ((1 << ch->src_width) & ((1 << ch->dst_width) - 1))
21      || ((ch->linked_ptr & 0x7))) {
22         return status_dma_alignment_error;
23     }
24     ptr->CHCTRL[ch_num].SRCADDR = DMA_CHCTRL_SRCADDR_SRCADDRL_SET(ch->src_addr);
25     ptr->CHCTRL[ch_num].DSTADDR = DMA_CHCTRL_DSTADDR_DSTADDRL_SET(ch->dst_addr);
26     ptr->CHCTRL[ch_num].TRANSIZE = DMA_CHCTRL_TRANSIZE_TRANSIZE_SET(ch->size_in_byte >> ch->src_width);
27     ptr->CHCTRL[ch_num].LLPOINTER = DMA_CHCTRL_LLPOINTER_LLPOINTERL_SET(ch->linked_ptr >> 3);
28 
29 #if DMA_SUPPORT_64BIT_ADDR
30     ptr->CHCTRL[ch_num].SRCADDRH = DMA_CHCTRL_SRCADDRH_SRCADDRH_SET(ch->src_addr_high);
31     ptr->CHCTRL[ch_num].DSTADDRH = DMA_CHCTRL_DSTADDRH_DSTADDRH_SET(ch->dst_addr_high);
32     ptr->CHCTRL[ch_num].LLPOINTERH = DMA_CHCTRL_LLPOINTERH_LLPOINTERH_SET(ch->linked_ptr_high);
33 #endif
34 
35     ptr->INTSTATUS = (DMA_INTSTATUS_TC_SET(1) | DMA_INTSTATUS_ABORT_SET(1) | DMA_INTSTATUS_ERROR_SET(1)) << ch_num;
36     tmp = DMA_CHCTRL_CTRL_SRCBUSINFIDX_SET(0)
37         | DMA_CHCTRL_CTRL_DSTBUSINFIDX_SET(0)
38         | DMA_CHCTRL_CTRL_PRIORITY_SET(ch->priority)
39         | DMA_CHCTRL_CTRL_SRCBURSTSIZE_SET(ch->src_burst_size)
40         | DMA_CHCTRL_CTRL_SRCWIDTH_SET(ch->src_width)
41         | DMA_CHCTRL_CTRL_DSTWIDTH_SET(ch->dst_width)
42         | DMA_CHCTRL_CTRL_SRCMODE_SET(ch->src_mode)
43         | DMA_CHCTRL_CTRL_DSTMODE_SET(ch->dst_mode)
44         | DMA_CHCTRL_CTRL_SRCADDRCTRL_SET(ch->src_addr_ctrl)
45         | DMA_CHCTRL_CTRL_DSTADDRCTRL_SET(ch->dst_addr_ctrl)
46         | DMA_CHCTRL_CTRL_SRCREQSEL_SET(ch_num)
47         | DMA_CHCTRL_CTRL_DSTREQSEL_SET(ch_num)
48         | ch->interrupt_mask;
49 
50     if (start_transfer) {
51         tmp |= DMA_CHCTRL_CTRL_ENABLE_MASK;
52     }
53     ptr->CHCTRL[ch_num].CTRL = tmp;
54 
55     return status_success;
56 }
57 
58 
dma_default_channel_config(DMA_Type * ptr,dma_channel_config_t * ch)59 void dma_default_channel_config(DMA_Type *ptr, dma_channel_config_t *ch)
60 {
61     ch->priority = 0;
62     ch->src_mode = DMA_HANDSHAKE_MODE_NORMAL;
63     ch->dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
64     ch->src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
65     ch->src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
66     ch->dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
67     ch->interrupt_mask = DMA_INTERRUPT_MASK_NONE;
68     ch->linked_ptr = 0;
69 #if DMA_SUPPORT_64BIT_ADDR
70     ch->linked_ptr_high = 0;
71 #endif
72 }
73 
dma_start_memcpy(DMA_Type * ptr,uint8_t ch_num,uint32_t dst,uint32_t src,uint32_t size,uint32_t burst_len_in_byte)74 hpm_stat_t dma_start_memcpy(DMA_Type *ptr, uint8_t ch_num,
75                                uint32_t dst, uint32_t src,
76                                uint32_t size, uint32_t burst_len_in_byte)
77 {
78     hpm_stat_t stat = status_success;
79     uint32_t width, count;
80     int32_t burst_size;
81     dma_channel_config_t config = {0};
82     dma_default_channel_config(ptr, &config);
83 
84     /* burst size checking (1-byte burst length will cause heavy overhead */
85     if (!burst_len_in_byte || burst_len_in_byte == 1 || burst_len_in_byte > size
86         || burst_len_in_byte >
87             ((1 << DMA_SOC_TRANSFER_WIDTH_MAX(ptr)) << DMA_SOC_TRANSFER_PER_BURST_MAX(ptr))) {
88         return status_invalid_argument;
89     }
90 
91     count = count_set_bits(burst_len_in_byte);
92     if ((count > 1) || (burst_len_in_byte & 0x1)) {
93         /* dma only supports 2^n bytes as burst size */
94         return status_invalid_argument;
95     }
96 
97     if ((size & (burst_len_in_byte - 1))) {
98         return status_dma_alignment_error;
99     }
100     burst_size = get_first_set_bit_from_lsb(burst_len_in_byte);
101 
102     config.src_width = DMA_TRANSFER_WIDTH_HALF_WORD;
103     config.dst_width = DMA_TRANSFER_WIDTH_HALF_WORD;
104     for (width = DMA_SOC_TRANSFER_WIDTH_MAX(ptr); width > DMA_TRANSFER_WIDTH_HALF_WORD; width--) {
105         if (!(burst_len_in_byte & ((1 << width) - 1))
106             && !(dst & ((1 << width) - 1))
107             && !(src & ((1 << width) - 1))
108             && !(size & ((1 << width) - 1))) {
109             config.src_width = width;
110             config.dst_width = width;
111             break;
112         }
113     }
114 
115     burst_size -= config.src_width;
116     do {
117         if (!(src & (((1 << config.src_width) << burst_size) - 1))) {
118             break;
119         }
120         burst_size--;
121     } while (burst_size > 0);
122 
123     config.src_addr = src;
124     config.dst_addr = dst;
125     config.size_in_byte = size;
126 
127     config.src_burst_size = burst_size;
128     stat = dma_setup_channel(ptr, ch_num, &config, true);
129     if (stat != status_success) {
130         return stat;
131     }
132 
133     return stat;
134 }
135 
dma_setup_handshake(DMA_Type * ptr,dma_handshake_config_t * pconfig,bool start_transfer)136 hpm_stat_t dma_setup_handshake(DMA_Type *ptr,  dma_handshake_config_t *pconfig, bool start_transfer)
137 {
138     hpm_stat_t stat = status_success;
139     dma_channel_config_t config = {0};
140     dma_default_channel_config(ptr, &config);
141 
142     if (true == pconfig->dst_fixed) {
143         config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
144         config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
145     }
146     if (true == pconfig->src_fixed) {
147         config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
148         config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
149     }
150 
151     if (pconfig->ch_index > DMA_SOC_CHANNEL_NUM) {
152         return status_invalid_argument;
153     }
154 
155     /*  In DMA handshake case, source width and destination width must be BYTE. */
156     config.src_width = DMA_TRANSFER_WIDTH_BYTE;
157     config.dst_width = DMA_TRANSFER_WIDTH_BYTE;
158     config.src_addr = pconfig->src;
159     config.dst_addr = pconfig->dst;
160     config.size_in_byte = pconfig->size_in_byte;
161     /*  In DMA handshake case, source burst size must be 1 transfer, that is 0. */
162     config.src_burst_size = 0;
163     stat = dma_setup_channel(ptr, pconfig->ch_index, &config, start_transfer);
164     if (stat != status_success) {
165         return stat;
166     }
167     return stat;
168 }
169