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
matrix_write(unsigned int base,unsigned int offset,const unsigned int value)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
matrix_read(int base,unsigned int offset)52 static unsigned int matrix_read(int base, unsigned int offset)
53 {
54 return io_read32(offset + base);
55 }
56
matrix_base(unsigned int matrix)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
matrix_write_protect_enable(unsigned int matrix_base)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
matrix_write_protect_disable(unsigned int matrix_base)77 void matrix_write_protect_disable(unsigned int matrix_base)
78 {
79 matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD);
80 }
81
matrix_configure_slave_security(unsigned int matrix_base,unsigned int slave,unsigned int srtop_setting,unsigned int srsplit_setting,unsigned int ssr_setting)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
get_peri_security(unsigned int peri_id)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
matrix_set_periph_world(unsigned int matrix,unsigned int peri_id,unsigned int world)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
matrix_dt_get_id(const void * fdt,int node,unsigned int * id)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
matrix_configure_periph_secure(unsigned int peri_id)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
matrix_configure_periph_non_secure(unsigned int * peri_id_array,unsigned int size)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
matrix_save_regs(vaddr_t base,struct matrix_state * state)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
matrix_suspend(void)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
matrix_restore_regs(vaddr_t base,struct matrix_state * state)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
matrix_resume(void)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
matrix_pm(enum pm_op op,uint32_t pm_hint __unused,const struct pm_callback_handle * hdl __unused)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
matrix_pm_init(void)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