1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2022 NXP
4 */
5 #include <assert.h>
6 #include <drivers/imx_mu.h>
7 #include <kernel/delay.h>
8 #include <kernel/spinlock.h>
9 #include <string.h>
10 #include <trace.h>
11
12 #include "imx_mu_platform.h"
13
14 #define RX_TIMEOUT (100 * 1000)
15
16 static unsigned int mu_spinlock = SPINLOCK_UNLOCK;
17
imx_mu_plat_init(vaddr_t base __unused)18 __weak void imx_mu_plat_init(vaddr_t base __unused)
19 {
20 }
21
imx_mu_plat_send(vaddr_t base __unused,unsigned int index __unused,uint32_t msg __unused)22 __weak TEE_Result imx_mu_plat_send(vaddr_t base __unused,
23 unsigned int index __unused,
24 uint32_t msg __unused)
25 {
26 return TEE_ERROR_NOT_IMPLEMENTED;
27 }
28
imx_mu_plat_receive(vaddr_t base __unused,unsigned int index __unused,uint32_t * msg __unused)29 __weak TEE_Result imx_mu_plat_receive(vaddr_t base __unused,
30 unsigned int index __unused,
31 uint32_t *msg __unused)
32 {
33 return TEE_ERROR_NOT_IMPLEMENTED;
34 }
35
36 /*
37 * Receive a message via the MU
38 *
39 * @base: virtual base address of the MU controller
40 * @[out]msg: message received
41 */
imx_mu_receive_msg(vaddr_t base,struct imx_mu_msg * msg)42 static TEE_Result imx_mu_receive_msg(vaddr_t base, struct imx_mu_msg *msg)
43 {
44 TEE_Result res = TEE_ERROR_GENERIC;
45 unsigned int count = 0;
46 uint32_t response = 0;
47 unsigned int nb_channel = 0;
48 uint64_t tout_rx = timeout_init_us(RX_TIMEOUT);
49
50 assert(base && msg);
51
52 do {
53 res = imx_mu_plat_receive(base, 0, &response);
54 if (timeout_elapsed(tout_rx))
55 break;
56 } while (res == TEE_ERROR_NO_DATA);
57
58 if (res)
59 return res;
60
61 memcpy(&msg->header, &response, sizeof(response));
62
63 /* Check the size of the message to receive */
64 if (msg->header.size > IMX_MU_MSG_SIZE) {
65 EMSG("Size of the message is > than IMX_MU_MSG_SIZE");
66 return TEE_ERROR_BAD_FORMAT;
67 }
68
69 nb_channel = imx_mu_plat_get_rx_channel();
70
71 for (count = 1; count < msg->header.size; count++) {
72 res = imx_mu_plat_receive(base, count % nb_channel,
73 &msg->data.u32[count - 1]);
74 if (res)
75 return res;
76 }
77
78 return TEE_SUCCESS;
79 }
80
81 /*
82 * Send a message via the MU
83 *
84 * @base: virtual base address of the MU controller
85 * @[in]msg: message to send
86 */
imx_mu_send_msg(vaddr_t base,struct imx_mu_msg * msg)87 static TEE_Result imx_mu_send_msg(vaddr_t base, struct imx_mu_msg *msg)
88 {
89 TEE_Result res = TEE_ERROR_GENERIC;
90 unsigned int count = 0;
91 unsigned int nb_channel = 0;
92 uint32_t word = 0;
93
94 assert(base && msg);
95
96 if (msg->header.size > IMX_MU_MSG_SIZE) {
97 EMSG("msg->size is > than IMX_MU_MSG_SIZE");
98 return TEE_ERROR_BAD_FORMAT;
99 }
100
101 memcpy(&word, &msg->header, sizeof(uint32_t));
102 res = imx_mu_plat_send(base, 0, word);
103 if (res)
104 return res;
105
106 nb_channel = imx_mu_plat_get_tx_channel();
107
108 for (count = 1; count < msg->header.size; count++) {
109 res = imx_mu_plat_send(base, count % nb_channel,
110 msg->data.u32[count - 1]);
111 if (res)
112 return res;
113 }
114
115 return TEE_SUCCESS;
116 }
117
imx_mu_init(vaddr_t base)118 void imx_mu_init(vaddr_t base)
119 {
120 uint32_t exceptions = 0;
121
122 if (!base) {
123 EMSG("Bad MU base address");
124 return;
125 }
126
127 exceptions = cpu_spin_lock_xsave(&mu_spinlock);
128
129 imx_mu_plat_init(base);
130
131 cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
132 }
133
imx_mu_call(vaddr_t base,struct imx_mu_msg * msg,bool wait_for_answer)134 TEE_Result imx_mu_call(vaddr_t base, struct imx_mu_msg *msg,
135 bool wait_for_answer)
136 {
137 TEE_Result res = TEE_ERROR_GENERIC;
138 uint32_t exceptions = 0;
139
140 if (!base || !msg)
141 return TEE_ERROR_BAD_PARAMETERS;
142
143 exceptions = cpu_spin_lock_xsave(&mu_spinlock);
144
145 res = imx_mu_send_msg(base, msg);
146 if (res == TEE_SUCCESS && wait_for_answer)
147 res = imx_mu_receive_msg(base, msg);
148
149 cpu_spin_unlock_xrestore(&mu_spinlock, exceptions);
150
151 return res;
152 }
153