• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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