Steven Kao | 530b217 | 2017-06-23 16:18:58 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <assert.h> |
| 8 | #include <errno.h> |
| 9 | #include <stdbool.h> |
| 10 | |
| 11 | #include <arch_helpers.h> |
| 12 | #include <common/debug.h> |
| 13 | #include <drivers/delay_timer.h> |
| 14 | #include <lib/mmio.h> |
| 15 | #include <lib/psci/psci.h> |
| 16 | #include <tegra_platform.h> |
| 17 | |
| 18 | #include "se_private.h" |
| 19 | |
| 20 | /******************************************************************************* |
| 21 | * Constants and Macros |
| 22 | ******************************************************************************/ |
| 23 | #define ERR_STATUS_SW_CLEAR U(0xFFFFFFFF) |
| 24 | #define INT_STATUS_SW_CLEAR U(0xFFFFFFFF) |
| 25 | #define MAX_TIMEOUT_MS U(100) /* Timeout in 100ms */ |
| 26 | #define NUM_SE_REGS_TO_SAVE U(4) |
| 27 | |
| 28 | /******************************************************************************* |
| 29 | * Data structure and global variables |
| 30 | ******************************************************************************/ |
| 31 | static uint32_t se_regs[NUM_SE_REGS_TO_SAVE]; |
| 32 | |
| 33 | /* |
| 34 | * Check that SE operation has completed after kickoff. |
| 35 | * |
| 36 | * This function is invoked after an SE operation has been started, |
| 37 | * and it checks the following conditions: |
| 38 | * |
| 39 | * 1. SE_STATUS = IDLE |
| 40 | * 2. AHB bus data transfer is complete. |
| 41 | * 3. SE_ERR_STATUS is clean. |
| 42 | */ |
| 43 | static bool tegra_se_is_operation_complete(void) |
| 44 | { |
| 45 | uint32_t val = 0, timeout = 0, sha_status, aes_status; |
| 46 | int32_t ret = 0; |
| 47 | bool se_is_busy, txn_has_errors, txn_successful; |
| 48 | |
| 49 | /* |
| 50 | * Poll the status register to check if the operation |
| 51 | * completed. |
| 52 | */ |
| 53 | do { |
| 54 | val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS); |
| 55 | se_is_busy = !!(val & CTX_SAVE_AUTO_SE_BUSY); |
| 56 | |
| 57 | /* sleep until SE finishes */ |
| 58 | if (se_is_busy) { |
| 59 | mdelay(1); |
| 60 | timeout++; |
| 61 | } |
| 62 | |
| 63 | } while (se_is_busy && (timeout < MAX_TIMEOUT_MS)); |
| 64 | |
| 65 | /* any transaction errors? */ |
| 66 | txn_has_errors = (tegra_se_read_32(SHA_ERR_STATUS) != 0U) || |
| 67 | (tegra_se_read_32(AES0_ERR_STATUS) != 0U); |
| 68 | |
| 69 | /* transaction successful? */ |
| 70 | sha_status = tegra_se_read_32(SHA_INT_STATUS) & SHA_SE_OP_DONE; |
| 71 | aes_status = tegra_se_read_32(AES0_INT_STATUS) & AES0_SE_OP_DONE; |
| 72 | txn_successful = (sha_status == SHA_SE_OP_DONE) && |
| 73 | (aes_status == AES0_SE_OP_DONE); |
| 74 | |
| 75 | if ((timeout == MAX_TIMEOUT_MS) || txn_has_errors || !txn_successful) { |
| 76 | ERROR("%s: Atomic context save operation failed!\n", |
| 77 | __func__); |
| 78 | ret = -ECANCELED; |
| 79 | } |
| 80 | |
| 81 | return (ret == 0); |
| 82 | } |
| 83 | |
| 84 | /* |
| 85 | * Wait for SE engine to be idle and clear any pending interrupts, before |
| 86 | * starting the next SE operation. |
| 87 | */ |
| 88 | static bool tegra_se_is_ready(void) |
| 89 | { |
| 90 | int32_t ret = 0; |
| 91 | uint32_t val = 0, timeout = 0; |
| 92 | bool se_is_ready; |
| 93 | |
| 94 | /* Wait for previous operation to finish */ |
| 95 | do { |
| 96 | val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS); |
| 97 | se_is_ready = (val == CTX_SAVE_AUTO_SE_READY); |
| 98 | |
| 99 | /* sleep until SE is ready */ |
| 100 | if (!se_is_ready) { |
| 101 | mdelay(1); |
| 102 | timeout++; |
| 103 | } |
| 104 | |
| 105 | } while (!se_is_ready && (timeout < MAX_TIMEOUT_MS)); |
| 106 | |
| 107 | if (timeout == MAX_TIMEOUT_MS) { |
| 108 | ERROR("%s: SE is not ready!\n", __func__); |
| 109 | ret = -ETIMEDOUT; |
| 110 | } |
| 111 | |
| 112 | /* Clear any pending interrupts from previous operation */ |
| 113 | tegra_se_write_32(AES0_INT_STATUS, INT_STATUS_SW_CLEAR); |
| 114 | tegra_se_write_32(AES1_INT_STATUS, INT_STATUS_SW_CLEAR); |
| 115 | tegra_se_write_32(RSA_INT_STATUS, INT_STATUS_SW_CLEAR); |
| 116 | tegra_se_write_32(SHA_INT_STATUS, INT_STATUS_SW_CLEAR); |
| 117 | |
| 118 | /* Clear error status for each engine seen from current port */ |
| 119 | tegra_se_write_32(AES0_ERR_STATUS, ERR_STATUS_SW_CLEAR); |
| 120 | tegra_se_write_32(AES1_ERR_STATUS, ERR_STATUS_SW_CLEAR); |
| 121 | tegra_se_write_32(RSA_ERR_STATUS, ERR_STATUS_SW_CLEAR); |
| 122 | tegra_se_write_32(SHA_ERR_STATUS, ERR_STATUS_SW_CLEAR); |
| 123 | |
| 124 | return (ret == 0); |
| 125 | } |
| 126 | |
| 127 | /* |
| 128 | * During System Suspend, this handler triggers the hardware context |
| 129 | * save operation. |
| 130 | */ |
| 131 | static int32_t tegra_se_save_context(void) |
| 132 | { |
| 133 | int32_t ret = -ECANCELED; |
| 134 | |
| 135 | /* |
| 136 | * 1. Ensure all SE Driver including RNG1/PKA1 are shut down. |
| 137 | * TSEC/R5s are powergated/idle. All tasks on SE1~SE4, RNG1, |
| 138 | * PKA1 are wrapped up. SE0 is ready for use. |
| 139 | * 2. Clear interrupt/error in SE0 status register. |
| 140 | * 3. Scrub SE0 register to avoid false failure for illegal |
| 141 | * configuration. Probably not needed, dependent on HW |
| 142 | * implementation. |
| 143 | * 4. Check SE is ready for HW CTX_SAVE by polling |
| 144 | * SE_CTX_SAVE_AUTO_STATUS.SE_READY. |
| 145 | * |
| 146 | * Steps 1-4 are executed by tegra_se_is_ready(). |
| 147 | * |
| 148 | * 5. Issue context save command. |
| 149 | * 6. Check SE is busy with CTX_SAVE, the command in step5 was not |
| 150 | * dropped for ongoing traffic in any of SE port/engine. |
| 151 | * 7. Poll SE register or wait for SE APB interrupt for task completion |
| 152 | * a. Polling: Read SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE |
| 153 | * b. Interrupt: After receiving interrupt from SE APB, read |
| 154 | * SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE. |
| 155 | * 8. Check AES0 and SHA ERR_STATUS to ensure no error case. |
| 156 | * 9. Check AES0 and SHA INT_STATUS to ensure operation has successfully |
| 157 | * completed. |
| 158 | * |
| 159 | * Steps 6-9 are executed by tegra_se_is_operation_complete(). |
| 160 | */ |
| 161 | if (tegra_se_is_ready()) { |
| 162 | |
| 163 | /* Issue context save command */ |
| 164 | tegra_se_write_32(AES0_OPERATION, SE_OP_CTX_SAVE); |
| 165 | |
| 166 | /* Wait for operation to finish */ |
| 167 | if (tegra_se_is_operation_complete()) { |
| 168 | ret = 0; |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | return ret; |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | * Handler to power down the SE hardware blocks - SE, RNG1 and PKA1. This |
| 177 | * needs to be called only during System Suspend. |
| 178 | */ |
| 179 | int32_t tegra_se_suspend(void) |
| 180 | { |
| 181 | int32_t ret = 0; |
| 182 | |
| 183 | /* save SE registers */ |
| 184 | se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT); |
| 185 | se_regs[1] = mmio_read_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL); |
| 186 | se_regs[2] = mmio_read_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT); |
| 187 | se_regs[3] = mmio_read_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT); |
| 188 | |
| 189 | /* Save SE context. The BootROM restores it during System Resume */ |
| 190 | ret = tegra_se_save_context(); |
| 191 | if (ret != 0) { |
| 192 | ERROR("%s: context save failed (%d)\n", __func__, ret); |
| 193 | } |
| 194 | |
| 195 | return ret; |
| 196 | } |
| 197 | |
| 198 | /* |
| 199 | * Handler to power up the SE hardware block(s) during System Resume. |
| 200 | */ |
| 201 | void tegra_se_resume(void) |
| 202 | { |
| 203 | /* |
| 204 | * When TZ takes over after System Resume, TZ should first reconfigure |
| 205 | * SE_MUTEX_WATCHDOG_NS_LIMIT, PKA1_MUTEX_WATCHDOG_NS_LIMIT, |
| 206 | * RNG1_MUTEX_WATCHDOG_NS_LIMIT and SE_ENTROPY_SRC_AGE_CTRL before |
| 207 | * other operations. |
| 208 | */ |
| 209 | mmio_write_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT, se_regs[0]); |
| 210 | mmio_write_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL, se_regs[1]); |
| 211 | mmio_write_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[2]); |
| 212 | mmio_write_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[3]); |
| 213 | } |