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