1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2017-2018 NXP
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "assert.h"
9 #include "fsl_device_registers.h"
10 #include "main/ipc.h"
11 #include "main/rpc.h"
12 #ifdef FSL_RTOS_FREE_RTOS
13 #include "FreeRTOS.h"
14 #include "task.h"
15 #endif
16 
17 /*******************************************************************************
18  * Definitions
19  ******************************************************************************/
20 
21 /* Component ID definition, used by tools. */
22 #ifndef FSL_COMPONENT_ID
23 #define FSL_COMPONENT_ID "platform.drivers.scfwapi"
24 #endif
25 
26 /*----------------------------------------------------------------------*/
27 /* RPC command/response                                                 */
28 /*----------------------------------------------------------------------*/
29 /* Please note: As the xTaskResumeAll can't be used in interrupt context in FreeRTOS.
30  * The sc_call_rpc can't be called from interrupt context in FreeRTOS enviroment.
31  */
sc_call_rpc(sc_ipc_t ipc,sc_rpc_msg_t * msg,sc_bool_t no_resp)32 void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, sc_bool_t no_resp)
33 {
34 #ifdef FSL_RTOS_FREE_RTOS
35     if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
36     {
37         /* Suspends the scheduler to make sure there's only one rpc call ongoing at a time. */
38         vTaskSuspendAll();
39     }
40 #endif
41     sc_ipc_write(ipc, msg);
42     if (!no_resp)
43     {
44         sc_ipc_read(ipc, msg);
45     }
46 #ifdef FSL_RTOS_FREE_RTOS
47     if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
48     {
49         (void)xTaskResumeAll();
50     }
51 #endif
52 }
53 
54 /*--------------------------------------------------------------------------*/
55 /* Open an IPC channel                                                      */
56 /*--------------------------------------------------------------------------*/
sc_ipc_open(sc_ipc_t * ipc,sc_ipc_id_t id)57 sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id)
58 {
59     MU_Type *base = (MU_Type *)id;
60 
61     /* get mu base associated with ipc channel */
62     if ((ipc == NULL) || (base == NULL))
63     {
64         return SC_ERR_IPC;
65     }
66 
67     /* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */
68     base->CR &= ~(MU_CR_GIEn_MASK | MU_CR_RIEn_MASK | MU_CR_TIEn_MASK | MU_CR_GIRn_MASK | MU_CR_Fn_MASK);
69 
70     /* Return MU address as handle */
71     *ipc = (sc_ipc_t)id;
72 
73     return SC_ERR_NONE;
74 }
75 
76 /*--------------------------------------------------------------------------*/
77 /* Close an IPC channel                                                     */
78 /*--------------------------------------------------------------------------*/
sc_ipc_close(sc_ipc_t ipc)79 void sc_ipc_close(sc_ipc_t ipc)
80 {
81 }
82 
83 /*--------------------------------------------------------------------------*/
84 /* Read message from an IPC channel                                         */
85 /*--------------------------------------------------------------------------*/
sc_ipc_read(sc_ipc_t ipc,void * data)86 void sc_ipc_read(sc_ipc_t ipc, void *data)
87 {
88     MU_Type *base     = (MU_Type *)ipc;
89     sc_rpc_msg_t *msg = (sc_rpc_msg_t *)data;
90     uint8_t count     = 0;
91 
92     /* Check parms */
93     if ((base == NULL) || (msg == NULL))
94     {
95         return;
96     }
97 
98     /* Read first word */
99     /* Wait RX register to be full. */
100     while ((base->SR & (1UL << (MU_SR_RFn_SHIFT + 3U))) == 0U)
101     {
102     }
103     *((uint32_t *)(void *)msg) = base->RR[0];
104     count++;
105 
106     /* Check size */
107     if (msg->size > SC_RPC_MAX_MSG)
108     {
109         *((uint32_t *)(void *)msg) = 0;
110         return;
111     }
112 
113     /* Read remaining words */
114     while (count < msg->size)
115     {
116         /* Wait RX register to be full. */
117         while ((base->SR & (1UL << (MU_SR_RFn_SHIFT + 3U - count % MU_RR_COUNT))) == 0U)
118         {
119         }
120         msg->DATA.u32[count - 1U] = base->RR[count % MU_RR_COUNT];
121         count++;
122     }
123 }
124 
125 /*--------------------------------------------------------------------------*/
126 /* Write a message to an IPC channel                                        */
127 /*--------------------------------------------------------------------------*/
sc_ipc_write(sc_ipc_t ipc,const void * data)128 void sc_ipc_write(sc_ipc_t ipc, const void *data)
129 {
130     MU_Type *base           = (MU_Type *)ipc;
131     const sc_rpc_msg_t *msg = (const sc_rpc_msg_t *)data;
132     uint8_t count           = 0;
133 
134     /* Check parms */
135     if ((base == NULL) || (msg == NULL))
136     {
137         return;
138     }
139 
140     /* Check size */
141     if (msg->size > SC_RPC_MAX_MSG)
142     {
143         return;
144     }
145 
146     /* Write first word */
147     while ((base->SR & (1UL << (MU_SR_TEn_SHIFT + 3U))) == 0U)
148     {
149     }
150     base->TR[0] = *((const uint32_t *)(const void *)msg);
151     count++;
152 
153     /* Write remaining words */
154     while (count < msg->size)
155     {
156         /* Wait Tx register to be empty and send Tx Data. */
157         while ((base->SR & (1UL << (MU_SR_TEn_SHIFT + 3U - count % MU_TR_COUNT))) == 0U)
158         {
159         }
160         base->TR[count % MU_TR_COUNT] = msg->DATA.u32[count - 1U];
161         count++;
162     }
163 }
164