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