1// 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} 137