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