1 /*
2 * Copyright 2021 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <errno.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <arch_helpers.h>
16 #include "caam.h"
17 #include <common/debug.h>
18 #include "jobdesc.h"
19 #include "sec_hw_specific.h"
20
21 static uintptr_t g_nxp_caam_addr;
22 static void *job_ring;
23
get_caam_addr(void)24 uintptr_t get_caam_addr(void)
25 {
26 if (g_nxp_caam_addr == 0) {
27 ERROR("Sec Init is not done.\n");
28 panic();
29 }
30 return g_nxp_caam_addr;
31 }
32
33 /* This function sets the TZ bit for the Job ring number passed as @num */
config_tz(int num)34 static void config_tz(int num)
35 {
36 uint32_t jricid;
37
38 /* Setting TZ bit of job ring */
39 switch (num) {
40 case 0:
41 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET);
42 sec_out32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET,
43 jricid | JRICID_MS_TZ);
44 break;
45 case 1:
46 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET);
47 sec_out32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET,
48 jricid | JRICID_MS_TZ);
49 break;
50 case 2:
51 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET);
52 sec_out32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET,
53 jricid | JRICID_MS_TZ);
54 break;
55 case 3:
56 jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET);
57 sec_out32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET,
58 jricid | JRICID_MS_TZ);
59 break;
60 default:
61 break;
62 }
63 }
64
65 /* This function checks if Virtualization is enabled for JR and
66 * accordingly sets the bot for starting JR<num> in JRSTARTR register
67 */
start_jr(int num)68 static inline void start_jr(int num)
69 {
70 uint32_t ctpr = sec_in32((g_nxp_caam_addr + SEC_REG_CTPR_MS_OFFSET));
71 uint32_t tmp = sec_in32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET));
72 uint32_t scfgr = sec_in32((g_nxp_caam_addr + SEC_REG_SCFGR_OFFSET));
73 bool start = false;
74
75 if ((ctpr & CTPR_VIRT_EN_INC) != 0U) {
76 if (((ctpr & CTPR_VIRT_EN_POR) != 0U) ||
77 ((scfgr & SCFGR_VIRT_EN) != 0U)) {
78 start = true;
79 }
80 } else {
81 if ((ctpr & CTPR_VIRT_EN_POR) != 0U) {
82 start = true;
83 }
84 }
85
86 if (start == true) {
87 switch (num) {
88 case 0:
89 tmp |= JRSTARTR_STARTJR0;
90 break;
91 case 1:
92 tmp |= JRSTARTR_STARTJR1;
93 break;
94 case 2:
95 tmp |= JRSTARTR_STARTJR2;
96 break;
97 case 3:
98 tmp |= JRSTARTR_STARTJR3;
99 break;
100 default:
101 break;
102 }
103 }
104 sec_out32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET), tmp);
105 }
106
107 /* This functions configures the Job Ring
108 * JR3 is reserved for use by Secure world
109 */
configure_jr(int num)110 static int configure_jr(int num)
111 {
112 int ret;
113 void *reg_base_addr;
114
115 switch (num) {
116 case 0:
117 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR0_OFFSET);
118 break;
119 case 1:
120 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR1_OFFSET);
121 break;
122 case 2:
123 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR2_OFFSET);
124 break;
125 case 3:
126 reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR3_OFFSET);
127 break;
128 default:
129 break;
130 }
131
132 /* Initialize the JR library */
133 ret = sec_jr_lib_init();
134 if (ret != 0) {
135 ERROR("Error in sec_jr_lib_init");
136 return -1;
137 }
138
139 start_jr(num);
140
141 /* Do HW configuration of the JR */
142 job_ring = init_job_ring(SEC_NOTIFICATION_TYPE_POLL, 0, 0,
143 reg_base_addr, 0);
144
145 if (job_ring == NULL) {
146 ERROR("Error in init_job_ring");
147 return -1;
148 }
149
150 return ret;
151 }
152
153 /* TBD - Configures and locks the ICID values for various JR */
configure_icid(void)154 static inline void configure_icid(void)
155 {
156 }
157
158 /* TBD configures the TZ settings of RTIC */
configure_rtic(void)159 static inline void configure_rtic(void)
160 {
161 }
162
sec_init(uintptr_t nxp_caam_addr)163 int sec_init(uintptr_t nxp_caam_addr)
164 {
165 g_nxp_caam_addr = nxp_caam_addr;
166 return config_sec_block();
167 }
168
169 /* This function configure SEC block:
170 * - It does basic parameter setting
171 * - Configures the default Job ring assigned to TZ /secure world
172 * - Instantiates the RNG
173 */
config_sec_block(void)174 int config_sec_block(void)
175 {
176 int ret = 0;
177 uint32_t mcfgr;
178
179 if (g_nxp_caam_addr == 0) {
180 ERROR("Sec Init is not done.\n");
181 return -1;
182 } else if (job_ring != NULL) {
183 NOTICE("Sec is already initialized and configured.\n");
184 return ret;
185 }
186
187 mcfgr = sec_in32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET);
188
189 /* Modify CAAM Read/Write attributes
190 * AXI Write - Cacheable, WB and WA
191 * AXI Read - Cacheable, RA
192 */
193 #if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS2088A)
194 mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0xb << MCFGR_AWCACHE_SHIFT);
195 mcfgr = (mcfgr & ~MCFGR_ARCACHE_MASK) | (0x6 << MCFGR_ARCACHE_SHIFT);
196 #else
197 mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT);
198 #endif
199
200 /* Set PS bit to 1 */
201 #ifdef CONFIG_PHYS_64BIT
202 mcfgr |= (1 << MCFGR_PS_SHIFT);
203 #endif
204 sec_out32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET, mcfgr);
205
206 /* Asssign ICID to all Job rings and lock them for usage */
207 configure_icid();
208
209 /* Configure the RTIC */
210 configure_rtic();
211
212 /* Configure the default JR for usage */
213 ret = configure_jr(DEFAULT_JR);
214 if (ret != 0) {
215 ERROR("\nFSL_JR: configuration failure\n");
216 return -1;
217 }
218 /* Do TZ configuration of default JR for sec firmware */
219 config_tz(DEFAULT_JR);
220
221 #ifdef CONFIG_RNG_INIT
222 /* Instantiate the RNG */
223 ret = hw_rng_instantiate();
224 if (ret != 0) {
225 ERROR("\nRNG Instantiation failure\n");
226 return -1;
227 }
228 #endif
229
230 return ret;
231 }
232
233 /* This function is used for sumbitting job to the Job Ring
234 * [param] [in] - jobdesc to be submitted
235 * Return - -1 in case of error and 0 in case of SUCCESS
236 */
run_descriptor_jr(struct job_descriptor * jobdesc)237 int run_descriptor_jr(struct job_descriptor *jobdesc)
238 {
239 int i = 0, ret = 0;
240 uint32_t *desc_addr = jobdesc->desc;
241 uint32_t desc_len = desc_length(jobdesc->desc);
242 uint32_t desc_word;
243
244 for (i = 0; i < desc_len; i++) {
245 desc_word = desc_addr[i];
246 VERBOSE("%x\n", desc_word);
247 sec_out32((uint32_t *)&desc_addr[i], desc_word);
248 }
249 dsb();
250
251 #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
252 flush_dcache_range((uintptr_t)desc_addr, desc_len * 4);
253 dmbsy();
254 dsbsy();
255 isb();
256 #endif
257
258 ret = enq_jr_desc(job_ring, jobdesc);
259 if (ret == 0) {
260 VERBOSE("JR enqueue done...\n");
261 } else {
262 ERROR("Error in Enqueue\n");
263 return ret;
264 }
265
266 VERBOSE("Dequeue in progress");
267
268 ret = dequeue_jr(job_ring, -1);
269 if (ret >= 0) {
270 VERBOSE("Dequeue of %x desc success\n", ret);
271 ret = 0;
272 } else {
273 ERROR("deq_ret %x\n", ret);
274 ret = -1;
275 }
276
277 return ret;
278 }
279
280 /* this function returns a random number using HW RNG Algo
281 * In case of failure, random number returned is 0
282 * prngWidth = 0 - 32 bit random number
283 * prngWidth > 0 means 64 bit random number
284 */
get_random(int rngWidth)285 unsigned long long get_random(int rngWidth)
286 {
287 unsigned long long result = 0;
288 uint8_t rand_byte[64] __aligned(CACHE_WRITEBACK_GRANULE);
289 uint8_t rand_byte_swp[8];
290 int bytes = 0;
291 int i = 0;
292 int ret = 0;
293
294 #ifdef CAAM_TEST
295 rand_byte[0] = U(0x12);
296 rand_byte[1] = U(0x34);
297 rand_byte[2] = U(0x56);
298 rand_byte[3] = U(0x78);
299 rand_byte[4] = U(0x9a);
300 rand_byte[5] = U(0xbc);
301 rand_byte[6] = U(0xde);
302 rand_byte[7] = U(0xf1);
303 #endif
304
305 if (rngWidth == 0U) {
306 bytes = 4;
307 } else {
308 bytes = 8;
309 }
310
311 memset(rand_byte, 0, 64);
312
313 ret = get_rand_bytes_hw(rand_byte, bytes);
314
315 for (i = 0; i < bytes; i++) {
316 if (ret != 0) {
317 /* Return 0 in case of failure */
318 rand_byte_swp[i] = 0;
319 } else {
320 rand_byte_swp[i] = rand_byte[bytes - i - 1];
321 result = (result << 8) | rand_byte_swp[i];
322 }
323 }
324
325 INFO("result %llx\n", result);
326
327 return result;
328
329 } /* _get_RNG() */
330
_get_hw_unq_key(uint64_t hw_key_phy_addr,unsigned int size)331 unsigned int _get_hw_unq_key(uint64_t hw_key_phy_addr, unsigned int size)
332 {
333 int ret = 0;
334 uint8_t *hw_key = (uint8_t *) ptov((phys_addr_t *) hw_key_phy_addr);
335
336 ret = get_hw_unq_key_blob_hw(hw_key, size);
337
338 return ret;
339 }
340