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