xref: /optee_os/core/drivers/firewall/stm32_etzpc.c (revision 7d9d593df977e5e18e1cc70e929ac6f1e341e405)
177ccb913SGatien Chevallier // SPDX-License-Identifier: BSD-3-Clause
277ccb913SGatien Chevallier /*
377ccb913SGatien Chevallier  * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
477ccb913SGatien Chevallier  * Copyright (c) 2017-2024, STMicroelectronics
577ccb913SGatien Chevallier  */
677ccb913SGatien Chevallier 
777ccb913SGatien Chevallier /*
877ccb913SGatien Chevallier  * STM32 ETPZC acts as a firewall on stm32mp SoC peripheral interfaces and
977ccb913SGatien Chevallier  * internal memories. The driver expects a single instance of the controller
1077ccb913SGatien Chevallier  * in the platform.
1177ccb913SGatien Chevallier  */
1277ccb913SGatien Chevallier 
1377ccb913SGatien Chevallier #include <assert.h>
1477ccb913SGatien Chevallier #include <drivers/clk_dt.h>
15f2e5b5e0SGatien Chevallier #include <drivers/firewall.h>
16f2e5b5e0SGatien Chevallier #include <drivers/firewall_device.h>
1777ccb913SGatien Chevallier #include <drivers/stm32mp_dt_bindings.h>
189c22da4bSEtienne Carriere #ifdef CFG_STM32MP15
199c22da4bSEtienne Carriere #include <drivers/stm32mp1_rcc.h>
209c22da4bSEtienne Carriere #endif
2177ccb913SGatien Chevallier #include <initcall.h>
2277ccb913SGatien Chevallier #include <io.h>
2377ccb913SGatien Chevallier #include <keep.h>
2477ccb913SGatien Chevallier #include <kernel/boot.h>
2577ccb913SGatien Chevallier #include <kernel/dt.h>
2677ccb913SGatien Chevallier #include <kernel/panic.h>
2777ccb913SGatien Chevallier #include <kernel/pm.h>
2877ccb913SGatien Chevallier #include <kernel/spinlock.h>
29f2e5b5e0SGatien Chevallier #include <kernel/tee_misc.h>
3077ccb913SGatien Chevallier #include <libfdt.h>
3177ccb913SGatien Chevallier #include <mm/core_memprot.h>
32f2e5b5e0SGatien Chevallier #include <mm/core_mmu.h>
3377ccb913SGatien Chevallier #include <stm32_util.h>
3477ccb913SGatien Chevallier #include <util.h>
3577ccb913SGatien Chevallier 
3677ccb913SGatien Chevallier /* ID Registers */
3777ccb913SGatien Chevallier #define ETZPC_TZMA0_SIZE		U(0x000)
3877ccb913SGatien Chevallier #define ETZPC_DECPROT0			U(0x010)
3977ccb913SGatien Chevallier #define ETZPC_DECPROT_LOCK0		U(0x030)
4077ccb913SGatien Chevallier #define ETZPC_HWCFGR			U(0x3F0)
4177ccb913SGatien Chevallier #define ETZPC_VERR			U(0x3F4)
4277ccb913SGatien Chevallier 
4377ccb913SGatien Chevallier /* ID Registers fields */
4477ccb913SGatien Chevallier #define ETZPC_TZMA0_SIZE_LOCK		BIT(31)
4577ccb913SGatien Chevallier #define ETZPC_DECPROT0_MASK		GENMASK_32(1, 0)
4677ccb913SGatien Chevallier #define ETZPC_HWCFGR_NUM_TZMA_MASK	GENMASK_32(7, 0)
4777ccb913SGatien Chevallier #define ETZPC_HWCFGR_NUM_TZMA_SHIFT	0
4877ccb913SGatien Chevallier #define ETZPC_HWCFGR_NUM_PER_SEC_MASK	GENMASK_32(15, 8)
4977ccb913SGatien Chevallier #define ETZPC_HWCFGR_NUM_PER_SEC_SHIFT	8
5077ccb913SGatien Chevallier #define ETZPC_HWCFGR_NUM_AHB_SEC_MASK	GENMASK_32(23, 16)
5177ccb913SGatien Chevallier #define ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT	16
5277ccb913SGatien Chevallier #define ETZPC_HWCFGR_CHUNKS1N4_MASK	GENMASK_32(31, 24)
5377ccb913SGatien Chevallier #define ETZPC_HWCFGR_CHUNKS1N4_SHIFT	24
5477ccb913SGatien Chevallier 
5577ccb913SGatien Chevallier #define DECPROT_SHIFT			1
5677ccb913SGatien Chevallier #define IDS_PER_DECPROT_REGS		U(16)
5777ccb913SGatien Chevallier #define IDS_PER_DECPROT_LOCK_REGS	U(32)
5877ccb913SGatien Chevallier 
5977ccb913SGatien Chevallier /*
6077ccb913SGatien Chevallier  * Implementation uses uint8_t to store each securable DECPROT configuration
6177ccb913SGatien Chevallier  * and uint16_t to store each securable TZMA configuration. When resuming
6277ccb913SGatien Chevallier  * from deep suspend, the DECPROT configurations are restored.
6377ccb913SGatien Chevallier  */
6477ccb913SGatien Chevallier #define PERIPH_PM_LOCK_BIT		BIT(7)
6577ccb913SGatien Chevallier #define PERIPH_PM_ATTR_MASK		GENMASK_32(2, 0)
6677ccb913SGatien Chevallier #define TZMA_PM_LOCK_BIT		BIT(15)
6777ccb913SGatien Chevallier #define TZMA_PM_VALUE_MASK		GENMASK_32(9, 0)
6877ccb913SGatien Chevallier 
69*7d9d593dSEtienne Carriere /* ETZPC DECPROT bit field values */
70*7d9d593dSEtienne Carriere enum etzpc_decprot_attributes {
71*7d9d593dSEtienne Carriere 	ETZPC_DECPROT_S_RW = 0,
72*7d9d593dSEtienne Carriere 	ETZPC_DECPROT_NS_R_S_W = 1,
73*7d9d593dSEtienne Carriere 	ETZPC_DECPROT_MCU_ISOLATION = 2,
74*7d9d593dSEtienne Carriere 	ETZPC_DECPROT_NS_RW = 3,
75*7d9d593dSEtienne Carriere 	ETZPC_DECPROT_MAX = 4,
76*7d9d593dSEtienne Carriere };
77*7d9d593dSEtienne Carriere 
7877ccb913SGatien Chevallier /*
7977ccb913SGatien Chevallier  * struct stm32_etzpc_platdata - Driver data set at initialization
8077ccb913SGatien Chevallier  *
8177ccb913SGatien Chevallier  * @name:	Name of the peripheral
8277ccb913SGatien Chevallier  * @clk:	ETZPC clock
8377ccb913SGatien Chevallier  * @periph_cfg:	Peripheral DECPROT configuration
8477ccb913SGatien Chevallier  * @tzma_cfg:	TZMA configuration
8577ccb913SGatien Chevallier  * @base:	ETZPC IOMEM base address
8677ccb913SGatien Chevallier  */
8777ccb913SGatien Chevallier struct stm32_etzpc_platdata {
8877ccb913SGatien Chevallier 	char *name;
8977ccb913SGatien Chevallier 	struct clk *clk;
9077ccb913SGatien Chevallier 	uint8_t *periph_cfg;
9177ccb913SGatien Chevallier 	uint16_t *tzma_cfg;
9277ccb913SGatien Chevallier 	struct io_pa_va base;
9377ccb913SGatien Chevallier };
9477ccb913SGatien Chevallier 
9577ccb913SGatien Chevallier /*
9677ccb913SGatien Chevallier  * struct stm32_etzpc_driver_data - configuration data from the hardware
9777ccb913SGatien Chevallier  *
9877ccb913SGatien Chevallier  * @num_tzma:	 Number of TZMA zones, read from the hardware
9977ccb913SGatien Chevallier  * @num_per_sec: Number of securable AHB & APB periphs, read from the hardware
10077ccb913SGatien Chevallier  * @num_ahb_sec: Number of securable AHB master zones, read from the hardware
10177ccb913SGatien Chevallier  */
10277ccb913SGatien Chevallier struct stm32_etzpc_driver_data {
10377ccb913SGatien Chevallier 	unsigned int num_tzma;
10477ccb913SGatien Chevallier 	unsigned int num_per_sec;
10577ccb913SGatien Chevallier 	unsigned int num_ahb_sec;
10677ccb913SGatien Chevallier };
10777ccb913SGatien Chevallier 
10877ccb913SGatien Chevallier /*
10977ccb913SGatien Chevallier  * struct etzpc_device - ETZPC device driver instance
11077ccb913SGatien Chevallier  * @pdata:	Platform data set during initialization
11177ccb913SGatien Chevallier  * @ddata:	Device configuration data from the hardware
11277ccb913SGatien Chevallier  * @lock:	Access contention
11377ccb913SGatien Chevallier  */
11477ccb913SGatien Chevallier struct etzpc_device {
11577ccb913SGatien Chevallier 	struct stm32_etzpc_platdata pdata;
11677ccb913SGatien Chevallier 	struct stm32_etzpc_driver_data ddata;
11777ccb913SGatien Chevallier 	unsigned int lock;
11877ccb913SGatien Chevallier };
11977ccb913SGatien Chevallier 
12077ccb913SGatien Chevallier static struct etzpc_device *etzpc_device;
12177ccb913SGatien Chevallier 
122f2e5b5e0SGatien Chevallier static const char *const etzpc_decprot_strings[] __maybe_unused = {
123d735136fSEtienne Carriere 	[ETZPC_DECPROT_S_RW] = "ETZPC_DECPROT_S_RW",
124d735136fSEtienne Carriere 	[ETZPC_DECPROT_NS_R_S_W] = "ETZPC_DECPROT_NS_R_S_W",
125d735136fSEtienne Carriere 	[ETZPC_DECPROT_MCU_ISOLATION] = "ETZPC_DECPROT_MCU_ISOLATION",
126d735136fSEtienne Carriere 	[ETZPC_DECPROT_NS_RW] = "ETZPC_DECPROT_NS_RW",
127f2e5b5e0SGatien Chevallier };
128f2e5b5e0SGatien Chevallier 
etzpc_lock(void)12977ccb913SGatien Chevallier static uint32_t etzpc_lock(void)
13077ccb913SGatien Chevallier {
13177ccb913SGatien Chevallier 	return cpu_spin_lock_xsave(&etzpc_device->lock);
13277ccb913SGatien Chevallier }
13377ccb913SGatien Chevallier 
etzpc_unlock(uint32_t exceptions)13477ccb913SGatien Chevallier static void etzpc_unlock(uint32_t exceptions)
13577ccb913SGatien Chevallier {
13677ccb913SGatien Chevallier 	cpu_spin_unlock_xrestore(&etzpc_device->lock, exceptions);
13777ccb913SGatien Chevallier }
13877ccb913SGatien Chevallier 
valid_decprot_id(unsigned int id)13977ccb913SGatien Chevallier static bool valid_decprot_id(unsigned int id)
14077ccb913SGatien Chevallier {
14177ccb913SGatien Chevallier 	return id < etzpc_device->ddata.num_per_sec;
14277ccb913SGatien Chevallier }
14377ccb913SGatien Chevallier 
valid_tzma_id(unsigned int id)14477ccb913SGatien Chevallier static bool __maybe_unused valid_tzma_id(unsigned int id)
14577ccb913SGatien Chevallier {
14677ccb913SGatien Chevallier 	return id < etzpc_device->ddata.num_tzma;
14777ccb913SGatien Chevallier }
14877ccb913SGatien Chevallier 
etzpc_binding2decprot(uint32_t mode)14977ccb913SGatien Chevallier static enum etzpc_decprot_attributes etzpc_binding2decprot(uint32_t mode)
15077ccb913SGatien Chevallier {
15177ccb913SGatien Chevallier 	switch (mode) {
15277ccb913SGatien Chevallier 	case DECPROT_S_RW:
15377ccb913SGatien Chevallier 		return ETZPC_DECPROT_S_RW;
15477ccb913SGatien Chevallier 	case DECPROT_NS_R_S_W:
15577ccb913SGatien Chevallier 		return ETZPC_DECPROT_NS_R_S_W;
15677ccb913SGatien Chevallier #ifdef CFG_STM32MP15
15777ccb913SGatien Chevallier 	case DECPROT_MCU_ISOLATION:
15877ccb913SGatien Chevallier 		return ETZPC_DECPROT_MCU_ISOLATION;
15977ccb913SGatien Chevallier #endif
16077ccb913SGatien Chevallier 	case DECPROT_NS_RW:
16177ccb913SGatien Chevallier 		return ETZPC_DECPROT_NS_RW;
16277ccb913SGatien Chevallier 	default:
16377ccb913SGatien Chevallier 		panic();
16477ccb913SGatien Chevallier 	}
16577ccb913SGatien Chevallier }
16677ccb913SGatien Chevallier 
1679c22da4bSEtienne Carriere static void
sanitize_decprot_config(uint32_t decprot_id __maybe_unused,enum etzpc_decprot_attributes attr __maybe_unused)1689c22da4bSEtienne Carriere sanitize_decprot_config(uint32_t decprot_id __maybe_unused,
1699c22da4bSEtienne Carriere 			enum etzpc_decprot_attributes attr __maybe_unused)
1709c22da4bSEtienne Carriere {
1719c22da4bSEtienne Carriere #ifdef CFG_STM32MP15
1729c22da4bSEtienne Carriere 	/*
1739c22da4bSEtienne Carriere 	 * STM32MP15: check dependency on RCC TZEN/MCKPROT configuration
1749c22da4bSEtienne Carriere 	 * when a ETZPC resource is secured or isolated for Cortex-M
1759c22da4bSEtienne Carriere 	 * coprocessor.
1769c22da4bSEtienne Carriere 	 */
1779c22da4bSEtienne Carriere 	switch (attr) {
1781bbb4042SEtienne Carriere 	case ETZPC_DECPROT_S_RW:
1791bbb4042SEtienne Carriere 	case ETZPC_DECPROT_NS_R_S_W:
1809c22da4bSEtienne Carriere 		if (!stm32_rcc_is_secure()) {
18141f3fcbbSEtienne Carriere 			IMSG("WARNING: RCC tzen:0, insecure ETZPC hardening %"PRIu32":%s",
18241f3fcbbSEtienne Carriere 			     decprot_id, etzpc_decprot_strings[attr]);
1839c22da4bSEtienne Carriere 			if (!IS_ENABLED(CFG_INSECURE))
1849c22da4bSEtienne Carriere 				panic();
1859c22da4bSEtienne Carriere 		}
1869c22da4bSEtienne Carriere 		break;
1871bbb4042SEtienne Carriere 	case ETZPC_DECPROT_MCU_ISOLATION:
1889c22da4bSEtienne Carriere 		if (!stm32_rcc_is_secure() || !stm32_rcc_is_mckprot()) {
18941f3fcbbSEtienne Carriere 			IMSG("WARNING: RCC tzen:%u mckprot:%u, insecure ETZPC hardening %"PRIu32":%s",
1909c22da4bSEtienne Carriere 			     stm32_rcc_is_secure(), stm32_rcc_is_mckprot(),
19141f3fcbbSEtienne Carriere 			     decprot_id, etzpc_decprot_strings[attr]);
1929c22da4bSEtienne Carriere 			if (!IS_ENABLED(CFG_INSECURE))
1939c22da4bSEtienne Carriere 				panic();
1949c22da4bSEtienne Carriere 		}
1959c22da4bSEtienne Carriere 		break;
1961bbb4042SEtienne Carriere 	case ETZPC_DECPROT_NS_RW:
1979c22da4bSEtienne Carriere 		break;
1989c22da4bSEtienne Carriere 	default:
1999c22da4bSEtienne Carriere 		assert(0);
2009c22da4bSEtienne Carriere 		break;
2019c22da4bSEtienne Carriere 	}
2029c22da4bSEtienne Carriere #endif
2039c22da4bSEtienne Carriere }
2049c22da4bSEtienne Carriere 
etzpc_configure_decprot(uint32_t decprot_id,enum etzpc_decprot_attributes attr)20577ccb913SGatien Chevallier static void etzpc_configure_decprot(uint32_t decprot_id,
20677ccb913SGatien Chevallier 				    enum etzpc_decprot_attributes attr)
20777ccb913SGatien Chevallier {
20877ccb913SGatien Chevallier 	size_t offset = U(4) * (decprot_id / IDS_PER_DECPROT_REGS);
20977ccb913SGatien Chevallier 	uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT;
21077ccb913SGatien Chevallier 	uint32_t masked_decprot = (uint32_t)attr & ETZPC_DECPROT0_MASK;
21177ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
21277ccb913SGatien Chevallier 	unsigned int exceptions = 0;
21377ccb913SGatien Chevallier 
21477ccb913SGatien Chevallier 	assert(valid_decprot_id(decprot_id));
21577ccb913SGatien Chevallier 
216f2e5b5e0SGatien Chevallier 	FMSG("ID : %"PRIu32", config %i", decprot_id, attr);
21777ccb913SGatien Chevallier 
2189c22da4bSEtienne Carriere 	sanitize_decprot_config(decprot_id, attr);
2199c22da4bSEtienne Carriere 
22077ccb913SGatien Chevallier 	exceptions = etzpc_lock();
22177ccb913SGatien Chevallier 
22277ccb913SGatien Chevallier 	io_clrsetbits32(base + ETZPC_DECPROT0 + offset,
22377ccb913SGatien Chevallier 			ETZPC_DECPROT0_MASK << shift,
22477ccb913SGatien Chevallier 			masked_decprot << shift);
22577ccb913SGatien Chevallier 
22677ccb913SGatien Chevallier 	etzpc_unlock(exceptions);
22777ccb913SGatien Chevallier }
22877ccb913SGatien Chevallier 
etzpc_get_decprot(uint32_t decprot_id)229*7d9d593dSEtienne Carriere static enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id)
23077ccb913SGatien Chevallier {
23177ccb913SGatien Chevallier 	size_t offset = U(4) * (decprot_id / IDS_PER_DECPROT_REGS);
23277ccb913SGatien Chevallier 	uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT;
23377ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
23477ccb913SGatien Chevallier 	uint32_t value = 0;
23577ccb913SGatien Chevallier 
23677ccb913SGatien Chevallier 	assert(valid_decprot_id(decprot_id));
23777ccb913SGatien Chevallier 
23877ccb913SGatien Chevallier 	value = (io_read32(base + ETZPC_DECPROT0 + offset) >> shift) &
23977ccb913SGatien Chevallier 		ETZPC_DECPROT0_MASK;
24077ccb913SGatien Chevallier 
24177ccb913SGatien Chevallier 	return (enum etzpc_decprot_attributes)value;
24277ccb913SGatien Chevallier }
24377ccb913SGatien Chevallier 
etzpc_lock_decprot(uint32_t decprot_id)24477ccb913SGatien Chevallier static void etzpc_lock_decprot(uint32_t decprot_id)
24577ccb913SGatien Chevallier {
24677ccb913SGatien Chevallier 	size_t offset = U(4) * (decprot_id / IDS_PER_DECPROT_LOCK_REGS);
24777ccb913SGatien Chevallier 	uint32_t mask = BIT(decprot_id % IDS_PER_DECPROT_LOCK_REGS);
24877ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
24977ccb913SGatien Chevallier 	uint32_t exceptions = 0;
25077ccb913SGatien Chevallier 
25177ccb913SGatien Chevallier 	assert(valid_decprot_id(decprot_id));
25277ccb913SGatien Chevallier 
25377ccb913SGatien Chevallier 	exceptions = etzpc_lock();
25477ccb913SGatien Chevallier 
25577ccb913SGatien Chevallier 	io_write32(base + offset + ETZPC_DECPROT_LOCK0, mask);
25677ccb913SGatien Chevallier 
25777ccb913SGatien Chevallier 	etzpc_unlock(exceptions);
25877ccb913SGatien Chevallier }
25977ccb913SGatien Chevallier 
decprot_is_locked(uint32_t decprot_id)26077ccb913SGatien Chevallier static bool decprot_is_locked(uint32_t decprot_id)
26177ccb913SGatien Chevallier {
26277ccb913SGatien Chevallier 	size_t offset = U(4) * (decprot_id / IDS_PER_DECPROT_LOCK_REGS);
26377ccb913SGatien Chevallier 	uint32_t mask = BIT(decprot_id % IDS_PER_DECPROT_LOCK_REGS);
26477ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
26577ccb913SGatien Chevallier 
26677ccb913SGatien Chevallier 	assert(valid_decprot_id(decprot_id));
26777ccb913SGatien Chevallier 
26877ccb913SGatien Chevallier 	return io_read32(base + offset + ETZPC_DECPROT_LOCK0) & mask;
26977ccb913SGatien Chevallier }
27077ccb913SGatien Chevallier 
etzpc_configure_tzma(uint32_t tzma_id,uint16_t tzma_value)271*7d9d593dSEtienne Carriere static void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value)
27277ccb913SGatien Chevallier {
27377ccb913SGatien Chevallier 	size_t offset = sizeof(uint32_t) * tzma_id;
27477ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
27577ccb913SGatien Chevallier 	uint32_t exceptions = 0;
27677ccb913SGatien Chevallier 
27777ccb913SGatien Chevallier 	assert(valid_tzma_id(tzma_id));
27877ccb913SGatien Chevallier 
27977ccb913SGatien Chevallier 	exceptions = etzpc_lock();
28077ccb913SGatien Chevallier 
28177ccb913SGatien Chevallier 	io_write32(base + ETZPC_TZMA0_SIZE + offset, tzma_value);
28277ccb913SGatien Chevallier 
28377ccb913SGatien Chevallier 	etzpc_unlock(exceptions);
28477ccb913SGatien Chevallier }
28577ccb913SGatien Chevallier 
etzpc_get_tzma(uint32_t tzma_id)28677ccb913SGatien Chevallier static uint16_t etzpc_get_tzma(uint32_t tzma_id)
28777ccb913SGatien Chevallier {
28877ccb913SGatien Chevallier 	size_t offset = sizeof(uint32_t) * tzma_id;
28977ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
29077ccb913SGatien Chevallier 
29177ccb913SGatien Chevallier 	assert(valid_tzma_id(tzma_id));
29277ccb913SGatien Chevallier 
29377ccb913SGatien Chevallier 	return io_read32(base + ETZPC_TZMA0_SIZE + offset);
29477ccb913SGatien Chevallier }
29577ccb913SGatien Chevallier 
etzpc_lock_tzma(uint32_t tzma_id)29677ccb913SGatien Chevallier static void etzpc_lock_tzma(uint32_t tzma_id)
29777ccb913SGatien Chevallier {
29877ccb913SGatien Chevallier 	size_t offset = sizeof(uint32_t) * tzma_id;
29977ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
30077ccb913SGatien Chevallier 	uint32_t exceptions = 0;
30177ccb913SGatien Chevallier 
30277ccb913SGatien Chevallier 	assert(valid_tzma_id(tzma_id));
30377ccb913SGatien Chevallier 
30477ccb913SGatien Chevallier 	exceptions = etzpc_lock();
30577ccb913SGatien Chevallier 
30677ccb913SGatien Chevallier 	io_setbits32(base + ETZPC_TZMA0_SIZE + offset, ETZPC_TZMA0_SIZE_LOCK);
30777ccb913SGatien Chevallier 
30877ccb913SGatien Chevallier 	etzpc_unlock(exceptions);
30977ccb913SGatien Chevallier }
31077ccb913SGatien Chevallier 
tzma_is_locked(uint32_t tzma_id)31177ccb913SGatien Chevallier static bool tzma_is_locked(uint32_t tzma_id)
31277ccb913SGatien Chevallier {
31377ccb913SGatien Chevallier 	size_t offset = sizeof(uint32_t) * tzma_id;
31477ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
31577ccb913SGatien Chevallier 
31677ccb913SGatien Chevallier 	assert(valid_tzma_id(tzma_id));
31777ccb913SGatien Chevallier 
31877ccb913SGatien Chevallier 	return io_read32(base + ETZPC_TZMA0_SIZE + offset) &
31977ccb913SGatien Chevallier 	       ETZPC_TZMA0_SIZE_LOCK;
32077ccb913SGatien Chevallier }
32177ccb913SGatien Chevallier 
etzpc_pm(enum pm_op op,unsigned int pm_hint __unused,const struct pm_callback_handle * pm_handle __unused)32277ccb913SGatien Chevallier static TEE_Result etzpc_pm(enum pm_op op, unsigned int pm_hint __unused,
32377ccb913SGatien Chevallier 			   const struct pm_callback_handle *pm_handle __unused)
32477ccb913SGatien Chevallier {
32577ccb913SGatien Chevallier 	struct stm32_etzpc_driver_data *ddata = &etzpc_device->ddata;
32677ccb913SGatien Chevallier 	struct stm32_etzpc_platdata *pdata = &etzpc_device->pdata;
32777ccb913SGatien Chevallier 	unsigned int n = 0;
32877ccb913SGatien Chevallier 
32977ccb913SGatien Chevallier 	if (op == PM_OP_SUSPEND) {
33077ccb913SGatien Chevallier 		for (n = 0; n < ddata->num_per_sec; n++) {
33177ccb913SGatien Chevallier 			pdata->periph_cfg[n] =
33277ccb913SGatien Chevallier 				(uint8_t)etzpc_get_decprot(n);
33377ccb913SGatien Chevallier 			if (decprot_is_locked(n))
33477ccb913SGatien Chevallier 				pdata->periph_cfg[n] |= PERIPH_PM_LOCK_BIT;
33577ccb913SGatien Chevallier 		}
33677ccb913SGatien Chevallier 
33777ccb913SGatien Chevallier 		for (n = 0; n < ddata->num_tzma; n++) {
33877ccb913SGatien Chevallier 			pdata->tzma_cfg[n] =
33977ccb913SGatien Chevallier 				(uint8_t)etzpc_get_tzma(n);
34077ccb913SGatien Chevallier 			if (tzma_is_locked(n))
34177ccb913SGatien Chevallier 				pdata->tzma_cfg[n] |= TZMA_PM_LOCK_BIT;
34277ccb913SGatien Chevallier 		}
34377ccb913SGatien Chevallier 
34477ccb913SGatien Chevallier 		return TEE_SUCCESS;
34577ccb913SGatien Chevallier 	}
34677ccb913SGatien Chevallier 
34777ccb913SGatien Chevallier 	/* PM_OP_RESUME */
34877ccb913SGatien Chevallier 	for (n = 0; n < ddata->num_per_sec; n++) {
34977ccb913SGatien Chevallier 		unsigned int attr = pdata->periph_cfg[n] & PERIPH_PM_ATTR_MASK;
35077ccb913SGatien Chevallier 
35177ccb913SGatien Chevallier 		etzpc_configure_decprot(n, (enum etzpc_decprot_attributes)attr);
35277ccb913SGatien Chevallier 
35377ccb913SGatien Chevallier 		if (pdata->periph_cfg[n] & PERIPH_PM_LOCK_BIT)
35477ccb913SGatien Chevallier 			etzpc_lock_decprot(n);
35577ccb913SGatien Chevallier 	}
35677ccb913SGatien Chevallier 
35777ccb913SGatien Chevallier 	for (n = 0; n < ddata->num_tzma; n++) {
35877ccb913SGatien Chevallier 		uint16_t value = pdata->tzma_cfg[n] & TZMA_PM_VALUE_MASK;
35977ccb913SGatien Chevallier 
36077ccb913SGatien Chevallier 		etzpc_configure_tzma(n, value);
36177ccb913SGatien Chevallier 
36277ccb913SGatien Chevallier 		if (pdata->tzma_cfg[n] & TZMA_PM_LOCK_BIT)
36377ccb913SGatien Chevallier 			etzpc_lock_tzma(n);
36477ccb913SGatien Chevallier 	}
36577ccb913SGatien Chevallier 
36677ccb913SGatien Chevallier 	return TEE_SUCCESS;
36777ccb913SGatien Chevallier }
36877ccb913SGatien Chevallier DECLARE_KEEP_PAGER(etzpc_pm);
36977ccb913SGatien Chevallier 
stm32_etzpc_check_access(struct firewall_query * firewall)37039263273SEtienne Carriere static TEE_Result stm32_etzpc_check_access(struct firewall_query *firewall)
37139263273SEtienne Carriere {
37239263273SEtienne Carriere 	enum etzpc_decprot_attributes attr_req = ETZPC_DECPROT_MAX;
37339263273SEtienne Carriere 	uint32_t id = 0;
37439263273SEtienne Carriere 
37539263273SEtienne Carriere 	if (!firewall || firewall->arg_count != 1)
37639263273SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
37739263273SEtienne Carriere 
37839263273SEtienne Carriere 	id = firewall->args[0] & ETZPC_ID_MASK;
37939263273SEtienne Carriere 	attr_req = etzpc_binding2decprot((firewall->args[0] &
38039263273SEtienne Carriere 					  ETZPC_MODE_MASK) >> ETZPC_MODE_SHIFT);
38139263273SEtienne Carriere 
38239263273SEtienne Carriere 	if (id < etzpc_device->ddata.num_per_sec) {
38339263273SEtienne Carriere 		if (etzpc_get_decprot(id) == attr_req)
38439263273SEtienne Carriere 			return TEE_SUCCESS;
38539263273SEtienne Carriere 		else
38639263273SEtienne Carriere 			return TEE_ERROR_ACCESS_DENIED;
38739263273SEtienne Carriere 	} else {
38839263273SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
38939263273SEtienne Carriere 	}
39039263273SEtienne Carriere }
39139263273SEtienne Carriere 
stm32_etzpc_acquire_access(struct firewall_query * firewall)392f2e5b5e0SGatien Chevallier static TEE_Result stm32_etzpc_acquire_access(struct firewall_query *firewall)
393f2e5b5e0SGatien Chevallier {
394f2e5b5e0SGatien Chevallier 	enum etzpc_decprot_attributes attr = ETZPC_DECPROT_MCU_ISOLATION;
395f2e5b5e0SGatien Chevallier 	uint32_t id = 0;
396f2e5b5e0SGatien Chevallier 
397f2e5b5e0SGatien Chevallier 	if (!firewall || firewall->arg_count != 1)
398f2e5b5e0SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
399f2e5b5e0SGatien Chevallier 
400f2e5b5e0SGatien Chevallier 	id = firewall->args[0] & ETZPC_ID_MASK;
401f2e5b5e0SGatien Chevallier 	if (id < etzpc_device->ddata.num_per_sec) {
402f2e5b5e0SGatien Chevallier 		attr = etzpc_get_decprot(id);
403f2e5b5e0SGatien Chevallier 		if (attr != ETZPC_DECPROT_S_RW &&
404f2e5b5e0SGatien Chevallier 		    attr != ETZPC_DECPROT_NS_R_S_W)
405f2e5b5e0SGatien Chevallier 			return TEE_ERROR_ACCESS_DENIED;
406f2e5b5e0SGatien Chevallier 	} else {
407f2e5b5e0SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
408f2e5b5e0SGatien Chevallier 	}
409f2e5b5e0SGatien Chevallier 
410f2e5b5e0SGatien Chevallier 	return TEE_SUCCESS;
411f2e5b5e0SGatien Chevallier }
412f2e5b5e0SGatien Chevallier 
413f2e5b5e0SGatien Chevallier static TEE_Result
stm32_etzpc_acquire_memory_access(struct firewall_query * firewall,paddr_t paddr,size_t size,bool read __unused,bool write __unused)414f2e5b5e0SGatien Chevallier stm32_etzpc_acquire_memory_access(struct firewall_query *firewall,
415f2e5b5e0SGatien Chevallier 				  paddr_t paddr, size_t size,
416f2e5b5e0SGatien Chevallier 				  bool read __unused, bool write __unused)
417f2e5b5e0SGatien Chevallier {
418f2e5b5e0SGatien Chevallier 	paddr_t tzma_base = 0;
419f2e5b5e0SGatien Chevallier 	size_t prot_size = 0;
420f2e5b5e0SGatien Chevallier 	uint32_t id = 0;
421f2e5b5e0SGatien Chevallier 
422f2e5b5e0SGatien Chevallier 	if (!firewall || firewall->arg_count != 1)
423f2e5b5e0SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
424f2e5b5e0SGatien Chevallier 
425f2e5b5e0SGatien Chevallier 	id = firewall->args[0] & ETZPC_ID_MASK;
426f2e5b5e0SGatien Chevallier 	switch (id) {
427f2e5b5e0SGatien Chevallier 	case ETZPC_TZMA0_ID:
428f2e5b5e0SGatien Chevallier 		tzma_base = ROM_BASE;
429f2e5b5e0SGatien Chevallier 		prot_size = etzpc_get_tzma(0) * SMALL_PAGE_SIZE;
430f2e5b5e0SGatien Chevallier 		break;
431f2e5b5e0SGatien Chevallier 	case ETZPC_TZMA1_ID:
432f2e5b5e0SGatien Chevallier 		tzma_base = SYSRAM_BASE;
433f2e5b5e0SGatien Chevallier 		prot_size = etzpc_get_tzma(1) * SMALL_PAGE_SIZE;
434f2e5b5e0SGatien Chevallier 		break;
435f2e5b5e0SGatien Chevallier 	default:
436f2e5b5e0SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
437f2e5b5e0SGatien Chevallier 	}
438f2e5b5e0SGatien Chevallier 
439f2e5b5e0SGatien Chevallier 	DMSG("Acquiring access for TZMA%u, secured from %#"PRIxPA" to %#"PRIxPA,
440f2e5b5e0SGatien Chevallier 	     id == ETZPC_TZMA0_ID ? 0 : 1, tzma_base, tzma_base + prot_size);
441f2e5b5e0SGatien Chevallier 
442f2e5b5e0SGatien Chevallier 	if (core_is_buffer_inside(paddr, size, tzma_base, prot_size))
443f2e5b5e0SGatien Chevallier 		return TEE_SUCCESS;
444f2e5b5e0SGatien Chevallier 
445f2e5b5e0SGatien Chevallier 	return TEE_ERROR_ACCESS_DENIED;
446f2e5b5e0SGatien Chevallier }
447f2e5b5e0SGatien Chevallier 
448f74d3fffSEtienne Carriere #ifdef CFG_STM32MP15
pager_permits_decprot_config(uint32_t decprot_id,enum etzpc_decprot_attributes attr)449f74d3fffSEtienne Carriere static bool pager_permits_decprot_config(uint32_t decprot_id,
450f74d3fffSEtienne Carriere 					 enum etzpc_decprot_attributes attr)
451f74d3fffSEtienne Carriere {
452f74d3fffSEtienne Carriere 	paddr_t ram_base = 0;
453f74d3fffSEtienne Carriere 	size_t ram_size = 0;
454f74d3fffSEtienne Carriere 
455f74d3fffSEtienne Carriere 	if (!IS_ENABLED(CFG_WITH_PAGER))
456f74d3fffSEtienne Carriere 		return true;
457f74d3fffSEtienne Carriere 
458f74d3fffSEtienne Carriere 	switch (decprot_id) {
459f74d3fffSEtienne Carriere 	case ETZPC_TZMA1_ID:
460f74d3fffSEtienne Carriere 		ram_base = SYSRAM_BASE;
461f74d3fffSEtienne Carriere 		ram_size = SYSRAM_SEC_SIZE;
462f74d3fffSEtienne Carriere 		break;
463f74d3fffSEtienne Carriere 	case STM32MP1_ETZPC_SRAM1_ID:
464f74d3fffSEtienne Carriere 		ram_base = SRAM1_BASE;
465f74d3fffSEtienne Carriere 		ram_size = SRAM1_SIZE;
466f74d3fffSEtienne Carriere 		break;
467f74d3fffSEtienne Carriere 	case STM32MP1_ETZPC_SRAM2_ID:
468f74d3fffSEtienne Carriere 		ram_base = SRAM2_BASE;
469f74d3fffSEtienne Carriere 		ram_size = SRAM2_SIZE;
470f74d3fffSEtienne Carriere 		break;
471f74d3fffSEtienne Carriere 	case STM32MP1_ETZPC_SRAM3_ID:
472f74d3fffSEtienne Carriere 		ram_base = SRAM3_BASE;
473f74d3fffSEtienne Carriere 		ram_size = SRAM3_SIZE;
474f74d3fffSEtienne Carriere 		break;
475f74d3fffSEtienne Carriere 	case STM32MP1_ETZPC_SRAM4_ID:
476f74d3fffSEtienne Carriere 		ram_base = SRAM4_BASE;
477f74d3fffSEtienne Carriere 		ram_size = SRAM4_SIZE;
478f74d3fffSEtienne Carriere 		break;
479f74d3fffSEtienne Carriere 	default:
480f74d3fffSEtienne Carriere 		return true;
481f74d3fffSEtienne Carriere 	}
482f74d3fffSEtienne Carriere 
483f74d3fffSEtienne Carriere 	if (stm32mp1_ram_intersect_pager_ram(ram_base, ram_size) &&
484f74d3fffSEtienne Carriere 	    attr != ETZPC_DECPROT_S_RW) {
485f74d3fffSEtienne Carriere 		EMSG("Internal RAM %#"PRIxPA"..%#"PRIxPA" is used by pager, must be secure",
486f74d3fffSEtienne Carriere 		     ram_base, ram_base + ram_size);
487f74d3fffSEtienne Carriere 		return false;
488f74d3fffSEtienne Carriere 	}
489f74d3fffSEtienne Carriere 
490f74d3fffSEtienne Carriere 	return true;
491f74d3fffSEtienne Carriere }
492f74d3fffSEtienne Carriere #endif /* CFG_STM32MP15 */
493f74d3fffSEtienne Carriere 
decprot_id_is_internal_ram(uint32_t id)494f117e429SEtienne Carriere static bool decprot_id_is_internal_ram(uint32_t id)
495f117e429SEtienne Carriere {
496f117e429SEtienne Carriere 	switch (id) {
497f117e429SEtienne Carriere 	case STM32MP1_ETZPC_SRAM1_ID:
498f117e429SEtienne Carriere 	case STM32MP1_ETZPC_SRAM2_ID:
499f117e429SEtienne Carriere 	case STM32MP1_ETZPC_SRAM3_ID:
500f117e429SEtienne Carriere #ifdef CFG_STM32MP15
501f117e429SEtienne Carriere 	case STM32MP1_ETZPC_SRAM4_ID:
502f117e429SEtienne Carriere 	case STM32MP1_ETZPC_RETRAM_ID:
503f117e429SEtienne Carriere #endif
504f117e429SEtienne Carriere 		return true;
505f117e429SEtienne Carriere 	default:
506f117e429SEtienne Carriere 		return false;
507f117e429SEtienne Carriere 	}
508f117e429SEtienne Carriere }
509f117e429SEtienne Carriere 
stm32_etzpc_configure_memory(struct firewall_query * firewall,paddr_t paddr,size_t size)510f117e429SEtienne Carriere static TEE_Result stm32_etzpc_configure_memory(struct firewall_query *firewall,
511f117e429SEtienne Carriere 					       paddr_t paddr, size_t size)
512f117e429SEtienne Carriere {
513f117e429SEtienne Carriere 	enum etzpc_decprot_attributes attr = ETZPC_DECPROT_MAX;
514f117e429SEtienne Carriere 	bool lock = false;
515f117e429SEtienne Carriere 	uint32_t mode = 0;
516f117e429SEtienne Carriere 	uint32_t id = 0;
517f117e429SEtienne Carriere 
518f117e429SEtienne Carriere 	if (firewall->arg_count != 1)
519f117e429SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
520f117e429SEtienne Carriere 
521f117e429SEtienne Carriere 	id = firewall->args[0] & ETZPC_ID_MASK;
522f117e429SEtienne Carriere 	mode = (firewall->args[0] & ETZPC_MODE_MASK) >> ETZPC_MODE_SHIFT;
523f117e429SEtienne Carriere 	attr = etzpc_binding2decprot(mode);
524f117e429SEtienne Carriere 	lock = firewall->args[0] & ETZPC_LOCK_MASK;
525f117e429SEtienne Carriere 
526f117e429SEtienne Carriere 	if (decprot_id_is_internal_ram(id)) {
527f117e429SEtienne Carriere 		/* Use OP-TEE SRAM addresses, not the alias one */
528f117e429SEtienne Carriere 		paddr = stm32mp1_pa_or_sram_alias_pa(paddr);
529f117e429SEtienne Carriere 
530f117e429SEtienne Carriere 		/* Target address range must match the full SRAM range */
531f117e429SEtienne Carriere 		switch (id) {
532f117e429SEtienne Carriere 		case STM32MP1_ETZPC_SRAM1_ID:
533f117e429SEtienne Carriere 			if (paddr != SRAM1_BASE || size != SRAM1_SIZE)
534f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
535f117e429SEtienne Carriere 			break;
536f117e429SEtienne Carriere 		case STM32MP1_ETZPC_SRAM2_ID:
537f117e429SEtienne Carriere 			if (paddr != SRAM2_BASE || size != SRAM2_SIZE)
538f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
539f117e429SEtienne Carriere 			break;
540f117e429SEtienne Carriere 		case STM32MP1_ETZPC_SRAM3_ID:
541f117e429SEtienne Carriere 			if (paddr != SRAM3_BASE || size != SRAM3_SIZE)
542f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
543f117e429SEtienne Carriere 			break;
544f117e429SEtienne Carriere #ifdef CFG_STM32MP15
545f117e429SEtienne Carriere 		case STM32MP1_ETZPC_SRAM4_ID:
546f117e429SEtienne Carriere 			if (paddr != SRAM4_BASE || size != SRAM4_SIZE)
547f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
548f117e429SEtienne Carriere 			break;
549f117e429SEtienne Carriere 		case STM32MP1_ETZPC_RETRAM_ID:
550f117e429SEtienne Carriere 			if (paddr != RETRAM_BASE || size != RETRAM_SIZE)
551f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
552f117e429SEtienne Carriere 			break;
553f117e429SEtienne Carriere #endif /*CFG_STM32MP15*/
554f117e429SEtienne Carriere 		default:
555f117e429SEtienne Carriere 			panic();
556f117e429SEtienne Carriere 		}
557f117e429SEtienne Carriere 
558f117e429SEtienne Carriere 		if (decprot_is_locked(id)) {
559f117e429SEtienne Carriere 			if (etzpc_get_decprot(id) != attr) {
560f117e429SEtienne Carriere 				EMSG("Internal RAM configuration locked");
561f117e429SEtienne Carriere 				return TEE_ERROR_ACCESS_DENIED;
562f117e429SEtienne Carriere 			}
563f117e429SEtienne Carriere 
564f117e429SEtienne Carriere 			return TEE_SUCCESS;
565f117e429SEtienne Carriere 		}
566f117e429SEtienne Carriere 
567f117e429SEtienne Carriere #ifdef CFG_STM32MP15
568f117e429SEtienne Carriere 		if (!pager_permits_decprot_config(id, attr))
569f117e429SEtienne Carriere 			return TEE_ERROR_ACCESS_DENIED;
570f117e429SEtienne Carriere #endif
571f117e429SEtienne Carriere 
572f117e429SEtienne Carriere 		etzpc_configure_decprot(id, attr);
573f117e429SEtienne Carriere 		if (lock)
574f117e429SEtienne Carriere 			etzpc_lock_decprot(id);
575f117e429SEtienne Carriere 	} else if (id == ETZPC_TZMA0_ID || id == ETZPC_TZMA1_ID) {
576f117e429SEtienne Carriere 		unsigned int tzma_id = 0;
577f117e429SEtienne Carriere 		uint16_t tzma_r0size = 0;
578f117e429SEtienne Carriere 		paddr_t ram_base = 0;
579f117e429SEtienne Carriere 		size_t ram_size = 0;
580f117e429SEtienne Carriere 
581f117e429SEtienne Carriere 		switch (id) {
582f117e429SEtienne Carriere 		case ETZPC_TZMA0_ID:
583f117e429SEtienne Carriere 			ram_base = ROM_BASE;
584f117e429SEtienne Carriere 			ram_size = ROM_SIZE;
585f117e429SEtienne Carriere 			tzma_id = 0;
586f117e429SEtienne Carriere 			break;
587f117e429SEtienne Carriere 		case ETZPC_TZMA1_ID:
588f117e429SEtienne Carriere 			ram_base = SYSRAM_BASE;
589f117e429SEtienne Carriere 			ram_size = SYSRAM_SIZE;
590f117e429SEtienne Carriere 			tzma_id = 1;
591f117e429SEtienne Carriere 			break;
592f117e429SEtienne Carriere 		default:
593f117e429SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
594f117e429SEtienne Carriere 		}
595f117e429SEtienne Carriere 
596f117e429SEtienne Carriere 		/* TZMA configuration supports only page aligned sizes */
597f117e429SEtienne Carriere 		if (!IS_ALIGNED(paddr, SMALL_PAGE_SIZE) ||
598f117e429SEtienne Carriere 		    !IS_ALIGNED(size, SMALL_PAGE_SIZE))
599f117e429SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
600f117e429SEtienne Carriere 
601f117e429SEtienne Carriere 		/*
602f117e429SEtienne Carriere 		 * TZMA supports only 2 access rights configuration
603f117e429SEtienne Carriere 		 * for RAM ranges: secure or non-secure.
604f117e429SEtienne Carriere 		 * Secure RAM range must start from RAM base address
605f117e429SEtienne Carriere 		 * and non-secure RAM range must end at RAM top address.
606f117e429SEtienne Carriere 		 */
607f117e429SEtienne Carriere 		switch (attr) {
608f117e429SEtienne Carriere 		case ETZPC_DECPROT_S_RW:
609f117e429SEtienne Carriere 			if (paddr != ram_base || size > ram_size)
610f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
611f117e429SEtienne Carriere 			tzma_r0size = ram_size / SMALL_PAGE_SIZE;
612f117e429SEtienne Carriere 			break;
613f117e429SEtienne Carriere 		case ETZPC_DECPROT_NS_RW:
614f117e429SEtienne Carriere 			if (paddr < ram_base ||
615f117e429SEtienne Carriere 			    paddr + size != ram_base + ram_size)
616f117e429SEtienne Carriere 				return TEE_ERROR_BAD_PARAMETERS;
617f117e429SEtienne Carriere 			tzma_r0size = (paddr - ram_base) / SMALL_PAGE_SIZE;
618f117e429SEtienne Carriere 			break;
619f117e429SEtienne Carriere 		default:
620f117e429SEtienne Carriere 			EMSG("Invalid TZMA mode %"PRIu32, mode);
621f117e429SEtienne Carriere 			return TEE_ERROR_BAD_PARAMETERS;
622f117e429SEtienne Carriere 		}
623f117e429SEtienne Carriere 
624f117e429SEtienne Carriere #ifdef CFG_STM32MP15
625f117e429SEtienne Carriere 		if (!pager_permits_decprot_config(id, attr))
626f117e429SEtienne Carriere 			return TEE_ERROR_ACCESS_DENIED;
627f117e429SEtienne Carriere #endif
628f117e429SEtienne Carriere 
629f117e429SEtienne Carriere 		if (tzma_is_locked(tzma_id)) {
630f117e429SEtienne Carriere 			if (etzpc_get_tzma(tzma_id) != tzma_r0size) {
631f117e429SEtienne Carriere 				EMSG("TZMA configuration locked");
632f117e429SEtienne Carriere 				return TEE_ERROR_ACCESS_DENIED;
633f117e429SEtienne Carriere 			}
634f117e429SEtienne Carriere 
635f117e429SEtienne Carriere 			return TEE_SUCCESS;
636f117e429SEtienne Carriere 		}
637f117e429SEtienne Carriere 
638f117e429SEtienne Carriere 		etzpc_configure_tzma(tzma_id, tzma_r0size);
639f117e429SEtienne Carriere 		if (lock)
640f117e429SEtienne Carriere 			etzpc_lock_tzma(tzma_id);
641f117e429SEtienne Carriere 	} else {
642f117e429SEtienne Carriere 		EMSG("Unknown firewall ID: %"PRIu32, id);
643f117e429SEtienne Carriere 
644f117e429SEtienne Carriere 		return TEE_ERROR_BAD_PARAMETERS;
645f117e429SEtienne Carriere 	}
646f117e429SEtienne Carriere 
647f117e429SEtienne Carriere 	return TEE_SUCCESS;
648f117e429SEtienne Carriere }
649f117e429SEtienne Carriere 
stm32_etzpc_configure(struct firewall_query * firewall)650f2e5b5e0SGatien Chevallier static TEE_Result stm32_etzpc_configure(struct firewall_query *firewall)
651f2e5b5e0SGatien Chevallier {
652f2e5b5e0SGatien Chevallier 	enum etzpc_decprot_attributes attr = ETZPC_DECPROT_MAX;
653f2e5b5e0SGatien Chevallier 	uint32_t id = 0;
654f2e5b5e0SGatien Chevallier 
655f2e5b5e0SGatien Chevallier 	if (firewall->arg_count != 1)
656f2e5b5e0SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
657f2e5b5e0SGatien Chevallier 
658f2e5b5e0SGatien Chevallier 	id = firewall->args[0] & ETZPC_ID_MASK;
659f2e5b5e0SGatien Chevallier 
660f2e5b5e0SGatien Chevallier 	if (id < etzpc_device->ddata.num_per_sec) {
661f2e5b5e0SGatien Chevallier 		uint32_t mode = 0;
662f2e5b5e0SGatien Chevallier 
663f2e5b5e0SGatien Chevallier 		/*
664f2e5b5e0SGatien Chevallier 		 * Peripheral configuration, we assume the configuration is as
665f2e5b5e0SGatien Chevallier 		 * follows:
666f2e5b5e0SGatien Chevallier 		 * firewall->args[0]: Firewall configuration to apply
667f2e5b5e0SGatien Chevallier 		 */
668f2e5b5e0SGatien Chevallier 
669f2e5b5e0SGatien Chevallier 		mode = (firewall->args[0] & ETZPC_MODE_MASK) >>
670f2e5b5e0SGatien Chevallier 		       ETZPC_MODE_SHIFT;
671f2e5b5e0SGatien Chevallier 		attr = etzpc_binding2decprot(mode);
672f2e5b5e0SGatien Chevallier 
673f2e5b5e0SGatien Chevallier 		if (decprot_is_locked(id)) {
674bea4f8d3SEtienne Carriere 			if (etzpc_get_decprot(id) != attr) {
675f2e5b5e0SGatien Chevallier 				EMSG("Peripheral configuration locked");
676f2e5b5e0SGatien Chevallier 				return TEE_ERROR_ACCESS_DENIED;
677f2e5b5e0SGatien Chevallier 			}
678f2e5b5e0SGatien Chevallier 
679bea4f8d3SEtienne Carriere 			DMSG("Compliant locked config for periph %"PRIu32" - attr %s",
680bea4f8d3SEtienne Carriere 			     id, etzpc_decprot_strings[attr]);
681bea4f8d3SEtienne Carriere 
682bea4f8d3SEtienne Carriere 			return TEE_SUCCESS;
683bea4f8d3SEtienne Carriere 		}
684bea4f8d3SEtienne Carriere 
685f74d3fffSEtienne Carriere #ifdef CFG_STM32MP15
686f74d3fffSEtienne Carriere 		if (!pager_permits_decprot_config(id, attr))
687f74d3fffSEtienne Carriere 			return TEE_ERROR_ACCESS_DENIED;
688f74d3fffSEtienne Carriere #endif
689f74d3fffSEtienne Carriere 
690f2e5b5e0SGatien Chevallier 		DMSG("Setting access config for periph %"PRIu32" - attr %s", id,
691f2e5b5e0SGatien Chevallier 		     etzpc_decprot_strings[attr]);
692f2e5b5e0SGatien Chevallier 
693f2e5b5e0SGatien Chevallier 		etzpc_configure_decprot(id, attr);
694f2e5b5e0SGatien Chevallier 		if (firewall->args[0] & ETZPC_LOCK_MASK)
695f2e5b5e0SGatien Chevallier 			etzpc_lock_decprot(id);
696f2e5b5e0SGatien Chevallier 
697f2e5b5e0SGatien Chevallier 		return TEE_SUCCESS;
698f2e5b5e0SGatien Chevallier 	}
699f2e5b5e0SGatien Chevallier 	EMSG("Unknown firewall ID: %"PRIu32, id);
700f2e5b5e0SGatien Chevallier 
701f2e5b5e0SGatien Chevallier 	return TEE_ERROR_BAD_PARAMETERS;
702f2e5b5e0SGatien Chevallier }
703f2e5b5e0SGatien Chevallier 
stm32_etzpc_set_driverdata(void)70477ccb913SGatien Chevallier static void stm32_etzpc_set_driverdata(void)
70577ccb913SGatien Chevallier {
70677ccb913SGatien Chevallier 	struct stm32_etzpc_driver_data *ddata = &etzpc_device->ddata;
70777ccb913SGatien Chevallier 	vaddr_t base = etzpc_device->pdata.base.va;
70877ccb913SGatien Chevallier 	uint32_t reg = io_read32(base + ETZPC_HWCFGR);
70977ccb913SGatien Chevallier 
71077ccb913SGatien Chevallier 	ddata->num_tzma = (reg & ETZPC_HWCFGR_NUM_TZMA_MASK) >>
71177ccb913SGatien Chevallier 			   ETZPC_HWCFGR_NUM_TZMA_SHIFT;
71277ccb913SGatien Chevallier 	ddata->num_per_sec = (reg & ETZPC_HWCFGR_NUM_PER_SEC_MASK) >>
71377ccb913SGatien Chevallier 			      ETZPC_HWCFGR_NUM_PER_SEC_SHIFT;
71477ccb913SGatien Chevallier 	ddata->num_ahb_sec = (reg & ETZPC_HWCFGR_NUM_AHB_SEC_MASK) >>
71577ccb913SGatien Chevallier 			      ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT;
71677ccb913SGatien Chevallier 
71777ccb913SGatien Chevallier 	DMSG("ETZPC revision 0x%02"PRIx8", per_sec %u, ahb_sec %u, tzma %u",
71877ccb913SGatien Chevallier 	     io_read8(base + ETZPC_VERR),
71977ccb913SGatien Chevallier 	     ddata->num_per_sec, ddata->num_ahb_sec, ddata->num_tzma);
72077ccb913SGatien Chevallier }
72177ccb913SGatien Chevallier 
fdt_etzpc_conf_decprot(const void * fdt,int node)72277ccb913SGatien Chevallier static void fdt_etzpc_conf_decprot(const void *fdt, int node)
72377ccb913SGatien Chevallier {
72477ccb913SGatien Chevallier 	const fdt32_t *cuint = NULL;
72577ccb913SGatien Chevallier 	size_t i = 0;
72677ccb913SGatien Chevallier 	int len = 0;
72777ccb913SGatien Chevallier 
72877ccb913SGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,decprot", &len);
72977ccb913SGatien Chevallier 	if (!cuint) {
73077ccb913SGatien Chevallier 		DMSG("No ETZPC DECPROT configuration in DT");
73177ccb913SGatien Chevallier 		return;
73277ccb913SGatien Chevallier 	}
73377ccb913SGatien Chevallier 
73477ccb913SGatien Chevallier 	clk_enable(etzpc_device->pdata.clk);
73577ccb913SGatien Chevallier 
73677ccb913SGatien Chevallier 	for (i = 0; i < len / sizeof(uint32_t); i++) {
73777ccb913SGatien Chevallier 		uint32_t value = fdt32_to_cpu(cuint[i]);
73877ccb913SGatien Chevallier 		uint32_t id = value & ETZPC_ID_MASK;
73977ccb913SGatien Chevallier 		uint32_t mode = (value & ETZPC_MODE_MASK) >> ETZPC_MODE_SHIFT;
74077ccb913SGatien Chevallier 		bool lock = value & ETZPC_LOCK_MASK;
74177ccb913SGatien Chevallier 		enum etzpc_decprot_attributes attr = ETZPC_DECPROT_MAX;
74277ccb913SGatien Chevallier 
74377ccb913SGatien Chevallier 		if (!valid_decprot_id(id)) {
74477ccb913SGatien Chevallier 			DMSG("Invalid DECPROT %"PRIu32, id);
74577ccb913SGatien Chevallier 			panic();
74677ccb913SGatien Chevallier 		}
74777ccb913SGatien Chevallier 
74877ccb913SGatien Chevallier 		attr = etzpc_binding2decprot(mode);
749f74d3fffSEtienne Carriere 
750f74d3fffSEtienne Carriere #ifdef CFG_STM32MP15
751f74d3fffSEtienne Carriere 		if (!pager_permits_decprot_config(id, attr))
752f74d3fffSEtienne Carriere 			panic();
753f74d3fffSEtienne Carriere #endif
754f74d3fffSEtienne Carriere 
75577ccb913SGatien Chevallier 		etzpc_configure_decprot(id, attr);
75677ccb913SGatien Chevallier 
75777ccb913SGatien Chevallier 		if (lock)
75877ccb913SGatien Chevallier 			etzpc_lock_decprot(id);
75977ccb913SGatien Chevallier 	}
76077ccb913SGatien Chevallier 
76177ccb913SGatien Chevallier 	clk_disable(etzpc_device->pdata.clk);
76277ccb913SGatien Chevallier }
76377ccb913SGatien Chevallier 
764f2e5b5e0SGatien Chevallier static TEE_Result
stm32_etzpc_dt_probe_bus(const void * fdt,int node,struct firewall_controller * ctrl __maybe_unused)765f2e5b5e0SGatien Chevallier stm32_etzpc_dt_probe_bus(const void *fdt, int node,
766f2e5b5e0SGatien Chevallier 			 struct firewall_controller *ctrl __maybe_unused)
767f2e5b5e0SGatien Chevallier {
768f2e5b5e0SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
769f2e5b5e0SGatien Chevallier 	struct firewall_query *fw = NULL;
770f2e5b5e0SGatien Chevallier 	int subnode = 0;
771f2e5b5e0SGatien Chevallier 
772f2e5b5e0SGatien Chevallier 	DMSG("Populating %s firewall bus", ctrl->name);
773f2e5b5e0SGatien Chevallier 
774f2e5b5e0SGatien Chevallier 	fdt_for_each_subnode(subnode, fdt, node) {
775f2e5b5e0SGatien Chevallier 		unsigned int i = 0;
776f2e5b5e0SGatien Chevallier 
777f2e5b5e0SGatien Chevallier 		if (fdt_get_status(fdt, subnode) == DT_STATUS_DISABLED)
778f2e5b5e0SGatien Chevallier 			continue;
779f2e5b5e0SGatien Chevallier 
780f2e5b5e0SGatien Chevallier 		if (IS_ENABLED(CFG_INSECURE) &&
781f2e5b5e0SGatien Chevallier 		    stm32mp_allow_probe_shared_device(fdt, subnode)) {
782f2e5b5e0SGatien Chevallier 			DMSG("Skipping firewall attributes check for %s",
783f2e5b5e0SGatien Chevallier 			     fdt_get_name(fdt, subnode, NULL));
784f2e5b5e0SGatien Chevallier 			goto skip_check;
785f2e5b5e0SGatien Chevallier 		}
786f2e5b5e0SGatien Chevallier 
787f2e5b5e0SGatien Chevallier 		DMSG("Acquiring firewall access for %s when probing bus",
788f2e5b5e0SGatien Chevallier 		     fdt_get_name(fdt, subnode, NULL));
789f2e5b5e0SGatien Chevallier 
790f2e5b5e0SGatien Chevallier 		do {
791f2e5b5e0SGatien Chevallier 			/*
792f2e5b5e0SGatien Chevallier 			 * The access-controllers property is mandatory for
793f2e5b5e0SGatien Chevallier 			 * firewall bus devices
794f2e5b5e0SGatien Chevallier 			 */
795f2e5b5e0SGatien Chevallier 			res = firewall_dt_get_by_index(fdt, subnode, i, &fw);
796f2e5b5e0SGatien Chevallier 			if (res == TEE_ERROR_ITEM_NOT_FOUND) {
797f2e5b5e0SGatien Chevallier 				/* Stop when nothing more to parse */
798f2e5b5e0SGatien Chevallier 				break;
799f2e5b5e0SGatien Chevallier 			} else if (res) {
800f2e5b5e0SGatien Chevallier 				EMSG("%s: Error on node %s: %#"PRIx32,
801f2e5b5e0SGatien Chevallier 				     ctrl->name,
802f2e5b5e0SGatien Chevallier 				     fdt_get_name(fdt, subnode, NULL), res);
803f2e5b5e0SGatien Chevallier 				panic();
804f2e5b5e0SGatien Chevallier 			}
805f2e5b5e0SGatien Chevallier 
806f2e5b5e0SGatien Chevallier 			res = firewall_acquire_access(fw);
807f2e5b5e0SGatien Chevallier 			if (res) {
808f2e5b5e0SGatien Chevallier 				EMSG("%s: %s not accessible: %#"PRIx32,
809f2e5b5e0SGatien Chevallier 				     ctrl->name,
810f2e5b5e0SGatien Chevallier 				     fdt_get_name(fdt, subnode, NULL), res);
811f2e5b5e0SGatien Chevallier 				panic();
812f2e5b5e0SGatien Chevallier 			}
813f2e5b5e0SGatien Chevallier 
814f2e5b5e0SGatien Chevallier 			firewall_put(fw);
815f2e5b5e0SGatien Chevallier 			i++;
816f2e5b5e0SGatien Chevallier 		} while (true);
817f2e5b5e0SGatien Chevallier 
818f2e5b5e0SGatien Chevallier skip_check:
819f2e5b5e0SGatien Chevallier 		res = dt_driver_maybe_add_probe_node(fdt, subnode);
820f2e5b5e0SGatien Chevallier 		if (res) {
821f2e5b5e0SGatien Chevallier 			EMSG("Failed on node %s with %#"PRIx32,
822f2e5b5e0SGatien Chevallier 			     fdt_get_name(fdt, subnode, NULL), res);
823f2e5b5e0SGatien Chevallier 			panic();
824f2e5b5e0SGatien Chevallier 		}
825f2e5b5e0SGatien Chevallier 	}
826f2e5b5e0SGatien Chevallier 
827f2e5b5e0SGatien Chevallier 	return TEE_SUCCESS;
828f2e5b5e0SGatien Chevallier }
829f2e5b5e0SGatien Chevallier 
init_etzpc_from_dt(const void * fdt,int node)83077ccb913SGatien Chevallier static TEE_Result init_etzpc_from_dt(const void *fdt, int node)
83177ccb913SGatien Chevallier {
83277ccb913SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
83377ccb913SGatien Chevallier 	struct dt_node_info etzpc_info = { };
83477ccb913SGatien Chevallier 	int len = 0;
83577ccb913SGatien Chevallier 
83677ccb913SGatien Chevallier 	fdt_fill_device_info(fdt, &etzpc_info, node);
83777ccb913SGatien Chevallier 	if (etzpc_info.reg == DT_INFO_INVALID_REG ||
83877ccb913SGatien Chevallier 	    etzpc_info.reg_size == DT_INFO_INVALID_REG_SIZE)
83977ccb913SGatien Chevallier 		return TEE_ERROR_ITEM_NOT_FOUND;
84077ccb913SGatien Chevallier 
84177ccb913SGatien Chevallier 	etzpc_device->pdata.base.pa = etzpc_info.reg;
84277ccb913SGatien Chevallier 	etzpc_device->pdata.name = strdup(fdt_get_name(fdt, node, &len));
84377ccb913SGatien Chevallier 	io_pa_or_va_secure(&etzpc_device->pdata.base, etzpc_info.reg_size);
84477ccb913SGatien Chevallier 	res = clk_dt_get_by_index(fdt, node, 0, &etzpc_device->pdata.clk);
84577ccb913SGatien Chevallier 	if (res)
84677ccb913SGatien Chevallier 		return res;
84777ccb913SGatien Chevallier 
84877ccb913SGatien Chevallier 	stm32_etzpc_set_driverdata();
84977ccb913SGatien Chevallier 
85077ccb913SGatien Chevallier 	etzpc_device->pdata.periph_cfg =
85177ccb913SGatien Chevallier 		calloc(etzpc_device->ddata.num_per_sec,
85277ccb913SGatien Chevallier 		       sizeof(*etzpc_device->pdata.periph_cfg));
853f2e5b5e0SGatien Chevallier 	if (!etzpc_device->pdata.periph_cfg)
854f2e5b5e0SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
85577ccb913SGatien Chevallier 
85677ccb913SGatien Chevallier 	etzpc_device->pdata.tzma_cfg =
85777ccb913SGatien Chevallier 		calloc(etzpc_device->ddata.num_tzma,
85877ccb913SGatien Chevallier 		       sizeof(*etzpc_device->pdata.tzma_cfg));
859f2e5b5e0SGatien Chevallier 	if (!etzpc_device->pdata.tzma_cfg) {
860f2e5b5e0SGatien Chevallier 		free(etzpc_device->pdata.periph_cfg);
86177ccb913SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
862f2e5b5e0SGatien Chevallier 	}
86377ccb913SGatien Chevallier 
86477ccb913SGatien Chevallier 	return TEE_SUCCESS;
86577ccb913SGatien Chevallier }
86677ccb913SGatien Chevallier 
867f2e5b5e0SGatien Chevallier static const struct firewall_controller_ops firewall_ops = {
868f2e5b5e0SGatien Chevallier 	.set_conf = stm32_etzpc_configure,
869f117e429SEtienne Carriere 	.set_memory_conf = stm32_etzpc_configure_memory,
87039263273SEtienne Carriere 	.check_access = stm32_etzpc_check_access,
871f2e5b5e0SGatien Chevallier 	.acquire_access = stm32_etzpc_acquire_access,
872f2e5b5e0SGatien Chevallier 	.acquire_memory_access = stm32_etzpc_acquire_memory_access,
873f2e5b5e0SGatien Chevallier };
874f2e5b5e0SGatien Chevallier 
stm32_etzpc_probe(const void * fdt,int node,const void * compat_data __unused)87577ccb913SGatien Chevallier static TEE_Result stm32_etzpc_probe(const void *fdt, int node,
87677ccb913SGatien Chevallier 				    const void *compat_data __unused)
87777ccb913SGatien Chevallier {
87877ccb913SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
879f2e5b5e0SGatien Chevallier 	struct firewall_controller *controller = NULL;
88077ccb913SGatien Chevallier 
88177ccb913SGatien Chevallier 	etzpc_device = calloc(1, sizeof(*etzpc_device));
88277ccb913SGatien Chevallier 	if (!etzpc_device)
883f2e5b5e0SGatien Chevallier 		panic();
88477ccb913SGatien Chevallier 
88577ccb913SGatien Chevallier 	res = init_etzpc_from_dt(fdt, node);
88677ccb913SGatien Chevallier 	if (res) {
88777ccb913SGatien Chevallier 		free(etzpc_device->pdata.periph_cfg);
88877ccb913SGatien Chevallier 		free(etzpc_device->pdata.tzma_cfg);
88977ccb913SGatien Chevallier 		free(etzpc_device->pdata.name);
89077ccb913SGatien Chevallier 		free(etzpc_device);
891f2e5b5e0SGatien Chevallier 		free(controller);
89277ccb913SGatien Chevallier 		return res;
89377ccb913SGatien Chevallier 	}
89477ccb913SGatien Chevallier 
895f2e5b5e0SGatien Chevallier 	controller = calloc(1, sizeof(*controller));
896f2e5b5e0SGatien Chevallier 	if (!controller)
89777ccb913SGatien Chevallier 		panic();
898f2e5b5e0SGatien Chevallier 
899f2e5b5e0SGatien Chevallier 	controller->base = &etzpc_device->pdata.base;
900f2e5b5e0SGatien Chevallier 	controller->name = etzpc_device->pdata.name;
901f2e5b5e0SGatien Chevallier 	controller->priv = etzpc_device;
902f2e5b5e0SGatien Chevallier 	controller->ops = &firewall_ops;
903f2e5b5e0SGatien Chevallier 
904f2e5b5e0SGatien Chevallier 	res = firewall_dt_controller_register(fdt, node, controller);
905f2e5b5e0SGatien Chevallier 	if (res)
906f2e5b5e0SGatien Chevallier 		panic("Cannot register ETZPC as a firewall controller");
907f2e5b5e0SGatien Chevallier 
908f2e5b5e0SGatien Chevallier 	fdt_etzpc_conf_decprot(fdt, node);
909f2e5b5e0SGatien Chevallier 
910f2e5b5e0SGatien Chevallier 	res = stm32_etzpc_dt_probe_bus(fdt, node, controller);
911f2e5b5e0SGatien Chevallier 	if (res)
912f2e5b5e0SGatien Chevallier 		panic("Cannot populate bus");
91377ccb913SGatien Chevallier 
91477ccb913SGatien Chevallier 	register_pm_core_service_cb(etzpc_pm, NULL, "stm32-etzpc");
91577ccb913SGatien Chevallier 
91677ccb913SGatien Chevallier 	return TEE_SUCCESS;
91777ccb913SGatien Chevallier }
91877ccb913SGatien Chevallier 
91977ccb913SGatien Chevallier static const struct dt_device_match etzpc_match_table[] = {
92077ccb913SGatien Chevallier 	{ .compatible = "st,stm32-etzpc" },
92177ccb913SGatien Chevallier 	{ }
92277ccb913SGatien Chevallier };
92377ccb913SGatien Chevallier 
92477ccb913SGatien Chevallier DEFINE_DT_DRIVER(etzpc_dt_driver) = {
92577ccb913SGatien Chevallier 	.name = "stm32-etzpc",
92677ccb913SGatien Chevallier 	.match_table = etzpc_match_table,
92777ccb913SGatien Chevallier 	.probe = stm32_etzpc_probe,
92877ccb913SGatien Chevallier };
929