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