1 // SPDX-License-Identifier: BSD-Source-Code 2 /* 3 * Copyright (c) 2013, Atmel Corporation 4 * Copyright (c) 2017, Timesys Corporation 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * - Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the disclaimer below. 13 * 14 * Atmel's name may not be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 #include <arm32.h> 29 #include <initcall.h> 30 #include <io.h> 31 #include <kernel/dt.h> 32 #include <kernel/pm.h> 33 #include <kernel/panic.h> 34 #include <matrix.h> 35 #include <mm/core_memprot.h> 36 #include <mm/core_mmu.h> 37 #include <platform_config.h> 38 #include <stdint.h> 39 #include <tz_matrix.h> 40 #include <trace.h> 41 42 #define WORLD_NON_SECURE 0 43 #define WORLD_SECURE 1 44 45 static void matrix_write(unsigned int base, 46 unsigned int offset, 47 const unsigned int value) 48 { 49 io_write32(offset + base, value); 50 } 51 52 static unsigned int matrix_read(int base, unsigned int offset) 53 { 54 return io_read32(offset + base); 55 } 56 57 vaddr_t matrix_base(unsigned int matrix) 58 { 59 unsigned int i = 0; 60 struct matrix *pmatrix = NULL; 61 62 do { 63 pmatrix = matrix_get(i++); 64 if (!pmatrix) 65 panic("Invalid matrix"); 66 } while (pmatrix->matrix != matrix); 67 68 return io_pa_or_va_secure(&pmatrix->p, CORE_MMU_PGDIR_SIZE); 69 } 70 71 void matrix_write_protect_enable(unsigned int matrix_base) 72 { 73 matrix_write(matrix_base, MATRIX_WPMR, 74 MATRIX_WPMR_WPKEY_PASSWD | MATRIX_WPMR_WPEN_ENABLE); 75 } 76 77 void matrix_write_protect_disable(unsigned int matrix_base) 78 { 79 matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD); 80 } 81 82 void matrix_configure_slave_security(unsigned int matrix_base, 83 unsigned int slave, 84 unsigned int srtop_setting, 85 unsigned int srsplit_setting, 86 unsigned int ssr_setting) 87 { 88 matrix_write(matrix_base, MATRIX_SSR(slave), ssr_setting); 89 matrix_write(matrix_base, MATRIX_SRTSR(slave), srtop_setting); 90 matrix_write(matrix_base, MATRIX_SASSR(slave), srsplit_setting); 91 } 92 93 static const struct peri_security *get_peri_security(unsigned int peri_id) 94 { 95 unsigned int i = 0; 96 struct peri_security *p = NULL; 97 98 do { 99 p = peri_security_get(i++); 100 if (p && peri_id == p->peri_id) 101 break; 102 } while (p); 103 104 return p; 105 } 106 107 static int matrix_set_periph_world(unsigned int matrix, unsigned int peri_id, 108 unsigned int world) 109 { 110 unsigned int spselr = 0; 111 unsigned int idx = peri_id / 32; 112 unsigned int bit = 0x01 << (peri_id % 32); 113 unsigned int base = matrix_base(matrix); 114 115 if (idx > 3) 116 return -1; 117 118 spselr = matrix_read(base, MATRIX_SPSELR(idx)); 119 if (world == WORLD_SECURE) 120 spselr &= ~bit; 121 else 122 spselr |= bit; 123 matrix_write(base, MATRIX_SPSELR(idx), spselr); 124 125 return 0; 126 } 127 128 TEE_Result matrix_dt_get_id(const void *fdt, int node, unsigned int *id) 129 { 130 unsigned int i = 0; 131 paddr_t pbase = 0; 132 struct peri_security *p = NULL; 133 134 pbase = fdt_reg_base_address(fdt, node); 135 if (pbase == DT_INFO_INVALID_REG) 136 return TEE_ERROR_BAD_PARAMETERS; 137 138 do { 139 p = peri_security_get(i++); 140 if (p && p->addr == pbase) { 141 *id = p->peri_id; 142 return TEE_SUCCESS; 143 } 144 } while (p); 145 146 return TEE_ERROR_ITEM_NOT_FOUND; 147 } 148 149 int matrix_configure_periph_secure(unsigned int peri_id) 150 { 151 const struct peri_security *psec = NULL; 152 153 psec = get_peri_security(peri_id); 154 if (!psec) 155 return -1; 156 157 return matrix_set_periph_world(psec->matrix, peri_id, WORLD_SECURE); 158 } 159 160 int matrix_configure_periph_non_secure(unsigned int *peri_id_array, 161 unsigned int size) 162 { 163 unsigned int i = 0; 164 unsigned int *peri_id_p = peri_id_array; 165 unsigned int matrix = 0; 166 unsigned int peri_id = 0; 167 const struct peri_security *peripheral_sec = NULL; 168 int ret = 0; 169 170 if (!peri_id_array || !size) 171 return -1; 172 173 for (i = 0; i < size; i++) { 174 peripheral_sec = get_peri_security(*peri_id_p); 175 if (!peripheral_sec) 176 return -1; 177 178 if (peripheral_sec->security_type != SECURITY_TYPE_PS) 179 return -1; 180 181 matrix = peripheral_sec->matrix; 182 peri_id = *peri_id_p; 183 ret = matrix_set_periph_world(matrix, peri_id, 184 WORLD_NON_SECURE); 185 if (ret) 186 return -1; 187 188 peri_id_p++; 189 } 190 191 return 0; 192 } 193 194 #ifdef CFG_PM_ARM32 195 196 static void matrix_save_regs(vaddr_t base, struct matrix_state *state) 197 { 198 int idx = 0; 199 200 for (idx = 0; idx < MATRIX_SPSELR_COUNT; idx++) 201 state->spselr[idx] = matrix_read(base, MATRIX_SPSELR(idx)); 202 203 for (idx = 0; idx < MATRIX_SLAVE_COUNT; idx++) { 204 state->ssr[idx] = matrix_read(base, MATRIX_SSR(idx)); 205 state->srtsr[idx] = matrix_read(base, MATRIX_SRTSR(idx)); 206 state->sassr[idx] = matrix_read(base, MATRIX_SASSR(idx)); 207 } 208 209 state->meier = matrix_read(base, MATRIX_MEIER); 210 state->meimr = matrix_read(base, MATRIX_MEIMR); 211 } 212 213 static void matrix_suspend(void) 214 { 215 unsigned int i = 0; 216 struct matrix *pmatrix = NULL; 217 218 for (pmatrix = matrix_get(i++); pmatrix; pmatrix = matrix_get(i++)) 219 matrix_save_regs(matrix_base(pmatrix->matrix), &pmatrix->state); 220 } 221 222 static void matrix_restore_regs(vaddr_t base, struct matrix_state *state) 223 { 224 int idx = 0; 225 226 matrix_write_protect_disable(base); 227 228 for (idx = 0; idx < MATRIX_SPSELR_COUNT; idx++) 229 matrix_write(base, MATRIX_SPSELR(idx), state->spselr[idx]); 230 231 for (idx = 0; idx < MATRIX_SLAVE_COUNT; idx++) { 232 matrix_write(base, MATRIX_SSR(idx), state->ssr[idx]); 233 matrix_write(base, MATRIX_SRTSR(idx), state->srtsr[idx]); 234 matrix_write(base, MATRIX_SASSR(idx), state->sassr[idx]); 235 } 236 237 matrix_write(base, MATRIX_MEIER, state->meier); 238 matrix_write(base, MATRIX_MEIMR, state->meimr); 239 } 240 241 static void matrix_resume(void) 242 { 243 unsigned int i = 0; 244 struct matrix *pmatrix = NULL; 245 246 for (pmatrix = matrix_get(i++); pmatrix; pmatrix = matrix_get(i++)) 247 matrix_restore_regs(matrix_base(pmatrix->matrix), 248 &pmatrix->state); 249 } 250 251 static TEE_Result matrix_pm(enum pm_op op, uint32_t pm_hint __unused, 252 const struct pm_callback_handle *hdl __unused) 253 { 254 switch (op) { 255 case PM_OP_RESUME: 256 matrix_resume(); 257 break; 258 case PM_OP_SUSPEND: 259 matrix_suspend(); 260 break; 261 default: 262 panic("Invalid PM operation"); 263 } 264 265 return TEE_SUCCESS; 266 } 267 268 static TEE_Result matrix_pm_init(void) 269 { 270 /* 271 * We can't call matrix_register_pm in matrix_init since allocator is 272 * not ready yet so we just call it later in this driver init callback. 273 */ 274 register_pm_driver_cb(matrix_pm, NULL, "sam-matrix"); 275 276 return TEE_SUCCESS; 277 } 278 driver_init(matrix_pm_init); 279 280 #endif 281