xref: /optee_os/core/arch/arm/plat-sam/matrix.c (revision 45febb458e2a4ad5496bc1b287db835d526a769b)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-Source-Code
2e20d1bceSAkshay Bhat /*
3e20d1bceSAkshay Bhat  * Copyright (c) 2013, Atmel Corporation
4e20d1bceSAkshay Bhat  * Copyright (c) 2017, Timesys Corporation
5e20d1bceSAkshay Bhat  *
6e20d1bceSAkshay Bhat  * All rights reserved.
7e20d1bceSAkshay Bhat  *
8e20d1bceSAkshay Bhat  * Redistribution and use in source and binary forms, with or without
9e20d1bceSAkshay Bhat  * modification, are permitted provided that the following conditions are met:
10e20d1bceSAkshay Bhat  *
11e20d1bceSAkshay Bhat  * - Redistributions of source code must retain the above copyright notice,
12e20d1bceSAkshay Bhat  * this list of conditions and the disclaimer below.
13e20d1bceSAkshay Bhat  *
14e20d1bceSAkshay Bhat  * Atmel's name may not be used to endorse or promote products derived from
15e20d1bceSAkshay Bhat  * this software without specific prior written permission.
16e20d1bceSAkshay Bhat  *
17e20d1bceSAkshay Bhat  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18e20d1bceSAkshay Bhat  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19e20d1bceSAkshay Bhat  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20e20d1bceSAkshay Bhat  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21e20d1bceSAkshay Bhat  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22e20d1bceSAkshay Bhat  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23e20d1bceSAkshay Bhat  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24e20d1bceSAkshay Bhat  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25e20d1bceSAkshay Bhat  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26e20d1bceSAkshay Bhat  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27e20d1bceSAkshay Bhat  */
28e20d1bceSAkshay Bhat #include <arm32.h>
299ea13e5fSClément Léger #include <initcall.h>
30e20d1bceSAkshay Bhat #include <io.h>
319a28dbc4SClément Léger #include <kernel/dt.h>
329ea13e5fSClément Léger #include <kernel/pm.h>
339ea13e5fSClément Léger #include <kernel/panic.h>
34e20d1bceSAkshay Bhat #include <matrix.h>
35*45febb45STony Han #include <mm/core_memprot.h>
36*45febb45STony Han #include <mm/core_mmu.h>
379ea13e5fSClément Léger #include <platform_config.h>
389ea13e5fSClément Léger #include <stdint.h>
39e20d1bceSAkshay Bhat #include <tz_matrix.h>
40e20d1bceSAkshay Bhat #include <trace.h>
41e20d1bceSAkshay Bhat 
42a06ff5e3SClément Léger #define WORLD_NON_SECURE	0
43a06ff5e3SClément Léger #define WORLD_SECURE		1
44a06ff5e3SClément Léger 
matrix_write(unsigned int base,unsigned int offset,const unsigned int value)45e20d1bceSAkshay Bhat static void matrix_write(unsigned int base,
46e20d1bceSAkshay Bhat 			 unsigned int offset,
47e20d1bceSAkshay Bhat 			 const unsigned int value)
48e20d1bceSAkshay Bhat {
495dbc88e3SEtienne Carriere 	io_write32(offset + base, value);
50e20d1bceSAkshay Bhat }
51e20d1bceSAkshay Bhat 
matrix_read(int base,unsigned int offset)52e20d1bceSAkshay Bhat static unsigned int matrix_read(int base, unsigned int offset)
53e20d1bceSAkshay Bhat {
545dbc88e3SEtienne Carriere 	return io_read32(offset + base);
55e20d1bceSAkshay Bhat }
56e20d1bceSAkshay Bhat 
matrix_base(unsigned int matrix)57*45febb45STony Han vaddr_t matrix_base(unsigned int matrix)
58*45febb45STony Han {
59*45febb45STony Han 	unsigned int i = 0;
60*45febb45STony Han 	struct matrix *pmatrix = NULL;
61*45febb45STony Han 
62*45febb45STony Han 	do {
63*45febb45STony Han 		pmatrix = matrix_get(i++);
64*45febb45STony Han 		if (!pmatrix)
65*45febb45STony Han 			panic("Invalid matrix");
66*45febb45STony Han 	} while (pmatrix->matrix != matrix);
67*45febb45STony Han 
68*45febb45STony Han 	return io_pa_or_va_secure(&pmatrix->p, CORE_MMU_PGDIR_SIZE);
69*45febb45STony Han }
70*45febb45STony Han 
matrix_write_protect_enable(unsigned int matrix_base)71e20d1bceSAkshay Bhat void matrix_write_protect_enable(unsigned int matrix_base)
72e20d1bceSAkshay Bhat {
73e20d1bceSAkshay Bhat 	matrix_write(matrix_base, MATRIX_WPMR,
744a6683cfSTony Han 		     MATRIX_WPMR_WPKEY_PASSWD | MATRIX_WPMR_WPEN_ENABLE);
75e20d1bceSAkshay Bhat }
76e20d1bceSAkshay Bhat 
matrix_write_protect_disable(unsigned int matrix_base)77e20d1bceSAkshay Bhat void matrix_write_protect_disable(unsigned int matrix_base)
78e20d1bceSAkshay Bhat {
79e20d1bceSAkshay Bhat 	matrix_write(matrix_base, MATRIX_WPMR, MATRIX_WPMR_WPKEY_PASSWD);
80e20d1bceSAkshay Bhat }
81e20d1bceSAkshay Bhat 
matrix_configure_slave_security(unsigned int matrix_base,unsigned int slave,unsigned int srtop_setting,unsigned int srsplit_setting,unsigned int ssr_setting)82e20d1bceSAkshay Bhat void matrix_configure_slave_security(unsigned int matrix_base,
83e20d1bceSAkshay Bhat 				     unsigned int slave,
84e20d1bceSAkshay Bhat 				     unsigned int srtop_setting,
85e20d1bceSAkshay Bhat 				     unsigned int srsplit_setting,
86e20d1bceSAkshay Bhat 				     unsigned int ssr_setting)
87e20d1bceSAkshay Bhat {
88e20d1bceSAkshay Bhat 	matrix_write(matrix_base, MATRIX_SSR(slave), ssr_setting);
89e20d1bceSAkshay Bhat 	matrix_write(matrix_base, MATRIX_SRTSR(slave), srtop_setting);
90e20d1bceSAkshay Bhat 	matrix_write(matrix_base, MATRIX_SASSR(slave), srsplit_setting);
91e20d1bceSAkshay Bhat }
92e20d1bceSAkshay Bhat 
get_peri_security(unsigned int peri_id)93e20d1bceSAkshay Bhat static const struct peri_security *get_peri_security(unsigned int peri_id)
94e20d1bceSAkshay Bhat {
95*45febb45STony Han 	unsigned int i = 0;
96*45febb45STony Han 	struct peri_security *p = NULL;
97e20d1bceSAkshay Bhat 
98*45febb45STony Han 	do {
99*45febb45STony Han 		p = peri_security_get(i++);
100*45febb45STony Han 		if (p && peri_id == p->peri_id)
101*45febb45STony Han 			break;
102*45febb45STony Han 	} while (p);
103e20d1bceSAkshay Bhat 
104*45febb45STony Han 	return p;
105e20d1bceSAkshay Bhat }
106e20d1bceSAkshay Bhat 
matrix_set_periph_world(unsigned int matrix,unsigned int peri_id,unsigned int world)107a06ff5e3SClément Léger static int matrix_set_periph_world(unsigned int matrix, unsigned int peri_id,
108a06ff5e3SClément Léger 				   unsigned int world)
109e20d1bceSAkshay Bhat {
110*45febb45STony Han 	unsigned int spselr = 0;
111*45febb45STony Han 	unsigned int idx = peri_id / 32;
112*45febb45STony Han 	unsigned int bit = 0x01 << (peri_id % 32);
113*45febb45STony Han 	unsigned int base = matrix_base(matrix);
114e20d1bceSAkshay Bhat 
115e20d1bceSAkshay Bhat 	if (idx > 3)
116e20d1bceSAkshay Bhat 		return -1;
117e20d1bceSAkshay Bhat 
118e20d1bceSAkshay Bhat 	spselr = matrix_read(base, MATRIX_SPSELR(idx));
119a06ff5e3SClément Léger 	if (world == WORLD_SECURE)
120a06ff5e3SClément Léger 		spselr &= ~bit;
121a06ff5e3SClément Léger 	else
122e20d1bceSAkshay Bhat 		spselr |= bit;
123e20d1bceSAkshay Bhat 	matrix_write(base, MATRIX_SPSELR(idx), spselr);
124e20d1bceSAkshay Bhat 
125e20d1bceSAkshay Bhat 	return 0;
126e20d1bceSAkshay Bhat }
127e20d1bceSAkshay Bhat 
matrix_dt_get_id(const void * fdt,int node,unsigned int * id)1289a28dbc4SClément Léger TEE_Result matrix_dt_get_id(const void *fdt, int node, unsigned int *id)
1299a28dbc4SClément Léger {
1309a28dbc4SClément Léger 	unsigned int i = 0;
1319a28dbc4SClément Léger 	paddr_t pbase = 0;
132*45febb45STony Han 	struct peri_security *p = NULL;
1339a28dbc4SClément Léger 
134f354a5d8SGatien Chevallier 	pbase = fdt_reg_base_address(fdt, node);
1359a28dbc4SClément Léger 	if (pbase == DT_INFO_INVALID_REG)
1369a28dbc4SClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
1379a28dbc4SClément Léger 
138*45febb45STony Han 	do {
139*45febb45STony Han 		p = peri_security_get(i++);
140*45febb45STony Han 		if (p && p->addr == pbase) {
141*45febb45STony Han 			*id = p->peri_id;
1429a28dbc4SClément Léger 			return TEE_SUCCESS;
1439a28dbc4SClément Léger 		}
144*45febb45STony Han 	} while (p);
1459a28dbc4SClément Léger 
1469a28dbc4SClément Léger 	return TEE_ERROR_ITEM_NOT_FOUND;
1479a28dbc4SClément Léger }
1489a28dbc4SClément Léger 
matrix_configure_periph_secure(unsigned int peri_id)149a06ff5e3SClément Léger int matrix_configure_periph_secure(unsigned int peri_id)
150a06ff5e3SClément Léger {
151a06ff5e3SClément Léger 	const struct peri_security *psec = NULL;
152a06ff5e3SClément Léger 
153a06ff5e3SClément Léger 	psec = get_peri_security(peri_id);
154a06ff5e3SClément Léger 	if (!psec)
155a06ff5e3SClément Léger 		return -1;
156a06ff5e3SClément Léger 
157a06ff5e3SClément Léger 	return matrix_set_periph_world(psec->matrix, peri_id, WORLD_SECURE);
158a06ff5e3SClément Léger }
159a06ff5e3SClément Léger 
matrix_configure_periph_non_secure(unsigned int * peri_id_array,unsigned int size)160a06ff5e3SClément Léger int matrix_configure_periph_non_secure(unsigned int *peri_id_array,
161e20d1bceSAkshay Bhat 				       unsigned int size)
162e20d1bceSAkshay Bhat {
163*45febb45STony Han 	unsigned int i = 0;
164*45febb45STony Han 	unsigned int *peri_id_p = peri_id_array;
165*45febb45STony Han 	unsigned int matrix = 0;
166*45febb45STony Han 	unsigned int peri_id = 0;
167*45febb45STony Han 	const struct peri_security *peripheral_sec = NULL;
168*45febb45STony Han 	int ret = 0;
169e20d1bceSAkshay Bhat 
170e20d1bceSAkshay Bhat 	if (!peri_id_array || !size)
171e20d1bceSAkshay Bhat 		return -1;
172e20d1bceSAkshay Bhat 
173e20d1bceSAkshay Bhat 	for (i = 0; i < size; i++) {
174e20d1bceSAkshay Bhat 		peripheral_sec = get_peri_security(*peri_id_p);
175e20d1bceSAkshay Bhat 		if (!peripheral_sec)
176e20d1bceSAkshay Bhat 			return -1;
177e20d1bceSAkshay Bhat 
178e20d1bceSAkshay Bhat 		if (peripheral_sec->security_type != SECURITY_TYPE_PS)
179e20d1bceSAkshay Bhat 			return -1;
180e20d1bceSAkshay Bhat 
181e20d1bceSAkshay Bhat 		matrix = peripheral_sec->matrix;
182e20d1bceSAkshay Bhat 		peri_id = *peri_id_p;
183a06ff5e3SClément Léger 		ret = matrix_set_periph_world(matrix, peri_id,
184a06ff5e3SClément Léger 					      WORLD_NON_SECURE);
185e20d1bceSAkshay Bhat 		if (ret)
186e20d1bceSAkshay Bhat 			return -1;
187e20d1bceSAkshay Bhat 
188e20d1bceSAkshay Bhat 		peri_id_p++;
189e20d1bceSAkshay Bhat 	}
190e20d1bceSAkshay Bhat 
191e20d1bceSAkshay Bhat 	return 0;
192e20d1bceSAkshay Bhat }
1939ea13e5fSClément Léger 
1949ea13e5fSClément Léger #ifdef CFG_PM_ARM32
1959ea13e5fSClément Léger 
matrix_save_regs(vaddr_t base,struct matrix_state * state)1969ea13e5fSClément Léger static void matrix_save_regs(vaddr_t base, struct matrix_state *state)
1979ea13e5fSClément Léger {
1989ea13e5fSClément Léger 	int idx = 0;
1999ea13e5fSClément Léger 
2009ea13e5fSClément Léger 	for (idx = 0; idx < MATRIX_SPSELR_COUNT; idx++)
2019ea13e5fSClément Léger 		state->spselr[idx] = matrix_read(base, MATRIX_SPSELR(idx));
2029ea13e5fSClément Léger 
2039ea13e5fSClément Léger 	for (idx = 0; idx < MATRIX_SLAVE_COUNT; idx++) {
2049ea13e5fSClément Léger 		state->ssr[idx] = matrix_read(base, MATRIX_SSR(idx));
2059ea13e5fSClément Léger 		state->srtsr[idx] = matrix_read(base, MATRIX_SRTSR(idx));
2069ea13e5fSClément Léger 		state->sassr[idx] = matrix_read(base, MATRIX_SASSR(idx));
2079ea13e5fSClément Léger 	}
2089ea13e5fSClément Léger 
2099ea13e5fSClément Léger 	state->meier = matrix_read(base, MATRIX_MEIER);
2109ea13e5fSClément Léger 	state->meimr = matrix_read(base, MATRIX_MEIMR);
2119ea13e5fSClément Léger }
2129ea13e5fSClément Léger 
matrix_suspend(void)2139ea13e5fSClément Léger static void matrix_suspend(void)
2149ea13e5fSClément Léger {
215*45febb45STony Han 	unsigned int i = 0;
216*45febb45STony Han 	struct matrix *pmatrix = NULL;
217*45febb45STony Han 
218*45febb45STony Han 	for (pmatrix = matrix_get(i++); pmatrix; pmatrix = matrix_get(i++))
219*45febb45STony Han 		matrix_save_regs(matrix_base(pmatrix->matrix), &pmatrix->state);
2209ea13e5fSClément Léger }
2219ea13e5fSClément Léger 
matrix_restore_regs(vaddr_t base,struct matrix_state * state)2229ea13e5fSClément Léger static void matrix_restore_regs(vaddr_t base, struct matrix_state *state)
2239ea13e5fSClément Léger {
2249ea13e5fSClément Léger 	int idx = 0;
2259ea13e5fSClément Léger 
2269ea13e5fSClément Léger 	matrix_write_protect_disable(base);
2279ea13e5fSClément Léger 
2289ea13e5fSClément Léger 	for (idx = 0; idx < MATRIX_SPSELR_COUNT; idx++)
2299ea13e5fSClément Léger 		matrix_write(base, MATRIX_SPSELR(idx), state->spselr[idx]);
2309ea13e5fSClément Léger 
2319ea13e5fSClément Léger 	for (idx = 0; idx < MATRIX_SLAVE_COUNT; idx++) {
2329ea13e5fSClément Léger 		matrix_write(base, MATRIX_SSR(idx), state->ssr[idx]);
2339ea13e5fSClément Léger 		matrix_write(base, MATRIX_SRTSR(idx), state->srtsr[idx]);
2349ea13e5fSClément Léger 		matrix_write(base, MATRIX_SASSR(idx), state->sassr[idx]);
2359ea13e5fSClément Léger 	}
2369ea13e5fSClément Léger 
2379ea13e5fSClément Léger 	matrix_write(base, MATRIX_MEIER, state->meier);
2389ea13e5fSClément Léger 	matrix_write(base, MATRIX_MEIMR, state->meimr);
2399ea13e5fSClément Léger }
2409ea13e5fSClément Léger 
matrix_resume(void)2419ea13e5fSClément Léger static void matrix_resume(void)
2429ea13e5fSClément Léger {
243*45febb45STony Han 	unsigned int i = 0;
244*45febb45STony Han 	struct matrix *pmatrix = NULL;
245*45febb45STony Han 
246*45febb45STony Han 	for (pmatrix = matrix_get(i++); pmatrix; pmatrix = matrix_get(i++))
247*45febb45STony Han 		matrix_restore_regs(matrix_base(pmatrix->matrix),
248*45febb45STony Han 				    &pmatrix->state);
2499ea13e5fSClément Léger }
2509ea13e5fSClément Léger 
matrix_pm(enum pm_op op,uint32_t pm_hint __unused,const struct pm_callback_handle * hdl __unused)2519ea13e5fSClément Léger static TEE_Result matrix_pm(enum pm_op op, uint32_t pm_hint __unused,
2529ea13e5fSClément Léger 			    const struct pm_callback_handle *hdl __unused)
2539ea13e5fSClément Léger {
2549ea13e5fSClément Léger 	switch (op) {
2559ea13e5fSClément Léger 	case PM_OP_RESUME:
2569ea13e5fSClément Léger 		matrix_resume();
2579ea13e5fSClément Léger 		break;
2589ea13e5fSClément Léger 	case PM_OP_SUSPEND:
2599ea13e5fSClément Léger 		matrix_suspend();
2609ea13e5fSClément Léger 		break;
2619ea13e5fSClément Léger 	default:
2629ea13e5fSClément Léger 		panic("Invalid PM operation");
2639ea13e5fSClément Léger 	}
2649ea13e5fSClément Léger 
2659ea13e5fSClément Léger 	return TEE_SUCCESS;
2669ea13e5fSClément Léger }
2679ea13e5fSClément Léger 
matrix_pm_init(void)2689ea13e5fSClément Léger static TEE_Result matrix_pm_init(void)
2699ea13e5fSClément Léger {
2709ea13e5fSClément Léger 	/*
2719ea13e5fSClément Léger 	 * We can't call matrix_register_pm in matrix_init since allocator is
2729ea13e5fSClément Léger 	 * not ready yet so we just call it later in this driver init callback.
2739ea13e5fSClément Léger 	 */
2749ea13e5fSClément Léger 	register_pm_driver_cb(matrix_pm, NULL, "sam-matrix");
2759ea13e5fSClément Léger 
2769ea13e5fSClément Léger 	return TEE_SUCCESS;
2779ea13e5fSClément Léger }
2789ea13e5fSClément Léger driver_init(matrix_pm_init);
2799ea13e5fSClément Léger 
2809ea13e5fSClément Léger #endif
281