blob: 5bd52b9d1e641d47d627f26aefde44f4039e491e [file] [log] [blame]
Marvin Hsu21eea972017-04-11 11:00:48 +08001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include <arch_helpers.h>
9#include <assert.h>
10#include <common/debug.h>
11#include <delay_timer.h>
12#include <errno.h>
13#include <mmio.h>
14#include <psci.h>
15#include <se_private.h>
16#include <security_engine.h>
17#include <tegra_platform.h>
18
19/*******************************************************************************
20 * Constants and Macros
21 ******************************************************************************/
22
23#define TIMEOUT_100MS 100UL // Timeout in 100ms
24
25/*******************************************************************************
26 * Data structure and global variables
27 ******************************************************************************/
28
29/* The security engine contexts are formatted as follows:
30 *
31 * SE1 CONTEXT:
32 * #--------------------------------#
33 * | Random Data 1 Block |
34 * #--------------------------------#
35 * | Sticky Bits 2 Blocks |
36 * #--------------------------------#
37 * | Key Table 64 Blocks |
38 * | For each Key (x16): |
39 * | Key: 2 Blocks |
40 * | Original-IV: 1 Block |
41 * | Updated-IV: 1 Block |
42 * #--------------------------------#
43 * | RSA Keys 64 Blocks |
44 * #--------------------------------#
45 * | Known Pattern 1 Block |
46 * #--------------------------------#
47 *
48 * SE2/PKA1 CONTEXT:
49 * #--------------------------------#
50 * | Random Data 1 Block |
51 * #--------------------------------#
52 * | Sticky Bits 2 Blocks |
53 * #--------------------------------#
54 * | Key Table 64 Blocks |
55 * | For each Key (x16): |
56 * | Key: 2 Blocks |
57 * | Original-IV: 1 Block |
58 * | Updated-IV: 1 Block |
59 * #--------------------------------#
60 * | RSA Keys 64 Blocks |
61 * #--------------------------------#
62 * | PKA sticky bits 1 Block |
63 * #--------------------------------#
64 * | PKA keys 512 Blocks |
65 * #--------------------------------#
66 * | Known Pattern 1 Block |
67 * #--------------------------------#
68 */
69
70/* SE input and output linked list buffers */
71static tegra_se_io_lst_t se1_src_ll_buf;
72static tegra_se_io_lst_t se1_dst_ll_buf;
73
74/* SE2 input and output linked list buffers */
75static tegra_se_io_lst_t se2_src_ll_buf;
76static tegra_se_io_lst_t se2_dst_ll_buf;
77
78/* SE1 security engine device handle */
79static tegra_se_dev_t se_dev_1 = {
80 .se_num = 1,
81 /* setup base address for se */
82 .se_base = TEGRA_SE1_BASE,
83 /* Setup context size in AES blocks */
84 .ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE1,
85 /* Setup SRC buffers for SE operations */
86 .src_ll_buf = &se1_src_ll_buf,
87 /* Setup DST buffers for SE operations */
88 .dst_ll_buf = &se1_dst_ll_buf,
89};
90
91/* SE2 security engine device handle */
92static tegra_se_dev_t se_dev_2 = {
93 .se_num = 2,
94 /* setup base address for se */
95 .se_base = TEGRA_SE2_BASE,
96 /* Setup context size in AES blocks */
97 .ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE2,
98 /* Setup SRC buffers for SE operations */
99 .src_ll_buf = &se2_src_ll_buf,
100 /* Setup DST buffers for SE operations */
101 .dst_ll_buf = &se2_dst_ll_buf,
102};
103
104/*******************************************************************************
105 * Functions Definition
106 ******************************************************************************/
107
108static void tegra_se_make_data_coherent(const tegra_se_dev_t *se_dev)
109{
110 flush_dcache_range(((uint64_t)(se_dev->src_ll_buf)),
111 sizeof(tegra_se_io_lst_t));
112 flush_dcache_range(((uint64_t)(se_dev->dst_ll_buf)),
113 sizeof(tegra_se_io_lst_t));
114}
115
116/*
Sam Payne809c7732017-05-15 11:10:37 -0700117 * Check that SE operation has completed after kickoff
118 * This function is invoked after an SE operation has been started,
Marvin Hsu21eea972017-04-11 11:00:48 +0800119 * and it checks the following conditions:
120 * 1. SE_INT_STATUS = SE_OP_DONE
121 * 2. SE_STATUS = IDLE
122 * 3. AHB bus data transfer complete.
123 * 4. SE_ERR_STATUS is clean.
124 */
Sam Payne809c7732017-05-15 11:10:37 -0700125static int32_t tegra_se_operation_complete(const tegra_se_dev_t *se_dev)
Marvin Hsu21eea972017-04-11 11:00:48 +0800126{
127 uint32_t val = 0;
128 int32_t ret = 0;
129 uint32_t timeout;
130
131 /* Poll the SE interrupt register to ensure H/W operation complete */
132 val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
133 for (timeout = 0; (SE_INT_OP_DONE(val) == SE_INT_OP_DONE_CLEAR) &&
134 (timeout < TIMEOUT_100MS); timeout++) {
135 mdelay(1);
136 val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
137 }
138
139 if (timeout == TIMEOUT_100MS) {
140 ERROR("%s: ERR: Atomic context save operation timeout!\n",
141 __func__);
142 ret = -ETIMEDOUT;
143 }
144
145 /* Poll the SE status idle to ensure H/W operation complete */
146 if (ret == 0) {
147 val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
148 for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS);
149 timeout++) {
150 mdelay(1);
151 val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
152 }
153
154 if (timeout == TIMEOUT_100MS) {
155 ERROR("%s: ERR: MEM_INTERFACE and SE state "
156 "idle state timeout.\n", __func__);
157 ret = -ETIMEDOUT;
158 }
159 }
160
161 /* Check AHB bus transfer complete */
162 if (ret == 0) {
163 val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET);
164 for (timeout = 0; ((val & (ARAHB_MST_ID_SE_MASK | ARAHB_MST_ID_SE2_MASK)) != 0U) &&
165 (timeout < TIMEOUT_100MS); timeout++) {
166 mdelay(1);
167 val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET);
168 }
169
170 if (timeout == TIMEOUT_100MS) {
171 ERROR("%s: SE write over AHB timeout.\n", __func__);
172 ret = -ETIMEDOUT;
173 }
174 }
175
176 /* Ensure that no errors are thrown during operation */
177 if (ret == 0) {
178 val = tegra_se_read_32(se_dev, SE_ERR_STATUS_REG_OFFSET);
179 if (val != 0U) {
180 ERROR("%s: error during SE operation! 0x%x", __func__, val);
181 ret = -ENOTSUP;
182 }
183 }
184
185 return ret;
186}
187
188/*
Samuel Payne25fdca22017-06-15 13:57:47 -0700189 * Returns true if the SE engine is configured to perform SE context save in
190 * hardware.
Marvin Hsu21eea972017-04-11 11:00:48 +0800191 */
Samuel Payne25fdca22017-06-15 13:57:47 -0700192static inline int32_t tegra_se_atomic_save_enabled(const tegra_se_dev_t *se_dev)
Marvin Hsu21eea972017-04-11 11:00:48 +0800193{
194 uint32_t val;
195 int32_t ret = 0;
196
197 val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
Samuel Payne25fdca22017-06-15 13:57:47 -0700198 if (SE_CTX_SAVE_AUTO_ENABLE(val) == SE_CTX_SAVE_AUTO_EN)
199 ret = 1;
Marvin Hsu21eea972017-04-11 11:00:48 +0800200
201 return ret;
202}
203
204/*
Sam Payne809c7732017-05-15 11:10:37 -0700205 * Wait for SE engine to be idle and clear pending interrupts before
206 * starting the next SE operation.
Marvin Hsu21eea972017-04-11 11:00:48 +0800207 */
Sam Payne809c7732017-05-15 11:10:37 -0700208static int32_t tegra_se_operation_prepare(const tegra_se_dev_t *se_dev)
Marvin Hsu21eea972017-04-11 11:00:48 +0800209{
210 int32_t ret = 0;
211 uint32_t val = 0;
Sam Payne809c7732017-05-15 11:10:37 -0700212 uint32_t timeout;
Marvin Hsu21eea972017-04-11 11:00:48 +0800213
214 /* Wait for previous operation to finish */
215 val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
216 for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS); timeout++) {
217 mdelay(1);
218 val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
219 }
220
221 if (timeout == TIMEOUT_100MS) {
222 ERROR("%s: ERR: SE status is not idle!\n", __func__);
223 ret = -ETIMEDOUT;
224 }
225
Sam Payne809c7732017-05-15 11:10:37 -0700226 /* Clear any pending interrupts from previous operation */
227 val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
228 tegra_se_write_32(se_dev, SE_INT_STATUS_REG_OFFSET, val);
229 return ret;
230}
231
232/*
233 * SE atomic context save. At SC7 entry, SE driver triggers the
234 * hardware automatically performs the context save operation.
235 */
236static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev)
237{
238 int32_t ret = 0;
239 uint32_t val = 0;
240 uint32_t blk_count_limit = 0;
241 uint32_t block_count;
242
243 /* Check that previous operation is finalized */
244 ret = tegra_se_operation_prepare(se_dev);
Marvin Hsu21eea972017-04-11 11:00:48 +0800245
Sam Payne809c7732017-05-15 11:10:37 -0700246 /* Ensure HW atomic context save has been enabled
247 * This should have been done at boot time.
248 * SE_CTX_SAVE_AUTO.ENABLE == ENABLE
249 */
250 if (ret == 0) {
Samuel Payne25fdca22017-06-15 13:57:47 -0700251 ret = tegra_se_atomic_save_enabled(se_dev);
Marvin Hsu21eea972017-04-11 11:00:48 +0800252 }
253
254 /* Read the context save progress counter: block_count
255 * Ensure no previous context save has been triggered
256 * SE_CTX_SAVE_AUTO.CURR_CNT == 0
257 */
258 if (ret == 0) {
259 val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
260 block_count = SE_CTX_SAVE_GET_BLK_COUNT(val);
261 if (block_count != 0U) {
262 ERROR("%s: ctx_save triggered multiple times\n",
263 __func__);
264 ret = -EALREADY;
265 }
266 }
267
268 /* Set the destination block count when the context save complete */
269 if (ret == 0) {
270 blk_count_limit = block_count + se_dev->ctx_size_blks;
271 }
272
273 /* Program SE_CONFIG register as for RNG operation
274 * SE_CONFIG.ENC_ALG = RNG
275 * SE_CONFIG.DEC_ALG = NOP
276 * SE_CONFIG.ENC_MODE is ignored
277 * SE_CONFIG.DEC_MODE is ignored
278 * SE_CONFIG.DST = MEMORY
279 */
280 if (ret == 0) {
281 val = (SE_CONFIG_ENC_ALG_RNG |
282 SE_CONFIG_DEC_ALG_NOP |
283 SE_CONFIG_DST_MEMORY);
284 tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
285
286 tegra_se_make_data_coherent(se_dev);
287
288 /* SE_CTX_SAVE operation */
289 tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET,
290 SE_OP_CTX_SAVE);
291
Sam Payne809c7732017-05-15 11:10:37 -0700292 ret = tegra_se_operation_complete(se_dev);
Marvin Hsu21eea972017-04-11 11:00:48 +0800293 }
294
295 /* Check that context has written the correct number of blocks */
296 if (ret == 0) {
297 val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
298 if (SE_CTX_SAVE_GET_BLK_COUNT(val) != blk_count_limit) {
299 ERROR("%s: expected %d blocks but %d were written\n",
300 __func__, blk_count_limit, val);
301 ret = -ECANCELED;
302 }
303 }
304
305 return ret;
306}
307
308/*
Sam Payne809c7732017-05-15 11:10:37 -0700309 * Security engine primitive operations, including normal operation
310 * and the context save operation.
311 */
312static int tegra_se_perform_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes)
313{
314 uint32_t nblocks = nbytes / TEGRA_SE_AES_BLOCK_SIZE;
315 int ret = 0;
316
317 assert(se_dev);
318
319 /* Use device buffers for in and out */
320 tegra_se_write_32(se_dev, SE_OUT_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->dst_ll_buf)));
321 tegra_se_write_32(se_dev, SE_IN_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->src_ll_buf)));
322
323 /* Check that previous operation is finalized */
324 ret = tegra_se_operation_prepare(se_dev);
325 if (ret != 0) {
326 goto op_error;
327 }
328
329 /* Program SE operation size */
330 if (nblocks) {
331 tegra_se_write_32(se_dev, SE_BLOCK_COUNT_REG_OFFSET, nblocks - 1);
332 }
333
334 /* Make SE LL data coherent before the SE operation */
335 tegra_se_make_data_coherent(se_dev);
336
337 /* Start hardware operation */
338 tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_START);
339
340 /* Wait for operation to finish */
341 ret = tegra_se_operation_complete(se_dev);
342
343op_error:
344 return ret;
345}
346
347/*
348 * Security Engine sequence to generat SRK
349 * SE and SE2 will generate different SRK by different
350 * entropy seeds.
351 */
352static int tegra_se_generate_srk(const tegra_se_dev_t *se_dev)
353{
354 int ret = PSCI_E_INTERN_FAIL;
355 uint32_t val;
356
357 /* Confgure the following hardware register settings:
358 * SE_CONFIG.DEC_ALG = NOP
359 * SE_CONFIG.ENC_ALG = RNG
360 * SE_CONFIG.DST = SRK
361 * SE_OPERATION.OP = START
362 * SE_CRYPTO_LAST_BLOCK = 0
363 */
364 se_dev->src_ll_buf->last_buff_num = 0;
365 se_dev->dst_ll_buf->last_buff_num = 0;
366
367 /* Configure random number generator */
368 val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_ENTROPY);
369 tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val);
370
371 /* Configure output destination = SRK */
372 val = (SE_CONFIG_ENC_ALG_RNG |
373 SE_CONFIG_DEC_ALG_NOP |
374 SE_CONFIG_DST_SRK);
375 tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
376
377 /* Perform hardware operation */
378 ret = tegra_se_perform_operation(se_dev, 0);
379
380 return ret;
381}
382
383/*
Marvin Hsu21eea972017-04-11 11:00:48 +0800384 * Initialize the SE engine handle
385 */
386void tegra_se_init(void)
387{
388 INFO("%s: start SE init\n", __func__);
389
Sam Payne809c7732017-05-15 11:10:37 -0700390 /* Generate random SRK to initialize DRBG */
391 tegra_se_generate_srk(&se_dev_1);
392 tegra_se_generate_srk(&se_dev_2);
Marvin Hsu21eea972017-04-11 11:00:48 +0800393
394 INFO("%s: SE init done\n", __func__);
395}
396
Samuel Payne1e6bed42017-06-12 10:15:43 -0700397static void tegra_se_enable_clocks(void)
398{
399 uint32_t val = 0;
400
401 /* Enable entropy clock */
402 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W);
403 val |= ENTROPY_CLK_ENB_BIT;
404 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val);
405
406 /* De-Assert Entropy Reset */
407 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W);
408 val &= ~ENTROPY_RESET_BIT;
409 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W, val);
410
411 /* Enable SE clock */
412 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V);
413 val |= SE_CLK_ENB_BIT;
414 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val);
415
416 /* De-Assert SE Reset */
417 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V);
418 val &= ~SE_RESET_BIT;
419 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V, val);
420}
421
422static void tegra_se_disable_clocks(void)
423{
424 uint32_t val = 0;
425
426 /* Disable entropy clock */
427 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W);
428 val &= ~ENTROPY_CLK_ENB_BIT;
429 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val);
430
431 /* Disable SE clock */
432 val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V);
433 val &= ~SE_CLK_ENB_BIT;
434 mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val);
435}
436
Marvin Hsu21eea972017-04-11 11:00:48 +0800437/*
438 * Security engine power suspend entry point.
439 * This function is invoked from PSCI power domain suspend handler.
440 */
441int32_t tegra_se_suspend(void)
442{
443 int32_t ret = 0;
Samuel Payneae1e0792017-06-12 16:38:23 -0700444 uint32_t val = 0;
445
446 /* SE does not use SMMU in EL3, disable SMMU.
447 * This will be re-enabled by kernel on resume */
448 val = mmio_read_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0);
449 val &= ~PPCS_SMMU_ENABLE;
450 mmio_write_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0, val);
451
Samuel Payne1e6bed42017-06-12 10:15:43 -0700452 tegra_se_enable_clocks();
Marvin Hsu21eea972017-04-11 11:00:48 +0800453
454 /* Atomic context save se2 and pka1 */
455 INFO("%s: SE2/PKA1 atomic context save\n", __func__);
456 ret = tegra_se_context_save_atomic(&se_dev_2);
457
458 /* Atomic context save se */
459 if (ret == 0) {
460 INFO("%s: SE1 atomic context save\n", __func__);
461 ret = tegra_se_context_save_atomic(&se_dev_1);
462 }
463
464 if (ret == 0) {
465 INFO("%s: SE atomic context save done\n", __func__);
466 }
467
Samuel Payne1e6bed42017-06-12 10:15:43 -0700468 tegra_se_disable_clocks();
469
Marvin Hsu21eea972017-04-11 11:00:48 +0800470 return ret;
471}
472
473/*
474 * Save TZRAM to shadow TZRAM in AON
475 */
476int32_t tegra_se_save_tzram(void)
477{
478 uint32_t val = 0;
479 int32_t ret = 0;
480 uint32_t timeout;
481
482 INFO("%s: SE TZRAM save start\n", __func__);
Samuel Payne1e6bed42017-06-12 10:15:43 -0700483 tegra_se_enable_clocks();
Marvin Hsu21eea972017-04-11 11:00:48 +0800484
485 val = (SE_TZRAM_OP_REQ_INIT | SE_TZRAM_OP_MODE_SAVE);
486 tegra_se_write_32(&se_dev_1, SE_TZRAM_OPERATION, val);
487
488 val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION);
489 for (timeout = 0; (SE_TZRAM_OP_BUSY(val) == SE_TZRAM_OP_BUSY_ON) &&
490 (timeout < TIMEOUT_100MS); timeout++) {
491 mdelay(1);
492 val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION);
493 }
494
495 if (timeout == TIMEOUT_100MS) {
496 ERROR("%s: ERR: TZRAM save timeout!\n", __func__);
497 ret = -ETIMEDOUT;
498 }
499
500 if (ret == 0) {
501 INFO("%s: SE TZRAM save done!\n", __func__);
502 }
503
Samuel Payne1e6bed42017-06-12 10:15:43 -0700504 tegra_se_disable_clocks();
505
Marvin Hsu21eea972017-04-11 11:00:48 +0800506 return ret;
507}
508
509/*
510 * The function is invoked by SE resume
511 */
512static void tegra_se_warm_boot_resume(const tegra_se_dev_t *se_dev)
513{
514 uint32_t val;
515
516 assert(se_dev);
517
518 /* Lock RNG source to ENTROPY on resume */
519 val = DRBG_RO_ENT_IGNORE_MEM_ENABLE |
520 DRBG_RO_ENT_SRC_LOCK_ENABLE |
521 DRBG_RO_ENT_SRC_ENABLE;
522 tegra_se_write_32(se_dev, SE_RNG_SRC_CONFIG_REG_OFFSET, val);
523
Sam Payne809c7732017-05-15 11:10:37 -0700524 /* Set a random value to SRK to initialize DRBG */
525 tegra_se_generate_srk(se_dev);
Marvin Hsu21eea972017-04-11 11:00:48 +0800526}
527
528/*
529 * The function is invoked on SC7 resume
530 */
531void tegra_se_resume(void)
532{
533 tegra_se_warm_boot_resume(&se_dev_1);
534 tegra_se_warm_boot_resume(&se_dev_2);
535}