1 /*
2 * Copyright (c) 2022 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <string.h>
9 #include "hpm_dma_manager.h"
10 #include "hpm_soc.h"
11 #include <stdio.h>
12
13 /*****************************************************************************************************************
14 *
15 * Definitions
16 *
17 *****************************************************************************************************************/
18
19 typedef struct _dma_instance_info {
20 DMA_Type *base;
21 int32_t irq_num;
22 } dma_channel_info_t;
23
24 /**
25 * @brief DMA Manager Context Structure
26 *
27 */
28 typedef struct _dma_manager_context {
29 dma_channel_info_t dma_instance[DMA_SOC_MAX_COUNT]; /**< DMA instances */
30 hpm_dma_channel_context_t channels[DMA_SOC_MAX_COUNT][DMA_SOC_CHANNEL_NUM]; /**< Array of DMA channels */
31 } hpm_dma_manager_context_t;
32
33 #define DMA_DISABLE_ALL_CHN_INT (DMA_INTERRUPT_MASK_ERROR | DMA_INTERRUPT_MASK_ABORT | DMA_INTERRUPT_MASK_TERMINAL_COUNT)
34
35
36 /*****************************************************************************************************************
37 *
38 * Prototypes
39 *
40 *****************************************************************************************************************/
41
42 /**
43 * @brief Search DMA channel context for specified DMA channel resource
44 *
45 * @param [in] resource DMA Channel resource
46 * @return The request DMA channel context if resource is valid or NULL if resource in invalid
47 */
48 static hpm_dma_channel_context_t *dma_manager_search_channel_context(const hpm_dma_resource_t *resource);
49
50 static uint32_t dma_manager_enter_critical(void);
51 static void dma_manager_exit_critical(uint32_t level);
52
53 static void dma0_isr(void);
54 SDK_DECLARE_EXT_ISR_M(IRQn_HDMA, dma0_isr);
55
56 #if defined(DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT > 1)
57 static void dma1_isr(void);
58 SDK_DECLARE_EXT_ISR_M(IRQn_XDMA, dma1_isr);
59 #endif
60
61 /*****************************************************************************************************************
62 *
63 * Variables
64 *
65 *****************************************************************************************************************/
66 static hpm_dma_manager_context_t s_dma_mngr_ctx;
67 #define HPM_DMA_MGR (&s_dma_mngr_ctx)
68
69
70
71 /*****************************************************************************************************************
72 *
73 * Codes
74 *
75 *****************************************************************************************************************/
handle_dma_isr(DMA_Type * ptr,uint32_t instance)76 static inline void handle_dma_isr(DMA_Type *ptr, uint32_t instance)
77 {
78 for (uint8_t channel = 0; channel < DMA_SOC_CHANNEL_NUM; channel++) {
79 uint32_t int_disable_mask = dma_check_channel_interrupt_mask(ptr, channel);
80 /* If Channel interrupt is enabled */
81 if (int_disable_mask != DMA_DISABLE_ALL_CHN_INT) {
82 uint32_t chn_int_stat = dma_check_transfer_status(ptr, channel);
83 if (chn_int_stat != DMA_CHANNEL_STATUS_ONGOING) {
84 hpm_dma_channel_context_t *chn_ctx = &HPM_DMA_MGR->channels[instance][channel];
85 if (chn_ctx->callback != NULL) {
86 chn_ctx->callback(ptr, channel, chn_ctx->user_data, chn_int_stat);
87 }
88 } /* end if (chn_int_stat != DMA_CHANNEL_STATUS_ONGOING) */
89 } /* end if (int_disable_mask != DMA_DISABLE_ALL_CHN_INT) */
90 } /* end for (uint8_t channel = 0; channel < DMA_SOC_MAX_COUNT; channel++) */
91 }
92
dma0_isr(void)93 void dma0_isr(void)
94 {
95 handle_dma_isr(HPM_HDMA, 0);
96 }
97
98 #if defined(DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT > 1)
dma1_isr(void)99 void dma1_isr(void)
100 {
101 handle_dma_isr(HPM_XDMA, 1);
102 }
103 #endif
104
dma_manager_enter_critical(void)105 static uint32_t dma_manager_enter_critical(void)
106 {
107 uint32_t level = read_csr(CSR_MSTATUS);
108 disable_global_irq(CSR_MSTATUS_MIE_MASK);
109 return level;
110 }
111
dma_manager_exit_critical(uint32_t level)112 static void dma_manager_exit_critical(uint32_t level)
113 {
114 write_csr(CSR_MSTATUS, level);
115 }
116
117 /* See hpm_dma_manager.h for more details */
dma_manager_init(void)118 void dma_manager_init(void)
119 {
120 (void) memset(HPM_DMA_MGR, 0, sizeof(*HPM_DMA_MGR));
121 HPM_DMA_MGR->dma_instance[0].base = HPM_HDMA,
122 HPM_DMA_MGR->dma_instance[0].irq_num = IRQn_HDMA;
123 #if defined(DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT > 1)
124 HPM_DMA_MGR->dma_instance[1].base = HPM_XDMA;
125 HPM_DMA_MGR->dma_instance[1].irq_num = IRQn_XDMA;
126 #endif
127 }
128
129 /* See hpm_dma_manager.h for more details */
dma_manager_request_resource(hpm_dma_resource_t * resource)130 hpm_stat_t dma_manager_request_resource(hpm_dma_resource_t *resource)
131 {
132 hpm_stat_t status;
133
134 if (resource == NULL) {
135 status = status_invalid_argument;
136 } else {
137 uint32_t instance;
138 uint32_t channel;
139 bool has_found = false;
140 uint32_t level = dma_manager_enter_critical();
141 for (instance = 0; instance < DMA_SOC_MAX_COUNT; instance++) {
142 for (channel = 0; channel < DMA_SOC_CHANNEL_NUM; channel++) {
143 if (!HPM_DMA_MGR->channels[instance][channel].is_allocated) {
144 has_found = true;
145 break;
146 }
147 }
148 if (has_found) {
149 break;
150 }
151 }
152
153 if (has_found) {
154 HPM_DMA_MGR->channels[instance][channel].is_allocated = true;
155 resource->base = HPM_DMA_MGR->dma_instance[instance].base;
156 resource->channel = channel;
157 resource->irq_num = HPM_DMA_MGR->dma_instance[instance].irq_num;
158 status = status_success;
159 } else {
160 status = status_dma_manager_no_resource;
161 }
162
163 dma_manager_exit_critical(level);
164 }
165
166 return status;
167 }
168
dma_manager_search_channel_context(const hpm_dma_resource_t * resource)169 static hpm_dma_channel_context_t *dma_manager_search_channel_context(const hpm_dma_resource_t *resource)
170 {
171 hpm_dma_channel_context_t *channel_ctx = NULL;
172
173 if ((resource != NULL) && (resource->channel < DMA_SOC_CHANNEL_NUM)) {
174 uint32_t instance;
175 uint32_t channel;
176 bool has_found = false;
177 for (instance = 0; instance < DMA_SOC_MAX_COUNT; instance++) {
178 if (resource->base == HPM_DMA_MGR->dma_instance[instance].base) {
179 has_found = true;
180 break;
181 }
182 }
183
184 channel = resource->channel;
185 if (has_found) {
186 channel_ctx = &HPM_DMA_MGR->channels[instance][channel];
187 }
188 }
189
190 return channel_ctx;
191 }
192
193 /* See hpm_dma_manager.h for more details */
dma_manager_release_resource(const hpm_dma_resource_t * resource)194 hpm_stat_t dma_manager_release_resource(const hpm_dma_resource_t *resource)
195 {
196 hpm_stat_t status;
197
198 hpm_dma_channel_context_t *channel_ctx = dma_manager_search_channel_context(resource);
199
200 if (channel_ctx == NULL) {
201 status = status_invalid_argument;
202 } else {
203
204 uint32_t level = dma_manager_enter_critical();
205 channel_ctx->is_allocated = false;
206 channel_ctx->user_data = NULL;
207 channel_ctx->callback = NULL;
208 status = status_success;
209 dma_manager_exit_critical(level);
210 }
211 return status;
212 }
213
214 /* See hpm_dma_manager.h for more details */
dma_manager_enable_channel_interrupt(const hpm_dma_resource_t * resource,uint32_t irq_mask)215 hpm_stat_t dma_manager_enable_channel_interrupt(const hpm_dma_resource_t *resource, uint32_t irq_mask)
216 {
217 hpm_stat_t status;
218
219 hpm_dma_channel_context_t *channel_ctx = dma_manager_search_channel_context(resource);
220
221 if (channel_ctx == NULL) {
222 status = status_invalid_argument;
223 } else {
224 dma_enable_channel_interrupt(resource->base, resource->channel, irq_mask);
225 status = status_success;
226 }
227 return status;
228 }
229
230 /* See hpm_dma_manager.h for more details */
dma_manager_disable_channel_interrupt(const hpm_dma_resource_t * resource,uint32_t irq_mask)231 hpm_stat_t dma_manager_disable_channel_interrupt(const hpm_dma_resource_t *resource, uint32_t irq_mask)
232 {
233 hpm_stat_t status;
234
235 hpm_dma_channel_context_t *channel_ctx = dma_manager_search_channel_context(resource);
236
237 if (channel_ctx == NULL) {
238 status = status_invalid_argument;
239 } else {
240 dma_disable_channel_interrupt(resource->base, resource->channel, irq_mask);
241 status = status_success;
242 }
243 return status;
244 }
245
246
247 /* See hpm_dma_manager.h for more details */
dma_manager_enable_dma_interrupt(const hpm_dma_resource_t * resource,uint32_t priority)248 hpm_stat_t dma_manager_enable_dma_interrupt(const hpm_dma_resource_t *resource, uint32_t priority)
249 {
250 hpm_stat_t status;
251
252 hpm_dma_channel_context_t *channel_ctx = dma_manager_search_channel_context(resource);
253
254 if (channel_ctx == NULL) {
255 status = status_invalid_argument;
256 } else {
257 intc_m_enable_irq_with_priority(resource->irq_num, priority);
258 status = status_success;
259 }
260 return status;
261 }
262
263 /* See hpm_dma_manager.h for more details */
dma_manager_disable_dma_interrupt(const hpm_dma_resource_t * resource)264 hpm_stat_t dma_manager_disable_dma_interrupt(const hpm_dma_resource_t *resource)
265 {
266 hpm_stat_t status;
267
268 hpm_dma_channel_context_t *channel_ctx = dma_manager_search_channel_context(resource);
269
270 if (channel_ctx == NULL) {
271 status = status_invalid_argument;
272 } else {
273 intc_m_disable_irq(resource->irq_num);
274 status = status_success;
275 }
276 return status;
277 }
278
279
280 /* See hpm_dma_manager.h for more details */
dma_manager_install_interrupt_callback(const hpm_dma_resource_t * resource,hpm_dma_channel_callback_t callback,void * user_data)281 hpm_stat_t dma_manager_install_interrupt_callback(const hpm_dma_resource_t *resource, hpm_dma_channel_callback_t callback, void *user_data)
282 {
283 hpm_stat_t status;
284
285 hpm_dma_channel_context_t *channel_ctx = dma_manager_search_channel_context(resource);
286
287 if (channel_ctx == NULL) {
288 status = status_invalid_argument;
289 } else {
290 channel_ctx->user_data = user_data;
291 channel_ctx->callback = callback;
292 status = status_success;
293 }
294 return status;
295 }
296