1 /*
2  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <stddef.h>
9 
10 #include <common/debug.h>
11 #include <drivers/arm/tzc380.h>
12 #include <lib/mmio.h>
13 
14 struct tzc380_instance {
15 	uintptr_t base;
16 	uint8_t addr_width;
17 	uint8_t num_regions;
18 };
19 
20 struct tzc380_instance tzc380;
21 
tzc380_read_build_config(uintptr_t base)22 static unsigned int tzc380_read_build_config(uintptr_t base)
23 {
24 	return mmio_read_32(base + TZC380_CONFIGURATION_OFF);
25 }
26 
tzc380_write_action(uintptr_t base,unsigned int action)27 static void tzc380_write_action(uintptr_t base, unsigned int action)
28 {
29 	mmio_write_32(base + ACTION_OFF, action);
30 }
31 
tzc380_write_region_base_low(uintptr_t base,unsigned int region,unsigned int val)32 static void tzc380_write_region_base_low(uintptr_t base, unsigned int region,
33 				      unsigned int val)
34 {
35 	mmio_write_32(base + REGION_SETUP_LOW_OFF(region), val);
36 }
37 
tzc380_write_region_base_high(uintptr_t base,unsigned int region,unsigned int val)38 static void tzc380_write_region_base_high(uintptr_t base, unsigned int region,
39 				       unsigned int val)
40 {
41 	mmio_write_32(base + REGION_SETUP_HIGH_OFF(region), val);
42 }
43 
tzc380_write_region_attributes(uintptr_t base,unsigned int region,unsigned int val)44 static void tzc380_write_region_attributes(uintptr_t base, unsigned int region,
45 					unsigned int val)
46 {
47 	mmio_write_32(base + REGION_ATTRIBUTES_OFF(region), val);
48 }
49 
tzc380_init(uintptr_t base)50 void tzc380_init(uintptr_t base)
51 {
52 	unsigned int tzc_build;
53 
54 	assert(base != 0U);
55 	tzc380.base = base;
56 
57 	/* Save values we will use later. */
58 	tzc_build = tzc380_read_build_config(tzc380.base);
59 	tzc380.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
60 			      BUILD_CONFIG_AW_MASK) + 1;
61 	tzc380.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
62 			       BUILD_CONFIG_NR_MASK) + 1;
63 }
64 
addr_low(uintptr_t addr)65 static uint32_t addr_low(uintptr_t addr)
66 {
67 	return (uint32_t)addr;
68 }
69 
addr_high(uintptr_t addr __unused)70 static uint32_t addr_high(uintptr_t addr __unused)
71 {
72 #if (UINTPTR_MAX == UINT64_MAX)
73 	return addr >> 32;
74 #else
75 	return 0;
76 #endif
77 }
78 
79 /*
80  * `tzc380_configure_region` is used to program regions into the TrustZone
81  * controller.
82  */
tzc380_configure_region(uint8_t region,uintptr_t region_base,unsigned int attr)83 void tzc380_configure_region(uint8_t region, uintptr_t region_base, unsigned int attr)
84 {
85 	assert(tzc380.base != 0U);
86 
87 	assert(region < tzc380.num_regions);
88 
89 	tzc380_write_region_base_low(tzc380.base, region, addr_low(region_base));
90 	tzc380_write_region_base_high(tzc380.base, region, addr_high(region_base));
91 	tzc380_write_region_attributes(tzc380.base, region, attr);
92 }
93 
tzc380_set_action(unsigned int action)94 void tzc380_set_action(unsigned int action)
95 {
96 	assert(tzc380.base != 0U);
97 
98 	/*
99 	 * - Currently no handler is provided to trap an error via interrupt
100 	 *   or exception.
101 	 * - The interrupt action has not been tested.
102 	 */
103 	tzc380_write_action(tzc380.base, action);
104 }
105