1 /*******************************************************************************
2 * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * PoalrFire SoC Microprocessor Subsystem PDMA bare metal driver implementation.
7 */
8
9 #include "mpfs_hal/mss_hal.h"
10 #include "mss_pdma.h"
11
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15
16 /* MACRO to set the correct channel memory offset for the memory mapped
17 * configuration register.
18 */
19 #define MSS_PDMA_REG_OFFSET(x) \
20 (uint64_t)(PDMA_REG_BASE + (PDMA_CHL_REG_OFFSET * (x)))
21
22 /* Default is maximum transaction size for both write_size and read_size. */
23 uint8_t g_channel_nextcfg_wsize[MSS_PDMA_lAST_CHANNEL] =
24 { 0x0Fu, 0x0Fu, 0x0Fu, 0x0Fu };
25 uint8_t g_channel_nextcfg_rsize[MSS_PDMA_lAST_CHANNEL] =
26 { 0x0Fu, 0x0Fu, 0x0Fu, 0x0Fu };
27 /*-------------------------------------------------------------------------*//**
28 * MSS_PDMA_init()
29 * See pse_pdma.h for description of this function.
30 */
31 void
MSS_PDMA_init(void)32 MSS_PDMA_init
33 (
34 void
35 )
36 {
37 ;
38 }
39
40 /*-------------------------------------------------------------------------*//**
41 * MSS_PDMA_setup_transfer()
42 * See pse_pdma.h for description of this function.
43 */
44 mss_pdma_error_id_t
MSS_PDMA_setup_transfer(mss_pdma_channel_id_t channel_id,mss_pdma_channel_config_t * channel_config)45 MSS_PDMA_setup_transfer
46 (
47 mss_pdma_channel_id_t channel_id,
48 mss_pdma_channel_config_t *channel_config
49 )
50 {
51 if (channel_id > MSS_PDMA_CHANNEL_3)
52 {
53 return MSS_PDMA_ERROR_INVALID_CHANNEL_ID;
54 }
55
56 /* Set the register structure pointer for the PDMA channel. */
57 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
58
59 /* Basic House Keeping, return if errors exist. */
60 if (channel_config->src_addr == 0u)
61 {
62 return MSS_PDMA_ERROR_INVALID_SRC_ADDR;
63 }
64
65 if (channel_config->dest_addr == 0u)
66 {
67 return MSS_PDMA_ERROR_INVALID_DEST_ADDR;
68 }
69
70 /* If a run transaction is in progress, return error.
71 * Channel can only be claimed when run is low */
72 if (pdmareg->control_reg & MASK_PDMA_CONTROL_RUN)
73 {
74 return MSS_PDMA_ERROR_TRANSACTION_IN_PROGRESS;
75 }
76
77 /* Set or clear the interrupts for the transfer. */
78 if (channel_config->enable_done_int)
79 {
80 pdmareg->control_reg |= ((uint32_t)MASK_PDMA_ENABLE_DONE_INT);
81 }
82 else
83 {
84 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT);
85 }
86
87 if (channel_config->enable_err_int)
88 {
89 pdmareg->control_reg |= ((uint32_t)MASK_PDMA_ENABLE_ERR_INT);
90 }
91 else
92 {
93 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT);
94 }
95
96 /* clear Next registers. */
97 pdmareg->control_reg |= (uint32_t)MASK_CLAIM_PDMA_CHANNEL;
98
99 /* Setup the source and destination addresses.*/
100 pdmareg->next_destination = channel_config->dest_addr;
101 pdmareg->next_source = channel_config->src_addr;
102
103 /* Set the transfer size. */
104 pdmareg->next_bytes = channel_config->num_bytes;
105
106 /* Setup repeat and force order requirements. */
107 if (channel_config->repeat)
108 {
109 pdmareg->next_config |= MASK_REPEAT_TRANSCTION;
110 }
111 else
112 {
113 pdmareg->next_config &= ~((uint32_t)MASK_REPEAT_TRANSCTION);
114 }
115
116 if (channel_config->force_order)
117 {
118 pdmareg->next_config |= ((uint32_t)MASK_FORCE_ORDERING);
119 }
120 else
121 {
122 pdmareg->next_config &= ~((uint32_t)MASK_FORCE_ORDERING);
123 }
124
125 /* PDMA transaction size.. set to maximum. */
126 pdmareg->next_config |=
127 (g_channel_nextcfg_wsize[channel_id] << SHIFT_CH_CONFIG_WSIZE);
128 pdmareg->next_config |=
129 (g_channel_nextcfg_rsize[channel_id] << SHIFT_CH_CONFIG_RSIZE);
130
131 return MSS_PDMA_OK;
132 }
133
134 /***************************************************************************//**
135 * See pse_pdma.h for description of this function.
136 */
137 mss_pdma_error_id_t
MSS_PDMA_set_transction_size(mss_pdma_channel_id_t channel_id,uint8_t write_size,uint8_t read_size)138 MSS_PDMA_set_transction_size
139 (
140 mss_pdma_channel_id_t channel_id,
141 uint8_t write_size,
142 uint8_t read_size
143 )
144 {
145 uint8_t value;
146
147 if (channel_id > MSS_PDMA_CHANNEL_3)
148 {
149 return MSS_PDMA_ERROR_INVALID_CHANNEL_ID;
150 }
151
152 if (write_size > 0x0Fu)
153 {
154 return MSS_PDMA_ERROR_INVALID_NEXTCFG_WSIZE;
155 }
156
157 if (read_size > 0x0Fu)
158 {
159 return MSS_PDMA_ERROR_INVALID_NEXTCFG_RSIZE;
160 }
161
162 g_channel_nextcfg_wsize[channel_id] = write_size;
163 g_channel_nextcfg_rsize[channel_id] = read_size;
164
165 return MSS_PDMA_OK;
166 }
167
168 /***************************************************************************//**
169 * See pse_pdma.h for description of this function.
170 */
171 mss_pdma_error_id_t
MSS_PDMA_start_transfer(mss_pdma_channel_id_t channel_id)172 MSS_PDMA_start_transfer
173 (
174 mss_pdma_channel_id_t channel_id
175 )
176 {
177 if (channel_id > MSS_PDMA_CHANNEL_3)
178 {
179 return MSS_PDMA_ERROR_INVALID_CHANNEL_ID;
180 }
181
182 /* Set the register structure pointer for the PDMA channel. */
183 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
184
185 /* If a run transaction is in progress, return error.
186 * Channel can only be claimed when run is low */
187 pdmareg->control_reg |= ((uint32_t)MASK_PDMA_CONTROL_RUN);
188
189 return MSS_PDMA_OK;
190 }
191
192 /***************************************************************************//**
193 * See pse_pdma.h for description of this function.
194 */
195 uint32_t
MSS_PDMA_get_active_transfer_type(mss_pdma_channel_id_t channel_id)196 MSS_PDMA_get_active_transfer_type
197 (
198 mss_pdma_channel_id_t channel_id
199 )
200 {
201 if (channel_id > MSS_PDMA_CHANNEL_3)
202 {
203 return 0u;
204 }
205
206 /* Set the register structure pointer for the PDMA channel. */
207 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
208
209 return pdmareg->exec_config;
210 }
211
212 /***************************************************************************//**
213 * See pse_pdma.h for description of this function.
214 */
215 uint64_t
MSS_PDMA_get_number_bytes_remaining(mss_pdma_channel_id_t channel_id)216 MSS_PDMA_get_number_bytes_remaining
217 (
218 mss_pdma_channel_id_t channel_id
219 )
220 {
221 if (channel_id > MSS_PDMA_CHANNEL_3)
222 {
223 return 0u;
224 }
225
226 /* Set the register structure pointer for the PDMA channel. */
227 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
228
229 return pdmareg->exec_bytes;
230 }
231
232 /***************************************************************************//**
233 * See pse_pdma.h for description of this function.
234 */
235 uint64_t
MSS_PDMA_get_destination_current_addr(mss_pdma_channel_id_t channel_id)236 MSS_PDMA_get_destination_current_addr
237 (
238 mss_pdma_channel_id_t channel_id
239 )
240 {
241 if (channel_id > MSS_PDMA_CHANNEL_3)
242 {
243 return 0u;
244 }
245
246 /* Set the register structure pointer for the PDMA channel. */
247 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
248
249 return pdmareg->exec_destination;
250 }
251
252 /***************************************************************************//**
253 * See pse_pdma.h for description of this function.
254 */
255 uint64_t
MSS_PDMA_get_source_current_addr(mss_pdma_channel_id_t channel_id)256 MSS_PDMA_get_source_current_addr
257 (
258 mss_pdma_channel_id_t channel_id
259 )
260 {
261 if (channel_id > MSS_PDMA_CHANNEL_3)
262 {
263 return 0u;
264 }
265
266 /* Set the register structure pointer for the PDMA channel. */
267 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
268
269 return pdmareg->exec_source;
270 }
271
272 /***************************************************************************//**
273 * See pse_pdma.h for description of this function.
274 */
275 uint8_t
MSS_PDMA_get_transfer_complete_status(mss_pdma_channel_id_t channel_id)276 MSS_PDMA_get_transfer_complete_status
277 (
278 mss_pdma_channel_id_t channel_id
279 )
280 {
281 if (channel_id > MSS_PDMA_CHANNEL_3)
282 {
283 return 0u;
284 }
285
286 /* Set the register structure pointer for the PDMA channel. */
287 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
288
289 if (pdmareg->control_reg & MASK_PDMA_TRANSFER_DONE)
290 {
291 return 1u;
292 }
293 else
294 {
295 return 0u;
296 }
297 }
298
299 /***************************************************************************//**
300 * See pse_pdma.h for description of this function.
301 */
302 uint8_t
MSS_PDMA_get_transfer_error_status(mss_pdma_channel_id_t channel_id)303 MSS_PDMA_get_transfer_error_status
304 (
305 mss_pdma_channel_id_t channel_id
306 )
307 {
308 if (channel_id > MSS_PDMA_CHANNEL_3)
309 {
310 return 0u;
311 }
312
313 /* Set the register structure pointer for the PDMA channel. */
314 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
315
316 if (pdmareg->control_reg & MASK_PDMA_TRANSFER_ERROR)
317 {
318 return 1u;
319 }
320 else
321 {
322 return 0u;
323 }
324 }
325
326 /***************************************************************************//**
327 * See pse_pdma.h for description of this function.
328 */
329 uint8_t
MSS_PDMA_clear_transfer_complete_status(mss_pdma_channel_id_t channel_id)330 MSS_PDMA_clear_transfer_complete_status
331 (
332 mss_pdma_channel_id_t channel_id
333 )
334 {
335 uint8_t intStatus = 0u;
336
337 if (channel_id > MSS_PDMA_CHANNEL_3)
338 {
339 return 0u;
340 }
341
342 /* Set the register structure pointer for the PDMA channel. */
343 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
344
345 if (pdmareg->control_reg & MASK_PDMA_TRANSFER_DONE)
346 {
347 intStatus = 1u;
348 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_TRANSFER_DONE);
349 }
350
351 return intStatus;
352 }
353
354 /***************************************************************************//**
355 * See pse_pdma.h for description of this function.
356 */
357 uint8_t
MSS_PDMA_clear_transfer_error_status(mss_pdma_channel_id_t channel_id)358 MSS_PDMA_clear_transfer_error_status
359 (
360 mss_pdma_channel_id_t channel_id
361 )
362 {
363 uint8_t intStatus = 0u;
364
365 if (channel_id > MSS_PDMA_CHANNEL_3)
366 {
367 return 0u;
368 }
369
370 /* Set the register structure pointer for the PDMA channel. */
371 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET(channel_id);
372
373 if (pdmareg->control_reg & MASK_PDMA_TRANSFER_ERROR)
374 {
375 intStatus = 1u;
376 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_TRANSFER_ERROR);
377 }
378
379 return intStatus;
380 }
381
382 /***************************************************************************//**
383 * Each DMA channel has two interrupts, one for transfer complete
384 * and the other for the transfer error.
385 */
386 uint8_t
dma_ch0_DONE_IRQHandler(void)387 dma_ch0_DONE_IRQHandler
388 (
389 void
390 )
391 {
392 /* Clear the interrupt enable bit. */
393 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
394 (MSS_PDMA_CHANNEL_0);
395
396 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT);
397
398 return 0u;
399 }
400
401 uint8_t
dma_ch0_ERR_IRQHandler(void)402 dma_ch0_ERR_IRQHandler
403 (
404 void
405 )
406 {
407 /* Clear the interrupt enable bit. */
408 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
409 (MSS_PDMA_CHANNEL_0);
410
411 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT);
412
413 return 0u;
414 }
415
416 uint8_t
dma_ch1_DONE_IRQHandler(void)417 dma_ch1_DONE_IRQHandler
418 (
419 void
420 )
421 {
422 /* Clear the interrupt enable bit. */
423 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
424 (MSS_PDMA_CHANNEL_1);
425
426 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT);
427
428 return 0u;
429 }
430
431 uint8_t
dma_ch1_ERR_IRQHandler(void)432 dma_ch1_ERR_IRQHandler
433 (
434 void
435 )
436 {
437 /* Clear the interrupt enable bit. */
438 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
439 (MSS_PDMA_CHANNEL_1);
440
441 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT);
442
443 return 0u;
444 }
445
446
447 uint8_t
dma_ch2_DONE_IRQHandler(void)448 dma_ch2_DONE_IRQHandler
449 (
450 void
451 )
452 {
453 /* Clear the interrupt enable bit. */
454 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
455 (MSS_PDMA_CHANNEL_2);
456
457 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT);
458
459 return 0u;
460 }
461
462 uint8_t
dma_ch2_ERR_IRQHandler(void)463 dma_ch2_ERR_IRQHandler
464 (
465 void
466 )
467 {
468 /* Clear the interrupt enable bit. */
469 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
470 (MSS_PDMA_CHANNEL_2);
471
472 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT);
473
474 return 0u;
475 }
476
477 uint8_t
dma_ch3_DONE_IRQHandler(void)478 dma_ch3_DONE_IRQHandler
479 (
480 void
481 )
482 {
483 /* Clear the interrupt enable bit. */
484 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
485 (MSS_PDMA_CHANNEL_3);
486
487 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_DONE_INT);
488
489 return 0u;
490 }
491
492 uint8_t
dma_ch3_ERR_IRQHandler(void)493 dma_ch3_ERR_IRQHandler
494 (
495 void
496 )
497 {
498 /* Clear the interrupt enable bit. */
499 volatile mss_pdma_t *pdmareg = (mss_pdma_t *)MSS_PDMA_REG_OFFSET
500 (MSS_PDMA_CHANNEL_3);
501
502 pdmareg->control_reg &= ~((uint32_t)MASK_PDMA_ENABLE_ERR_INT);
503
504 return 0u;
505 }
506
507 #ifdef __cplusplus
508 }
509 #endif