mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-14 00:47:26 +00:00
137 lines
3.4 KiB
C
137 lines
3.4 KiB
C
|
// SPDX-License-Identifier: GPL-2.0+
|
||
|
/*
|
||
|
* Simple API for configuring TrustZone memory restrictions for TZC400
|
||
|
*/
|
||
|
|
||
|
#define LOG_CATEGORY LOGC_ARCH
|
||
|
|
||
|
#include <linux/iopoll.h>
|
||
|
#include <mach/tzc.h>
|
||
|
|
||
|
#define TZC_TIMEOUT_US 100
|
||
|
|
||
|
#define TZC_BUILD_CONFIG 0x00
|
||
|
#define TZC_ACTION 0x04
|
||
|
#define TZC_ACTION_NONE 0
|
||
|
#define TZC_ACTION_ERR 1
|
||
|
#define TZC_ACTION_INT 2
|
||
|
#define TZC_ACTION_INT_ERR 3
|
||
|
#define TZC_GATE_KEEPER 0x08
|
||
|
|
||
|
#define TZC_REGION0_OFFSET 0x100
|
||
|
#define TZC_REGION_CFG_SIZE 0x20
|
||
|
#define TZC_REGION1_OFFSET 0x120
|
||
|
#define TZC_REGION_BASE 0x00
|
||
|
#define TZC_REGION_TOP 0x08
|
||
|
#define TZC_REGION_ATTRIBUTE 0x10
|
||
|
#define TZC_REGION_ACCESS 0x14
|
||
|
|
||
|
static uint32_t tzc_read(uintptr_t tzc, size_t reg)
|
||
|
{
|
||
|
return readl(tzc + reg);
|
||
|
}
|
||
|
|
||
|
static void tzc_write(uintptr_t tzc, size_t reg, uint32_t val)
|
||
|
{
|
||
|
writel(val, tzc + reg);
|
||
|
}
|
||
|
|
||
|
static uint16_t tzc_config_get_active_filters(const struct tzc_region *cfg)
|
||
|
{
|
||
|
uint16_t active_filters = 0;
|
||
|
|
||
|
for ( ; cfg->top != 0; cfg++)
|
||
|
active_filters |= cfg->filters_mask;
|
||
|
|
||
|
return active_filters;
|
||
|
}
|
||
|
|
||
|
int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg)
|
||
|
{
|
||
|
uintptr_t region = tzc + TZC_REGION1_OFFSET;
|
||
|
uint32_t nsid, attr_reg, active_filters;
|
||
|
int ret;
|
||
|
|
||
|
active_filters = tzc_config_get_active_filters(cfg);
|
||
|
if (active_filters == 0)
|
||
|
return -EINVAL;
|
||
|
|
||
|
ret = tzc_disable_filters(tzc, active_filters);
|
||
|
if (ret < 0)
|
||
|
return ret;
|
||
|
|
||
|
for ( ; cfg->top != 0; cfg++, region += TZC_REGION_CFG_SIZE) {
|
||
|
attr_reg = (cfg->sec_mode & 0x03) << 30;
|
||
|
attr_reg |= (cfg->filters_mask & 0x03) << 0;
|
||
|
nsid = cfg->nsec_id & 0xffff;
|
||
|
nsid |= nsid << 16;
|
||
|
|
||
|
tzc_write(region, TZC_REGION_BASE, cfg->base);
|
||
|
tzc_write(region, TZC_REGION_TOP, cfg->top);
|
||
|
tzc_write(region, TZC_REGION_ACCESS, nsid);
|
||
|
tzc_write(region, TZC_REGION_ATTRIBUTE, attr_reg);
|
||
|
}
|
||
|
|
||
|
tzc_write(tzc, TZC_ACTION, TZC_ACTION_ERR);
|
||
|
return tzc_enable_filters(tzc, active_filters);
|
||
|
}
|
||
|
|
||
|
int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask)
|
||
|
{
|
||
|
uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
|
||
|
uint32_t filter_status = filters_mask << 16;
|
||
|
|
||
|
gate &= ~filters_mask;
|
||
|
tzc_write(tzc, TZC_GATE_KEEPER, gate);
|
||
|
|
||
|
return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
|
||
|
(gate & filter_status) == 0, TZC_TIMEOUT_US);
|
||
|
}
|
||
|
|
||
|
int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask)
|
||
|
{
|
||
|
uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
|
||
|
uint32_t filter_status = filters_mask << 16;
|
||
|
|
||
|
gate |= filters_mask;
|
||
|
tzc_write(tzc, TZC_GATE_KEEPER, gate);
|
||
|
|
||
|
return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
|
||
|
(gate & filter_status) == filter_status,
|
||
|
TZC_TIMEOUT_US);
|
||
|
}
|
||
|
|
||
|
static const char *sec_access_str_from_attr(uint32_t attr)
|
||
|
{
|
||
|
const char *const sec_mode[] = { "none", "RO ", "WO ", "RW " };
|
||
|
|
||
|
return sec_mode[(attr >> 30) & 0x03];
|
||
|
}
|
||
|
|
||
|
void tzc_dump_config(uintptr_t tzc)
|
||
|
{
|
||
|
uint32_t build_config, base, top, attr, nsaid;
|
||
|
int num_regions, i;
|
||
|
uintptr_t region;
|
||
|
|
||
|
build_config = tzc_read(tzc, TZC_BUILD_CONFIG);
|
||
|
num_regions = ((build_config >> 0) & 0x1f) + 1;
|
||
|
|
||
|
for (i = 0; i < num_regions; i++) {
|
||
|
region = tzc + TZC_REGION0_OFFSET + i * TZC_REGION_CFG_SIZE;
|
||
|
|
||
|
base = tzc_read(region, TZC_REGION_BASE);
|
||
|
top = tzc_read(region, TZC_REGION_TOP);
|
||
|
attr = tzc_read(region, TZC_REGION_ATTRIBUTE);
|
||
|
nsaid = tzc_read(region, TZC_REGION_ACCESS);
|
||
|
|
||
|
if (attr == 0 && nsaid == 0)
|
||
|
continue;
|
||
|
|
||
|
log_info("TZC region %u: %08x->%08x - filters 0x%x\n",
|
||
|
i, base, top, (attr >> 0) & 0xf);
|
||
|
log_info("\t Secure access %s NSAID %08x\n",
|
||
|
sec_access_str_from_attr(attr), nsaid);
|
||
|
}
|
||
|
}
|