blob: b2f0bf6725c4080690fa57679a64c0561125518d [file] [log] [blame]
Vikram Kanigiri411ac8f2016-01-29 11:37:04 +00001/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <assert.h>
32#include <debug.h>
33#include <mmio.h>
34#include <tzc_dmc500.h>
35#include "tzc_common.h"
36#include "tzc_common_private.c"
37
38/*
39 * Macros which will be used by common core functions.
40 */
41#define TZC_DMC500_REGION_BASE_LOW_0_OFFSET 0x054
42#define TZC_DMC500_REGION_BASE_HIGH_0_OFFSET 0x058
43#define TZC_DMC500_REGION_TOP_LOW_0_OFFSET 0x05C
44#define TZC_DMC500_REGION_TOP_HIGH_0_OFFSET 0x060
45#define TZC_DMC500_REGION_ATTR_0_OFFSET 0x064
46#define TZC_DMC500_REGION_ID_ACCESS_0_OFFSET 0x068
47
48#define TZC_DMC500_ACTION_OFF 0x50
49
50/* Pointer to the tzc_dmc500_driver_data structure populated by the platform */
51static const tzc_dmc500_driver_data_t *g_driver_data;
52
53#define verify_region_attr(region, attr) \
54 ((g_conf_regions[(region)].sec_attr == \
55 ((attr) >> TZC_REGION_ATTR_SEC_SHIFT)) \
56 && ((attr) & (0x1 << TZC_REGION_ATTR_F_EN_SHIFT)))
57
58/*
59 * Structure for configured regions attributes in DMC500.
60 */
61typedef struct tzc_dmc500_regions {
62 tzc_region_attributes_t sec_attr;
63 int is_enabled;
64} tzc_dmc500_regions_t;
65
66/*
67 * Array storing the attributes of the configured regions. This array
68 * will be used by the `tzc_dmc500_verify_complete` to verify the flush
69 * completion.
70 */
71static tzc_dmc500_regions_t g_conf_regions[MAX_REGION_VAL + 1];
72
73/* Helper Macros for making the code readable */
74#define DMC_INST_BASE_ADDR(instance) (g_driver_data->dmc_base[instance])
75#define DMC_INST_SI_BASE(instance, interface) \
76 (DMC_INST_BASE_ADDR(instance) + IFACE_OFFSET(interface))
77
78DEFINE_TZC_COMMON_WRITE_ACTION(_dmc500, DMC500)
79DEFINE_TZC_COMMON_WRITE_REGION_BASE(_dmc500, DMC500)
80DEFINE_TZC_COMMON_WRITE_REGION_TOP(_dmc500, DMC500)
81DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(_dmc500, DMC500)
82DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(_dmc500, DMC500)
83
84DEFINE_TZC_COMMON_CONFIGURE_REGION0(_dmc500)
85DEFINE_TZC_COMMON_CONFIGURE_REGION(_dmc500)
86
87static inline unsigned int _tzc_dmc500_read_region_attr_0(
88 uintptr_t dmc_si_base,
89 int region_no)
90{
91 return mmio_read_32(dmc_si_base +
92 TZC_REGION_OFFSET(TZC_DMC500_REGION_SIZE, region_no) +
93 TZC_DMC500_REGION_ATTR_0_OFFSET);
94}
95
96static inline void _tzc_dmc500_write_flush_control(uintptr_t dmc_si_base)
97{
98 mmio_write_32(dmc_si_base + SI_FLUSH_CTRL_OFFSET, 1);
99}
100
101/*
102 * Sets the Flush controls for all the DMC Instances and System Interfaces.
103 * This initiates the flush of configuration settings from the shadow
104 * registers to the actual configuration register. The caller should poll
105 * changed register to confirm update.
106 */
107void tzc_dmc500_config_complete(void)
108{
109 int dmc_inst, sys_if;
110
111 assert(g_driver_data);
112
113 for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
114 assert(DMC_INST_BASE_ADDR(dmc_inst));
115 for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; sys_if++)
116 _tzc_dmc500_write_flush_control(
117 DMC_INST_SI_BASE(dmc_inst, sys_if));
118 }
119}
120
121/*
122 * This function reads back the secure attributes from the configuration
123 * register for each DMC Instance and System Interface and compares it with
124 * the configured value. The successful verification of the region attributes
125 * confirms that the flush operation has completed.
126 * If the verification fails, the caller is expected to invoke this API again
127 * till it succeeds.
128 * Returns 0 on success and 1 on failure.
129 */
130int tzc_dmc500_verify_complete(void)
131{
132 int dmc_inst, sys_if, region_no;
133 unsigned int attr;
134
135 assert(g_driver_data);
136 /* Region 0 must be configured */
137 assert(g_conf_regions[0].is_enabled);
138
139 /* Iterate over all configured regions */
140 for (region_no = 0; region_no <= MAX_REGION_VAL; region_no++) {
141 if (!g_conf_regions[region_no].is_enabled)
142 continue;
143 for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count;
144 dmc_inst++) {
145 assert(DMC_INST_BASE_ADDR(dmc_inst));
146 for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT;
147 sys_if++) {
148 attr = _tzc_dmc500_read_region_attr_0(
149 DMC_INST_SI_BASE(dmc_inst, sys_if),
150 region_no);
151 VERBOSE("Verifying DMC500 region:%d"
152 " dmc_inst:%d sys_if:%d attr:%x\n",
153 region_no, dmc_inst, sys_if, attr);
154 if (!verify_region_attr(region_no, attr))
155 return 1;
156 }
157 }
158 }
159
160 return 0;
161}
162
163/*
164 * `tzc_dmc500_configure_region0` is used to program region 0 in both the
165 * system interfaces of all the DMC-500 instances. Region 0 covers the whole
166 * address space that is not mapped to any other region for a system interface,
167 * and is always enabled; this cannot be changed. This function only changes
168 * the access permissions.
169 */
170void tzc_dmc500_configure_region0(tzc_region_attributes_t sec_attr,
171 unsigned int nsaid_permissions)
172{
173 int dmc_inst, sys_if;
174
175 /* Assert if DMC-500 is not initialized */
176 assert(g_driver_data);
177
178 /* Configure region_0 in all DMC instances */
179 for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
180 assert(DMC_INST_BASE_ADDR(dmc_inst));
181 for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; sys_if++)
182 _tzc_dmc500_configure_region0(
183 DMC_INST_SI_BASE(dmc_inst, sys_if),
184 sec_attr, nsaid_permissions);
185 }
186
187 g_conf_regions[0].sec_attr = sec_attr;
188 g_conf_regions[0].is_enabled = 1;
189}
190
191/*
192 * `tzc_dmc500_configure_region` is used to program a region into all system
193 * interfaces of all the DMC instances.
194 * NOTE:
195 * Region 0 is special; it is preferable to use tzc_dmc500_configure_region0
196 * for this region (see comment for that function).
197 */
198void tzc_dmc500_configure_region(int region_no,
Yatharth Kocharfc719752016-04-08 14:40:44 +0100199 unsigned long long region_base,
200 unsigned long long region_top,
Vikram Kanigiri411ac8f2016-01-29 11:37:04 +0000201 tzc_region_attributes_t sec_attr,
202 unsigned int nsaid_permissions)
203{
204 int dmc_inst, sys_if;
205
206 assert(g_driver_data);
207 /* Do range checks on regions. */
208 assert(region_no >= 0 && region_no <= MAX_REGION_VAL);
209
210 /*
211 * Do address range check based on DMC-TZ configuration. A 43bit address
212 * is the max and expected case.
213 */
214 assert(((region_top <= (UINT64_MAX >> (64 - 43))) &&
215 (region_base < region_top)));
216
217 /* region_base and (region_top + 1) must be 4KB aligned */
218 assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0);
219
220 for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
221 assert(DMC_INST_BASE_ADDR(dmc_inst));
222 for (sys_if = 0; sys_if < MAX_SYS_IF_COUNT; sys_if++)
223 _tzc_dmc500_configure_region(
224 DMC_INST_SI_BASE(dmc_inst, sys_if),
225 TZC_DMC500_REGION_ATTR_F_EN_MASK,
226 region_no, region_base, region_top,
227 sec_attr, nsaid_permissions);
228 }
229
230 g_conf_regions[region_no].sec_attr = sec_attr;
231 g_conf_regions[region_no].is_enabled = 1;
232}
233
234/* Sets the action value for all the DMC instances */
235void tzc_dmc500_set_action(tzc_action_t action)
236{
237 int dmc_inst;
238
239 assert(g_driver_data);
240
241 for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
242 assert(DMC_INST_BASE_ADDR(dmc_inst));
243 /*
244 * - Currently no handler is provided to trap an error via
245 * interrupt or exception.
246 * - The interrupt action has not been tested.
247 */
248 _tzc_dmc500_write_action(DMC_INST_BASE_ADDR(dmc_inst), action);
249 }
250}
251
252/*
253 * A DMC-500 instance must be present at each base address provided by the
254 * platform. It also expects platform to pass at least one instance of
255 * DMC-500.
256 */
257static void validate_plat_driver_data(
258 const tzc_dmc500_driver_data_t *plat_driver_data)
259{
260#if DEBUG
261 int i;
262 unsigned int dmc_id;
263 uintptr_t dmc_base;
264
265 assert(plat_driver_data);
266 assert(plat_driver_data->dmc_count > 0 &&
267 (plat_driver_data->dmc_count <= MAX_DMC_COUNT));
268
269 for (i = 0; i < plat_driver_data->dmc_count; i++) {
270 dmc_base = plat_driver_data->dmc_base[i];
271 assert(dmc_base);
272
273 dmc_id = _tzc_read_peripheral_id(dmc_base);
274 assert(dmc_id == DMC500_PERIPHERAL_ID);
275 }
276#endif /* DEBUG */
277}
278
279
280/*
281 * Initializes the base address and count of DMC instances.
282 *
283 * Note : Only pointer to plat_driver_data is saved, so it is caller's
284 * responsibility to keep it valid until the driver is used.
285 */
286void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data)
287{
288 /* Check valid pointer is passed */
289 assert(plat_driver_data);
290
291 /*
292 * NOTE: This driver expects the DMC-500 controller is already in
293 * READY state. Hence, it uses the reconfiguration method for
294 * programming TrustZone regions
295 */
296 /* Validates the information passed by platform */
297 validate_plat_driver_data(plat_driver_data);
298 g_driver_data = plat_driver_data;
299}