1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
4 * Copyright 2017-2022 NXP
5 */
6 #include <drivers/imx_mu.h>
7 #include <drivers/imx_sc_api.h>
8 #include <imx-regs.h>
9 #include <initcall.h>
10 #include <kernel/mutex.h>
11 #include <mm/core_memprot.h>
12 #include <tee_api_types.h>
13 #include <trace.h>
14
15 #define RNG_INIT_RETRY 100
16
17 #define SC_RPC_VERSION 1
18 #define SC_RPC_MAX_MSG 8
19
20 /* Defines for struct sc_rpc_msg svc field */
21 #define SC_RPC_SVC_PM 2
22 #define SC_RPC_SVC_RM 3
23 #define SC_RPC_SVC_SECO 9
24
25 /* Define for PM function calls */
26 enum sc_pm_func {
27 SC_PM_FUNC_SET_RESOURCE_POWER_MODE = 3
28 };
29
30 /* Defines for RM function calls */
31 enum sc_rm_func {
32 SC_RM_FUNC_GET_PARTITION = 5,
33 SC_RM_FUNC_ASSIGN_RESOURCE = 8
34 };
35
36 /* Define for SECO function calls */
37 enum sc_seco_func {
38 SC_SECO_FUNC_START_RNG = 22
39 };
40
41 /* Internal SCFW API error codes */
42 enum sc_error {
43 SC_ERR_NONE = 0, /* Success */
44 SC_ERR_VERSION, /* Incompatible API version */
45 SC_ERR_CONFIG, /* Configuration error */
46 SC_ERR_PARM, /* Bad parameter */
47 SC_ERR_NOACCESS, /* Permission error (no access) */
48 SC_ERR_LOCKED, /* Permission error (locked) */
49 SC_ERR_UNAVAILABLE, /* Unavailable (out of resources) */
50 SC_ERR_NOTFOUND, /* Not found */
51 SC_ERR_NOPOWER, /* No power */
52 SC_ERR_IPC, /* Generic IPC error */
53 SC_ERR_BUSY, /* Resource is currently busy/active */
54 SC_ERR_FAIL, /* General I/O failure */
55 SC_ERR_LAST
56 };
57
58 /* RNG SECO states */
59 enum sc_seco_rng_status {
60 SC_SECO_RNG_STAT_UNAVAILABLE = 0,
61 SC_SECO_RNG_STAT_INPROGRESS,
62 SC_SECO_RNG_STAT_READY
63 };
64
65 /* Resources IDs */
66 enum sc_resource {
67 SC_RES_CAAM_JR1 = 500,
68 SC_RES_CAAM_JR2,
69 SC_RES_CAAM_JR3,
70 SC_RES_CAAM_JR1_OUT = 514,
71 SC_RES_CAAM_JR2_OUT,
72 SC_RES_CAAM_JR3_OUT,
73 SC_RES_CAAM_JR0 = 519,
74 SC_RES_CAAM_JR0_OUT,
75 SC_RES_LAST = 546
76 };
77
78 /* Power modes */
79 enum sc_power_mode {
80 SC_PM_PW_MODE_OFF = 0,
81 SC_PM_PW_MODE_STBY,
82 SC_PM_PW_MODE_LP,
83 SC_PM_PW_MODE_ON
84 };
85
86 static vaddr_t secure_ipc_addr;
87
88 register_phys_mem(MEM_AREA_IO_SEC, SC_IPC_BASE_SECURE, SC_IPC_SIZE);
89
90 /*
91 * Get the partition ID of secure world
92 *
93 * @partition Partition ID
94 */
sc_rm_get_partition(uint8_t * partition)95 static TEE_Result sc_rm_get_partition(uint8_t *partition)
96 {
97 TEE_Result res = TEE_ERROR_GENERIC;
98 enum sc_error err = SC_ERR_LAST;
99 struct imx_mu_msg msg = {
100 .header.version = SC_RPC_VERSION,
101 .header.size = 1,
102 .header.tag = SC_RPC_SVC_RM,
103 .header.command = SC_RM_FUNC_GET_PARTITION,
104 };
105
106 res = imx_mu_call(secure_ipc_addr, &msg, true);
107 if (res != TEE_SUCCESS) {
108 EMSG("Communication error");
109 return res;
110 }
111
112 err = msg.header.command;
113 if (err != SC_ERR_NONE) {
114 EMSG("Unable to get partition ID, sc_error: %d", err);
115 return TEE_ERROR_GENERIC;
116 }
117
118 *partition = IMX_MU_DATA_U8(&msg, 0);
119
120 return TEE_SUCCESS;
121 }
122
123 /*
124 * Set the given power mode of a resource
125 *
126 * @resource ID of the resource
127 * @mode Power mode to apply
128 */
sc_pm_set_resource_power_mode(enum sc_resource resource,enum sc_power_mode mode)129 static TEE_Result sc_pm_set_resource_power_mode(enum sc_resource resource,
130 enum sc_power_mode mode)
131 {
132 TEE_Result res = TEE_ERROR_GENERIC;
133 enum sc_error scu_error = SC_ERR_LAST;
134 struct imx_mu_msg msg = {
135 .header.version = SC_RPC_VERSION,
136 .header.size = 2,
137 .header.tag = SC_RPC_SVC_PM,
138 .header.command = SC_PM_FUNC_SET_RESOURCE_POWER_MODE,
139 };
140
141 IMX_MU_DATA_U16(&msg, 0) = (uint16_t)resource;
142 IMX_MU_DATA_U8(&msg, 2) = (uint8_t)mode;
143
144 res = imx_mu_call(secure_ipc_addr, &msg, true);
145 if (res != TEE_SUCCESS) {
146 EMSG("Communication error");
147 return res;
148 }
149
150 scu_error = msg.header.command;
151 if (scu_error != SC_ERR_NONE) {
152 EMSG("Unable to set resource power mode sc_error: %d",
153 scu_error);
154 return TEE_ERROR_GENERIC;
155 }
156
157 return TEE_SUCCESS;
158 }
159
160 /*
161 * Assign ownership of a resource to the secure partition
162 *
163 * @resource Resource to assign
164 */
sc_rm_assign_resource(enum sc_resource resource)165 static TEE_Result sc_rm_assign_resource(enum sc_resource resource)
166 {
167 TEE_Result res = TEE_ERROR_GENERIC;
168 enum sc_error err = SC_ERR_LAST;
169 uint8_t secure_partition = 0;
170 struct imx_mu_msg msg = {
171 .header.version = SC_RPC_VERSION,
172 .header.size = 2,
173 .header.tag = SC_RPC_SVC_RM,
174 .header.command = SC_RM_FUNC_ASSIGN_RESOURCE,
175 };
176
177 res = sc_rm_get_partition(&secure_partition);
178 if (res != TEE_SUCCESS) {
179 EMSG("Cannot get secure partition ID");
180 return res;
181 }
182
183 IMX_MU_DATA_U16(&msg, 0) = (uint16_t)resource;
184 IMX_MU_DATA_U8(&msg, 2) = secure_partition;
185
186 res = imx_mu_call(secure_ipc_addr, &msg, true);
187 if (res != TEE_SUCCESS) {
188 EMSG("Communication error");
189 return res;
190 }
191
192 err = msg.header.command;
193 if (err != SC_ERR_NONE) {
194 EMSG("Unable to assign resource, sc_error: %d", err);
195 return TEE_ERROR_GENERIC;
196 }
197
198 return TEE_SUCCESS;
199 }
200
imx_sc_rm_enable_jr(unsigned int jr_index)201 TEE_Result imx_sc_rm_enable_jr(unsigned int jr_index)
202 {
203 TEE_Result res = TEE_ERROR_GENERIC;
204 enum sc_resource jr_res = SC_RES_LAST;
205 enum sc_resource jr_out_res = SC_RES_LAST;
206
207 switch (jr_index) {
208 case 0:
209 jr_res = SC_RES_CAAM_JR0;
210 jr_out_res = SC_RES_CAAM_JR0_OUT;
211 break;
212
213 case 1:
214 jr_res = SC_RES_CAAM_JR1;
215 jr_out_res = SC_RES_CAAM_JR1_OUT;
216 break;
217
218 case 2:
219 jr_res = SC_RES_CAAM_JR2;
220 jr_out_res = SC_RES_CAAM_JR2_OUT;
221 break;
222
223 case 3:
224 jr_res = SC_RES_CAAM_JR3;
225 jr_out_res = SC_RES_CAAM_JR3_OUT;
226 break;
227
228 default:
229 EMSG("Wrong JR Index, should be 0, 1, 2 or 3");
230 return TEE_ERROR_GENERIC;
231 }
232
233 /* Assign JR resources to secure world */
234 res = sc_rm_assign_resource(jr_res);
235 if (res != TEE_SUCCESS) {
236 EMSG("Assign SC_R_CAAM_JR%u resource failed", jr_index);
237 return res;
238 }
239
240 res = sc_rm_assign_resource(jr_out_res);
241 if (res != TEE_SUCCESS) {
242 EMSG("Assign SC_R_CAAM_JR%u_OUT resource failed", jr_index);
243 return res;
244 }
245
246 /* Power ON JR resources */
247 res = sc_pm_set_resource_power_mode(jr_res, SC_PM_PW_MODE_ON);
248 if (res != TEE_SUCCESS) {
249 EMSG("POWER ON SC_R_CAAM_JR%u resource failed", jr_index);
250 return res;
251 }
252
253 res = sc_pm_set_resource_power_mode(jr_out_res, SC_PM_PW_MODE_ON);
254 if (res != TEE_SUCCESS) {
255 EMSG("POWER ON SC_R_CAAM_JR%u_OUT resource failed", jr_index);
256 return res;
257 }
258
259 return TEE_SUCCESS;
260 }
261
imx_sc_seco_start_rng(void)262 TEE_Result imx_sc_seco_start_rng(void)
263 {
264 TEE_Result res = TEE_ERROR_GENERIC;
265 enum sc_error err = SC_ERR_LAST;
266 enum sc_seco_rng_status status = SC_SECO_RNG_STAT_UNAVAILABLE;
267 unsigned int retry = 0;
268 struct imx_mu_msg msg = {
269 .header.version = SC_RPC_VERSION,
270 .header.size = 1,
271 .header.tag = SC_RPC_SVC_SECO,
272 .header.command = SC_SECO_FUNC_START_RNG,
273 };
274
275 for (retry = RNG_INIT_RETRY; retry; retry--) {
276 res = imx_mu_call(secure_ipc_addr, &msg, true);
277 if (res != TEE_SUCCESS) {
278 EMSG("Configuration error");
279 return res;
280 }
281
282 err = msg.header.command;
283 if (err != SC_ERR_NONE) {
284 EMSG("RNG status: %d", err);
285 return TEE_ERROR_GENERIC;
286 }
287
288 status = IMX_MU_DATA_U32(&msg, 0);
289
290 if (status == SC_SECO_RNG_STAT_READY)
291 return TEE_SUCCESS;
292 }
293
294 return TEE_ERROR_GENERIC;
295 }
296
imx_sc_driver_init(void)297 TEE_Result imx_sc_driver_init(void)
298 {
299 vaddr_t va = 0;
300
301 va = core_mmu_get_va(SC_IPC_BASE_SECURE, MEM_AREA_IO_SEC, SC_IPC_SIZE);
302 if (!va)
303 return TEE_ERROR_GENERIC;
304
305 imx_mu_init(va);
306 secure_ipc_addr = va;
307
308 return TEE_SUCCESS;
309 }
310