159c253f9SEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
259c253f9SEtienne Carriere /*
359c253f9SEtienne Carriere * Copyright (c) 2019-2020, STMicroelectronics
459c253f9SEtienne Carriere */
559c253f9SEtienne Carriere
659c253f9SEtienne Carriere #include <assert.h>
759c253f9SEtienne Carriere #include <config.h>
8*35a04c15SGatien Chevallier #include <drivers/clk.h>
9*35a04c15SGatien Chevallier #include <drivers/clk_dt.h>
10*35a04c15SGatien Chevallier #include <drivers/stm32mp_dt_bindings.h>
1159c253f9SEtienne Carriere #include <drivers/tzc400.h>
1259c253f9SEtienne Carriere #include <initcall.h>
13*35a04c15SGatien Chevallier #include <io.h>
14*35a04c15SGatien Chevallier #include <keep.h>
15*35a04c15SGatien Chevallier #include <kernel/dt.h>
1659c253f9SEtienne Carriere #include <kernel/interrupt.h>
1759c253f9SEtienne Carriere #include <kernel/panic.h>
18*35a04c15SGatien Chevallier #include <kernel/pm.h>
19*35a04c15SGatien Chevallier #include <kernel/tee_misc.h>
20*35a04c15SGatien Chevallier #include <libfdt.h>
2159c253f9SEtienne Carriere #include <mm/core_memprot.h>
2259c253f9SEtienne Carriere #include <platform_config.h>
23*35a04c15SGatien Chevallier #include <stm32_util.h>
2459c253f9SEtienne Carriere #include <trace.h>
2559c253f9SEtienne Carriere #include <util.h>
2659c253f9SEtienne Carriere
27*35a04c15SGatien Chevallier #define IS_PAGE_ALIGNED(addr) (((addr) & SMALL_PAGE_MASK) == 0)
28*35a04c15SGatien Chevallier #define FILTER_MASK(_width) GENMASK_32(((_width) - U(1)), U(0))
29*35a04c15SGatien Chevallier
30*35a04c15SGatien Chevallier /*
31*35a04c15SGatien Chevallier * struct stm32mp_tzc_region - Define a TZC400 region configuration
32*35a04c15SGatien Chevallier * @cfg: Region configuration bit mask
33*35a04c15SGatien Chevallier * @addr: Region physical base address
34*35a04c15SGatien Chevallier * @len: Region byte size
35*35a04c15SGatien Chevallier */
36*35a04c15SGatien Chevallier struct stm32mp_tzc_region {
37*35a04c15SGatien Chevallier uint32_t cfg;
38*35a04c15SGatien Chevallier uint32_t addr;
39*35a04c15SGatien Chevallier uint32_t len;
40*35a04c15SGatien Chevallier };
41*35a04c15SGatien Chevallier
42*35a04c15SGatien Chevallier /*
43*35a04c15SGatien Chevallier * struct stm32mp_tzc_platdata - Device platform data
44*35a04c15SGatien Chevallier * @name: Device name for debug purpose
45*35a04c15SGatien Chevallier * @base: TZC400 IOMEM base address
46*35a04c15SGatien Chevallier * @clk: TZC400 bus clocks (1 or 2 clocks, depending on the platform)
47*35a04c15SGatien Chevallier * @mem_base: Physical base address of the memory covered by the device
48*35a04c15SGatien Chevallier * @mem_size: Byte size of the physical memory covered by the device
49*35a04c15SGatien Chevallier * @itr_chip: Interrupt controller handle
50*35a04c15SGatien Chevallier * @itr_num: TZC400 interrupt number handled by @itr_chip
51*35a04c15SGatien Chevallier */
52*35a04c15SGatien Chevallier struct stm32mp_tzc_platdata {
53*35a04c15SGatien Chevallier const char *name;
54*35a04c15SGatien Chevallier vaddr_t base;
55*35a04c15SGatien Chevallier struct clk *clk[2];
56*35a04c15SGatien Chevallier uint32_t mem_base;
57*35a04c15SGatien Chevallier uint32_t mem_size;
58*35a04c15SGatien Chevallier struct itr_chip *itr_chip;
59*35a04c15SGatien Chevallier size_t itr_num;
60*35a04c15SGatien Chevallier };
61*35a04c15SGatien Chevallier
62*35a04c15SGatien Chevallier /*
63*35a04c15SGatien Chevallier * struct stm32mp_tzc_driver_data - Device configuration read from the hardware
64*35a04c15SGatien Chevallier * @nb_filters: Number of TZC400 filter cells
65*35a04c15SGatien Chevallier * @nb_regions: Number of regions supported by the TZC400
66*35a04c15SGatien Chevallier */
67*35a04c15SGatien Chevallier struct stm32mp_tzc_driver_data {
68*35a04c15SGatien Chevallier uint32_t nb_filters;
69*35a04c15SGatien Chevallier uint32_t nb_regions;
70*35a04c15SGatien Chevallier };
71*35a04c15SGatien Chevallier
72*35a04c15SGatien Chevallier /*
73*35a04c15SGatien Chevallier * struct tzc_device - Device data
74*35a04c15SGatien Chevallier * @pdata: Device configuration read from the platform DT
75*35a04c15SGatien Chevallier * @ddata: Device configuration data read from the hardware
76*35a04c15SGatien Chevallier * @reg: Array of regions configured in the controller
77*35a04c15SGatien Chevallier * @nb_reg_used: Number of cells in @reg
78*35a04c15SGatien Chevallier */
79*35a04c15SGatien Chevallier struct tzc_device {
80*35a04c15SGatien Chevallier struct stm32mp_tzc_platdata pdata;
81*35a04c15SGatien Chevallier struct stm32mp_tzc_driver_data ddata;
82*35a04c15SGatien Chevallier struct tzc_region_config *reg;
83*35a04c15SGatien Chevallier uint32_t nb_reg_used;
84*35a04c15SGatien Chevallier };
85*35a04c15SGatien Chevallier
86*35a04c15SGatien Chevallier /*
87*35a04c15SGatien Chevallier * struct tzc_region_non_sec - Registered non-secure memory region
88*35a04c15SGatien Chevallier * @region: Memory region description
89*35a04c15SGatien Chevallier * @link: Link in non-secure memory list
90*35a04c15SGatien Chevallier *
91*35a04c15SGatien Chevallier * At TZC driver initialization, there are memory regions defined in the DT
92*35a04c15SGatien Chevallier * with TZC configuration information. TZC is first configured for each of
93*35a04c15SGatien Chevallier * these regions and each is carved out from the overall memory address range
94*35a04c15SGatien Chevallier * controlled by TZC. This results in a series a memory regions that, by
95*35a04c15SGatien Chevallier * construction, are assigned to non-secure world.
96*35a04c15SGatien Chevallier */
97*35a04c15SGatien Chevallier struct tzc_region_non_sec {
98*35a04c15SGatien Chevallier struct tzc_region_config region;
99*35a04c15SGatien Chevallier SLIST_ENTRY(tzc_region_non_sec) link;
100*35a04c15SGatien Chevallier };
101*35a04c15SGatien Chevallier
102*35a04c15SGatien Chevallier static SLIST_HEAD(nsec_list_head, tzc_region_non_sec) nsec_region_list =
103*35a04c15SGatien Chevallier SLIST_HEAD_INITIALIZER(nsec_list_head);
104200aed24SGatien Chevallier
tzc_it_handler(struct itr_handler * handler __unused)10559c253f9SEtienne Carriere static enum itr_return tzc_it_handler(struct itr_handler *handler __unused)
10659c253f9SEtienne Carriere {
10759c253f9SEtienne Carriere EMSG("TZC permission failure");
10859c253f9SEtienne Carriere tzc_fail_dump();
10959c253f9SEtienne Carriere
11059c253f9SEtienne Carriere if (IS_ENABLED(CFG_STM32MP_PANIC_ON_TZC_PERM_VIOLATION))
11159c253f9SEtienne Carriere panic();
11259c253f9SEtienne Carriere else
11359c253f9SEtienne Carriere tzc_int_clear();
11459c253f9SEtienne Carriere
11559c253f9SEtienne Carriere return ITRR_HANDLED;
11659c253f9SEtienne Carriere }
117*35a04c15SGatien Chevallier DECLARE_KEEP_PAGER(tzc_it_handler);
11859c253f9SEtienne Carriere
tzc_region_check_overlap(struct tzc_device * tzc_dev,const struct tzc_region_config * reg)119*35a04c15SGatien Chevallier static TEE_Result tzc_region_check_overlap(struct tzc_device *tzc_dev,
120*35a04c15SGatien Chevallier const struct tzc_region_config *reg)
12159c253f9SEtienne Carriere {
122*35a04c15SGatien Chevallier unsigned int i = 0;
12359c253f9SEtienne Carriere
124*35a04c15SGatien Chevallier /* Check if base address already defined in another region */
125*35a04c15SGatien Chevallier for (i = 0; i < tzc_dev->nb_reg_used; i++)
126*35a04c15SGatien Chevallier if (reg->base <= tzc_dev->reg[i].top &&
127*35a04c15SGatien Chevallier reg->top >= tzc_dev->reg[i].base)
128*35a04c15SGatien Chevallier return TEE_ERROR_ACCESS_CONFLICT;
12959c253f9SEtienne Carriere
13059c253f9SEtienne Carriere return TEE_SUCCESS;
13159c253f9SEtienne Carriere }
132*35a04c15SGatien Chevallier
tzc_set_driverdata(struct tzc_device * tzc_dev)133*35a04c15SGatien Chevallier static void tzc_set_driverdata(struct tzc_device *tzc_dev)
134*35a04c15SGatien Chevallier {
135*35a04c15SGatien Chevallier uintptr_t base = tzc_dev->pdata.base;
136*35a04c15SGatien Chevallier uint32_t regval = 0;
137*35a04c15SGatien Chevallier
138*35a04c15SGatien Chevallier regval = io_read32(base + BUILD_CONFIG_OFF);
139*35a04c15SGatien Chevallier tzc_dev->ddata.nb_filters = ((regval >> BUILD_CONFIG_NF_SHIFT) &
140*35a04c15SGatien Chevallier BUILD_CONFIG_NF_MASK) + 1;
141*35a04c15SGatien Chevallier tzc_dev->ddata.nb_regions = ((regval >> BUILD_CONFIG_NR_SHIFT) &
142*35a04c15SGatien Chevallier BUILD_CONFIG_NR_MASK);
143*35a04c15SGatien Chevallier
144*35a04c15SGatien Chevallier DMSG("TZC400 Filters %"PRIu32" Regions %"PRIu32,
145*35a04c15SGatien Chevallier tzc_dev->ddata.nb_filters, tzc_dev->ddata.nb_regions);
146*35a04c15SGatien Chevallier }
147*35a04c15SGatien Chevallier
stm32mp_tzc_region0(bool enable)148*35a04c15SGatien Chevallier static void stm32mp_tzc_region0(bool enable)
149*35a04c15SGatien Chevallier {
150*35a04c15SGatien Chevallier struct tzc_region_config region_cfg_0 = {
151*35a04c15SGatien Chevallier .base = 0,
152*35a04c15SGatien Chevallier .top = UINT_MAX,
153*35a04c15SGatien Chevallier .sec_attr = TZC_REGION_S_NONE,
154*35a04c15SGatien Chevallier .ns_device_access = 0,
155*35a04c15SGatien Chevallier };
156*35a04c15SGatien Chevallier
157*35a04c15SGatien Chevallier if (enable)
158*35a04c15SGatien Chevallier region_cfg_0.sec_attr = TZC_REGION_S_RDWR;
159*35a04c15SGatien Chevallier
160*35a04c15SGatien Chevallier tzc_configure_region(0, ®ion_cfg_0);
161*35a04c15SGatien Chevallier }
162*35a04c15SGatien Chevallier
stm32mp_tzc_reset_region(struct tzc_device * tzc_dev)163*35a04c15SGatien Chevallier static void stm32mp_tzc_reset_region(struct tzc_device *tzc_dev)
164*35a04c15SGatien Chevallier {
165*35a04c15SGatien Chevallier unsigned int i = 0;
166*35a04c15SGatien Chevallier const struct tzc_region_config cfg = { .top = 0x00000FFF };
167*35a04c15SGatien Chevallier
168*35a04c15SGatien Chevallier /* Clean old configuration */
169*35a04c15SGatien Chevallier for (i = 0; i < tzc_dev->ddata.nb_regions; i++)
170*35a04c15SGatien Chevallier tzc_configure_region(i + 1, &cfg);
171*35a04c15SGatien Chevallier }
172*35a04c15SGatien Chevallier
append_region(struct tzc_device * tzc_dev,const struct tzc_region_config * region_cfg)173*35a04c15SGatien Chevallier static TEE_Result append_region(struct tzc_device *tzc_dev,
174*35a04c15SGatien Chevallier const struct tzc_region_config *region_cfg)
175*35a04c15SGatien Chevallier {
176*35a04c15SGatien Chevallier TEE_Result res = TEE_SUCCESS;
177*35a04c15SGatien Chevallier unsigned int index = tzc_dev->nb_reg_used;
178*35a04c15SGatien Chevallier
179*35a04c15SGatien Chevallier if (index >= tzc_dev->ddata.nb_regions ||
180*35a04c15SGatien Chevallier !core_is_buffer_inside(region_cfg->base,
181*35a04c15SGatien Chevallier region_cfg->top + 1 - region_cfg->base,
182*35a04c15SGatien Chevallier tzc_dev->pdata.mem_base,
183*35a04c15SGatien Chevallier tzc_dev->pdata.mem_size))
184*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
185*35a04c15SGatien Chevallier
186*35a04c15SGatien Chevallier res = tzc_region_check_overlap(tzc_dev, region_cfg);
187*35a04c15SGatien Chevallier if (res)
188*35a04c15SGatien Chevallier return res;
189*35a04c15SGatien Chevallier
190*35a04c15SGatien Chevallier tzc_dev->reg[tzc_dev->nb_reg_used] = *region_cfg;
191*35a04c15SGatien Chevallier tzc_dev->nb_reg_used++;
192*35a04c15SGatien Chevallier
193*35a04c15SGatien Chevallier tzc_configure_region(tzc_dev->nb_reg_used, region_cfg);
194*35a04c15SGatien Chevallier
195*35a04c15SGatien Chevallier return TEE_SUCCESS;
196*35a04c15SGatien Chevallier }
197*35a04c15SGatien Chevallier
198*35a04c15SGatien Chevallier static TEE_Result
exclude_region_from_nsec(const struct tzc_region_config * reg_exclude)199*35a04c15SGatien Chevallier exclude_region_from_nsec(const struct tzc_region_config *reg_exclude)
200*35a04c15SGatien Chevallier {
201*35a04c15SGatien Chevallier struct tzc_region_non_sec *reg = NULL;
202*35a04c15SGatien Chevallier
203*35a04c15SGatien Chevallier SLIST_FOREACH(reg, &nsec_region_list, link) {
204*35a04c15SGatien Chevallier if (core_is_buffer_inside(reg_exclude->base,
205*35a04c15SGatien Chevallier reg_exclude->top + 1 -
206*35a04c15SGatien Chevallier reg_exclude->base,
207*35a04c15SGatien Chevallier reg->region.base,
208*35a04c15SGatien Chevallier reg->region.top + 1 -
209*35a04c15SGatien Chevallier reg->region.base))
210*35a04c15SGatien Chevallier break;
211*35a04c15SGatien Chevallier }
212*35a04c15SGatien Chevallier
213*35a04c15SGatien Chevallier if (!reg)
214*35a04c15SGatien Chevallier return TEE_ERROR_ITEM_NOT_FOUND;
215*35a04c15SGatien Chevallier
216*35a04c15SGatien Chevallier if (reg_exclude->base == reg->region.base &&
217*35a04c15SGatien Chevallier reg_exclude->top == reg->region.top) {
218*35a04c15SGatien Chevallier /* Remove this entry */
219*35a04c15SGatien Chevallier SLIST_REMOVE(&nsec_region_list, reg, tzc_region_non_sec, link);
220*35a04c15SGatien Chevallier free(reg);
221*35a04c15SGatien Chevallier } else if (reg_exclude->base == reg->region.base) {
222*35a04c15SGatien Chevallier reg->region.base = reg_exclude->top + 1;
223*35a04c15SGatien Chevallier } else if (reg_exclude->top == reg->region.top) {
224*35a04c15SGatien Chevallier reg->region.top = reg_exclude->base - 1;
225*35a04c15SGatien Chevallier } else {
226*35a04c15SGatien Chevallier struct tzc_region_non_sec *new_nsec =
227*35a04c15SGatien Chevallier calloc(1, sizeof(*new_nsec));
228*35a04c15SGatien Chevallier
229*35a04c15SGatien Chevallier if (!new_nsec)
230*35a04c15SGatien Chevallier return TEE_ERROR_OUT_OF_MEMORY;
231*35a04c15SGatien Chevallier
232*35a04c15SGatien Chevallier new_nsec->region = reg->region;
233*35a04c15SGatien Chevallier reg->region.top = reg_exclude->base - 1;
234*35a04c15SGatien Chevallier new_nsec->region.base = reg_exclude->top + 1;
235*35a04c15SGatien Chevallier SLIST_INSERT_AFTER(reg, new_nsec, link);
236*35a04c15SGatien Chevallier }
237*35a04c15SGatien Chevallier
238*35a04c15SGatien Chevallier return TEE_SUCCESS;
239*35a04c15SGatien Chevallier }
240*35a04c15SGatien Chevallier
stm32mp_tzc_cfg_boot_region(struct tzc_device * tzc_dev)241*35a04c15SGatien Chevallier static void stm32mp_tzc_cfg_boot_region(struct tzc_device *tzc_dev)
242*35a04c15SGatien Chevallier {
243*35a04c15SGatien Chevallier unsigned int idx = 0;
244*35a04c15SGatien Chevallier static struct tzc_region_config boot_region[] = {
245*35a04c15SGatien Chevallier {
246*35a04c15SGatien Chevallier .base = CFG_TZDRAM_START,
247*35a04c15SGatien Chevallier .top = CFG_TZDRAM_START + CFG_TZDRAM_SIZE - 1,
248*35a04c15SGatien Chevallier .sec_attr = TZC_REGION_S_RDWR,
249*35a04c15SGatien Chevallier .ns_device_access = 0,
250*35a04c15SGatien Chevallier },
251*35a04c15SGatien Chevallier #ifdef CFG_CORE_RESERVED_SHM
252*35a04c15SGatien Chevallier {
253*35a04c15SGatien Chevallier .base = CFG_SHMEM_START,
254*35a04c15SGatien Chevallier .top = CFG_SHMEM_START + CFG_SHMEM_SIZE - 1,
255*35a04c15SGatien Chevallier .sec_attr = TZC_REGION_S_NONE,
256*35a04c15SGatien Chevallier .ns_device_access =
257*35a04c15SGatien Chevallier TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID),
258*35a04c15SGatien Chevallier }
259*35a04c15SGatien Chevallier #endif
260*35a04c15SGatien Chevallier };
261*35a04c15SGatien Chevallier
262*35a04c15SGatien Chevallier static_assert(IS_PAGE_ALIGNED(CFG_TZDRAM_START));
263*35a04c15SGatien Chevallier static_assert(IS_PAGE_ALIGNED(CFG_TZDRAM_SIZE));
264*35a04c15SGatien Chevallier #ifdef CFG_CORE_RESERVED_SHM
265*35a04c15SGatien Chevallier static_assert(IS_PAGE_ALIGNED(CFG_SHMEM_START));
266*35a04c15SGatien Chevallier static_assert(IS_PAGE_ALIGNED(CFG_SHMEM_SIZE));
267*35a04c15SGatien Chevallier #endif
268*35a04c15SGatien Chevallier
269*35a04c15SGatien Chevallier stm32mp_tzc_region0(true);
270*35a04c15SGatien Chevallier
271*35a04c15SGatien Chevallier stm32mp_tzc_reset_region(tzc_dev);
272*35a04c15SGatien Chevallier
273*35a04c15SGatien Chevallier for (idx = 0; idx < ARRAY_SIZE(boot_region); idx++) {
274*35a04c15SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
275*35a04c15SGatien Chevallier
276*35a04c15SGatien Chevallier boot_region[idx].filters =
277*35a04c15SGatien Chevallier FILTER_MASK(tzc_dev->ddata.nb_filters);
278*35a04c15SGatien Chevallier
279*35a04c15SGatien Chevallier res = append_region(tzc_dev, &boot_region[idx]);
280*35a04c15SGatien Chevallier if (res) {
281*35a04c15SGatien Chevallier EMSG("Failed to add region %u", idx);
282*35a04c15SGatien Chevallier panic();
283*35a04c15SGatien Chevallier }
284*35a04c15SGatien Chevallier
285*35a04c15SGatien Chevallier res = exclude_region_from_nsec(&boot_region[idx]);
286*35a04c15SGatien Chevallier if (res) {
287*35a04c15SGatien Chevallier EMSG("Failed to configure region %u", idx);
288*35a04c15SGatien Chevallier panic();
289*35a04c15SGatien Chevallier }
290*35a04c15SGatien Chevallier }
291*35a04c15SGatien Chevallier
292*35a04c15SGatien Chevallier /* Remove region0 access */
293*35a04c15SGatien Chevallier stm32mp_tzc_region0(false);
294*35a04c15SGatien Chevallier }
295*35a04c15SGatien Chevallier
add_node_memory_regions(struct tzc_device * tzc_dev,const void * fdt,int node)296*35a04c15SGatien Chevallier static TEE_Result add_node_memory_regions(struct tzc_device *tzc_dev,
297*35a04c15SGatien Chevallier const void *fdt, int node)
298*35a04c15SGatien Chevallier {
299*35a04c15SGatien Chevallier const fdt32_t *conf_list = NULL;
300*35a04c15SGatien Chevallier unsigned int nregions = 0;
301*35a04c15SGatien Chevallier unsigned int i = 0;
302*35a04c15SGatien Chevallier int len = 0;
303*35a04c15SGatien Chevallier
304*35a04c15SGatien Chevallier conf_list = fdt_getprop(fdt, node, "memory-region", &len);
305*35a04c15SGatien Chevallier if (!conf_list)
306*35a04c15SGatien Chevallier return TEE_SUCCESS;
307*35a04c15SGatien Chevallier
308*35a04c15SGatien Chevallier nregions = len / sizeof(uint32_t);
309*35a04c15SGatien Chevallier if (nregions > tzc_dev->ddata.nb_regions) {
310*35a04c15SGatien Chevallier EMSG("Too many regions defined in %s",
311*35a04c15SGatien Chevallier fdt_get_name(fdt, node, NULL));
312*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
313*35a04c15SGatien Chevallier }
314*35a04c15SGatien Chevallier
315*35a04c15SGatien Chevallier for (i = 0; i < nregions; i++) {
316*35a04c15SGatien Chevallier uint32_t phandle = fdt32_to_cpu(*(conf_list + i));
317*35a04c15SGatien Chevallier struct tzc_region_config region_cfg = { };
318*35a04c15SGatien Chevallier const fdt32_t *prop = NULL;
319*35a04c15SGatien Chevallier paddr_t region_base = 0;
320*35a04c15SGatien Chevallier size_t region_size = 0;
321*35a04c15SGatien Chevallier int pnode = 0;
322*35a04c15SGatien Chevallier
323*35a04c15SGatien Chevallier pnode = fdt_node_offset_by_phandle(fdt, phandle);
324*35a04c15SGatien Chevallier if (pnode < 0)
325*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
326*35a04c15SGatien Chevallier
327*35a04c15SGatien Chevallier region_base = fdt_reg_base_address(fdt, pnode);
328*35a04c15SGatien Chevallier region_size = fdt_reg_size(fdt, pnode);
329*35a04c15SGatien Chevallier assert(region_base != (paddr_t)-1 && region_size != (size_t)-1);
330*35a04c15SGatien Chevallier
331*35a04c15SGatien Chevallier if (!IS_PAGE_ALIGNED(region_base) ||
332*35a04c15SGatien Chevallier !IS_PAGE_ALIGNED(region_size))
333*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
334*35a04c15SGatien Chevallier
335*35a04c15SGatien Chevallier region_cfg.base = region_base;
336*35a04c15SGatien Chevallier region_cfg.top = region_base + region_size - 1;
337*35a04c15SGatien Chevallier region_cfg.filters = FILTER_MASK(tzc_dev->ddata.nb_filters);
338*35a04c15SGatien Chevallier
339*35a04c15SGatien Chevallier prop = fdt_getprop(fdt, pnode, "st,protreg", &len);
340*35a04c15SGatien Chevallier if (!prop || (unsigned int)len != (2 * sizeof(uint32_t)))
341*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
342*35a04c15SGatien Chevallier
343*35a04c15SGatien Chevallier switch (fdt32_to_cpu(prop[0])) {
344*35a04c15SGatien Chevallier case DT_TZC_REGION_S_NONE:
345*35a04c15SGatien Chevallier region_cfg.sec_attr = TZC_REGION_S_NONE;
346*35a04c15SGatien Chevallier break;
347*35a04c15SGatien Chevallier case DT_TZC_REGION_S_RD:
348*35a04c15SGatien Chevallier region_cfg.sec_attr = TZC_REGION_S_RD;
349*35a04c15SGatien Chevallier break;
350*35a04c15SGatien Chevallier case DT_TZC_REGION_S_WR:
351*35a04c15SGatien Chevallier region_cfg.sec_attr = TZC_REGION_S_WR;
352*35a04c15SGatien Chevallier break;
353*35a04c15SGatien Chevallier case DT_TZC_REGION_S_RDWR:
354*35a04c15SGatien Chevallier region_cfg.sec_attr = TZC_REGION_S_RDWR;
355*35a04c15SGatien Chevallier break;
356*35a04c15SGatien Chevallier default:
357*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
358*35a04c15SGatien Chevallier }
359*35a04c15SGatien Chevallier region_cfg.ns_device_access = fdt32_to_cpu(prop[1]);
360*35a04c15SGatien Chevallier
361*35a04c15SGatien Chevallier DMSG("%#08"PRIxVA" - %#08"PRIxVA" : Sec access %i NS access %#"PRIx32,
362*35a04c15SGatien Chevallier region_cfg.base, region_cfg.top, region_cfg.sec_attr,
363*35a04c15SGatien Chevallier region_cfg.ns_device_access);
364*35a04c15SGatien Chevallier
365*35a04c15SGatien Chevallier if (append_region(tzc_dev, ®ion_cfg))
366*35a04c15SGatien Chevallier panic("Error adding region");
367*35a04c15SGatien Chevallier
368*35a04c15SGatien Chevallier if (exclude_region_from_nsec(®ion_cfg))
369*35a04c15SGatien Chevallier panic("Not able to exclude region");
370*35a04c15SGatien Chevallier }
371*35a04c15SGatien Chevallier
372*35a04c15SGatien Chevallier return TEE_SUCCESS;
373*35a04c15SGatien Chevallier }
374*35a04c15SGatien Chevallier
375*35a04c15SGatien Chevallier /*
376*35a04c15SGatien Chevallier * Adds a TZC region entry for each non-secure memory area defined by
377*35a04c15SGatien Chevallier * nsec_region_list. The function releases resources used to build this
378*35a04c15SGatien Chevallier * non-secure region list.
379*35a04c15SGatien Chevallier */
add_carved_out_nsec(struct tzc_device * tzc_dev)380*35a04c15SGatien Chevallier static void add_carved_out_nsec(struct tzc_device *tzc_dev)
381*35a04c15SGatien Chevallier {
382*35a04c15SGatien Chevallier struct tzc_region_non_sec *region = NULL;
383*35a04c15SGatien Chevallier struct tzc_region_non_sec *region_safe = NULL;
384*35a04c15SGatien Chevallier
385*35a04c15SGatien Chevallier SLIST_FOREACH_SAFE(region, &nsec_region_list, link, region_safe) {
386*35a04c15SGatien Chevallier DMSG("%#08"PRIxVA" - %#08"PRIxVA" : Sec access %i NS access %#"PRIx32,
387*35a04c15SGatien Chevallier region->region.base, region->region.top,
388*35a04c15SGatien Chevallier region->region.sec_attr,
389*35a04c15SGatien Chevallier region->region.ns_device_access);
390*35a04c15SGatien Chevallier
391*35a04c15SGatien Chevallier if (append_region(tzc_dev, ®ion->region))
392*35a04c15SGatien Chevallier panic("Error adding region");
393*35a04c15SGatien Chevallier
394*35a04c15SGatien Chevallier SLIST_REMOVE(&nsec_region_list, region,
395*35a04c15SGatien Chevallier tzc_region_non_sec, link);
396*35a04c15SGatien Chevallier free(region);
397*35a04c15SGatien Chevallier };
398*35a04c15SGatien Chevallier }
399*35a04c15SGatien Chevallier
stm32mp_tzc_parse_fdt(struct tzc_device * tzc_dev,const void * fdt,int node)400*35a04c15SGatien Chevallier static TEE_Result stm32mp_tzc_parse_fdt(struct tzc_device *tzc_dev,
401*35a04c15SGatien Chevallier const void *fdt, int node)
402*35a04c15SGatien Chevallier {
403*35a04c15SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
404*35a04c15SGatien Chevallier struct io_pa_va base = { };
405*35a04c15SGatien Chevallier size_t reg_size = 0;
406*35a04c15SGatien Chevallier int offs = 0;
407*35a04c15SGatien Chevallier
408*35a04c15SGatien Chevallier res = interrupt_dt_get(fdt, node, &tzc_dev->pdata.itr_chip,
409*35a04c15SGatien Chevallier &tzc_dev->pdata.itr_num);
410*35a04c15SGatien Chevallier if (res)
411*35a04c15SGatien Chevallier return res;
412*35a04c15SGatien Chevallier
413*35a04c15SGatien Chevallier res = clk_dt_get_by_index(fdt, node, 0, tzc_dev->pdata.clk);
414*35a04c15SGatien Chevallier if (res)
415*35a04c15SGatien Chevallier return res;
416*35a04c15SGatien Chevallier
417*35a04c15SGatien Chevallier res = clk_dt_get_by_index(fdt, node, 1, tzc_dev->pdata.clk + 1);
418*35a04c15SGatien Chevallier if (res == TEE_ERROR_ITEM_NOT_FOUND)
419*35a04c15SGatien Chevallier DMSG("No secondary clock for %s",
420*35a04c15SGatien Chevallier fdt_get_name(fdt, node, NULL));
421*35a04c15SGatien Chevallier else if (res)
422*35a04c15SGatien Chevallier return res;
423*35a04c15SGatien Chevallier
424*35a04c15SGatien Chevallier base.pa = fdt_reg_base_address(fdt, node);
425*35a04c15SGatien Chevallier if (base.pa == DT_INFO_INVALID_REG)
426*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
427*35a04c15SGatien Chevallier
428*35a04c15SGatien Chevallier reg_size = fdt_reg_size(fdt, node);
429*35a04c15SGatien Chevallier if (reg_size == DT_INFO_INVALID_REG_SIZE)
430*35a04c15SGatien Chevallier return TEE_ERROR_BAD_PARAMETERS;
431*35a04c15SGatien Chevallier
432*35a04c15SGatien Chevallier tzc_dev->pdata.name = strdup(fdt_get_name(fdt, node, NULL));
433*35a04c15SGatien Chevallier tzc_dev->pdata.base = io_pa_or_va_secure(&base, reg_size);
434*35a04c15SGatien Chevallier
435*35a04c15SGatien Chevallier offs = fdt_node_offset_by_prop_value(fdt, offs, "device_type",
436*35a04c15SGatien Chevallier "memory", sizeof("memory"));
437*35a04c15SGatien Chevallier if (offs < 0)
438*35a04c15SGatien Chevallier panic("No memory reference for TZC DT node");
439*35a04c15SGatien Chevallier
440*35a04c15SGatien Chevallier tzc_dev->pdata.mem_base = fdt_reg_base_address(fdt, offs);
441*35a04c15SGatien Chevallier tzc_dev->pdata.mem_size = fdt_reg_size(fdt, offs);
442*35a04c15SGatien Chevallier
443*35a04c15SGatien Chevallier assert(tzc_dev->pdata.mem_base != DT_INFO_INVALID_REG &&
444*35a04c15SGatien Chevallier tzc_dev->pdata.mem_size != DT_INFO_INVALID_REG_SIZE);
445*35a04c15SGatien Chevallier
446*35a04c15SGatien Chevallier return TEE_SUCCESS;
447*35a04c15SGatien Chevallier }
448*35a04c15SGatien Chevallier
stm32mp1_tzc_pm(enum pm_op op,unsigned int pm_hint __unused,const struct pm_callback_handle * hdl)449*35a04c15SGatien Chevallier static TEE_Result stm32mp1_tzc_pm(enum pm_op op,
450*35a04c15SGatien Chevallier unsigned int pm_hint __unused,
451*35a04c15SGatien Chevallier const struct pm_callback_handle *hdl)
452*35a04c15SGatien Chevallier {
453*35a04c15SGatien Chevallier unsigned int i = 0;
454*35a04c15SGatien Chevallier struct tzc_device *tzc_dev =
455*35a04c15SGatien Chevallier (struct tzc_device *)PM_CALLBACK_GET_HANDLE(hdl);
456*35a04c15SGatien Chevallier
457*35a04c15SGatien Chevallier if (op == PM_OP_RESUME) {
458*35a04c15SGatien Chevallier stm32mp_tzc_region0(true);
459*35a04c15SGatien Chevallier
460*35a04c15SGatien Chevallier stm32mp_tzc_reset_region(tzc_dev);
461*35a04c15SGatien Chevallier
462*35a04c15SGatien Chevallier for (i = 0; i < tzc_dev->nb_reg_used; i++)
463*35a04c15SGatien Chevallier tzc_configure_region(i + 1, &tzc_dev->reg[i]);
464*35a04c15SGatien Chevallier
465*35a04c15SGatien Chevallier stm32mp_tzc_region0(false);
466*35a04c15SGatien Chevallier }
467*35a04c15SGatien Chevallier
468*35a04c15SGatien Chevallier return TEE_SUCCESS;
469*35a04c15SGatien Chevallier }
470*35a04c15SGatien Chevallier DECLARE_KEEP_PAGER(stm32mp1_tzc_pm);
471*35a04c15SGatien Chevallier
stm32mp1_tzc_probe(const void * fdt,int node,const void * compt_data __unused)472*35a04c15SGatien Chevallier static TEE_Result stm32mp1_tzc_probe(const void *fdt, int node,
473*35a04c15SGatien Chevallier const void *compt_data __unused)
474*35a04c15SGatien Chevallier {
475*35a04c15SGatien Chevallier TEE_Result res = TEE_ERROR_GENERIC;
476*35a04c15SGatien Chevallier struct tzc_device *tzc_dev = NULL;
477*35a04c15SGatien Chevallier struct tzc_region_non_sec *nsec_region = NULL;
478*35a04c15SGatien Chevallier
479*35a04c15SGatien Chevallier tzc_dev = calloc(1, sizeof(*tzc_dev));
480*35a04c15SGatien Chevallier if (!tzc_dev)
481*35a04c15SGatien Chevallier panic();
482*35a04c15SGatien Chevallier
483*35a04c15SGatien Chevallier res = stm32mp_tzc_parse_fdt(tzc_dev, fdt, node);
484*35a04c15SGatien Chevallier if (res) {
485*35a04c15SGatien Chevallier free(tzc_dev);
486*35a04c15SGatien Chevallier return res;
487*35a04c15SGatien Chevallier }
488*35a04c15SGatien Chevallier
489*35a04c15SGatien Chevallier tzc_set_driverdata(tzc_dev);
490*35a04c15SGatien Chevallier tzc_dev->reg = calloc(tzc_dev->ddata.nb_regions,
491*35a04c15SGatien Chevallier sizeof(*tzc_dev->reg));
492*35a04c15SGatien Chevallier if (!tzc_dev->reg)
493*35a04c15SGatien Chevallier panic();
494*35a04c15SGatien Chevallier
495*35a04c15SGatien Chevallier if (clk_enable(tzc_dev->pdata.clk[0]))
496*35a04c15SGatien Chevallier panic();
497*35a04c15SGatien Chevallier if (tzc_dev->pdata.clk[1] && clk_enable(tzc_dev->pdata.clk[1]))
498*35a04c15SGatien Chevallier panic();
499*35a04c15SGatien Chevallier
500*35a04c15SGatien Chevallier tzc_init(tzc_dev->pdata.base);
501*35a04c15SGatien Chevallier
502*35a04c15SGatien Chevallier nsec_region = calloc(1, sizeof(*nsec_region));
503*35a04c15SGatien Chevallier if (!nsec_region)
504*35a04c15SGatien Chevallier panic();
505*35a04c15SGatien Chevallier
506*35a04c15SGatien Chevallier nsec_region->region.base = tzc_dev->pdata.mem_base;
507*35a04c15SGatien Chevallier nsec_region->region.top = tzc_dev->pdata.mem_base +
508*35a04c15SGatien Chevallier tzc_dev->pdata.mem_size - 1;
509*35a04c15SGatien Chevallier nsec_region->region.sec_attr = TZC_REGION_S_NONE;
510*35a04c15SGatien Chevallier nsec_region->region.ns_device_access = TZC_REGION_NSEC_ALL_ACCESS_RDWR;
511*35a04c15SGatien Chevallier nsec_region->region.filters = FILTER_MASK(tzc_dev->ddata.nb_filters);
512*35a04c15SGatien Chevallier
513*35a04c15SGatien Chevallier SLIST_INSERT_HEAD(&nsec_region_list, nsec_region, link);
514*35a04c15SGatien Chevallier
515*35a04c15SGatien Chevallier stm32mp_tzc_cfg_boot_region(tzc_dev);
516*35a04c15SGatien Chevallier
517*35a04c15SGatien Chevallier res = add_node_memory_regions(tzc_dev, fdt, node);
518*35a04c15SGatien Chevallier if (res) {
519*35a04c15SGatien Chevallier EMSG("Can't add memory regions: %"PRIx32, res);
520*35a04c15SGatien Chevallier panic();
521*35a04c15SGatien Chevallier }
522*35a04c15SGatien Chevallier
523*35a04c15SGatien Chevallier add_carved_out_nsec(tzc_dev);
524*35a04c15SGatien Chevallier
525*35a04c15SGatien Chevallier tzc_dump_state();
526*35a04c15SGatien Chevallier
527*35a04c15SGatien Chevallier res = interrupt_create_handler(tzc_dev->pdata.itr_chip,
528*35a04c15SGatien Chevallier tzc_dev->pdata.itr_num, tzc_it_handler,
529*35a04c15SGatien Chevallier NULL, 0, NULL);
530*35a04c15SGatien Chevallier if (res)
531*35a04c15SGatien Chevallier panic();
532*35a04c15SGatien Chevallier
533*35a04c15SGatien Chevallier interrupt_enable(tzc_dev->pdata.itr_chip, tzc_dev->pdata.itr_num);
534*35a04c15SGatien Chevallier tzc_set_action(TZC_ACTION_INT);
535*35a04c15SGatien Chevallier
536*35a04c15SGatien Chevallier register_pm_core_service_cb(stm32mp1_tzc_pm, tzc_dev,
537*35a04c15SGatien Chevallier "stm32mp1-tzc400");
538*35a04c15SGatien Chevallier
539*35a04c15SGatien Chevallier return TEE_SUCCESS;
540*35a04c15SGatien Chevallier }
541*35a04c15SGatien Chevallier
542*35a04c15SGatien Chevallier static const struct dt_device_match tzc_secu_match_table[] = {
543*35a04c15SGatien Chevallier { .compatible = "st,stm32mp1-tzc" },
544*35a04c15SGatien Chevallier { }
545*35a04c15SGatien Chevallier };
546*35a04c15SGatien Chevallier
547*35a04c15SGatien Chevallier DEFINE_DT_DRIVER(tzc_stm32mp1_dt_driver) = {
548*35a04c15SGatien Chevallier .name = "stm32mp1-tzc400",
549*35a04c15SGatien Chevallier .type = DT_DRIVER_NOTYPE,
550*35a04c15SGatien Chevallier .match_table = tzc_secu_match_table,
551*35a04c15SGatien Chevallier .probe = stm32mp1_tzc_probe,
552*35a04c15SGatien Chevallier };
553