]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_A2F200_IAR_and_Keil/MicroSemi_Code/drivers/mss_pdma/mss_pdma.c
Create directory structure to hold the (not yet created) Keil and IAR demo projects...
[freertos] / Demo / CORTEX_A2F200_IAR_and_Keil / MicroSemi_Code / drivers / mss_pdma / mss_pdma.c
1 /*******************************************************************************\r
2  * (c) Copyright 2008 Actel Corporation.  All rights reserved.\r
3  * \r
4  * SmartFusion microcontroller subsystem Peripheral DMA bare metal software\r
5  * driver implementation.\r
6  *\r
7  * SVN $Revision: 2110 $\r
8  * SVN $Date: 2010-02-05 15:24:19 +0000 (Fri, 05 Feb 2010) $\r
9  */\r
10 #include "mss_pdma.h"\r
11 #include "../../CMSIS/mss_assert.h"\r
12 \r
13 #ifdef __cplusplus\r
14 extern "C" {\r
15 #endif \r
16 \r
17 #if defined(__GNUC__)\r
18 __attribute__((__interrupt__)) void DMA_IRQHandler( void );\r
19 #else\r
20 void DMA_IRQHandler( void );\r
21 #endif\r
22 \r
23 /***************************************************************************//**\r
24   Offset of the posted writes WRITE_ADJ bits in a PDMA channel's configuration\r
25   register.\r
26  */\r
27 #define CHANNEL_N_POSTED_WRITE_ADJUST_SHIFT   14\r
28 \r
29 /*-------------------------------------------------------------------------*//**\r
30  * Look-up table use to derice a channel's control register value from the\r
31  * requested source/destination. This table is incexed on the pdma_src_dest_t\r
32  * enumeration.\r
33  */\r
34 #define CHANNEL_N_CTRL_PDMA_MASK        (uint32_t)0x00000001\r
35 #define CHANNEL_N_PERIPH_SELECT_SHIFT   (uint32_t)23\r
36 #define CHANNEL_N_DIRECTION_MASK        (uint32_t)0x00000002\r
37 \r
38 const uint32_t src_dest_to_ctrl_reg_lut[] =\r
39 {\r
40     CHANNEL_N_CTRL_PDMA_MASK,                                                                               /* PDMA_FROM_UART_0 */\r
41     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)1 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK,  /* PDMA_TO_UART_0 */\r
42     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)2 << CHANNEL_N_PERIPH_SELECT_SHIFT),                             /* PDMA_FROM_UART_1 */\r
43     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)3 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK,  /* PDMA_TO_UART_1 */\r
44     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)4 << CHANNEL_N_PERIPH_SELECT_SHIFT),                             /* PDMA_FROM_SPI_0 */\r
45     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)5 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK,  /* PDMA_TO_SPI_0 */\r
46     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)6 << CHANNEL_N_PERIPH_SELECT_SHIFT),                             /* PDMA_FROM_SPI_1 */\r
47     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)7 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK,  /* PDMA_TO_SPI_1 */\r
48     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)8 << CHANNEL_N_PERIPH_SELECT_SHIFT),                             /* PDMA_FROM_FPGA_1 */\r
49     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)8 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK,  /* PDMA_TO_FPGA_1 */\r
50     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)9 << CHANNEL_N_PERIPH_SELECT_SHIFT),                             /* PDMA_FROM_FPGA_0 */\r
51     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)9 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK,  /* PDMA_TO_FPGA_0 */\r
52     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)10 << CHANNEL_N_PERIPH_SELECT_SHIFT) | CHANNEL_N_DIRECTION_MASK, /* PDMA_TO_ACE */\r
53     CHANNEL_N_CTRL_PDMA_MASK | ( (uint32_t)11 << CHANNEL_N_PERIPH_SELECT_SHIFT)                             /* PDMA_FROM_ACE */\r
54 };\r
55 \r
56 /*-------------------------------------------------------------------------*//**\r
57  *\r
58  */\r
59 #define PDMA_MASTER_ENABLE  (uint32_t)0x04\r
60 #define PDMA_SOFT_RESET     (uint32_t)0x20\r
61 \r
62 /*-------------------------------------------------------------------------*//**\r
63  *\r
64  */\r
65 #define NB_OF_PDMA_CHANNELS     8\r
66 \r
67 #define NEXT_CHANNEL_A      0U\r
68 #define NEXT_CHANNEL_B      1U\r
69 \r
70 #define CHANNEL_STOPPED     0U\r
71 #define CHANNEL_STARTED     1U\r
72 \r
73 static uint8_t g_pdma_next_channel[NB_OF_PDMA_CHANNELS];\r
74 static uint8_t g_pdma_started_a[NB_OF_PDMA_CHANNELS];\r
75 static uint8_t g_pdma_started_b[NB_OF_PDMA_CHANNELS];\r
76 static pdma_channel_isr_t g_pdma_isr_table[NB_OF_PDMA_CHANNELS];\r
77 static const uint16_t g_pdma_status_mask[NB_OF_PDMA_CHANNELS] =\r
78 {\r
79     (uint16_t)0x0003, /* PDMA_CHANNEL_0 */\r
80     (uint16_t)0x000C, /* PDMA_CHANNEL_1 */\r
81     (uint16_t)0x0030, /* PDMA_CHANNEL_2 */\r
82     (uint16_t)0x00C0, /* PDMA_CHANNEL_3 */\r
83     (uint16_t)0x0300, /* PDMA_CHANNEL_4 */\r
84     (uint16_t)0x0C00, /* PDMA_CHANNEL_5 */\r
85     (uint16_t)0x3000, /* PDMA_CHANNEL_6 */\r
86     (uint16_t)0xC000, /* PDMA_CHANNEL_7 */\r
87 };\r
88 \r
89 \r
90 \r
91 /***************************************************************************//**\r
92  * See mss_pdma.h for description of this function.\r
93  */\r
94 void PDMA_init( void )\r
95 {\r
96     int32_t i;\r
97     \r
98     /* Enable PDMA master access to comms matrix. */\r
99     SYSREG->AHB_MATRIX_CR |= PDMA_MASTER_ENABLE;\r
100     \r
101     /* Reset PDMA block. */\r
102     SYSREG->SOFT_RST_CR |= PDMA_SOFT_RESET;\r
103     \r
104     /* Clear any previously pended MSS PDMA interrupt */\r
105     NVIC_ClearPendingIRQ( DMA_IRQn );\r
106         \r
107     /* Take PDMA controller out of reset*/\r
108     SYSREG->SOFT_RST_CR &= ~PDMA_SOFT_RESET;\r
109     \r
110     /* Initialize channels state information. */\r
111     for ( i = 0; i < NB_OF_PDMA_CHANNELS; ++i )\r
112     {\r
113         g_pdma_next_channel[i] = NEXT_CHANNEL_A;\r
114         g_pdma_started_a[i] = CHANNEL_STOPPED;\r
115         g_pdma_started_b[i] = CHANNEL_STOPPED;\r
116         g_pdma_isr_table[i] = 0;\r
117     }\r
118 }\r
119 \r
120 /***************************************************************************//**\r
121  * See mss_pdma.h for description of this function.\r
122  */\r
123 #define CHANNEL_RESET_MASK  (uint32_t)0x00000020\r
124 \r
125 void PDMA_configure\r
126 (\r
127     pdma_channel_id_t channel_id,\r
128     pdma_src_dest_t src_dest,\r
129     uint32_t channel_cfg,\r
130     uint8_t write_adjust\r
131 )\r
132 {\r
133     /* Reset the channel. */\r
134     PDMA->CHANNEL[channel_id].CRTL |= CHANNEL_RESET_MASK;\r
135     PDMA->CHANNEL[channel_id].CRTL &= ~CHANNEL_RESET_MASK;\r
136 \r
137     /* Configure PDMA channel's data source and destination. */\r
138     if ( src_dest != PDMA_MEM_TO_MEM )\r
139     {\r
140         PDMA->CHANNEL[channel_id].CRTL |= src_dest_to_ctrl_reg_lut[src_dest];\r
141     }\r
142     \r
143     /* Configure PDMA channel trnasfer size, priority, source and destination address increment. */\r
144     PDMA->CHANNEL[channel_id].CRTL |= channel_cfg;\r
145 \r
146     /* Posted write adjust. */\r
147     PDMA->CHANNEL[channel_id].CRTL |= ((uint32_t)write_adjust << CHANNEL_N_POSTED_WRITE_ADJUST_SHIFT);\r
148 }\r
149 \r
150 /***************************************************************************//**\r
151  * See mss_pdma.h for description of this function.\r
152  */\r
153 #define PAUSE_MASK  (uint32_t)0x00000010\r
154 \r
155 #define BUFFER_B_SELECT_MASK    (uint32_t)0x00000004\r
156 \r
157 #define CLEAR_PORT_A_DONE_MASK      (uint32_t)0x00000080\r
158 #define CLEAR_PORT_B_DONE_MASK      (uint32_t)0x00000100\r
159 \r
160 #define PORT_A_COMPLETE_MASK        (uint32_t)0x00000001\r
161 #define PORT_B_COMPLETE_MASK        (uint32_t)0x00000002\r
162 \r
163 void PDMA_start\r
164 (\r
165     pdma_channel_id_t channel_id,\r
166     uint32_t src_addr,\r
167     uint32_t dest_addr,\r
168     uint16_t transfer_count\r
169 )\r
170 {\r
171     /* Pause transfer. */\r
172     PDMA->CHANNEL[channel_id].CRTL |= PAUSE_MASK;\r
173     \r
174     /* Clear complete transfers. */\r
175     if ( PDMA->CHANNEL[channel_id].STATUS & PORT_A_COMPLETE_MASK )\r
176     {\r
177         PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;\r
178         g_pdma_started_a[channel_id] = CHANNEL_STOPPED;\r
179     }\r
180     if ( PDMA->CHANNEL[channel_id].STATUS & PORT_B_COMPLETE_MASK )\r
181     {\r
182         PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;\r
183         g_pdma_started_b[channel_id] = CHANNEL_STOPPED;\r
184     }\r
185     \r
186     /* Load source, destination and transfer count. */\r
187     if ( PDMA->CHANNEL[channel_id].STATUS & BUFFER_B_SELECT_MASK )\r
188     {\r
189         g_pdma_next_channel[channel_id] = NEXT_CHANNEL_A;\r
190         g_pdma_started_b[channel_id] = CHANNEL_STARTED;\r
191         \r
192         PDMA->CHANNEL[channel_id].BUFFER_B_SRC_ADDR = src_addr;\r
193         PDMA->CHANNEL[channel_id].BUFFER_B_DEST_ADDR = dest_addr;\r
194         PDMA->CHANNEL[channel_id].BUFFER_B_TRANSFER_COUNT = transfer_count;\r
195     }\r
196     else\r
197     {\r
198         g_pdma_next_channel[channel_id] = NEXT_CHANNEL_B;\r
199         g_pdma_started_a[channel_id] = CHANNEL_STARTED;\r
200         \r
201         PDMA->CHANNEL[channel_id].BUFFER_A_SRC_ADDR = src_addr;\r
202         PDMA->CHANNEL[channel_id].BUFFER_A_DEST_ADDR = dest_addr;\r
203         PDMA->CHANNEL[channel_id].BUFFER_A_TRANSFER_COUNT = transfer_count;\r
204     }\r
205     \r
206     /* Start transfer */\r
207     PDMA->CHANNEL[channel_id].CRTL &= ~PAUSE_MASK;\r
208 }\r
209 \r
210 /***************************************************************************//**\r
211  * See mss_pdma.h for description of this function.\r
212  */\r
213 void PDMA_load_next_buffer\r
214 (\r
215     pdma_channel_id_t channel_id,\r
216     uint32_t src_addr,\r
217     uint32_t dest_addr,\r
218     uint16_t transfer_count\r
219 )\r
220 {\r
221     if ( NEXT_CHANNEL_A == g_pdma_next_channel[channel_id] )\r
222     {\r
223         /* Wait for channel A current transfer completion. */\r
224         if ( CHANNEL_STARTED == g_pdma_started_a[channel_id] )\r
225         {\r
226             uint32_t completed;\r
227             uint32_t channel_mask;\r
228             channel_mask = (uint32_t)1 << ((uint32_t)channel_id * 2U);\r
229             do {\r
230                 completed = PDMA->BUFFER_STATUS & channel_mask;\r
231             } while( !completed );\r
232             PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;\r
233         }\r
234         /* Load source, destination and transfer count. */\r
235         PDMA->CHANNEL[channel_id].BUFFER_A_SRC_ADDR = src_addr;\r
236         PDMA->CHANNEL[channel_id].BUFFER_A_DEST_ADDR = dest_addr;\r
237         PDMA->CHANNEL[channel_id].BUFFER_A_TRANSFER_COUNT = transfer_count;\r
238         \r
239         /* Update channel state information. */\r
240         g_pdma_next_channel[channel_id] = NEXT_CHANNEL_B;\r
241         g_pdma_started_a[channel_id] = CHANNEL_STARTED;\r
242     }\r
243     else\r
244     {\r
245         /* Wait for channel B current transfer completion. */\r
246         if ( CHANNEL_STARTED == g_pdma_started_b[channel_id] )\r
247         {\r
248             uint32_t completed;\r
249             uint32_t channel_mask;\r
250             channel_mask = (uint32_t)1 << (((uint32_t)channel_id * 2U) + 1U);\r
251             do {\r
252                 completed = PDMA->BUFFER_STATUS & channel_mask;\r
253             } while( !completed );\r
254             PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;\r
255         }            \r
256         /* Load source, destination and transfer count. */\r
257         PDMA->CHANNEL[channel_id].BUFFER_B_SRC_ADDR = src_addr;\r
258         PDMA->CHANNEL[channel_id].BUFFER_B_DEST_ADDR = dest_addr;\r
259         PDMA->CHANNEL[channel_id].BUFFER_B_TRANSFER_COUNT = transfer_count;\r
260         \r
261         /* Update channel state information. */\r
262         g_pdma_next_channel[channel_id] = NEXT_CHANNEL_A;\r
263         g_pdma_started_b[channel_id] = CHANNEL_STARTED;\r
264     }\r
265 }\r
266 \r
267 /***************************************************************************//**\r
268  * See mss_pdma.h for description of this function.\r
269  */\r
270 uint32_t PDMA_status\r
271 (\r
272     pdma_channel_id_t  channel_id\r
273 )\r
274 {\r
275     uint32_t status;\r
276     \r
277     status = PDMA->CHANNEL[channel_id].STATUS & (PORT_A_COMPLETE_MASK | PORT_B_COMPLETE_MASK);\r
278     \r
279     return status;\r
280 }\r
281 \r
282 /***************************************************************************//**\r
283  *\r
284  */\r
285 #define CHANNEL_0_STATUS_BITS_MASK     (uint16_t)0x0003\r
286 #define CHANNEL_1_STATUS_BITS_MASK     (uint16_t)0x000C\r
287 #define CHANNEL_2_STATUS_BITS_MASK     (uint16_t)0x0030\r
288 #define CHANNEL_3_STATUS_BITS_MASK     (uint16_t)0x00C0\r
289 #define CHANNEL_4_STATUS_BITS_MASK     (uint16_t)0x0300\r
290 #define CHANNEL_5_STATUS_BITS_MASK     (uint16_t)0x0C00\r
291 #define CHANNEL_6_STATUS_BITS_MASK     (uint16_t)0x3000\r
292 #define CHANNEL_7_STATUS_BITS_MASK     (uint16_t)0xC000\r
293 \r
294 static pdma_channel_id_t get_channel_id_from_status\r
295 (\r
296     uint16_t status\r
297 )\r
298 {\r
299     pdma_channel_id_t channel_id = PDMA_CHANNEL_0;\r
300     \r
301     if ( status & CHANNEL_0_STATUS_BITS_MASK )\r
302     {\r
303         channel_id = PDMA_CHANNEL_0;\r
304     }\r
305     else if ( status & CHANNEL_1_STATUS_BITS_MASK )\r
306     {\r
307         channel_id = PDMA_CHANNEL_1;\r
308     }\r
309     else if ( status & CHANNEL_2_STATUS_BITS_MASK )\r
310     {\r
311         channel_id = PDMA_CHANNEL_2;\r
312     }\r
313     else if ( status & CHANNEL_3_STATUS_BITS_MASK )\r
314     {\r
315         channel_id = PDMA_CHANNEL_3;\r
316     }\r
317     else if ( status & CHANNEL_4_STATUS_BITS_MASK )\r
318     {\r
319         channel_id = PDMA_CHANNEL_4;\r
320     }\r
321     else if ( status & CHANNEL_5_STATUS_BITS_MASK )\r
322     {\r
323         channel_id = PDMA_CHANNEL_5;\r
324     }\r
325     else if ( status & CHANNEL_6_STATUS_BITS_MASK )\r
326     {\r
327         channel_id = PDMA_CHANNEL_6;\r
328     }\r
329     else if ( status & CHANNEL_7_STATUS_BITS_MASK )\r
330     {\r
331         channel_id = PDMA_CHANNEL_7;\r
332     }\r
333     else\r
334     {\r
335         ASSERT(0);\r
336     }\r
337     return channel_id;\r
338 }\r
339 \r
340 /***************************************************************************//**\r
341  *\r
342  */\r
343 #if defined(__GNUC__)\r
344 __attribute__((__interrupt__)) void DMA_IRQHandler( void )\r
345 #else\r
346 void DMA_IRQHandler( void )\r
347 #endif\r
348 {\r
349     uint16_t status;\r
350     pdma_channel_id_t channel_id;\r
351     \r
352     status = (uint16_t)PDMA->BUFFER_STATUS;\r
353     \r
354     do {\r
355         channel_id = get_channel_id_from_status( status );\r
356         status &= (uint16_t)~g_pdma_status_mask[channel_id];\r
357         if ( 0 != g_pdma_isr_table[channel_id])\r
358         {\r
359             g_pdma_isr_table[channel_id]();\r
360         }\r
361     } while ( 0U != status );\r
362       \r
363     NVIC_ClearPendingIRQ( DMA_IRQn );\r
364 }\r
365 \r
366 /***************************************************************************//**\r
367  * See mss_pdma.h for description of this function.\r
368  */\r
369 void PDMA_set_irq_handler\r
370 (\r
371     pdma_channel_id_t channel_id,\r
372     pdma_channel_isr_t handler\r
373 )\r
374 {\r
375     /* Save address of handler function in PDMA driver ISR lookup table. */\r
376     g_pdma_isr_table[channel_id] = handler;\r
377     \r
378     /* Enable PDMA channel's interrupt. */\r
379     PDMA->CHANNEL[channel_id].CRTL |= PDMA_IRQ_ENABLE_MASK;\r
380     \r
381     /* Enable PDMA interrupt in Cortex-M3 NVIC. */\r
382     NVIC_EnableIRQ( DMA_IRQn );\r
383 }\r
384 \r
385 /***************************************************************************//**\r
386  * See mss_pdma.h for description of this function.\r
387  */\r
388 void PDMA_enable_irq( pdma_channel_id_t channel_id )\r
389 {\r
390     PDMA->CHANNEL[channel_id].CRTL |= PDMA_IRQ_ENABLE_MASK;\r
391     NVIC_EnableIRQ( DMA_IRQn );\r
392 }\r
393 \r
394 /***************************************************************************//**\r
395  * See mss_pdma.h for description of this function.\r
396  */\r
397 void PDMA_clear_irq\r
398 (\r
399     pdma_channel_id_t channel_id\r
400 )\r
401 {\r
402     /* Clear interrupt in PDMA controller. */\r
403     PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_A_DONE_MASK;\r
404     PDMA->CHANNEL[channel_id].CRTL |= CLEAR_PORT_B_DONE_MASK;\r
405     \r
406     /* Clear interrupt in Cortex-M3 NVIC. */\r
407     NVIC_ClearPendingIRQ( DMA_IRQn );\r
408 }\r
409 \r
410 #ifdef __cplusplus\r
411 }\r
412 #endif\r
413 \r