1958897f5SClement Faure // SPDX-License-Identifier: BSD-2-Clause
2958897f5SClement Faure /*
3958897f5SClement Faure * Copyright (C) 2016 Freescale Semiconductor, Inc.
4*c2f16fe3SClement Faure * Copyright 2017-2022 NXP
5958897f5SClement Faure */
6958897f5SClement Faure #include <drivers/imx_mu.h>
7958897f5SClement Faure #include <drivers/imx_sc_api.h>
8958897f5SClement Faure #include <imx-regs.h>
9958897f5SClement Faure #include <initcall.h>
10958897f5SClement Faure #include <kernel/mutex.h>
11958897f5SClement Faure #include <mm/core_memprot.h>
12958897f5SClement Faure #include <tee_api_types.h>
13958897f5SClement Faure #include <trace.h>
14958897f5SClement Faure
15958897f5SClement Faure #define RNG_INIT_RETRY 100
16958897f5SClement Faure
17958897f5SClement Faure #define SC_RPC_VERSION 1
18958897f5SClement Faure #define SC_RPC_MAX_MSG 8
19958897f5SClement Faure
20958897f5SClement Faure /* Defines for struct sc_rpc_msg svc field */
21958897f5SClement Faure #define SC_RPC_SVC_PM 2
22958897f5SClement Faure #define SC_RPC_SVC_RM 3
23958897f5SClement Faure #define SC_RPC_SVC_SECO 9
24958897f5SClement Faure
25958897f5SClement Faure /* Define for PM function calls */
26958897f5SClement Faure enum sc_pm_func {
27958897f5SClement Faure SC_PM_FUNC_SET_RESOURCE_POWER_MODE = 3
28958897f5SClement Faure };
29958897f5SClement Faure
30958897f5SClement Faure /* Defines for RM function calls */
31958897f5SClement Faure enum sc_rm_func {
32958897f5SClement Faure SC_RM_FUNC_GET_PARTITION = 5,
33958897f5SClement Faure SC_RM_FUNC_ASSIGN_RESOURCE = 8
34958897f5SClement Faure };
35958897f5SClement Faure
36958897f5SClement Faure /* Define for SECO function calls */
37958897f5SClement Faure enum sc_seco_func {
38958897f5SClement Faure SC_SECO_FUNC_START_RNG = 22
39958897f5SClement Faure };
40958897f5SClement Faure
41958897f5SClement Faure /* Internal SCFW API error codes */
42958897f5SClement Faure enum sc_error {
43958897f5SClement Faure SC_ERR_NONE = 0, /* Success */
44958897f5SClement Faure SC_ERR_VERSION, /* Incompatible API version */
45958897f5SClement Faure SC_ERR_CONFIG, /* Configuration error */
46958897f5SClement Faure SC_ERR_PARM, /* Bad parameter */
47958897f5SClement Faure SC_ERR_NOACCESS, /* Permission error (no access) */
48958897f5SClement Faure SC_ERR_LOCKED, /* Permission error (locked) */
49958897f5SClement Faure SC_ERR_UNAVAILABLE, /* Unavailable (out of resources) */
50958897f5SClement Faure SC_ERR_NOTFOUND, /* Not found */
51958897f5SClement Faure SC_ERR_NOPOWER, /* No power */
52958897f5SClement Faure SC_ERR_IPC, /* Generic IPC error */
53958897f5SClement Faure SC_ERR_BUSY, /* Resource is currently busy/active */
54958897f5SClement Faure SC_ERR_FAIL, /* General I/O failure */
55958897f5SClement Faure SC_ERR_LAST
56958897f5SClement Faure };
57958897f5SClement Faure
58958897f5SClement Faure /* RNG SECO states */
59958897f5SClement Faure enum sc_seco_rng_status {
60958897f5SClement Faure SC_SECO_RNG_STAT_UNAVAILABLE = 0,
61958897f5SClement Faure SC_SECO_RNG_STAT_INPROGRESS,
62958897f5SClement Faure SC_SECO_RNG_STAT_READY
63958897f5SClement Faure };
64958897f5SClement Faure
65958897f5SClement Faure /* Resources IDs */
66958897f5SClement Faure enum sc_resource {
67958897f5SClement Faure SC_RES_CAAM_JR1 = 500,
68958897f5SClement Faure SC_RES_CAAM_JR2,
69958897f5SClement Faure SC_RES_CAAM_JR3,
70958897f5SClement Faure SC_RES_CAAM_JR1_OUT = 514,
71958897f5SClement Faure SC_RES_CAAM_JR2_OUT,
72958897f5SClement Faure SC_RES_CAAM_JR3_OUT,
73958897f5SClement Faure SC_RES_CAAM_JR0 = 519,
74958897f5SClement Faure SC_RES_CAAM_JR0_OUT,
75958897f5SClement Faure SC_RES_LAST = 546
76958897f5SClement Faure };
77958897f5SClement Faure
78958897f5SClement Faure /* Power modes */
79958897f5SClement Faure enum sc_power_mode {
80958897f5SClement Faure SC_PM_PW_MODE_OFF = 0,
81958897f5SClement Faure SC_PM_PW_MODE_STBY,
82958897f5SClement Faure SC_PM_PW_MODE_LP,
83958897f5SClement Faure SC_PM_PW_MODE_ON
84958897f5SClement Faure };
85958897f5SClement Faure
86958897f5SClement Faure static vaddr_t secure_ipc_addr;
87958897f5SClement Faure
88958897f5SClement Faure register_phys_mem(MEM_AREA_IO_SEC, SC_IPC_BASE_SECURE, SC_IPC_SIZE);
89958897f5SClement Faure
90958897f5SClement Faure /*
91958897f5SClement Faure * Get the partition ID of secure world
92958897f5SClement Faure *
93958897f5SClement Faure * @partition Partition ID
94958897f5SClement Faure */
sc_rm_get_partition(uint8_t * partition)95958897f5SClement Faure static TEE_Result sc_rm_get_partition(uint8_t *partition)
96958897f5SClement Faure {
97958897f5SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
98958897f5SClement Faure enum sc_error err = SC_ERR_LAST;
99*c2f16fe3SClement Faure struct imx_mu_msg msg = {
100958897f5SClement Faure .header.version = SC_RPC_VERSION,
101958897f5SClement Faure .header.size = 1,
102*c2f16fe3SClement Faure .header.tag = SC_RPC_SVC_RM,
103*c2f16fe3SClement Faure .header.command = SC_RM_FUNC_GET_PARTITION,
104958897f5SClement Faure };
105958897f5SClement Faure
106*c2f16fe3SClement Faure res = imx_mu_call(secure_ipc_addr, &msg, true);
107958897f5SClement Faure if (res != TEE_SUCCESS) {
108958897f5SClement Faure EMSG("Communication error");
109958897f5SClement Faure return res;
110958897f5SClement Faure }
111958897f5SClement Faure
112*c2f16fe3SClement Faure err = msg.header.command;
113958897f5SClement Faure if (err != SC_ERR_NONE) {
114958897f5SClement Faure EMSG("Unable to get partition ID, sc_error: %d", err);
115958897f5SClement Faure return TEE_ERROR_GENERIC;
116958897f5SClement Faure }
117958897f5SClement Faure
118*c2f16fe3SClement Faure *partition = IMX_MU_DATA_U8(&msg, 0);
119958897f5SClement Faure
120958897f5SClement Faure return TEE_SUCCESS;
121958897f5SClement Faure }
122958897f5SClement Faure
123958897f5SClement Faure /*
124958897f5SClement Faure * Set the given power mode of a resource
125958897f5SClement Faure *
126958897f5SClement Faure * @resource ID of the resource
127958897f5SClement Faure * @mode Power mode to apply
128958897f5SClement Faure */
sc_pm_set_resource_power_mode(enum sc_resource resource,enum sc_power_mode mode)129958897f5SClement Faure static TEE_Result sc_pm_set_resource_power_mode(enum sc_resource resource,
130958897f5SClement Faure enum sc_power_mode mode)
131958897f5SClement Faure {
132958897f5SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
133958897f5SClement Faure enum sc_error scu_error = SC_ERR_LAST;
134*c2f16fe3SClement Faure struct imx_mu_msg msg = {
135958897f5SClement Faure .header.version = SC_RPC_VERSION,
136958897f5SClement Faure .header.size = 2,
137*c2f16fe3SClement Faure .header.tag = SC_RPC_SVC_PM,
138*c2f16fe3SClement Faure .header.command = SC_PM_FUNC_SET_RESOURCE_POWER_MODE,
139958897f5SClement Faure };
140958897f5SClement Faure
141*c2f16fe3SClement Faure IMX_MU_DATA_U16(&msg, 0) = (uint16_t)resource;
142*c2f16fe3SClement Faure IMX_MU_DATA_U8(&msg, 2) = (uint8_t)mode;
143958897f5SClement Faure
144*c2f16fe3SClement Faure res = imx_mu_call(secure_ipc_addr, &msg, true);
145958897f5SClement Faure if (res != TEE_SUCCESS) {
146958897f5SClement Faure EMSG("Communication error");
147958897f5SClement Faure return res;
148958897f5SClement Faure }
149958897f5SClement Faure
150*c2f16fe3SClement Faure scu_error = msg.header.command;
151958897f5SClement Faure if (scu_error != SC_ERR_NONE) {
152958897f5SClement Faure EMSG("Unable to set resource power mode sc_error: %d",
153958897f5SClement Faure scu_error);
154958897f5SClement Faure return TEE_ERROR_GENERIC;
155958897f5SClement Faure }
156958897f5SClement Faure
157958897f5SClement Faure return TEE_SUCCESS;
158958897f5SClement Faure }
159958897f5SClement Faure
160958897f5SClement Faure /*
161958897f5SClement Faure * Assign ownership of a resource to the secure partition
162958897f5SClement Faure *
163958897f5SClement Faure * @resource Resource to assign
164958897f5SClement Faure */
sc_rm_assign_resource(enum sc_resource resource)165958897f5SClement Faure static TEE_Result sc_rm_assign_resource(enum sc_resource resource)
166958897f5SClement Faure {
167958897f5SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
168958897f5SClement Faure enum sc_error err = SC_ERR_LAST;
169958897f5SClement Faure uint8_t secure_partition = 0;
170*c2f16fe3SClement Faure struct imx_mu_msg msg = {
171958897f5SClement Faure .header.version = SC_RPC_VERSION,
172958897f5SClement Faure .header.size = 2,
173*c2f16fe3SClement Faure .header.tag = SC_RPC_SVC_RM,
174*c2f16fe3SClement Faure .header.command = SC_RM_FUNC_ASSIGN_RESOURCE,
175958897f5SClement Faure };
176958897f5SClement Faure
177958897f5SClement Faure res = sc_rm_get_partition(&secure_partition);
178958897f5SClement Faure if (res != TEE_SUCCESS) {
179958897f5SClement Faure EMSG("Cannot get secure partition ID");
180958897f5SClement Faure return res;
181958897f5SClement Faure }
182958897f5SClement Faure
183*c2f16fe3SClement Faure IMX_MU_DATA_U16(&msg, 0) = (uint16_t)resource;
184*c2f16fe3SClement Faure IMX_MU_DATA_U8(&msg, 2) = secure_partition;
185958897f5SClement Faure
186*c2f16fe3SClement Faure res = imx_mu_call(secure_ipc_addr, &msg, true);
187958897f5SClement Faure if (res != TEE_SUCCESS) {
188958897f5SClement Faure EMSG("Communication error");
189958897f5SClement Faure return res;
190958897f5SClement Faure }
191958897f5SClement Faure
192*c2f16fe3SClement Faure err = msg.header.command;
193958897f5SClement Faure if (err != SC_ERR_NONE) {
194958897f5SClement Faure EMSG("Unable to assign resource, sc_error: %d", err);
195958897f5SClement Faure return TEE_ERROR_GENERIC;
196958897f5SClement Faure }
197958897f5SClement Faure
198958897f5SClement Faure return TEE_SUCCESS;
199958897f5SClement Faure }
200958897f5SClement Faure
imx_sc_rm_enable_jr(unsigned int jr_index)201958897f5SClement Faure TEE_Result imx_sc_rm_enable_jr(unsigned int jr_index)
202958897f5SClement Faure {
203958897f5SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
204958897f5SClement Faure enum sc_resource jr_res = SC_RES_LAST;
205958897f5SClement Faure enum sc_resource jr_out_res = SC_RES_LAST;
206958897f5SClement Faure
207958897f5SClement Faure switch (jr_index) {
208958897f5SClement Faure case 0:
209958897f5SClement Faure jr_res = SC_RES_CAAM_JR0;
210958897f5SClement Faure jr_out_res = SC_RES_CAAM_JR0_OUT;
211958897f5SClement Faure break;
212958897f5SClement Faure
213958897f5SClement Faure case 1:
214958897f5SClement Faure jr_res = SC_RES_CAAM_JR1;
215958897f5SClement Faure jr_out_res = SC_RES_CAAM_JR1_OUT;
216958897f5SClement Faure break;
217958897f5SClement Faure
218958897f5SClement Faure case 2:
219958897f5SClement Faure jr_res = SC_RES_CAAM_JR2;
220958897f5SClement Faure jr_out_res = SC_RES_CAAM_JR2_OUT;
221958897f5SClement Faure break;
222958897f5SClement Faure
223958897f5SClement Faure case 3:
224958897f5SClement Faure jr_res = SC_RES_CAAM_JR3;
225958897f5SClement Faure jr_out_res = SC_RES_CAAM_JR3_OUT;
226958897f5SClement Faure break;
227958897f5SClement Faure
228958897f5SClement Faure default:
229958897f5SClement Faure EMSG("Wrong JR Index, should be 0, 1, 2 or 3");
230958897f5SClement Faure return TEE_ERROR_GENERIC;
231958897f5SClement Faure }
232958897f5SClement Faure
233958897f5SClement Faure /* Assign JR resources to secure world */
234958897f5SClement Faure res = sc_rm_assign_resource(jr_res);
235958897f5SClement Faure if (res != TEE_SUCCESS) {
236958897f5SClement Faure EMSG("Assign SC_R_CAAM_JR%u resource failed", jr_index);
237958897f5SClement Faure return res;
238958897f5SClement Faure }
239958897f5SClement Faure
240958897f5SClement Faure res = sc_rm_assign_resource(jr_out_res);
241958897f5SClement Faure if (res != TEE_SUCCESS) {
242958897f5SClement Faure EMSG("Assign SC_R_CAAM_JR%u_OUT resource failed", jr_index);
243958897f5SClement Faure return res;
244958897f5SClement Faure }
245958897f5SClement Faure
246958897f5SClement Faure /* Power ON JR resources */
247958897f5SClement Faure res = sc_pm_set_resource_power_mode(jr_res, SC_PM_PW_MODE_ON);
248958897f5SClement Faure if (res != TEE_SUCCESS) {
249958897f5SClement Faure EMSG("POWER ON SC_R_CAAM_JR%u resource failed", jr_index);
250958897f5SClement Faure return res;
251958897f5SClement Faure }
252958897f5SClement Faure
253958897f5SClement Faure res = sc_pm_set_resource_power_mode(jr_out_res, SC_PM_PW_MODE_ON);
254958897f5SClement Faure if (res != TEE_SUCCESS) {
255958897f5SClement Faure EMSG("POWER ON SC_R_CAAM_JR%u_OUT resource failed", jr_index);
256958897f5SClement Faure return res;
257958897f5SClement Faure }
258958897f5SClement Faure
259958897f5SClement Faure return TEE_SUCCESS;
260958897f5SClement Faure }
261958897f5SClement Faure
imx_sc_seco_start_rng(void)262958897f5SClement Faure TEE_Result imx_sc_seco_start_rng(void)
263958897f5SClement Faure {
264958897f5SClement Faure TEE_Result res = TEE_ERROR_GENERIC;
265958897f5SClement Faure enum sc_error err = SC_ERR_LAST;
266958897f5SClement Faure enum sc_seco_rng_status status = SC_SECO_RNG_STAT_UNAVAILABLE;
267958897f5SClement Faure unsigned int retry = 0;
268*c2f16fe3SClement Faure struct imx_mu_msg msg = {
269958897f5SClement Faure .header.version = SC_RPC_VERSION,
270958897f5SClement Faure .header.size = 1,
271*c2f16fe3SClement Faure .header.tag = SC_RPC_SVC_SECO,
272*c2f16fe3SClement Faure .header.command = SC_SECO_FUNC_START_RNG,
273958897f5SClement Faure };
274958897f5SClement Faure
275958897f5SClement Faure for (retry = RNG_INIT_RETRY; retry; retry--) {
276*c2f16fe3SClement Faure res = imx_mu_call(secure_ipc_addr, &msg, true);
277958897f5SClement Faure if (res != TEE_SUCCESS) {
278958897f5SClement Faure EMSG("Configuration error");
279958897f5SClement Faure return res;
280958897f5SClement Faure }
281958897f5SClement Faure
282*c2f16fe3SClement Faure err = msg.header.command;
283958897f5SClement Faure if (err != SC_ERR_NONE) {
284958897f5SClement Faure EMSG("RNG status: %d", err);
285958897f5SClement Faure return TEE_ERROR_GENERIC;
286958897f5SClement Faure }
287958897f5SClement Faure
288*c2f16fe3SClement Faure status = IMX_MU_DATA_U32(&msg, 0);
289958897f5SClement Faure
290958897f5SClement Faure if (status == SC_SECO_RNG_STAT_READY)
291958897f5SClement Faure return TEE_SUCCESS;
292958897f5SClement Faure }
293958897f5SClement Faure
294958897f5SClement Faure return TEE_ERROR_GENERIC;
295958897f5SClement Faure }
296958897f5SClement Faure
imx_sc_driver_init(void)297958897f5SClement Faure TEE_Result imx_sc_driver_init(void)
298958897f5SClement Faure {
299958897f5SClement Faure vaddr_t va = 0;
300958897f5SClement Faure
301958897f5SClement Faure va = core_mmu_get_va(SC_IPC_BASE_SECURE, MEM_AREA_IO_SEC, SC_IPC_SIZE);
302958897f5SClement Faure if (!va)
303958897f5SClement Faure return TEE_ERROR_GENERIC;
304958897f5SClement Faure
305*c2f16fe3SClement Faure imx_mu_init(va);
306958897f5SClement Faure secure_ipc_addr = va;
307958897f5SClement Faure
308958897f5SClement Faure return TEE_SUCCESS;
309958897f5SClement Faure }
310