1f1f72019SOlivier Deprez /*
2f1f72019SOlivier Deprez * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
341554fb2SHarvey Hsieh * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
4ce3c97c9SMarvin Hsu *
5ce3c97c9SMarvin Hsu * SPDX-License-Identifier: BSD-3-Clause
6ce3c97c9SMarvin Hsu */
7ce3c97c9SMarvin Hsu
8ce3c97c9SMarvin Hsu #include <arch_helpers.h>
9ce3c97c9SMarvin Hsu #include <assert.h>
10ce3c97c9SMarvin Hsu #include <common/debug.h>
116e756f6dSAmbroise Vincent #include <drivers/delay_timer.h>
12ce3c97c9SMarvin Hsu #include <errno.h>
136e756f6dSAmbroise Vincent #include <lib/mmio.h>
146e756f6dSAmbroise Vincent #include <lib/psci/psci.h>
15ce3c97c9SMarvin Hsu #include <se_private.h>
16ce3c97c9SMarvin Hsu #include <security_engine.h>
17ce3c97c9SMarvin Hsu #include <tegra_platform.h>
18ce3c97c9SMarvin Hsu
19ce3c97c9SMarvin Hsu /*******************************************************************************
20ce3c97c9SMarvin Hsu * Constants and Macros
21ce3c97c9SMarvin Hsu ******************************************************************************/
22ce3c97c9SMarvin Hsu
2341554fb2SHarvey Hsieh #define TIMEOUT_100MS 100U /* Timeout in 100ms */
245ed1755aSMarvin Hsu #define RNG_AES_KEY_INDEX 1
25ce3c97c9SMarvin Hsu
26ce3c97c9SMarvin Hsu /*******************************************************************************
27ce3c97c9SMarvin Hsu * Data structure and global variables
28ce3c97c9SMarvin Hsu ******************************************************************************/
29ce3c97c9SMarvin Hsu
30ce3c97c9SMarvin Hsu /* The security engine contexts are formatted as follows:
31ce3c97c9SMarvin Hsu *
32ce3c97c9SMarvin Hsu * SE1 CONTEXT:
33ce3c97c9SMarvin Hsu * #--------------------------------#
34ce3c97c9SMarvin Hsu * | Random Data 1 Block |
35ce3c97c9SMarvin Hsu * #--------------------------------#
36ce3c97c9SMarvin Hsu * | Sticky Bits 2 Blocks |
37ce3c97c9SMarvin Hsu * #--------------------------------#
38ce3c97c9SMarvin Hsu * | Key Table 64 Blocks |
39ce3c97c9SMarvin Hsu * | For each Key (x16): |
40ce3c97c9SMarvin Hsu * | Key: 2 Blocks |
41ce3c97c9SMarvin Hsu * | Original-IV: 1 Block |
42ce3c97c9SMarvin Hsu * | Updated-IV: 1 Block |
43ce3c97c9SMarvin Hsu * #--------------------------------#
44ce3c97c9SMarvin Hsu * | RSA Keys 64 Blocks |
45ce3c97c9SMarvin Hsu * #--------------------------------#
46ce3c97c9SMarvin Hsu * | Known Pattern 1 Block |
47ce3c97c9SMarvin Hsu * #--------------------------------#
48ce3c97c9SMarvin Hsu *
49ce3c97c9SMarvin Hsu * SE2/PKA1 CONTEXT:
50ce3c97c9SMarvin Hsu * #--------------------------------#
51ce3c97c9SMarvin Hsu * | Random Data 1 Block |
52ce3c97c9SMarvin Hsu * #--------------------------------#
53ce3c97c9SMarvin Hsu * | Sticky Bits 2 Blocks |
54ce3c97c9SMarvin Hsu * #--------------------------------#
55ce3c97c9SMarvin Hsu * | Key Table 64 Blocks |
56ce3c97c9SMarvin Hsu * | For each Key (x16): |
57ce3c97c9SMarvin Hsu * | Key: 2 Blocks |
58ce3c97c9SMarvin Hsu * | Original-IV: 1 Block |
59ce3c97c9SMarvin Hsu * | Updated-IV: 1 Block |
60ce3c97c9SMarvin Hsu * #--------------------------------#
61ce3c97c9SMarvin Hsu * | RSA Keys 64 Blocks |
62ce3c97c9SMarvin Hsu * #--------------------------------#
63ce3c97c9SMarvin Hsu * | PKA sticky bits 1 Block |
64ce3c97c9SMarvin Hsu * #--------------------------------#
65ce3c97c9SMarvin Hsu * | PKA keys 512 Blocks |
66ce3c97c9SMarvin Hsu * #--------------------------------#
67ce3c97c9SMarvin Hsu * | Known Pattern 1 Block |
68ce3c97c9SMarvin Hsu * #--------------------------------#
69ce3c97c9SMarvin Hsu */
70ce3c97c9SMarvin Hsu
7141554fb2SHarvey Hsieh /* Known pattern data for T210 */
7241554fb2SHarvey Hsieh static const uint8_t se_ctx_known_pattern_data[SE_CTX_KNOWN_PATTERN_SIZE] = {
735ed1755aSMarvin Hsu /* 128 bit AES block */
7441554fb2SHarvey Hsieh 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
7541554fb2SHarvey Hsieh 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
765ed1755aSMarvin Hsu };
775ed1755aSMarvin Hsu
78ce3c97c9SMarvin Hsu /* SE input and output linked list buffers */
79ce3c97c9SMarvin Hsu static tegra_se_io_lst_t se1_src_ll_buf;
80ce3c97c9SMarvin Hsu static tegra_se_io_lst_t se1_dst_ll_buf;
81ce3c97c9SMarvin Hsu
82ce3c97c9SMarvin Hsu /* SE2 input and output linked list buffers */
83ce3c97c9SMarvin Hsu static tegra_se_io_lst_t se2_src_ll_buf;
84ce3c97c9SMarvin Hsu static tegra_se_io_lst_t se2_dst_ll_buf;
85ce3c97c9SMarvin Hsu
8641554fb2SHarvey Hsieh /* SE1 context buffer, 132 blocks */
8741554fb2SHarvey Hsieh static __aligned(64) uint8_t se1_ctx_buf[SE_CTX_DRBG_BUFER_SIZE];
8841554fb2SHarvey Hsieh
89ce3c97c9SMarvin Hsu /* SE1 security engine device handle */
90ce3c97c9SMarvin Hsu static tegra_se_dev_t se_dev_1 = {
91ce3c97c9SMarvin Hsu .se_num = 1,
925ed1755aSMarvin Hsu /* Setup base address for se */
93ce3c97c9SMarvin Hsu .se_base = TEGRA_SE1_BASE,
94ce3c97c9SMarvin Hsu /* Setup context size in AES blocks */
95ce3c97c9SMarvin Hsu .ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE1,
96ce3c97c9SMarvin Hsu /* Setup SRC buffers for SE operations */
97ce3c97c9SMarvin Hsu .src_ll_buf = &se1_src_ll_buf,
98ce3c97c9SMarvin Hsu /* Setup DST buffers for SE operations */
99ce3c97c9SMarvin Hsu .dst_ll_buf = &se1_dst_ll_buf,
1005ed1755aSMarvin Hsu /* Setup context save destination */
10141554fb2SHarvey Hsieh .ctx_save_buf = (uint32_t *)&se1_ctx_buf
102ce3c97c9SMarvin Hsu };
103ce3c97c9SMarvin Hsu
10441554fb2SHarvey Hsieh /* SE2 security engine device handle (T210B01 only) */
105ce3c97c9SMarvin Hsu static tegra_se_dev_t se_dev_2 = {
106ce3c97c9SMarvin Hsu .se_num = 2,
1075ed1755aSMarvin Hsu /* Setup base address for se */
108ce3c97c9SMarvin Hsu .se_base = TEGRA_SE2_BASE,
109ce3c97c9SMarvin Hsu /* Setup context size in AES blocks */
110ce3c97c9SMarvin Hsu .ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE2,
111ce3c97c9SMarvin Hsu /* Setup SRC buffers for SE operations */
112ce3c97c9SMarvin Hsu .src_ll_buf = &se2_src_ll_buf,
113ce3c97c9SMarvin Hsu /* Setup DST buffers for SE operations */
114ce3c97c9SMarvin Hsu .dst_ll_buf = &se2_dst_ll_buf,
1155ed1755aSMarvin Hsu /* Setup context save destination */
11641554fb2SHarvey Hsieh .ctx_save_buf = (uint32_t *)(TEGRA_TZRAM_CARVEOUT_BASE + 0x1000)
117ce3c97c9SMarvin Hsu };
118ce3c97c9SMarvin Hsu
119620b2233SSamuel Payne static bool ecid_valid;
120620b2233SSamuel Payne
121ce3c97c9SMarvin Hsu /*******************************************************************************
122ce3c97c9SMarvin Hsu * Functions Definition
123ce3c97c9SMarvin Hsu ******************************************************************************/
124ce3c97c9SMarvin Hsu
tegra_se_make_data_coherent(const tegra_se_dev_t * se_dev)125ce3c97c9SMarvin Hsu static void tegra_se_make_data_coherent(const tegra_se_dev_t *se_dev)
126ce3c97c9SMarvin Hsu {
127ce3c97c9SMarvin Hsu flush_dcache_range(((uint64_t)(se_dev->src_ll_buf)),
128ce3c97c9SMarvin Hsu sizeof(tegra_se_io_lst_t));
129ce3c97c9SMarvin Hsu flush_dcache_range(((uint64_t)(se_dev->dst_ll_buf)),
130ce3c97c9SMarvin Hsu sizeof(tegra_se_io_lst_t));
131ce3c97c9SMarvin Hsu }
132ce3c97c9SMarvin Hsu
133ce3c97c9SMarvin Hsu /*
1348668fe0cSSam Payne * Check that SE operation has completed after kickoff
1358668fe0cSSam Payne * This function is invoked after an SE operation has been started,
136ce3c97c9SMarvin Hsu * and it checks the following conditions:
137ce3c97c9SMarvin Hsu * 1. SE_INT_STATUS = SE_OP_DONE
138ce3c97c9SMarvin Hsu * 2. SE_STATUS = IDLE
139ce3c97c9SMarvin Hsu * 3. AHB bus data transfer complete.
140ce3c97c9SMarvin Hsu * 4. SE_ERR_STATUS is clean.
141ce3c97c9SMarvin Hsu */
tegra_se_operation_complete(const tegra_se_dev_t * se_dev)1428668fe0cSSam Payne static int32_t tegra_se_operation_complete(const tegra_se_dev_t *se_dev)
143ce3c97c9SMarvin Hsu {
144ce3c97c9SMarvin Hsu uint32_t val = 0;
145ce3c97c9SMarvin Hsu int32_t ret = 0;
146ce3c97c9SMarvin Hsu uint32_t timeout;
147ce3c97c9SMarvin Hsu
148ce3c97c9SMarvin Hsu /* Poll the SE interrupt register to ensure H/W operation complete */
149ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
150ce3c97c9SMarvin Hsu for (timeout = 0; (SE_INT_OP_DONE(val) == SE_INT_OP_DONE_CLEAR) &&
151ce3c97c9SMarvin Hsu (timeout < TIMEOUT_100MS); timeout++) {
152ce3c97c9SMarvin Hsu mdelay(1);
153ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
154ce3c97c9SMarvin Hsu }
155ce3c97c9SMarvin Hsu
156ce3c97c9SMarvin Hsu if (timeout == TIMEOUT_100MS) {
157ce3c97c9SMarvin Hsu ERROR("%s: ERR: Atomic context save operation timeout!\n",
158ce3c97c9SMarvin Hsu __func__);
159ce3c97c9SMarvin Hsu ret = -ETIMEDOUT;
160ce3c97c9SMarvin Hsu }
161ce3c97c9SMarvin Hsu
162ce3c97c9SMarvin Hsu /* Poll the SE status idle to ensure H/W operation complete */
163ce3c97c9SMarvin Hsu if (ret == 0) {
164ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
165ce3c97c9SMarvin Hsu for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS);
166ce3c97c9SMarvin Hsu timeout++) {
167ce3c97c9SMarvin Hsu mdelay(1);
168ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
169ce3c97c9SMarvin Hsu }
170ce3c97c9SMarvin Hsu
171ce3c97c9SMarvin Hsu if (timeout == TIMEOUT_100MS) {
172ce3c97c9SMarvin Hsu ERROR("%s: ERR: MEM_INTERFACE and SE state "
173ce3c97c9SMarvin Hsu "idle state timeout.\n", __func__);
174ce3c97c9SMarvin Hsu ret = -ETIMEDOUT;
175ce3c97c9SMarvin Hsu }
176ce3c97c9SMarvin Hsu }
177ce3c97c9SMarvin Hsu
178ce3c97c9SMarvin Hsu /* Check AHB bus transfer complete */
179ce3c97c9SMarvin Hsu if (ret == 0) {
180ce3c97c9SMarvin Hsu val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET);
181ce3c97c9SMarvin Hsu for (timeout = 0; ((val & (ARAHB_MST_ID_SE_MASK | ARAHB_MST_ID_SE2_MASK)) != 0U) &&
182ce3c97c9SMarvin Hsu (timeout < TIMEOUT_100MS); timeout++) {
183ce3c97c9SMarvin Hsu mdelay(1);
184ce3c97c9SMarvin Hsu val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET);
185ce3c97c9SMarvin Hsu }
186ce3c97c9SMarvin Hsu
187ce3c97c9SMarvin Hsu if (timeout == TIMEOUT_100MS) {
188ce3c97c9SMarvin Hsu ERROR("%s: SE write over AHB timeout.\n", __func__);
189ce3c97c9SMarvin Hsu ret = -ETIMEDOUT;
190ce3c97c9SMarvin Hsu }
191ce3c97c9SMarvin Hsu }
192ce3c97c9SMarvin Hsu
193ce3c97c9SMarvin Hsu /* Ensure that no errors are thrown during operation */
194ce3c97c9SMarvin Hsu if (ret == 0) {
195ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_ERR_STATUS_REG_OFFSET);
196ce3c97c9SMarvin Hsu if (val != 0U) {
197ce3c97c9SMarvin Hsu ERROR("%s: error during SE operation! 0x%x", __func__, val);
198ce3c97c9SMarvin Hsu ret = -ENOTSUP;
199ce3c97c9SMarvin Hsu }
200ce3c97c9SMarvin Hsu }
201ce3c97c9SMarvin Hsu
202ce3c97c9SMarvin Hsu return ret;
203ce3c97c9SMarvin Hsu }
204ce3c97c9SMarvin Hsu
205ce3c97c9SMarvin Hsu /*
2068668fe0cSSam Payne * Wait for SE engine to be idle and clear pending interrupts before
2078668fe0cSSam Payne * starting the next SE operation.
208ce3c97c9SMarvin Hsu */
tegra_se_operation_prepare(const tegra_se_dev_t * se_dev)2098668fe0cSSam Payne static int32_t tegra_se_operation_prepare(const tegra_se_dev_t *se_dev)
210ce3c97c9SMarvin Hsu {
211ce3c97c9SMarvin Hsu int32_t ret = 0;
212ce3c97c9SMarvin Hsu uint32_t val = 0;
2138668fe0cSSam Payne uint32_t timeout;
214ce3c97c9SMarvin Hsu
21541554fb2SHarvey Hsieh /* disable SE interrupt to prevent interrupt issued by SE operation */
21641554fb2SHarvey Hsieh tegra_se_write_32(se_dev, SE_INT_ENABLE_REG_OFFSET, 0U);
21741554fb2SHarvey Hsieh
218ce3c97c9SMarvin Hsu /* Wait for previous operation to finish */
219ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
220ce3c97c9SMarvin Hsu for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS); timeout++) {
221ce3c97c9SMarvin Hsu mdelay(1);
222ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
223ce3c97c9SMarvin Hsu }
224ce3c97c9SMarvin Hsu
225ce3c97c9SMarvin Hsu if (timeout == TIMEOUT_100MS) {
226ce3c97c9SMarvin Hsu ERROR("%s: ERR: SE status is not idle!\n", __func__);
227ce3c97c9SMarvin Hsu ret = -ETIMEDOUT;
228ce3c97c9SMarvin Hsu }
229ce3c97c9SMarvin Hsu
2308668fe0cSSam Payne /* Clear any pending interrupts from previous operation */
231ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
232ce3c97c9SMarvin Hsu tegra_se_write_32(se_dev, SE_INT_STATUS_REG_OFFSET, val);
2338668fe0cSSam Payne return ret;
2348668fe0cSSam Payne }
2358668fe0cSSam Payne
2368668fe0cSSam Payne /*
2378668fe0cSSam Payne * SE atomic context save. At SC7 entry, SE driver triggers the
2388668fe0cSSam Payne * hardware automatically performs the context save operation.
2398668fe0cSSam Payne */
tegra_se_context_save_atomic(const tegra_se_dev_t * se_dev)2408668fe0cSSam Payne static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev)
2418668fe0cSSam Payne {
2428668fe0cSSam Payne int32_t ret = 0;
2438668fe0cSSam Payne uint32_t val = 0;
2448668fe0cSSam Payne uint32_t blk_count_limit = 0;
2458668fe0cSSam Payne uint32_t block_count;
2468668fe0cSSam Payne
2478668fe0cSSam Payne /* Check that previous operation is finalized */
2488668fe0cSSam Payne ret = tegra_se_operation_prepare(se_dev);
249ce3c97c9SMarvin Hsu
250ce3c97c9SMarvin Hsu /* Read the context save progress counter: block_count
251ce3c97c9SMarvin Hsu * Ensure no previous context save has been triggered
252ce3c97c9SMarvin Hsu * SE_CTX_SAVE_AUTO.CURR_CNT == 0
253ce3c97c9SMarvin Hsu */
254ce3c97c9SMarvin Hsu if (ret == 0) {
255ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
256ce3c97c9SMarvin Hsu block_count = SE_CTX_SAVE_GET_BLK_COUNT(val);
257ce3c97c9SMarvin Hsu if (block_count != 0U) {
258ce3c97c9SMarvin Hsu ERROR("%s: ctx_save triggered multiple times\n",
259ce3c97c9SMarvin Hsu __func__);
260ce3c97c9SMarvin Hsu ret = -EALREADY;
261ce3c97c9SMarvin Hsu }
262ce3c97c9SMarvin Hsu }
263ce3c97c9SMarvin Hsu
264ce3c97c9SMarvin Hsu /* Set the destination block count when the context save complete */
265ce3c97c9SMarvin Hsu if (ret == 0) {
266ce3c97c9SMarvin Hsu blk_count_limit = block_count + se_dev->ctx_size_blks;
267ce3c97c9SMarvin Hsu }
268ce3c97c9SMarvin Hsu
269ce3c97c9SMarvin Hsu /* Program SE_CONFIG register as for RNG operation
270ce3c97c9SMarvin Hsu * SE_CONFIG.ENC_ALG = RNG
271ce3c97c9SMarvin Hsu * SE_CONFIG.DEC_ALG = NOP
272ce3c97c9SMarvin Hsu * SE_CONFIG.ENC_MODE is ignored
273ce3c97c9SMarvin Hsu * SE_CONFIG.DEC_MODE is ignored
274ce3c97c9SMarvin Hsu * SE_CONFIG.DST = MEMORY
275ce3c97c9SMarvin Hsu */
276ce3c97c9SMarvin Hsu if (ret == 0) {
277ce3c97c9SMarvin Hsu val = (SE_CONFIG_ENC_ALG_RNG |
278ce3c97c9SMarvin Hsu SE_CONFIG_DEC_ALG_NOP |
279ce3c97c9SMarvin Hsu SE_CONFIG_DST_MEMORY);
280ce3c97c9SMarvin Hsu tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
281ce3c97c9SMarvin Hsu
282ce3c97c9SMarvin Hsu tegra_se_make_data_coherent(se_dev);
283ce3c97c9SMarvin Hsu
284ce3c97c9SMarvin Hsu /* SE_CTX_SAVE operation */
285ce3c97c9SMarvin Hsu tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET,
286ce3c97c9SMarvin Hsu SE_OP_CTX_SAVE);
287ce3c97c9SMarvin Hsu
2888668fe0cSSam Payne ret = tegra_se_operation_complete(se_dev);
289ce3c97c9SMarvin Hsu }
290ce3c97c9SMarvin Hsu
291ce3c97c9SMarvin Hsu /* Check that context has written the correct number of blocks */
292ce3c97c9SMarvin Hsu if (ret == 0) {
293ce3c97c9SMarvin Hsu val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
294ce3c97c9SMarvin Hsu if (SE_CTX_SAVE_GET_BLK_COUNT(val) != blk_count_limit) {
295ce3c97c9SMarvin Hsu ERROR("%s: expected %d blocks but %d were written\n",
296ce3c97c9SMarvin Hsu __func__, blk_count_limit, val);
297ce3c97c9SMarvin Hsu ret = -ECANCELED;
298ce3c97c9SMarvin Hsu }
299ce3c97c9SMarvin Hsu }
300ce3c97c9SMarvin Hsu
301ce3c97c9SMarvin Hsu return ret;
302ce3c97c9SMarvin Hsu }
303ce3c97c9SMarvin Hsu
304ce3c97c9SMarvin Hsu /*
3058668fe0cSSam Payne * Security engine primitive operations, including normal operation
3068668fe0cSSam Payne * and the context save operation.
3078668fe0cSSam Payne */
tegra_se_perform_operation(const tegra_se_dev_t * se_dev,uint32_t nbytes,bool context_save)3085ed1755aSMarvin Hsu static int tegra_se_perform_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes,
3095ed1755aSMarvin Hsu bool context_save)
3108668fe0cSSam Payne {
3118668fe0cSSam Payne uint32_t nblocks = nbytes / TEGRA_SE_AES_BLOCK_SIZE;
3128668fe0cSSam Payne int ret = 0;
3138668fe0cSSam Payne
3148668fe0cSSam Payne assert(se_dev);
3158668fe0cSSam Payne
3168668fe0cSSam Payne /* Use device buffers for in and out */
3178668fe0cSSam Payne tegra_se_write_32(se_dev, SE_OUT_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->dst_ll_buf)));
3188668fe0cSSam Payne tegra_se_write_32(se_dev, SE_IN_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->src_ll_buf)));
3198668fe0cSSam Payne
3208668fe0cSSam Payne /* Check that previous operation is finalized */
3218668fe0cSSam Payne ret = tegra_se_operation_prepare(se_dev);
3228668fe0cSSam Payne if (ret != 0) {
3238668fe0cSSam Payne goto op_error;
3248668fe0cSSam Payne }
3258668fe0cSSam Payne
3268668fe0cSSam Payne /* Program SE operation size */
3278668fe0cSSam Payne if (nblocks) {
3288668fe0cSSam Payne tegra_se_write_32(se_dev, SE_BLOCK_COUNT_REG_OFFSET, nblocks - 1);
3298668fe0cSSam Payne }
3308668fe0cSSam Payne
3318668fe0cSSam Payne /* Make SE LL data coherent before the SE operation */
3328668fe0cSSam Payne tegra_se_make_data_coherent(se_dev);
3338668fe0cSSam Payne
3348668fe0cSSam Payne /* Start hardware operation */
3355ed1755aSMarvin Hsu if (context_save)
3365ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_CTX_SAVE);
3375ed1755aSMarvin Hsu else
3388668fe0cSSam Payne tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_START);
3398668fe0cSSam Payne
3408668fe0cSSam Payne /* Wait for operation to finish */
3418668fe0cSSam Payne ret = tegra_se_operation_complete(se_dev);
3428668fe0cSSam Payne
3438668fe0cSSam Payne op_error:
3448668fe0cSSam Payne return ret;
3458668fe0cSSam Payne }
3468668fe0cSSam Payne
3478668fe0cSSam Payne /*
3485ed1755aSMarvin Hsu * Normal security engine operations other than the context save
3495ed1755aSMarvin Hsu */
tegra_se_start_normal_operation(const tegra_se_dev_t * se_dev,uint32_t nbytes)3505ed1755aSMarvin Hsu int tegra_se_start_normal_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes)
3515ed1755aSMarvin Hsu {
3525ed1755aSMarvin Hsu return tegra_se_perform_operation(se_dev, nbytes, false);
3535ed1755aSMarvin Hsu }
3545ed1755aSMarvin Hsu
3555ed1755aSMarvin Hsu /*
3565ed1755aSMarvin Hsu * Security engine context save operation
3575ed1755aSMarvin Hsu */
tegra_se_start_ctx_save_operation(const tegra_se_dev_t * se_dev,uint32_t nbytes)3585ed1755aSMarvin Hsu int tegra_se_start_ctx_save_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes)
3595ed1755aSMarvin Hsu {
3605ed1755aSMarvin Hsu return tegra_se_perform_operation(se_dev, nbytes, true);
3615ed1755aSMarvin Hsu }
3625ed1755aSMarvin Hsu
3635ed1755aSMarvin Hsu /*
3648668fe0cSSam Payne * Security Engine sequence to generat SRK
3658668fe0cSSam Payne * SE and SE2 will generate different SRK by different
3668668fe0cSSam Payne * entropy seeds.
3678668fe0cSSam Payne */
tegra_se_generate_srk(const tegra_se_dev_t * se_dev)3688668fe0cSSam Payne static int tegra_se_generate_srk(const tegra_se_dev_t *se_dev)
3698668fe0cSSam Payne {
3708668fe0cSSam Payne int ret = PSCI_E_INTERN_FAIL;
3718668fe0cSSam Payne uint32_t val;
3728668fe0cSSam Payne
3738668fe0cSSam Payne /* Confgure the following hardware register settings:
3748668fe0cSSam Payne * SE_CONFIG.DEC_ALG = NOP
3758668fe0cSSam Payne * SE_CONFIG.ENC_ALG = RNG
3768668fe0cSSam Payne * SE_CONFIG.DST = SRK
3778668fe0cSSam Payne * SE_OPERATION.OP = START
3788668fe0cSSam Payne * SE_CRYPTO_LAST_BLOCK = 0
3798668fe0cSSam Payne */
3808668fe0cSSam Payne se_dev->src_ll_buf->last_buff_num = 0;
3818668fe0cSSam Payne se_dev->dst_ll_buf->last_buff_num = 0;
3828668fe0cSSam Payne
3838668fe0cSSam Payne /* Configure random number generator */
384620b2233SSamuel Payne if (ecid_valid)
385620b2233SSamuel Payne val = (DRBG_MODE_FORCE_INSTANTION | DRBG_SRC_ENTROPY);
386620b2233SSamuel Payne else
3878668fe0cSSam Payne val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_ENTROPY);
3888668fe0cSSam Payne tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val);
3898668fe0cSSam Payne
3908668fe0cSSam Payne /* Configure output destination = SRK */
3918668fe0cSSam Payne val = (SE_CONFIG_ENC_ALG_RNG |
3928668fe0cSSam Payne SE_CONFIG_DEC_ALG_NOP |
3938668fe0cSSam Payne SE_CONFIG_DST_SRK);
3948668fe0cSSam Payne tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
3958668fe0cSSam Payne
3968668fe0cSSam Payne /* Perform hardware operation */
3975ed1755aSMarvin Hsu ret = tegra_se_start_normal_operation(se_dev, 0);
3988668fe0cSSam Payne
3998668fe0cSSam Payne return ret;
4008668fe0cSSam Payne }
4018668fe0cSSam Payne
4028668fe0cSSam Payne /*
4035ed1755aSMarvin Hsu * Generate plain text random data to some memory location using
4045ed1755aSMarvin Hsu * SE/SE2's SP800-90 random number generator. The random data size
4055ed1755aSMarvin Hsu * must be some multiple of the AES block size (16 bytes).
4065ed1755aSMarvin Hsu */
tegra_se_lp_generate_random_data(tegra_se_dev_t * se_dev)4075ed1755aSMarvin Hsu static int tegra_se_lp_generate_random_data(tegra_se_dev_t *se_dev)
4085ed1755aSMarvin Hsu {
4095ed1755aSMarvin Hsu int ret = 0;
4105ed1755aSMarvin Hsu uint32_t val;
4115ed1755aSMarvin Hsu
4125ed1755aSMarvin Hsu /* Set some arbitrary memory location to store the random data */
4135ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
4145ed1755aSMarvin Hsu if (!se_dev->ctx_save_buf) {
4155ed1755aSMarvin Hsu ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__);
4165ed1755aSMarvin Hsu return PSCI_E_NOT_PRESENT;
4175ed1755aSMarvin Hsu }
4185ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(((tegra_se_context_t *)
4195ed1755aSMarvin Hsu se_dev->ctx_save_buf)->rand_data)));
4205ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = SE_CTX_SAVE_RANDOM_DATA_SIZE;
4215ed1755aSMarvin Hsu
4225ed1755aSMarvin Hsu
4235ed1755aSMarvin Hsu /* Confgure the following hardware register settings:
4245ed1755aSMarvin Hsu * SE_CONFIG.DEC_ALG = NOP
4255ed1755aSMarvin Hsu * SE_CONFIG.ENC_ALG = RNG
4265ed1755aSMarvin Hsu * SE_CONFIG.ENC_MODE = KEY192
4275ed1755aSMarvin Hsu * SE_CONFIG.DST = MEMORY
4285ed1755aSMarvin Hsu */
4295ed1755aSMarvin Hsu val = (SE_CONFIG_ENC_ALG_RNG |
4305ed1755aSMarvin Hsu SE_CONFIG_DEC_ALG_NOP |
4315ed1755aSMarvin Hsu SE_CONFIG_ENC_MODE_KEY192 |
4325ed1755aSMarvin Hsu SE_CONFIG_DST_MEMORY);
4335ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
4345ed1755aSMarvin Hsu
4355ed1755aSMarvin Hsu /* Program the RNG options in SE_CRYPTO_CONFIG as follows:
4365ed1755aSMarvin Hsu * XOR_POS = BYPASS
4375ed1755aSMarvin Hsu * INPUT_SEL = RANDOM (Entropy or LFSR)
4385ed1755aSMarvin Hsu * HASH_ENB = DISABLE
4395ed1755aSMarvin Hsu */
4405ed1755aSMarvin Hsu val = (SE_CRYPTO_INPUT_RANDOM |
4415ed1755aSMarvin Hsu SE_CRYPTO_XOR_BYPASS |
4425ed1755aSMarvin Hsu SE_CRYPTO_CORE_ENCRYPT |
4435ed1755aSMarvin Hsu SE_CRYPTO_HASH_DISABLE |
4445ed1755aSMarvin Hsu SE_CRYPTO_KEY_INDEX(RNG_AES_KEY_INDEX) |
4455ed1755aSMarvin Hsu SE_CRYPTO_IV_ORIGINAL);
4465ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CRYPTO_REG_OFFSET, val);
4475ed1755aSMarvin Hsu
4485ed1755aSMarvin Hsu /* Configure RNG */
449620b2233SSamuel Payne if (ecid_valid)
4505ed1755aSMarvin Hsu val = (DRBG_MODE_FORCE_INSTANTION | DRBG_SRC_LFSR);
451620b2233SSamuel Payne else
452620b2233SSamuel Payne val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_LFSR);
4535ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val);
4545ed1755aSMarvin Hsu
4555ed1755aSMarvin Hsu /* SE normal operation */
4565ed1755aSMarvin Hsu ret = tegra_se_start_normal_operation(se_dev, SE_CTX_SAVE_RANDOM_DATA_SIZE);
4575ed1755aSMarvin Hsu
4585ed1755aSMarvin Hsu return ret;
4595ed1755aSMarvin Hsu }
4605ed1755aSMarvin Hsu
4615ed1755aSMarvin Hsu /*
4625ed1755aSMarvin Hsu * Encrypt memory blocks with SRK as part of the security engine context.
4635ed1755aSMarvin Hsu * The data blocks include: random data and the known pattern data, where
4645ed1755aSMarvin Hsu * the random data is the first block and known pattern is the last block.
4655ed1755aSMarvin Hsu */
tegra_se_lp_data_context_save(tegra_se_dev_t * se_dev,uint64_t src_addr,uint64_t dst_addr,uint32_t data_size)4665ed1755aSMarvin Hsu static int tegra_se_lp_data_context_save(tegra_se_dev_t *se_dev,
4675ed1755aSMarvin Hsu uint64_t src_addr, uint64_t dst_addr, uint32_t data_size)
4685ed1755aSMarvin Hsu {
4695ed1755aSMarvin Hsu int ret = 0;
4705ed1755aSMarvin Hsu
4715ed1755aSMarvin Hsu se_dev->src_ll_buf->last_buff_num = 0;
4725ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
4735ed1755aSMarvin Hsu se_dev->src_ll_buf->buffer[0].addr = src_addr;
4745ed1755aSMarvin Hsu se_dev->src_ll_buf->buffer[0].data_len = data_size;
4755ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = dst_addr;
4765ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = data_size;
4775ed1755aSMarvin Hsu
4785ed1755aSMarvin Hsu /* By setting the context source from memory and calling the context save
4795ed1755aSMarvin Hsu * operation, the SE encrypts the memory data with SRK.
4805ed1755aSMarvin Hsu */
4815ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, SE_CTX_SAVE_SRC_MEM);
4825ed1755aSMarvin Hsu
4835ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev, data_size);
4845ed1755aSMarvin Hsu
4855ed1755aSMarvin Hsu return ret;
4865ed1755aSMarvin Hsu }
4875ed1755aSMarvin Hsu
4885ed1755aSMarvin Hsu /*
4895ed1755aSMarvin Hsu * Context save the key table access control sticky bits and
4905ed1755aSMarvin Hsu * security status of each key-slot. The encrypted sticky-bits are
4915ed1755aSMarvin Hsu * 32 bytes (2 AES blocks) and formatted as the following structure:
4925ed1755aSMarvin Hsu * { bit in registers bit in context save
4935ed1755aSMarvin Hsu * SECURITY_0[4] 158
4945ed1755aSMarvin Hsu * SE_RSA_KEYTABLE_ACCE4SS_1[2:0] 157:155
4955ed1755aSMarvin Hsu * SE_RSA_KEYTABLE_ACCE4SS_0[2:0] 154:152
4965ed1755aSMarvin Hsu * SE_RSA_SECURITY_PERKEY_0[1:0] 151:150
4975ed1755aSMarvin Hsu * SE_CRYPTO_KEYTABLE_ACCESS_15[7:0] 149:142
4985ed1755aSMarvin Hsu * ...,
4995ed1755aSMarvin Hsu * SE_CRYPTO_KEYTABLE_ACCESS_0[7:0] 29:22
5005ed1755aSMarvin Hsu * SE_CRYPTO_SECURITY_PERKEY_0[15:0] 21:6
5015ed1755aSMarvin Hsu * SE_TZRAM_SECURITY_0[1:0] 5:4
5025ed1755aSMarvin Hsu * SE_SECURITY_0[16] 3:3
5035ed1755aSMarvin Hsu * SE_SECURITY_0[2:0] } 2:0
5045ed1755aSMarvin Hsu */
tegra_se_lp_sticky_bits_context_save(tegra_se_dev_t * se_dev)5055ed1755aSMarvin Hsu static int tegra_se_lp_sticky_bits_context_save(tegra_se_dev_t *se_dev)
5065ed1755aSMarvin Hsu {
5075ed1755aSMarvin Hsu int ret = PSCI_E_INTERN_FAIL;
5085ed1755aSMarvin Hsu uint32_t val = 0;
5095ed1755aSMarvin Hsu
5105ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
5115ed1755aSMarvin Hsu if (!se_dev->ctx_save_buf) {
5125ed1755aSMarvin Hsu ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__);
5135ed1755aSMarvin Hsu return PSCI_E_NOT_PRESENT;
5145ed1755aSMarvin Hsu }
5155ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(((tegra_se_context_t *)
5165ed1755aSMarvin Hsu se_dev->ctx_save_buf)->sticky_bits)));
5175ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = SE_CTX_SAVE_STICKY_BITS_SIZE;
5185ed1755aSMarvin Hsu
5195ed1755aSMarvin Hsu /*
5205ed1755aSMarvin Hsu * The 1st AES block save the sticky-bits context 1 - 16 bytes (0 - 3 words).
5215ed1755aSMarvin Hsu * The 2nd AES block save the sticky-bits context 17 - 32 bytes (4 - 7 words).
5225ed1755aSMarvin Hsu */
5235ed1755aSMarvin Hsu for (int i = 0; i < 2; i++) {
5245ed1755aSMarvin Hsu val = SE_CTX_SAVE_SRC_STICKY_BITS |
5255ed1755aSMarvin Hsu SE_CTX_SAVE_STICKY_WORD_QUAD(i);
5265ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
5275ed1755aSMarvin Hsu
5285ed1755aSMarvin Hsu /* SE context save operation */
5295ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev,
5305ed1755aSMarvin Hsu SE_CTX_SAVE_STICKY_BITS_SIZE);
5315ed1755aSMarvin Hsu if (ret)
5325ed1755aSMarvin Hsu break;
5335ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr += SE_CTX_SAVE_STICKY_BITS_SIZE;
5345ed1755aSMarvin Hsu }
5355ed1755aSMarvin Hsu
5365ed1755aSMarvin Hsu return ret;
5375ed1755aSMarvin Hsu }
5385ed1755aSMarvin Hsu
tegra_se_aeskeytable_context_save(tegra_se_dev_t * se_dev)5395ed1755aSMarvin Hsu static int tegra_se_aeskeytable_context_save(tegra_se_dev_t *se_dev)
5405ed1755aSMarvin Hsu {
5415ed1755aSMarvin Hsu uint32_t val = 0;
5425ed1755aSMarvin Hsu int ret = 0;
5435ed1755aSMarvin Hsu
5445ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
5455ed1755aSMarvin Hsu if (!se_dev->ctx_save_buf) {
5465ed1755aSMarvin Hsu ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__);
5475ed1755aSMarvin Hsu ret = -EINVAL;
5485ed1755aSMarvin Hsu goto aes_keytable_save_err;
5495ed1755aSMarvin Hsu }
5505ed1755aSMarvin Hsu
5515ed1755aSMarvin Hsu /* AES key context save */
5525ed1755aSMarvin Hsu for (int slot = 0; slot < TEGRA_SE_AES_KEYSLOT_COUNT; slot++) {
5535ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
5545ed1755aSMarvin Hsu ((tegra_se_context_t *)se_dev->
5555ed1755aSMarvin Hsu ctx_save_buf)->key_slots[slot].key)));
5565ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE;
5575ed1755aSMarvin Hsu for (int i = 0; i < 2; i++) {
5585ed1755aSMarvin Hsu val = SE_CTX_SAVE_SRC_AES_KEYTABLE |
5595ed1755aSMarvin Hsu SE_CTX_SAVE_KEY_INDEX(slot) |
5605ed1755aSMarvin Hsu SE_CTX_SAVE_WORD_QUAD(i);
5615ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
5625ed1755aSMarvin Hsu
5635ed1755aSMarvin Hsu /* SE context save operation */
5645ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev,
5655ed1755aSMarvin Hsu TEGRA_SE_KEY_128_SIZE);
5665ed1755aSMarvin Hsu if (ret) {
5675ed1755aSMarvin Hsu ERROR("%s: ERR: AES key CTX_SAVE OP failed, "
5685ed1755aSMarvin Hsu "slot=%d, word_quad=%d.\n",
5695ed1755aSMarvin Hsu __func__, slot, i);
5705ed1755aSMarvin Hsu goto aes_keytable_save_err;
5715ed1755aSMarvin Hsu }
5725ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr += TEGRA_SE_KEY_128_SIZE;
5735ed1755aSMarvin Hsu }
5745ed1755aSMarvin Hsu
5755ed1755aSMarvin Hsu /* OIV context save */
5765ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
5775ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
5785ed1755aSMarvin Hsu ((tegra_se_context_t *)se_dev->
5795ed1755aSMarvin Hsu ctx_save_buf)->key_slots[slot].oiv)));
5805ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_IV_SIZE;
5815ed1755aSMarvin Hsu
5825ed1755aSMarvin Hsu val = SE_CTX_SAVE_SRC_AES_KEYTABLE |
5835ed1755aSMarvin Hsu SE_CTX_SAVE_KEY_INDEX(slot) |
5845ed1755aSMarvin Hsu SE_CTX_SAVE_WORD_QUAD_ORIG_IV;
5855ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
5865ed1755aSMarvin Hsu
5875ed1755aSMarvin Hsu /* SE context save operation */
5885ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_AES_IV_SIZE);
5895ed1755aSMarvin Hsu if (ret) {
5905ed1755aSMarvin Hsu ERROR("%s: ERR: OIV CTX_SAVE OP failed, slot=%d.\n",
5915ed1755aSMarvin Hsu __func__, slot);
5925ed1755aSMarvin Hsu goto aes_keytable_save_err;
5935ed1755aSMarvin Hsu }
5945ed1755aSMarvin Hsu
5955ed1755aSMarvin Hsu /* UIV context save */
5965ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
5975ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
5985ed1755aSMarvin Hsu ((tegra_se_context_t *)se_dev->
5995ed1755aSMarvin Hsu ctx_save_buf)->key_slots[slot].uiv)));
6005ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_IV_SIZE;
6015ed1755aSMarvin Hsu
6025ed1755aSMarvin Hsu val = SE_CTX_SAVE_SRC_AES_KEYTABLE |
6035ed1755aSMarvin Hsu SE_CTX_SAVE_KEY_INDEX(slot) |
6045ed1755aSMarvin Hsu SE_CTX_SAVE_WORD_QUAD_UPD_IV;
6055ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
6065ed1755aSMarvin Hsu
6075ed1755aSMarvin Hsu /* SE context save operation */
6085ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_AES_IV_SIZE);
6095ed1755aSMarvin Hsu if (ret) {
6105ed1755aSMarvin Hsu ERROR("%s: ERR: UIV CTX_SAVE OP failed, slot=%d\n",
6115ed1755aSMarvin Hsu __func__, slot);
6125ed1755aSMarvin Hsu goto aes_keytable_save_err;
6135ed1755aSMarvin Hsu }
6145ed1755aSMarvin Hsu }
6155ed1755aSMarvin Hsu
6165ed1755aSMarvin Hsu aes_keytable_save_err:
6175ed1755aSMarvin Hsu return ret;
6185ed1755aSMarvin Hsu }
6195ed1755aSMarvin Hsu
tegra_se_lp_rsakeytable_context_save(tegra_se_dev_t * se_dev)6205ed1755aSMarvin Hsu static int tegra_se_lp_rsakeytable_context_save(tegra_se_dev_t *se_dev)
6215ed1755aSMarvin Hsu {
6225ed1755aSMarvin Hsu uint32_t val = 0;
6235ed1755aSMarvin Hsu int ret = 0;
62441554fb2SHarvey Hsieh /* For T210, First the modulus and then exponent must be
6255ed1755aSMarvin Hsu * encrypted and saved. This is repeated for SLOT 0
6265ed1755aSMarvin Hsu * and SLOT 1. Hence the order:
6275ed1755aSMarvin Hsu * SLOT 0 modulus : RSA_KEY_INDEX : 1
62841554fb2SHarvey Hsieh * SLOT 0 exponent : RSA_KEY_INDEX : 0
6295ed1755aSMarvin Hsu * SLOT 1 modulus : RSA_KEY_INDEX : 3
63041554fb2SHarvey Hsieh * SLOT 1 exponent : RSA_KEY_INDEX : 2
6315ed1755aSMarvin Hsu */
6325ed1755aSMarvin Hsu const unsigned int key_index_mod[TEGRA_SE_RSA_KEYSLOT_COUNT][2] = {
6335ed1755aSMarvin Hsu /* RSA key slot 0 */
63441554fb2SHarvey Hsieh {SE_RSA_KEY_INDEX_SLOT0_MOD, SE_RSA_KEY_INDEX_SLOT0_EXP},
6355ed1755aSMarvin Hsu /* RSA key slot 1 */
63641554fb2SHarvey Hsieh {SE_RSA_KEY_INDEX_SLOT1_MOD, SE_RSA_KEY_INDEX_SLOT1_EXP},
6375ed1755aSMarvin Hsu };
6385ed1755aSMarvin Hsu
6395ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
6405ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
6415ed1755aSMarvin Hsu ((tegra_se_context_t *)se_dev->
6425ed1755aSMarvin Hsu ctx_save_buf)->rsa_keys)));
6435ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE;
6445ed1755aSMarvin Hsu
6455ed1755aSMarvin Hsu for (int slot = 0; slot < TEGRA_SE_RSA_KEYSLOT_COUNT; slot++) {
6465ed1755aSMarvin Hsu /* loop for modulus and exponent */
6475ed1755aSMarvin Hsu for (int index = 0; index < 2; index++) {
6485ed1755aSMarvin Hsu for (int word_quad = 0; word_quad < 16; word_quad++) {
6495ed1755aSMarvin Hsu val = SE_CTX_SAVE_SRC_RSA_KEYTABLE |
6505ed1755aSMarvin Hsu SE_CTX_SAVE_RSA_KEY_INDEX(
6515ed1755aSMarvin Hsu key_index_mod[slot][index]) |
6525ed1755aSMarvin Hsu SE_CTX_RSA_WORD_QUAD(word_quad);
6535ed1755aSMarvin Hsu tegra_se_write_32(se_dev,
6545ed1755aSMarvin Hsu SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
6555ed1755aSMarvin Hsu
6565ed1755aSMarvin Hsu /* SE context save operation */
6575ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev,
6585ed1755aSMarvin Hsu TEGRA_SE_KEY_128_SIZE);
6595ed1755aSMarvin Hsu if (ret) {
6605ed1755aSMarvin Hsu ERROR("%s: ERR: slot=%d.\n",
6615ed1755aSMarvin Hsu __func__, slot);
6625ed1755aSMarvin Hsu goto rsa_keytable_save_err;
6635ed1755aSMarvin Hsu }
6645ed1755aSMarvin Hsu
6655ed1755aSMarvin Hsu /* Update the pointer to the next word quad */
6665ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr +=
6675ed1755aSMarvin Hsu TEGRA_SE_KEY_128_SIZE;
6685ed1755aSMarvin Hsu }
6695ed1755aSMarvin Hsu }
6705ed1755aSMarvin Hsu }
6715ed1755aSMarvin Hsu
6725ed1755aSMarvin Hsu rsa_keytable_save_err:
6735ed1755aSMarvin Hsu return ret;
6745ed1755aSMarvin Hsu }
6755ed1755aSMarvin Hsu
tegra_se_pkakeytable_sticky_bits_save(tegra_se_dev_t * se_dev)6765ed1755aSMarvin Hsu static int tegra_se_pkakeytable_sticky_bits_save(tegra_se_dev_t *se_dev)
6775ed1755aSMarvin Hsu {
6785ed1755aSMarvin Hsu int ret = 0;
6795ed1755aSMarvin Hsu
6805ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
6815ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
6825ed1755aSMarvin Hsu ((tegra_se2_context_blob_t *)se_dev->
6835ed1755aSMarvin Hsu ctx_save_buf)->pka_ctx.sticky_bits)));
6845ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_BLOCK_SIZE;
6855ed1755aSMarvin Hsu
6865ed1755aSMarvin Hsu /* PKA1 sticky bits are 1 AES block (16 bytes) */
6875ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET,
6885ed1755aSMarvin Hsu SE_CTX_SAVE_SRC_PKA1_STICKY_BITS |
6895ed1755aSMarvin Hsu SE_CTX_STICKY_WORD_QUAD_WORDS_0_3);
6905ed1755aSMarvin Hsu
6915ed1755aSMarvin Hsu /* SE context save operation */
6925ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev, 0);
6935ed1755aSMarvin Hsu if (ret) {
6945ed1755aSMarvin Hsu ERROR("%s: ERR: PKA1 sticky bits CTX_SAVE OP failed\n",
6955ed1755aSMarvin Hsu __func__);
6965ed1755aSMarvin Hsu goto pka_sticky_bits_save_err;
6975ed1755aSMarvin Hsu }
6985ed1755aSMarvin Hsu
6995ed1755aSMarvin Hsu pka_sticky_bits_save_err:
7005ed1755aSMarvin Hsu return ret;
7015ed1755aSMarvin Hsu }
7025ed1755aSMarvin Hsu
tegra_se_pkakeytable_context_save(tegra_se_dev_t * se_dev)7035ed1755aSMarvin Hsu static int tegra_se_pkakeytable_context_save(tegra_se_dev_t *se_dev)
7045ed1755aSMarvin Hsu {
7055ed1755aSMarvin Hsu uint32_t val = 0;
7065ed1755aSMarvin Hsu int ret = 0;
7075ed1755aSMarvin Hsu
7085ed1755aSMarvin Hsu se_dev->dst_ll_buf->last_buff_num = 0;
7095ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
7105ed1755aSMarvin Hsu ((tegra_se2_context_blob_t *)se_dev->
7115ed1755aSMarvin Hsu ctx_save_buf)->pka_ctx.pka_keys)));
7125ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE;
7135ed1755aSMarvin Hsu
7145ed1755aSMarvin Hsu /* for each slot, save word quad 0-127 */
7155ed1755aSMarvin Hsu for (int slot = 0; slot < TEGRA_SE_PKA1_KEYSLOT_COUNT; slot++) {
7165ed1755aSMarvin Hsu for (int word_quad = 0; word_quad < 512/4; word_quad++) {
7175ed1755aSMarvin Hsu val = SE_CTX_SAVE_SRC_PKA1_KEYTABLE |
7185ed1755aSMarvin Hsu SE_CTX_PKA1_WORD_QUAD_L((slot * 128) +
7195ed1755aSMarvin Hsu word_quad) |
7205ed1755aSMarvin Hsu SE_CTX_PKA1_WORD_QUAD_H((slot * 128) +
7215ed1755aSMarvin Hsu word_quad);
7225ed1755aSMarvin Hsu tegra_se_write_32(se_dev,
7235ed1755aSMarvin Hsu SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
7245ed1755aSMarvin Hsu
7255ed1755aSMarvin Hsu /* SE context save operation */
7265ed1755aSMarvin Hsu ret = tegra_se_start_ctx_save_operation(se_dev,
7275ed1755aSMarvin Hsu TEGRA_SE_KEY_128_SIZE);
7285ed1755aSMarvin Hsu if (ret) {
7295ed1755aSMarvin Hsu ERROR("%s: ERR: pka1 keytable ctx save error\n",
7305ed1755aSMarvin Hsu __func__);
7315ed1755aSMarvin Hsu goto pka_keytable_save_err;
7325ed1755aSMarvin Hsu }
7335ed1755aSMarvin Hsu
7345ed1755aSMarvin Hsu /* Update the pointer to the next word quad */
7355ed1755aSMarvin Hsu se_dev->dst_ll_buf->buffer[0].addr +=
7365ed1755aSMarvin Hsu TEGRA_SE_KEY_128_SIZE;
7375ed1755aSMarvin Hsu }
7385ed1755aSMarvin Hsu }
7395ed1755aSMarvin Hsu
7405ed1755aSMarvin Hsu pka_keytable_save_err:
7415ed1755aSMarvin Hsu return ret;
7425ed1755aSMarvin Hsu }
7435ed1755aSMarvin Hsu
tegra_se_save_SRK(tegra_se_dev_t * se_dev)7445ed1755aSMarvin Hsu static int tegra_se_save_SRK(tegra_se_dev_t *se_dev)
7455ed1755aSMarvin Hsu {
7465ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET,
7475ed1755aSMarvin Hsu SE_CTX_SAVE_SRC_SRK);
7485ed1755aSMarvin Hsu
7495ed1755aSMarvin Hsu /* SE context save operation */
7505ed1755aSMarvin Hsu return tegra_se_start_ctx_save_operation(se_dev, 0);
7515ed1755aSMarvin Hsu }
7525ed1755aSMarvin Hsu
7535ed1755aSMarvin Hsu /*
7545ed1755aSMarvin Hsu * Lock both SE from non-TZ clients.
7555ed1755aSMarvin Hsu */
tegra_se_lock(tegra_se_dev_t * se_dev)7565ed1755aSMarvin Hsu static inline void tegra_se_lock(tegra_se_dev_t *se_dev)
7575ed1755aSMarvin Hsu {
7585ed1755aSMarvin Hsu uint32_t val;
7595ed1755aSMarvin Hsu
7605ed1755aSMarvin Hsu assert(se_dev);
7615ed1755aSMarvin Hsu val = tegra_se_read_32(se_dev, SE_SECURITY_REG_OFFSET);
7625ed1755aSMarvin Hsu val |= SE_SECURITY_TZ_LOCK_SOFT(SE_SECURE);
7635ed1755aSMarvin Hsu tegra_se_write_32(se_dev, SE_SECURITY_REG_OFFSET, val);
7645ed1755aSMarvin Hsu }
7655ed1755aSMarvin Hsu
7665ed1755aSMarvin Hsu /*
7675ed1755aSMarvin Hsu * Use SRK to encrypt SE state and save to TZRAM carveout
7685ed1755aSMarvin Hsu */
tegra_se_context_save_sw(tegra_se_dev_t * se_dev)7695ed1755aSMarvin Hsu static int tegra_se_context_save_sw(tegra_se_dev_t *se_dev)
7705ed1755aSMarvin Hsu {
7715ed1755aSMarvin Hsu int err = 0;
7725ed1755aSMarvin Hsu
7735ed1755aSMarvin Hsu assert(se_dev);
7745ed1755aSMarvin Hsu
7755ed1755aSMarvin Hsu /* Lock entire SE/SE2 as TZ protected */
7765ed1755aSMarvin Hsu tegra_se_lock(se_dev);
7775ed1755aSMarvin Hsu
7785ed1755aSMarvin Hsu INFO("%s: generate SRK\n", __func__);
7795ed1755aSMarvin Hsu /* Generate SRK */
7805ed1755aSMarvin Hsu err = tegra_se_generate_srk(se_dev);
7815ed1755aSMarvin Hsu if (err) {
7825ed1755aSMarvin Hsu ERROR("%s: ERR: SRK generation failed\n", __func__);
7835ed1755aSMarvin Hsu return err;
7845ed1755aSMarvin Hsu }
7855ed1755aSMarvin Hsu
7865ed1755aSMarvin Hsu INFO("%s: generate random data\n", __func__);
7875ed1755aSMarvin Hsu /* Generate random data */
7885ed1755aSMarvin Hsu err = tegra_se_lp_generate_random_data(se_dev);
7895ed1755aSMarvin Hsu if (err) {
7905ed1755aSMarvin Hsu ERROR("%s: ERR: LP random pattern generation failed\n", __func__);
7915ed1755aSMarvin Hsu return err;
7925ed1755aSMarvin Hsu }
7935ed1755aSMarvin Hsu
7945ed1755aSMarvin Hsu INFO("%s: encrypt random data\n", __func__);
7955ed1755aSMarvin Hsu /* Encrypt the random data block */
7965ed1755aSMarvin Hsu err = tegra_se_lp_data_context_save(se_dev,
7975ed1755aSMarvin Hsu ((uint64_t)(&(((tegra_se_context_t *)se_dev->
7985ed1755aSMarvin Hsu ctx_save_buf)->rand_data))),
7995ed1755aSMarvin Hsu ((uint64_t)(&(((tegra_se_context_t *)se_dev->
8005ed1755aSMarvin Hsu ctx_save_buf)->rand_data))),
8015ed1755aSMarvin Hsu SE_CTX_SAVE_RANDOM_DATA_SIZE);
8025ed1755aSMarvin Hsu if (err) {
8035ed1755aSMarvin Hsu ERROR("%s: ERR: random pattern encryption failed\n", __func__);
8045ed1755aSMarvin Hsu return err;
8055ed1755aSMarvin Hsu }
8065ed1755aSMarvin Hsu
8075ed1755aSMarvin Hsu INFO("%s: save SE sticky bits\n", __func__);
8085ed1755aSMarvin Hsu /* Save AES sticky bits context */
8095ed1755aSMarvin Hsu err = tegra_se_lp_sticky_bits_context_save(se_dev);
8105ed1755aSMarvin Hsu if (err) {
8115ed1755aSMarvin Hsu ERROR("%s: ERR: sticky bits context save failed\n", __func__);
8125ed1755aSMarvin Hsu return err;
8135ed1755aSMarvin Hsu }
8145ed1755aSMarvin Hsu
8155ed1755aSMarvin Hsu INFO("%s: save AES keytables\n", __func__);
8165ed1755aSMarvin Hsu /* Save AES key table context */
8175ed1755aSMarvin Hsu err = tegra_se_aeskeytable_context_save(se_dev);
8185ed1755aSMarvin Hsu if (err) {
8195ed1755aSMarvin Hsu ERROR("%s: ERR: LP keytable save failed\n", __func__);
8205ed1755aSMarvin Hsu return err;
8215ed1755aSMarvin Hsu }
8225ed1755aSMarvin Hsu
8235ed1755aSMarvin Hsu /* RSA key slot table context save */
8245ed1755aSMarvin Hsu INFO("%s: save RSA keytables\n", __func__);
8255ed1755aSMarvin Hsu err = tegra_se_lp_rsakeytable_context_save(se_dev);
8265ed1755aSMarvin Hsu if (err) {
8275ed1755aSMarvin Hsu ERROR("%s: ERR: rsa key table context save failed\n", __func__);
8285ed1755aSMarvin Hsu return err;
8295ed1755aSMarvin Hsu }
8305ed1755aSMarvin Hsu
8315ed1755aSMarvin Hsu /* Only SE2 has an interface with PKA1; thus, PKA1's context is saved
8325ed1755aSMarvin Hsu * via SE2.
8335ed1755aSMarvin Hsu */
8345ed1755aSMarvin Hsu if (se_dev->se_num == 2) {
8355ed1755aSMarvin Hsu /* Encrypt PKA1 sticky bits on SE2 only */
8365ed1755aSMarvin Hsu INFO("%s: save PKA sticky bits\n", __func__);
8375ed1755aSMarvin Hsu err = tegra_se_pkakeytable_sticky_bits_save(se_dev);
8385ed1755aSMarvin Hsu if (err) {
8395ed1755aSMarvin Hsu ERROR("%s: ERR: PKA sticky bits context save failed\n", __func__);
8405ed1755aSMarvin Hsu return err;
8415ed1755aSMarvin Hsu }
8425ed1755aSMarvin Hsu
8435ed1755aSMarvin Hsu /* Encrypt PKA1 keyslots on SE2 only */
8445ed1755aSMarvin Hsu INFO("%s: save PKA keytables\n", __func__);
8455ed1755aSMarvin Hsu err = tegra_se_pkakeytable_context_save(se_dev);
8465ed1755aSMarvin Hsu if (err) {
8475ed1755aSMarvin Hsu ERROR("%s: ERR: PKA key table context save failed\n", __func__);
8485ed1755aSMarvin Hsu return err;
8495ed1755aSMarvin Hsu }
8505ed1755aSMarvin Hsu }
8515ed1755aSMarvin Hsu
8525ed1755aSMarvin Hsu /* Encrypt known pattern */
8535ed1755aSMarvin Hsu if (se_dev->se_num == 1) {
8545ed1755aSMarvin Hsu err = tegra_se_lp_data_context_save(se_dev,
8555ed1755aSMarvin Hsu ((uint64_t)(&se_ctx_known_pattern_data)),
8565ed1755aSMarvin Hsu ((uint64_t)(&(((tegra_se_context_blob_t *)se_dev->ctx_save_buf)->known_pattern))),
8575ed1755aSMarvin Hsu SE_CTX_KNOWN_PATTERN_SIZE);
8585ed1755aSMarvin Hsu } else if (se_dev->se_num == 2) {
8595ed1755aSMarvin Hsu err = tegra_se_lp_data_context_save(se_dev,
8605ed1755aSMarvin Hsu ((uint64_t)(&se_ctx_known_pattern_data)),
8615ed1755aSMarvin Hsu ((uint64_t)(&(((tegra_se2_context_blob_t *)se_dev->ctx_save_buf)->known_pattern))),
8625ed1755aSMarvin Hsu SE_CTX_KNOWN_PATTERN_SIZE);
8635ed1755aSMarvin Hsu }
8645ed1755aSMarvin Hsu if (err) {
8655ed1755aSMarvin Hsu ERROR("%s: ERR: save LP known pattern failure\n", __func__);
8665ed1755aSMarvin Hsu return err;
8675ed1755aSMarvin Hsu }
8685ed1755aSMarvin Hsu
8695ed1755aSMarvin Hsu /* Write lp context buffer address into PMC scratch register */
8705ed1755aSMarvin Hsu if (se_dev->se_num == 1) {
87141554fb2SHarvey Hsieh /* SE context address, support T210 only */
87241554fb2SHarvey Hsieh mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SCRATCH43_REG_OFFSET,
8735ed1755aSMarvin Hsu ((uint64_t)(se_dev->ctx_save_buf)));
8745ed1755aSMarvin Hsu } else if (se_dev->se_num == 2) {
8755ed1755aSMarvin Hsu /* SE2 & PKA1 context address */
8765ed1755aSMarvin Hsu mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SECURE_SCRATCH116_OFFSET,
8775ed1755aSMarvin Hsu ((uint64_t)(se_dev->ctx_save_buf)));
8785ed1755aSMarvin Hsu }
8795ed1755aSMarvin Hsu
8805ed1755aSMarvin Hsu /* Saves SRK to PMC secure scratch registers for BootROM, which
8815ed1755aSMarvin Hsu * verifies and restores the security engine context on warm boot.
8825ed1755aSMarvin Hsu */
8835ed1755aSMarvin Hsu err = tegra_se_save_SRK(se_dev);
8845ed1755aSMarvin Hsu if (err < 0) {
8855ed1755aSMarvin Hsu ERROR("%s: ERR: LP SRK save failure\n", __func__);
8865ed1755aSMarvin Hsu return err;
8875ed1755aSMarvin Hsu }
8885ed1755aSMarvin Hsu
8895ed1755aSMarvin Hsu INFO("%s: SE context save done \n", __func__);
8905ed1755aSMarvin Hsu
8915ed1755aSMarvin Hsu return err;
8925ed1755aSMarvin Hsu }
8935ed1755aSMarvin Hsu
8945ed1755aSMarvin Hsu /*
895ce3c97c9SMarvin Hsu * Initialize the SE engine handle
896ce3c97c9SMarvin Hsu */
tegra_se_init(void)897ce3c97c9SMarvin Hsu void tegra_se_init(void)
898ce3c97c9SMarvin Hsu {
899620b2233SSamuel Payne uint32_t val = 0;
900ce3c97c9SMarvin Hsu INFO("%s: start SE init\n", __func__);
901ce3c97c9SMarvin Hsu
9028668fe0cSSam Payne /* Generate random SRK to initialize DRBG */
9038668fe0cSSam Payne tegra_se_generate_srk(&se_dev_1);
90441554fb2SHarvey Hsieh
90541554fb2SHarvey Hsieh if (tegra_chipid_is_t210_b01()) {
9068668fe0cSSam Payne tegra_se_generate_srk(&se_dev_2);
90741554fb2SHarvey Hsieh }
908ce3c97c9SMarvin Hsu
909620b2233SSamuel Payne /* determine if ECID is valid */
910620b2233SSamuel Payne val = mmio_read_32(TEGRA_FUSE_BASE + FUSE_JTAG_SECUREID_VALID);
911620b2233SSamuel Payne ecid_valid = (val == ECID_VALID);
912620b2233SSamuel Payne
913ce3c97c9SMarvin Hsu INFO("%s: SE init done\n", __func__);
914ce3c97c9SMarvin Hsu }
915ce3c97c9SMarvin Hsu
tegra_se_enable_clocks(void)91699359f1dSSamuel Payne static void tegra_se_enable_clocks(void)
91799359f1dSSamuel Payne {
91899359f1dSSamuel Payne uint32_t val = 0;
91999359f1dSSamuel Payne
92099359f1dSSamuel Payne /* Enable entropy clock */
92199359f1dSSamuel Payne val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W);
92299359f1dSSamuel Payne val |= ENTROPY_CLK_ENB_BIT;
92399359f1dSSamuel Payne mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val);
92499359f1dSSamuel Payne
92599359f1dSSamuel Payne /* De-Assert Entropy Reset */
92699359f1dSSamuel Payne val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W);
92799359f1dSSamuel Payne val &= ~ENTROPY_RESET_BIT;
92899359f1dSSamuel Payne mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W, val);
92999359f1dSSamuel Payne
93041554fb2SHarvey Hsieh /*
931*35aa1c1eSLeo He * Switch SE clock source to CLK_M, to make sure SE clock
932*35aa1c1eSLeo He * is on when saving SE context
93341554fb2SHarvey Hsieh */
93441554fb2SHarvey Hsieh mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_RST_CTL_CLK_SRC_SE,
93541554fb2SHarvey Hsieh SE_CLK_SRC_CLK_M);
93641554fb2SHarvey Hsieh
93799359f1dSSamuel Payne /* Enable SE clock */
93899359f1dSSamuel Payne val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V);
93999359f1dSSamuel Payne val |= SE_CLK_ENB_BIT;
94099359f1dSSamuel Payne mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val);
94199359f1dSSamuel Payne
94299359f1dSSamuel Payne /* De-Assert SE Reset */
94399359f1dSSamuel Payne val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V);
94499359f1dSSamuel Payne val &= ~SE_RESET_BIT;
94599359f1dSSamuel Payne mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V, val);
94699359f1dSSamuel Payne }
94799359f1dSSamuel Payne
tegra_se_disable_clocks(void)94899359f1dSSamuel Payne static void tegra_se_disable_clocks(void)
94999359f1dSSamuel Payne {
95099359f1dSSamuel Payne uint32_t val = 0;
95199359f1dSSamuel Payne
95299359f1dSSamuel Payne /* Disable entropy clock */
95399359f1dSSamuel Payne val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W);
95499359f1dSSamuel Payne val &= ~ENTROPY_CLK_ENB_BIT;
95599359f1dSSamuel Payne mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val);
95699359f1dSSamuel Payne
95799359f1dSSamuel Payne /* Disable SE clock */
95899359f1dSSamuel Payne val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V);
95999359f1dSSamuel Payne val &= ~SE_CLK_ENB_BIT;
96099359f1dSSamuel Payne mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val);
96199359f1dSSamuel Payne }
96299359f1dSSamuel Payne
963ce3c97c9SMarvin Hsu /*
964ce3c97c9SMarvin Hsu * Security engine power suspend entry point.
965ce3c97c9SMarvin Hsu * This function is invoked from PSCI power domain suspend handler.
966ce3c97c9SMarvin Hsu */
tegra_se_suspend(void)967ce3c97c9SMarvin Hsu int32_t tegra_se_suspend(void)
968ce3c97c9SMarvin Hsu {
969ce3c97c9SMarvin Hsu int32_t ret = 0;
97086d0a52bSSamuel Payne uint32_t val = 0;
97186d0a52bSSamuel Payne
97286d0a52bSSamuel Payne /* SE does not use SMMU in EL3, disable SMMU.
97386d0a52bSSamuel Payne * This will be re-enabled by kernel on resume */
97486d0a52bSSamuel Payne val = mmio_read_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0);
97586d0a52bSSamuel Payne val &= ~PPCS_SMMU_ENABLE;
97686d0a52bSSamuel Payne mmio_write_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0, val);
97786d0a52bSSamuel Payne
97899359f1dSSamuel Payne tegra_se_enable_clocks();
979ce3c97c9SMarvin Hsu
98041554fb2SHarvey Hsieh if (tegra_chipid_is_t210_b01()) {
98141554fb2SHarvey Hsieh /* It is T210 B01, Atomic context save se2 and pka1 */
982ce3c97c9SMarvin Hsu INFO("%s: SE2/PKA1 atomic context save\n", __func__);
983ce3c97c9SMarvin Hsu ret = tegra_se_context_save_atomic(&se_dev_2);
98441554fb2SHarvey Hsieh if (ret != 0) {
98541554fb2SHarvey Hsieh ERROR("%s: SE2 ctx save failed (%d)\n", __func__, ret);
9865ed1755aSMarvin Hsu }
987ce3c97c9SMarvin Hsu
988ce3c97c9SMarvin Hsu ret = tegra_se_context_save_atomic(&se_dev_1);
98941554fb2SHarvey Hsieh if (ret != 0) {
99041554fb2SHarvey Hsieh ERROR("%s: SE1 ctx save failed (%d)\n", __func__, ret);
9915ed1755aSMarvin Hsu }
9925ed1755aSMarvin Hsu } else {
99341554fb2SHarvey Hsieh /* It is T210, SW context save se */
99441554fb2SHarvey Hsieh INFO("%s: SE1 legacy(SW) context save\n", __func__);
99541554fb2SHarvey Hsieh ret = tegra_se_context_save_sw(&se_dev_1);
99641554fb2SHarvey Hsieh if (ret != 0) {
99741554fb2SHarvey Hsieh ERROR("%s: SE1 ctx save failed (%d)\n", __func__, ret);
99841554fb2SHarvey Hsieh }
9995ed1755aSMarvin Hsu }
1000ce3c97c9SMarvin Hsu
100199359f1dSSamuel Payne tegra_se_disable_clocks();
100299359f1dSSamuel Payne
1003ce3c97c9SMarvin Hsu return ret;
1004ce3c97c9SMarvin Hsu }
1005ce3c97c9SMarvin Hsu
1006ce3c97c9SMarvin Hsu /*
1007ce3c97c9SMarvin Hsu * Save TZRAM to shadow TZRAM in AON
1008ce3c97c9SMarvin Hsu */
tegra_se_save_tzram(void)1009ce3c97c9SMarvin Hsu int32_t tegra_se_save_tzram(void)
1010ce3c97c9SMarvin Hsu {
1011ce3c97c9SMarvin Hsu uint32_t val = 0;
1012ce3c97c9SMarvin Hsu int32_t ret = 0;
1013ce3c97c9SMarvin Hsu uint32_t timeout;
1014ce3c97c9SMarvin Hsu
1015ce3c97c9SMarvin Hsu INFO("%s: SE TZRAM save start\n", __func__);
101699359f1dSSamuel Payne tegra_se_enable_clocks();
1017ce3c97c9SMarvin Hsu
1018ce3c97c9SMarvin Hsu val = (SE_TZRAM_OP_REQ_INIT | SE_TZRAM_OP_MODE_SAVE);
1019ce3c97c9SMarvin Hsu tegra_se_write_32(&se_dev_1, SE_TZRAM_OPERATION, val);
1020ce3c97c9SMarvin Hsu
1021ce3c97c9SMarvin Hsu val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION);
1022ce3c97c9SMarvin Hsu for (timeout = 0; (SE_TZRAM_OP_BUSY(val) == SE_TZRAM_OP_BUSY_ON) &&
1023ce3c97c9SMarvin Hsu (timeout < TIMEOUT_100MS); timeout++) {
1024ce3c97c9SMarvin Hsu mdelay(1);
1025ce3c97c9SMarvin Hsu val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION);
1026ce3c97c9SMarvin Hsu }
1027ce3c97c9SMarvin Hsu
1028ce3c97c9SMarvin Hsu if (timeout == TIMEOUT_100MS) {
1029ce3c97c9SMarvin Hsu ERROR("%s: ERR: TZRAM save timeout!\n", __func__);
1030ce3c97c9SMarvin Hsu ret = -ETIMEDOUT;
1031ce3c97c9SMarvin Hsu }
1032ce3c97c9SMarvin Hsu
1033ce3c97c9SMarvin Hsu if (ret == 0) {
1034ce3c97c9SMarvin Hsu INFO("%s: SE TZRAM save done!\n", __func__);
1035ce3c97c9SMarvin Hsu }
1036ce3c97c9SMarvin Hsu
103799359f1dSSamuel Payne tegra_se_disable_clocks();
103899359f1dSSamuel Payne
1039ce3c97c9SMarvin Hsu return ret;
1040ce3c97c9SMarvin Hsu }
1041ce3c97c9SMarvin Hsu
1042ce3c97c9SMarvin Hsu /*
1043ce3c97c9SMarvin Hsu * The function is invoked by SE resume
1044ce3c97c9SMarvin Hsu */
tegra_se_warm_boot_resume(const tegra_se_dev_t * se_dev)1045ce3c97c9SMarvin Hsu static void tegra_se_warm_boot_resume(const tegra_se_dev_t *se_dev)
1046ce3c97c9SMarvin Hsu {
1047ce3c97c9SMarvin Hsu uint32_t val;
1048ce3c97c9SMarvin Hsu
1049ce3c97c9SMarvin Hsu assert(se_dev);
1050ce3c97c9SMarvin Hsu
1051ce3c97c9SMarvin Hsu /* Lock RNG source to ENTROPY on resume */
1052ce3c97c9SMarvin Hsu val = DRBG_RO_ENT_IGNORE_MEM_ENABLE |
1053ce3c97c9SMarvin Hsu DRBG_RO_ENT_SRC_LOCK_ENABLE |
1054ce3c97c9SMarvin Hsu DRBG_RO_ENT_SRC_ENABLE;
1055ce3c97c9SMarvin Hsu tegra_se_write_32(se_dev, SE_RNG_SRC_CONFIG_REG_OFFSET, val);
1056ce3c97c9SMarvin Hsu
10578668fe0cSSam Payne /* Set a random value to SRK to initialize DRBG */
10588668fe0cSSam Payne tegra_se_generate_srk(se_dev);
1059ce3c97c9SMarvin Hsu }
1060ce3c97c9SMarvin Hsu
1061ce3c97c9SMarvin Hsu /*
1062ce3c97c9SMarvin Hsu * The function is invoked on SC7 resume
1063ce3c97c9SMarvin Hsu */
tegra_se_resume(void)1064ce3c97c9SMarvin Hsu void tegra_se_resume(void)
1065ce3c97c9SMarvin Hsu {
1066ce3c97c9SMarvin Hsu tegra_se_warm_boot_resume(&se_dev_1);
106741554fb2SHarvey Hsieh
106841554fb2SHarvey Hsieh if (tegra_chipid_is_t210_b01()) {
1069ce3c97c9SMarvin Hsu tegra_se_warm_boot_resume(&se_dev_2);
1070ce3c97c9SMarvin Hsu }
107141554fb2SHarvey Hsieh }
1072