xref: /optee_os/core/arch/arm/plat-sam/matrix.c (revision 45febb458e2a4ad5496bc1b287db835d526a769b)
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