]> git.sur5r.net Git - freertos/blob
c0c2e3a43c1c8c50e70bab589bdce79bd530dabf
[freertos] /
1 /*******************************************************************************\r
2  * (c) Copyright 2012 Microsemi SoC Products Group.  All rights reserved.\r
3  *\r
4  * SmartFusion2 COMBLK access functions.\r
5  *\r
6  * SVN $Revision: 5615 $\r
7  * SVN $Date: 2013-04-05 14:48:10 +0100 (Fri, 05 Apr 2013) $\r
8  */\r
9  \r
10 #include "mss_comblk.h"\r
11 #include "../../CMSIS/mss_assert.h"\r
12 \r
13 /*==============================================================================\r
14  *\r
15  */\r
16 /*------------------------------------------------------------------------------\r
17  * Control register bit masks.\r
18  */\r
19 #define CR_FLUSHOUT_MASK    0x01u\r
20 #define CR_SIZETX_MASK      0x04u\r
21 #define CR_ENABLE_MASK      0x10u\r
22 #define CR_LOOPBACK_MASK    0x20u\r
23 \r
24 /*------------------------------------------------------------------------------\r
25  * Status and interrupt enable registers bit masks.\r
26  */\r
27 #define TXTOKAY_MASK    0x01u\r
28 #define RCVOKAY_MASK    0x02u\r
29 \r
30 /*------------------------------------------------------------------------------\r
31  * DATA8 register bit masks.\r
32  */\r
33 #define DATA8_COMMAND_MASK  0x8000u\r
34 \r
35 /*------------------------------------------------------------------------------\r
36  * COMBLK driver states.\r
37  */\r
38 #define COMBLK_IDLE             0u\r
39 #define COMBLK_TX_CMD           1u\r
40 #define COMBLK_TX_DATA          2u\r
41 #define COMBLK_WAIT_RESPONSE    3u\r
42 #define COMBLK_RX_RESPONSE      4u\r
43 #define COMBLK_TX_PAGED_DATA    5u\r
44 \r
45 /*==============================================================================\r
46  * COMBLK interrupt servcie routine.\r
47  */\r
48 void ComBlk_IRQHandler(void);\r
49 \r
50 /*==============================================================================\r
51  * Local functions.\r
52  */\r
53 static void abort_current_cmd(void);\r
54 static void send_cmd_opcode(uint8_t opcode);\r
55 static uint32_t fill_tx_fifo(const uint8_t * p_cmd, uint32_t cmd_size);\r
56 static void handle_tx_okay_irq(void);\r
57 static void handle_rx_okay_irq(void);\r
58 static void complete_request(uint16_t response_length);\r
59 static void process_sys_ctrl_command(uint8_t cmd_opcode);\r
60 \r
61 /*==============================================================================\r
62  * Global variables:\r
63  */\r
64 static volatile uint8_t g_comblk_cmd_opcode = 0u;\r
65 static const uint8_t * g_comblk_p_cmd = 0u;\r
66 static volatile uint16_t g_comblk_cmd_size = 0u;\r
67 static const uint8_t * g_comblk_p_data = 0u;\r
68 static volatile uint32_t g_comblk_data_size = 0u;\r
69 static uint8_t * g_comblk_p_response = 0u;\r
70 static uint16_t g_comblk_response_size = 0u;\r
71 static volatile uint16_t g_comblk_response_idx = 0u;\r
72 static comblk_completion_handler_t g_comblk_completion_handler = 0;\r
73 \r
74 /*typedef uint32_t (*comblk_page_handler_t)(uint8_t const ** pp_next_page);\r
75 */\r
76 static uint32_t (*g_comblk_page_handler)(uint8_t const ** pp_next_page) = 0;\r
77 \r
78 static uint8_t g_request_in_progress = 0u;\r
79 \r
80 static uint8_t g_comblk_state = COMBLK_IDLE;\r
81 \r
82 static comblk_async_event_handler_t g_async_event_handler = 0;\r
83 \r
84 /*==============================================================================\r
85  *\r
86  */\r
87 void MSS_COMBLK_init(comblk_async_event_handler_t async_event_handler)\r
88 {\r
89     /*\r
90      * Disable and clear previous interrupts.\r
91      */\r
92     NVIC_DisableIRQ(ComBlk_IRQn);\r
93     COMBLK->INT_ENABLE = 0u;\r
94     NVIC_ClearPendingIRQ(ComBlk_IRQn);\r
95     \r
96     g_async_event_handler = async_event_handler;\r
97     \r
98     /*\r
99      * Initialialize COMBLK driver state variables:\r
100      */\r
101     g_request_in_progress = 0u;\r
102     g_comblk_cmd_opcode = 0u;\r
103     g_comblk_p_cmd = 0u;\r
104     g_comblk_cmd_size = 0u;\r
105     g_comblk_p_data = 0u;\r
106     g_comblk_data_size = 0u;\r
107     g_comblk_p_response = 0u;\r
108     g_comblk_response_size = 0u;\r
109     g_comblk_response_idx = 0u;\r
110     g_comblk_completion_handler = 0;\r
111     \r
112     g_comblk_state = COMBLK_IDLE;\r
113     \r
114     COMBLK->CONTROL |= CR_ENABLE_MASK;\r
115     COMBLK->CONTROL &= ~CR_LOOPBACK_MASK;\r
116     \r
117     /*--------------------------------------------------------------------------\r
118      * Enable receive interrupt to receive asynchronous events from the system\r
119      * controller.\r
120      */\r
121     COMBLK->INT_ENABLE &= ~TXTOKAY_MASK;\r
122     COMBLK->INT_ENABLE |= RCVOKAY_MASK;\r
123     NVIC_EnableIRQ(ComBlk_IRQn);\r
124 }\r
125 \r
126 /*==============================================================================\r
127  *\r
128  */\r
129 void MSS_COMBLK_send_cmd_with_ptr\r
130 (\r
131     uint8_t cmd_opcode,\r
132     uint32_t cmd_params_ptr,\r
133     uint8_t * p_response,\r
134     uint16_t response_size,\r
135     comblk_completion_handler_t completion_handler\r
136 )\r
137 {\r
138     uint32_t tx_okay;\r
139     \r
140     /*--------------------------------------------------------------------------\r
141      * Disable and clear previous interrupts.\r
142      */\r
143     NVIC_DisableIRQ(ComBlk_IRQn);\r
144     COMBLK->INT_ENABLE = 0u;\r
145     NVIC_ClearPendingIRQ(ComBlk_IRQn);\r
146     \r
147     /*--------------------------------------------------------------------------\r
148      * Abort current command if any.\r
149      */\r
150     abort_current_cmd();\r
151     \r
152     /*--------------------------------------------------------------------------\r
153      * Initialialize COMBLK driver state variables:\r
154      */\r
155     g_request_in_progress = 1u;\r
156     g_comblk_cmd_opcode = cmd_opcode;\r
157     g_comblk_p_cmd = 0u;\r
158     g_comblk_cmd_size = 0u;\r
159     g_comblk_p_data = 0u;\r
160     g_comblk_data_size = 0u;\r
161     g_comblk_p_response = p_response;\r
162     g_comblk_response_size = response_size;\r
163     g_comblk_response_idx = 0u;\r
164     g_comblk_page_handler = 0u;\r
165     g_comblk_completion_handler = completion_handler;\r
166     \r
167     /*--------------------------------------------------------------------------\r
168      * Send command opcode as a single byte write to the Tx FIFO.\r
169      */\r
170     send_cmd_opcode(g_comblk_cmd_opcode);\r
171     \r
172     /*--------------------------------------------------------------------------\r
173      * Send the command parameters pointer to the Tx FIFO as a single 4 bytes\r
174      * write to the Tx FIFO.\r
175      */\r
176     COMBLK->CONTROL |= CR_SIZETX_MASK;\r
177     \r
178     /* Wait for space to become available in Tx FIFO. */\r
179     do {\r
180         tx_okay = COMBLK->STATUS & TXTOKAY_MASK;\r
181     } while(0u == tx_okay);\r
182     \r
183     /* Send command opcode. */\r
184     COMBLK->DATA32 = cmd_params_ptr;\r
185     \r
186     COMBLK->CONTROL &= ~CR_SIZETX_MASK;\r
187     \r
188     g_comblk_state = COMBLK_WAIT_RESPONSE;\r
189     \r
190     /*--------------------------------------------------------------------------\r
191      * Enable interrupt.\r
192      */\r
193     COMBLK->INT_ENABLE |= RCVOKAY_MASK;\r
194     NVIC_EnableIRQ(ComBlk_IRQn);\r
195 }\r
196 \r
197 /*==============================================================================\r
198  *\r
199  */\r
200 void MSS_COMBLK_send_cmd\r
201 (\r
202     const uint8_t * p_cmd,\r
203     uint16_t cmd_size,\r
204     const uint8_t * p_data,\r
205     uint32_t data_size,\r
206     uint8_t * p_response,\r
207     uint16_t response_size,\r
208     comblk_completion_handler_t completion_handler\r
209 )\r
210 {\r
211     uint32_t size_sent;\r
212     \r
213     ASSERT(cmd_size > 0);\r
214     \r
215     /*\r
216      * Disable and clear previous interrupts.\r
217      */\r
218     NVIC_DisableIRQ(ComBlk_IRQn);\r
219     COMBLK->INT_ENABLE = 0u;\r
220     NVIC_ClearPendingIRQ(ComBlk_IRQn);\r
221     \r
222     /*\r
223      * Abort current command if any.\r
224      */\r
225     abort_current_cmd();\r
226     \r
227     /*\r
228      * Initialialize COMBLK driver state variables:\r
229      */\r
230     g_request_in_progress = 1u;\r
231     g_comblk_cmd_opcode = p_cmd[0];\r
232     g_comblk_p_cmd = p_cmd;\r
233     g_comblk_cmd_size = cmd_size;\r
234     g_comblk_p_data = p_data;\r
235     g_comblk_data_size = data_size;\r
236     g_comblk_p_response = p_response;\r
237     g_comblk_response_size = response_size;\r
238     g_comblk_response_idx = 0u;\r
239     g_comblk_page_handler = 0u;\r
240     g_comblk_completion_handler = completion_handler;\r
241     \r
242     COMBLK->INT_ENABLE |= RCVOKAY_MASK;\r
243 \r
244     /*\r
245      * Fill FIFO with command.\r
246      */\r
247     send_cmd_opcode(g_comblk_cmd_opcode);\r
248     size_sent = fill_tx_fifo(&p_cmd[1], cmd_size - 1u);\r
249     ++size_sent;    /* Adjust for opcode byte sent. */\r
250     if(size_sent < cmd_size)\r
251     {\r
252         g_comblk_cmd_size = g_comblk_cmd_size - (uint16_t)size_sent;\r
253         g_comblk_p_cmd = &g_comblk_p_cmd[size_sent];\r
254         \r
255         g_comblk_state = COMBLK_TX_CMD;\r
256     }\r
257     else\r
258     {\r
259         g_comblk_cmd_size = 0u;\r
260         if(g_comblk_data_size > 0u)\r
261         {\r
262             g_comblk_state = COMBLK_TX_DATA;\r
263         }\r
264         else\r
265         {\r
266             g_comblk_state = COMBLK_WAIT_RESPONSE;\r
267         }\r
268     }\r
269 \r
270     /*\r
271      * Enable interrupt.\r
272      */\r
273     NVIC_EnableIRQ(ComBlk_IRQn);\r
274 }\r
275 \r
276 /*==============================================================================\r
277  *\r
278  */\r
279 void MSS_COMBLK_send_paged_cmd\r
280 (\r
281     const uint8_t * p_cmd,\r
282     uint16_t cmd_size,\r
283     uint8_t * p_response,\r
284     uint16_t response_size,\r
285     uint32_t (*page_read_handler)(uint8_t const **),\r
286     void (*completion_handler)(uint8_t *, uint16_t)\r
287 )\r
288 {\r
289     uint32_t size_sent;\r
290     uint8_t irq_enable = 0u;\r
291     \r
292     ASSERT(cmd_size > 0u);\r
293     \r
294     /*\r
295      * Disable and clear previous interrupts.\r
296      */\r
297     NVIC_DisableIRQ(ComBlk_IRQn);\r
298     COMBLK->INT_ENABLE = 0u;\r
299     NVIC_ClearPendingIRQ(ComBlk_IRQn);\r
300     \r
301     /*\r
302      * Abort current command if any.\r
303      */\r
304     abort_current_cmd();\r
305     \r
306     /*\r
307      * Initialialize COMBLK driver state variables:\r
308      */\r
309     g_request_in_progress = 1u;\r
310     g_comblk_cmd_opcode = p_cmd[0];\r
311     g_comblk_p_cmd = p_cmd;\r
312     g_comblk_cmd_size = cmd_size;\r
313     g_comblk_p_data = 0;\r
314     g_comblk_data_size = 0u;\r
315     g_comblk_p_response = p_response;\r
316     g_comblk_response_size = response_size;\r
317     g_comblk_response_idx = 0u;\r
318     g_comblk_page_handler = page_read_handler;\r
319     g_comblk_completion_handler = completion_handler;\r
320     \r
321     /*\r
322      * Fill FIFO with command.\r
323      */\r
324     send_cmd_opcode(g_comblk_cmd_opcode);\r
325     size_sent = fill_tx_fifo(&p_cmd[1], cmd_size - 1u);\r
326     ++size_sent;    /* Adjust for opcode byte sent. */\r
327     if(size_sent < cmd_size)\r
328     {\r
329         g_comblk_cmd_size = g_comblk_cmd_size - (uint16_t)size_sent;\r
330         g_comblk_p_cmd = &g_comblk_p_cmd[size_sent];\r
331         \r
332         g_comblk_state = COMBLK_TX_CMD;\r
333         irq_enable = TXTOKAY_MASK | RCVOKAY_MASK;\r
334     }\r
335     else\r
336     {\r
337         g_comblk_cmd_size = 0u;\r
338         g_comblk_state = COMBLK_TX_PAGED_DATA;\r
339         irq_enable = TXTOKAY_MASK | RCVOKAY_MASK;\r
340     }\r
341 \r
342     /*\r
343      * Enable interrupt.\r
344      */\r
345     COMBLK->INT_ENABLE |= irq_enable;\r
346     NVIC_EnableIRQ(ComBlk_IRQn);\r
347 }\r
348 \r
349 /*==============================================================================\r
350  * COMBLK interrupt handler.\r
351  */\r
352 void ComBlk_IRQHandler(void)\r
353 {\r
354     uint8_t status;\r
355     uint8_t tx_okay;\r
356     uint8_t rcv_okay;\r
357     \r
358     status = (uint8_t)COMBLK->STATUS;\r
359     \r
360     /* Mask off interrupt that are not enabled.*/\r
361     status &= COMBLK->INT_ENABLE;\r
362     \r
363     rcv_okay = status & RCVOKAY_MASK;\r
364     if(rcv_okay)\r
365     {\r
366         handle_rx_okay_irq();\r
367     }\r
368         \r
369     tx_okay = status & TXTOKAY_MASK;\r
370     if(tx_okay)\r
371     {\r
372         handle_tx_okay_irq();\r
373     }\r
374 }\r
375 \r
376 /*==============================================================================\r
377  *\r
378  */\r
379 static void handle_tx_okay_irq(void)\r
380 {\r
381     switch(g_comblk_state)\r
382     {\r
383         /*----------------------------------------------------------------------\r
384          * The TX_OKAY interrupt should only be enabled for states COMBLK_TX_CMD\r
385          * and COMBLK_TX_DATA. \r
386          */\r
387         case COMBLK_TX_CMD:\r
388             if(g_comblk_cmd_size > 0u)\r
389             {\r
390                 uint32_t size_sent;\r
391                 size_sent = fill_tx_fifo(g_comblk_p_cmd, g_comblk_cmd_size);\r
392                 if(size_sent < g_comblk_cmd_size)\r
393                 {\r
394                     g_comblk_cmd_size = g_comblk_cmd_size - (uint16_t)size_sent;\r
395                     g_comblk_p_cmd = &g_comblk_p_cmd[size_sent];\r
396                 }\r
397                 else\r
398                 {\r
399                     g_comblk_cmd_size = 0u;\r
400                     if(g_comblk_data_size > 0u)\r
401                     {\r
402                         g_comblk_state = COMBLK_TX_DATA;\r
403                     }\r
404                     else\r
405                     {\r
406                         g_comblk_state = COMBLK_WAIT_RESPONSE;\r
407                     }\r
408                 }\r
409             }\r
410             else\r
411             {\r
412                 /*\r
413                  * This is an invalid situation indicating a bug in the driver\r
414                  * or corrupted memory.\r
415                  */\r
416                 ASSERT(0);\r
417                 abort_current_cmd();\r
418             }\r
419         break;\r
420             \r
421         case COMBLK_TX_DATA:\r
422             if(g_comblk_data_size > 0u)\r
423             {\r
424                 uint32_t size_sent;\r
425                 size_sent = fill_tx_fifo(g_comblk_p_data, g_comblk_data_size);\r
426                 if(size_sent < g_comblk_data_size)\r
427                 {\r
428                     g_comblk_data_size = g_comblk_data_size - size_sent;\r
429                     g_comblk_p_data = &g_comblk_p_data[size_sent];\r
430                 }\r
431                 else\r
432                 {\r
433                     COMBLK->INT_ENABLE &= ~TXTOKAY_MASK;\r
434                     g_comblk_state = COMBLK_WAIT_RESPONSE;\r
435                 }\r
436             }\r
437             else\r
438             {\r
439                 /*\r
440                  * This is an invalid situation indicating a bug in the driver\r
441                  * or corrupted memory.\r
442                  */\r
443                 ASSERT(0);\r
444                 abort_current_cmd();\r
445             }\r
446         break;\r
447            \r
448         case COMBLK_TX_PAGED_DATA:\r
449             /*\r
450              * Read a page of data if required.\r
451              */\r
452             if(0u == g_comblk_data_size)\r
453             {\r
454                 if(g_comblk_page_handler != 0)\r
455                 {\r
456                     g_comblk_data_size = g_comblk_page_handler(&g_comblk_p_data);\r
457                     if(0u == g_comblk_data_size)\r
458                     {\r
459                         COMBLK->INT_ENABLE &= ~TXTOKAY_MASK;\r
460                         g_comblk_state = COMBLK_WAIT_RESPONSE;\r
461                     }\r
462                 }\r
463                 else\r
464                 {\r
465                     ASSERT(0);\r
466                     abort_current_cmd();\r
467                 }\r
468             }\r
469             \r
470             /*\r
471              * Transmit the page data or move to COMBLK_WAIT_RESPONSE state if\r
472              * no further page data could be obtained by the call to the page\r
473              * handler above.\r
474              */\r
475             if(0u == g_comblk_data_size)\r
476             {\r
477                 COMBLK->INT_ENABLE &= ~TXTOKAY_MASK;\r
478                 g_comblk_state = COMBLK_WAIT_RESPONSE;\r
479             }\r
480             else\r
481             {\r
482                 uint32_t size_sent;\r
483                 size_sent = fill_tx_fifo(g_comblk_p_data, g_comblk_data_size);\r
484                 g_comblk_data_size = g_comblk_data_size - size_sent;\r
485                 g_comblk_p_data = &g_comblk_p_data[size_sent];\r
486             }\r
487         break;\r
488             \r
489         /*----------------------------------------------------------------------\r
490          * The TX_OKAY interrupt should NOT be enabled for states COMBLK_IDLE,\r
491          * COMBLK_WAIT_RESPONSE and COMBLK_RX_RESPONSE.\r
492          */\r
493         case COMBLK_IDLE:\r
494             /* Fall through */\r
495         case COMBLK_WAIT_RESPONSE:\r
496             /* Fall through */\r
497         case COMBLK_RX_RESPONSE:\r
498             /* Fall through */\r
499         default:\r
500             COMBLK->INT_ENABLE &= ~TXTOKAY_MASK;\r
501             complete_request(0u);\r
502             g_comblk_state = COMBLK_IDLE;\r
503         break;\r
504     }\r
505 }\r
506 \r
507 /*==============================================================================\r
508  *\r
509  */\r
510 static void handle_rx_okay_irq(void)\r
511 {\r
512     uint16_t data16;\r
513     uint16_t is_command;\r
514     \r
515     data16 = (uint16_t)COMBLK->DATA8;\r
516     is_command = data16 & DATA8_COMMAND_MASK;\r
517             \r
518     switch(g_comblk_state)\r
519     {\r
520         /*----------------------------------------------------------------------\r
521          * The RCV_OKAY interrupt should only be enabled for states\r
522          * COMBLK_WAIT_RESPONSE and COMBLK_RX_RESPONSE. \r
523          */\r
524         case COMBLK_WAIT_RESPONSE:\r
525             if(is_command)\r
526             {\r
527                 uint8_t rxed_opcode;\r
528                 rxed_opcode = (uint8_t)data16;\r
529                 if(rxed_opcode == g_comblk_cmd_opcode)\r
530                 {\r
531                     g_comblk_response_idx = 0u;\r
532                     g_comblk_p_response[g_comblk_response_idx] = rxed_opcode;\r
533                     ++g_comblk_response_idx;\r
534                     g_comblk_state = COMBLK_RX_RESPONSE;\r
535                 }\r
536                 else\r
537                 {\r
538                     process_sys_ctrl_command(rxed_opcode);\r
539                 }\r
540             }\r
541         break;\r
542             \r
543         case COMBLK_RX_RESPONSE:\r
544             if(is_command)\r
545             {\r
546                 uint8_t rxed_opcode;\r
547                 rxed_opcode = (uint8_t)data16;\r
548                 process_sys_ctrl_command(rxed_opcode);\r
549             }\r
550             else\r
551             {\r
552                 if(g_comblk_response_idx < g_comblk_response_size)\r
553                 {\r
554                     uint8_t rxed_data;\r
555                     \r
556                     rxed_data = (uint8_t)data16;\r
557                     g_comblk_p_response[g_comblk_response_idx] = rxed_data;\r
558                     ++g_comblk_response_idx;\r
559                 }\r
560                 \r
561                 if(g_comblk_response_idx == g_comblk_response_size)\r
562                 {\r
563                     complete_request(g_comblk_response_idx);\r
564                     g_comblk_state = COMBLK_IDLE;\r
565                 }\r
566             }\r
567         break;\r
568             \r
569         /*----------------------------------------------------------------------\r
570          * The RCV_OKAY interrupt should NOT be enabled for states\r
571          * COMBLK_IDLE, COMBLK_TX_CMD and COMBLK_TX_DATA. \r
572          */\r
573         case COMBLK_TX_PAGED_DATA:\r
574             /* This is needed because when there is an error, we need to terminate loading the data */\r
575             if(!is_command)\r
576             {\r
577                 g_comblk_p_response[1] = (uint8_t)data16;\r
578                 complete_request(2u);\r
579                 g_comblk_state = COMBLK_IDLE;\r
580             }\r
581         break;\r
582         case COMBLK_IDLE:\r
583             /* Fall through */\r
584         case COMBLK_TX_CMD:\r
585             /* Fall through */\r
586         case COMBLK_TX_DATA:\r
587             /* Fall through */\r
588             if(is_command)\r
589             {\r
590                 uint8_t rxed_opcode;\r
591                 rxed_opcode = (uint8_t)data16;\r
592                 process_sys_ctrl_command(rxed_opcode);\r
593             }\r
594         break;\r
595         \r
596         default:\r
597             complete_request(0u);\r
598             g_comblk_state = COMBLK_IDLE;\r
599         break;\r
600     }\r
601 }\r
602 \r
603 /*==============================================================================\r
604  *\r
605  */\r
606 static void complete_request\r
607 (\r
608     uint16_t response_length\r
609 )\r
610 {\r
611     if(g_comblk_completion_handler != 0)\r
612     {\r
613         g_comblk_completion_handler(g_comblk_p_response, response_length);\r
614         g_comblk_completion_handler = 0;\r
615         g_request_in_progress = 0u;\r
616     }\r
617 }\r
618 \r
619 /*==============================================================================\r
620  *\r
621  */\r
622 static void abort_current_cmd(void)\r
623 {\r
624     if(g_request_in_progress)\r
625     {\r
626         uint32_t flush_in_progress;\r
627         \r
628         /*\r
629          * Call completion handler just in case we are in a multi threaded system\r
630          * to avoid a task lockup.\r
631          */\r
632         complete_request(g_comblk_response_idx);\r
633         \r
634         /*\r
635          * Flush the FIFOs\r
636          */\r
637         COMBLK->CONTROL |= CR_FLUSHOUT_MASK;\r
638         do {\r
639             flush_in_progress = COMBLK->CONTROL & CR_FLUSHOUT_MASK;\r
640         } while(flush_in_progress);\r
641     }\r
642 }\r
643 \r
644 /*==============================================================================\r
645  *\r
646  */\r
647 static void send_cmd_opcode\r
648 (\r
649     uint8_t opcode\r
650 )\r
651 {\r
652     uint32_t tx_okay;\r
653     \r
654     /* Set transmit FIFO to transfer bytes. */\r
655     COMBLK->CONTROL &= ~CR_SIZETX_MASK;\r
656     \r
657     /* Wait for space to become available in Tx FIFO. */\r
658     do {\r
659         tx_okay = COMBLK->STATUS & TXTOKAY_MASK;\r
660     } while(0u == tx_okay);\r
661     \r
662     /* Send command opcode. */\r
663     COMBLK->FRAME_START8 = opcode;\r
664 }\r
665 \r
666 /*==============================================================================\r
667  *\r
668  */\r
669 static uint32_t fill_tx_fifo\r
670 (\r
671     const uint8_t * p_cmd,\r
672     uint32_t cmd_size\r
673 )\r
674 {\r
675     volatile uint32_t tx_okay;\r
676     uint32_t size_sent;\r
677 \r
678     /* Set transmit FIFO to transfer bytes. */\r
679     COMBLK->CONTROL &= ~CR_SIZETX_MASK;\r
680     \r
681     size_sent = 0u;\r
682     tx_okay = COMBLK->STATUS & TXTOKAY_MASK;\r
683     while((tx_okay != 0u) && (size_sent < cmd_size))\r
684     {\r
685         COMBLK->DATA8 = p_cmd[size_sent];\r
686         ++size_sent;\r
687         tx_okay = COMBLK->STATUS & TXTOKAY_MASK;\r
688     }\r
689     \r
690     return size_sent;\r
691 }\r
692 \r
693 /*==============================================================================\r
694  *\r
695  */\r
696 static void process_sys_ctrl_command(uint8_t cmd_opcode)\r
697 {\r
698     if(g_async_event_handler != 0)\r
699     {\r
700         g_async_event_handler(cmd_opcode);\r
701     }\r
702 }\r
703 \r