blob: cdc4a40edafc2f936eaa89dc0776371641ff5f83 [file] [log] [blame]
Alexandru Gagniuc0ea61632021-07-15 14:19:25 -05001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Simple API for configuring TrustZone memory restrictions for TZC400
4 */
5
6#define LOG_CATEGORY LOGC_ARCH
7
8#include <linux/iopoll.h>
9#include <mach/tzc.h>
10
11#define TZC_TIMEOUT_US 100
12
13#define TZC_BUILD_CONFIG 0x00
14#define TZC_ACTION 0x04
15#define TZC_ACTION_NONE 0
16#define TZC_ACTION_ERR 1
17#define TZC_ACTION_INT 2
18#define TZC_ACTION_INT_ERR 3
19#define TZC_GATE_KEEPER 0x08
20
21#define TZC_REGION0_OFFSET 0x100
22#define TZC_REGION_CFG_SIZE 0x20
23#define TZC_REGION1_OFFSET 0x120
24#define TZC_REGION_BASE 0x00
25#define TZC_REGION_TOP 0x08
26#define TZC_REGION_ATTRIBUTE 0x10
27#define TZC_REGION_ACCESS 0x14
28
29static uint32_t tzc_read(uintptr_t tzc, size_t reg)
30{
31 return readl(tzc + reg);
32}
33
34static void tzc_write(uintptr_t tzc, size_t reg, uint32_t val)
35{
36 writel(val, tzc + reg);
37}
38
39static uint16_t tzc_config_get_active_filters(const struct tzc_region *cfg)
40{
41 uint16_t active_filters = 0;
42
43 for ( ; cfg->top != 0; cfg++)
44 active_filters |= cfg->filters_mask;
45
46 return active_filters;
47}
48
49int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg)
50{
51 uintptr_t region = tzc + TZC_REGION1_OFFSET;
52 uint32_t nsid, attr_reg, active_filters;
53 int ret;
54
55 active_filters = tzc_config_get_active_filters(cfg);
56 if (active_filters == 0)
57 return -EINVAL;
58
59 ret = tzc_disable_filters(tzc, active_filters);
60 if (ret < 0)
61 return ret;
62
63 for ( ; cfg->top != 0; cfg++, region += TZC_REGION_CFG_SIZE) {
64 attr_reg = (cfg->sec_mode & 0x03) << 30;
65 attr_reg |= (cfg->filters_mask & 0x03) << 0;
66 nsid = cfg->nsec_id & 0xffff;
67 nsid |= nsid << 16;
68
69 tzc_write(region, TZC_REGION_BASE, cfg->base);
70 tzc_write(region, TZC_REGION_TOP, cfg->top);
71 tzc_write(region, TZC_REGION_ACCESS, nsid);
72 tzc_write(region, TZC_REGION_ATTRIBUTE, attr_reg);
73 }
74
75 tzc_write(tzc, TZC_ACTION, TZC_ACTION_ERR);
76 return tzc_enable_filters(tzc, active_filters);
77}
78
79int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask)
80{
81 uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
82 uint32_t filter_status = filters_mask << 16;
83
84 gate &= ~filters_mask;
85 tzc_write(tzc, TZC_GATE_KEEPER, gate);
86
87 return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
88 (gate & filter_status) == 0, TZC_TIMEOUT_US);
89}
90
91int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask)
92{
93 uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
94 uint32_t filter_status = filters_mask << 16;
95
96 gate |= filters_mask;
97 tzc_write(tzc, TZC_GATE_KEEPER, gate);
98
99 return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
100 (gate & filter_status) == filter_status,
101 TZC_TIMEOUT_US);
102}
103
104static const char *sec_access_str_from_attr(uint32_t attr)
105{
106 const char *const sec_mode[] = { "none", "RO ", "WO ", "RW " };
107
108 return sec_mode[(attr >> 30) & 0x03];
109}
110
111void tzc_dump_config(uintptr_t tzc)
112{
113 uint32_t build_config, base, top, attr, nsaid;
114 int num_regions, i;
115 uintptr_t region;
116
117 build_config = tzc_read(tzc, TZC_BUILD_CONFIG);
118 num_regions = ((build_config >> 0) & 0x1f) + 1;
119
120 for (i = 0; i < num_regions; i++) {
121 region = tzc + TZC_REGION0_OFFSET + i * TZC_REGION_CFG_SIZE;
122
123 base = tzc_read(region, TZC_REGION_BASE);
124 top = tzc_read(region, TZC_REGION_TOP);
125 attr = tzc_read(region, TZC_REGION_ATTRIBUTE);
126 nsaid = tzc_read(region, TZC_REGION_ACCESS);
127
128 if (attr == 0 && nsaid == 0)
129 continue;
130
131 log_info("TZC region %u: %08x->%08x - filters 0x%x\n",
132 i, base, top, (attr >> 0) & 0xf);
133 log_info("\t Secure access %s NSAID %08x\n",
134 sec_access_str_from_attr(attr), nsaid);
135 }
136}