• 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,uint8_t ch_num,dma_channel_config_t * ch,bool start_transfer)10 hpm_stat_t dma_setup_channel(DMA_Type *ptr, uint8_t ch_num, dma_channel_config_t *ch, bool start_transfer)
11 {
12     uint32_t tmp;
13 
14     if ((ch->dst_width > DMA_SOC_TRANSFER_WIDTH_MAX(ptr))
15             || (ch->src_width > DMA_SOC_TRANSFER_WIDTH_MAX(ptr))
16             || (ch_num >= DMA_SOC_CHANNEL_NUM)) {
17         return status_invalid_argument;
18     }
19     if ((ch->size_in_byte & ((1 << ch->dst_width) - 1))
20      || (ch->src_addr & ((1 << ch->src_width) - 1))
21      || (ch->dst_addr & ((1 << ch->dst_width) - 1))
22      || ((1 << ch->src_width) & ((1 << ch->dst_width) - 1))
23      || ((ch->linked_ptr & 0x7))) {
24         return status_dma_alignment_error;
25     }
26     ptr->CHCTRL[ch_num].SRCADDR = DMA_CHCTRL_SRCADDR_SRCADDRL_SET(ch->src_addr);
27     ptr->CHCTRL[ch_num].DSTADDR = DMA_CHCTRL_DSTADDR_DSTADDRL_SET(ch->dst_addr);
28     ptr->CHCTRL[ch_num].TRANSIZE = DMA_CHCTRL_TRANSIZE_TRANSIZE_SET(ch->size_in_byte >> ch->src_width);
29     ptr->CHCTRL[ch_num].LLPOINTER = DMA_CHCTRL_LLPOINTER_LLPOINTERL_SET(ch->linked_ptr >> DMA_CHCTRL_LLPOINTER_LLPOINTERL_SHIFT);
30 
31 #if DMA_SUPPORT_64BIT_ADDR
32     ptr->CHCTRL[ch_num].SRCADDRH = DMA_CHCTRL_SRCADDRH_SRCADDRH_SET(ch->src_addr_high);
33     ptr->CHCTRL[ch_num].DSTADDRH = DMA_CHCTRL_DSTADDRH_DSTADDRH_SET(ch->dst_addr_high);
34     ptr->CHCTRL[ch_num].LLPOINTERH = DMA_CHCTRL_LLPOINTERH_LLPOINTERH_SET(ch->linked_ptr_high);
35 #endif
36 
37     ptr->INTSTATUS = (DMA_INTSTATUS_TC_SET(1) | DMA_INTSTATUS_ABORT_SET(1) | DMA_INTSTATUS_ERROR_SET(1)) << ch_num;
38     tmp = DMA_CHCTRL_CTRL_SRCBUSINFIDX_SET(0)
39         | DMA_CHCTRL_CTRL_DSTBUSINFIDX_SET(0)
40         | DMA_CHCTRL_CTRL_PRIORITY_SET(ch->priority)
41         | DMA_CHCTRL_CTRL_SRCBURSTSIZE_SET(ch->src_burst_size)
42         | DMA_CHCTRL_CTRL_SRCWIDTH_SET(ch->src_width)
43         | DMA_CHCTRL_CTRL_DSTWIDTH_SET(ch->dst_width)
44         | DMA_CHCTRL_CTRL_SRCMODE_SET(ch->src_mode)
45         | DMA_CHCTRL_CTRL_DSTMODE_SET(ch->dst_mode)
46         | DMA_CHCTRL_CTRL_SRCADDRCTRL_SET(ch->src_addr_ctrl)
47         | DMA_CHCTRL_CTRL_DSTADDRCTRL_SET(ch->dst_addr_ctrl)
48         | DMA_CHCTRL_CTRL_SRCREQSEL_SET(ch_num)
49         | DMA_CHCTRL_CTRL_DSTREQSEL_SET(ch_num)
50         | ch->interrupt_mask;
51 
52     if (start_transfer) {
53         tmp |= DMA_CHCTRL_CTRL_ENABLE_MASK;
54     }
55     ptr->CHCTRL[ch_num].CTRL = tmp;
56 
57     return status_success;
58 }
59 
60 
dma_default_channel_config(DMA_Type * ptr,dma_channel_config_t * ch)61 void dma_default_channel_config(DMA_Type *ptr, dma_channel_config_t *ch)
62 {
63     (void) ptr;
64     ch->priority = DMA_CHANNEL_PRIORITY_LOW;
65     ch->src_mode = DMA_HANDSHAKE_MODE_NORMAL;
66     ch->dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
67     ch->src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
68     ch->src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
69     ch->dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
70     ch->interrupt_mask = DMA_INTERRUPT_MASK_NONE;
71     ch->linked_ptr = 0;
72 #if DMA_SUPPORT_64BIT_ADDR
73     ch->linked_ptr_high = 0;
74 #endif
75 }
76 
dma_config_linked_descriptor(DMA_Type * ptr,dma_linked_descriptor_t * descriptor,uint8_t ch_num,dma_channel_config_t * config)77 hpm_stat_t dma_config_linked_descriptor(DMA_Type *ptr, dma_linked_descriptor_t *descriptor, uint8_t ch_num, dma_channel_config_t *config)
78 {
79     uint32_t tmp;
80 
81     if ((config->dst_width > DMA_SOC_TRANSFER_WIDTH_MAX(ptr))
82             || (config->src_width > DMA_SOC_TRANSFER_WIDTH_MAX(ptr))
83             || (ch_num >= DMA_SOC_CHANNEL_NUM)) {
84         return status_invalid_argument;
85     }
86     if ((config->size_in_byte & ((1 << config->dst_width) - 1))
87      || (config->src_addr & ((1 << config->src_width) - 1))
88      || (config->dst_addr & ((1 << config->dst_width) - 1))
89      || ((1 << config->src_width) & ((1 << config->dst_width) - 1))
90      || ((config->linked_ptr & 0x7))) {
91         return status_dma_alignment_error;
92     }
93     descriptor->src_addr = DMA_CHCTRL_SRCADDR_SRCADDRL_SET(config->src_addr);
94     descriptor->dst_addr = DMA_CHCTRL_DSTADDR_DSTADDRL_SET(config->dst_addr);
95     descriptor->trans_size = DMA_CHCTRL_TRANSIZE_TRANSIZE_SET(config->size_in_byte >> config->src_width);
96     descriptor->linked_ptr = DMA_CHCTRL_LLPOINTER_LLPOINTERL_SET(config->linked_ptr >> DMA_CHCTRL_LLPOINTER_LLPOINTERL_SHIFT);
97 
98 #if DMA_SUPPORT_64BIT_ADDR
99     descriptor->src_addr_high = DMA_CHCTRL_SRCADDRH_SRCADDRH_SET(config->src_addr_high);
100     descriptor->dst_addr_high = DMA_CHCTRL_DSTADDRH_DSTADDRH_SET(config->dst_addr_high);
101     descriptor->linked_ptr_high = DMA_CHCTRL_LLPOINTERH_LLPOINTERH_SET(config->linked_ptr_high);
102 #endif
103 
104     tmp = DMA_CHCTRL_CTRL_SRCBUSINFIDX_SET(0)
105         | DMA_CHCTRL_CTRL_DSTBUSINFIDX_SET(0)
106         | DMA_CHCTRL_CTRL_PRIORITY_SET(config->priority)
107         | DMA_CHCTRL_CTRL_SRCBURSTSIZE_SET(config->src_burst_size)
108         | DMA_CHCTRL_CTRL_SRCWIDTH_SET(config->src_width)
109         | DMA_CHCTRL_CTRL_DSTWIDTH_SET(config->dst_width)
110         | DMA_CHCTRL_CTRL_SRCMODE_SET(config->src_mode)
111         | DMA_CHCTRL_CTRL_DSTMODE_SET(config->dst_mode)
112         | DMA_CHCTRL_CTRL_SRCADDRCTRL_SET(config->src_addr_ctrl)
113         | DMA_CHCTRL_CTRL_DSTADDRCTRL_SET(config->dst_addr_ctrl)
114         | DMA_CHCTRL_CTRL_SRCREQSEL_SET(ch_num)
115         | DMA_CHCTRL_CTRL_DSTREQSEL_SET(ch_num)
116         | config->interrupt_mask
117         | DMA_CHCTRL_CTRL_ENABLE_MASK;
118     descriptor->ctrl = tmp;
119 
120     return status_success;
121 }
122 
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)123 hpm_stat_t dma_start_memcpy(DMA_Type *ptr, uint8_t ch_num,
124                                uint32_t dst, uint32_t src,
125                                uint32_t size, uint32_t burst_len_in_byte)
126 {
127     hpm_stat_t stat = status_success;
128     uint32_t width, count;
129     int32_t burst_size;
130     dma_channel_config_t config = {0};
131     dma_default_channel_config(ptr, &config);
132 
133     /* burst size checking (1-byte burst length will cause heavy overhead */
134     if (!burst_len_in_byte || burst_len_in_byte == 1 || burst_len_in_byte > size
135         || burst_len_in_byte >
136             (uint32_t) ((1 << DMA_SOC_TRANSFER_WIDTH_MAX(ptr)) << DMA_SOC_TRANSFER_PER_BURST_MAX(ptr))) {
137         return status_invalid_argument;
138     }
139 
140     count = count_set_bits(burst_len_in_byte);
141     if ((count > 1) || (burst_len_in_byte & 0x1)) {
142         /* dma only supports 2^n bytes as burst size */
143         return status_invalid_argument;
144     }
145 
146     if ((size & (burst_len_in_byte - 1))) {
147         return status_dma_alignment_error;
148     }
149     burst_size = get_first_set_bit_from_lsb(burst_len_in_byte);
150 
151     config.src_width = DMA_TRANSFER_WIDTH_HALF_WORD;
152     config.dst_width = DMA_TRANSFER_WIDTH_HALF_WORD;
153     for (width = DMA_SOC_TRANSFER_WIDTH_MAX(ptr); width > DMA_TRANSFER_WIDTH_HALF_WORD; width--) {
154         if (!(burst_len_in_byte & ((1 << width) - 1))
155             && !(dst & ((1 << width) - 1))
156             && !(src & ((1 << width) - 1))
157             && !(size & ((1 << width) - 1))) {
158             config.src_width = width;
159             config.dst_width = width;
160             break;
161         }
162     }
163 
164     burst_size -= config.src_width;
165     do {
166         if (!(src & (((1 << config.src_width) << burst_size) - 1))) {
167             break;
168         }
169         burst_size--;
170     } while (burst_size > 0);
171 
172     config.src_addr = src;
173     config.dst_addr = dst;
174     config.size_in_byte = size;
175 
176     config.src_burst_size = burst_size;
177     stat = dma_setup_channel(ptr, ch_num, &config, true);
178     if (stat != status_success) {
179         return stat;
180     }
181 
182     return stat;
183 }
184 
dma_default_handshake_config(DMA_Type * ptr,dma_handshake_config_t * config)185 void dma_default_handshake_config(DMA_Type *ptr, dma_handshake_config_t *config)
186 {
187     (void) ptr;
188     memset(config, 0, sizeof(dma_handshake_config_t));
189 }
190 
dma_setup_handshake(DMA_Type * ptr,dma_handshake_config_t * pconfig,bool start_transfer)191 hpm_stat_t dma_setup_handshake(DMA_Type *ptr,  dma_handshake_config_t *pconfig, bool start_transfer)
192 {
193     hpm_stat_t stat = status_success;
194     dma_channel_config_t config = {0};
195     dma_default_channel_config(ptr, &config);
196 
197     if (true == pconfig->dst_fixed) {
198         config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
199         config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
200     }
201     if (true == pconfig->src_fixed) {
202         config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
203         config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
204     }
205 
206     if (pconfig->ch_index >= DMA_SOC_CHANNEL_NUM) {
207         return status_invalid_argument;
208     }
209 
210     config.src_width = pconfig->data_width;
211     config.dst_width = pconfig->data_width;
212     config.src_addr = pconfig->src;
213     config.dst_addr = pconfig->dst;
214     config.size_in_byte = pconfig->size_in_byte;
215     /*  In DMA handshake case, source burst size must be 1 transfer, that is 0. */
216     config.src_burst_size = 0;
217     stat = dma_setup_channel(ptr, pconfig->ch_index, &config, start_transfer);
218     if (stat != status_success) {
219         return stat;
220     }
221     return stat;
222 }
223