diff options
author | Rouven Czerwinski <r.czerwinski@pengutronix.de> | 2019-03-18 10:46:55 +0100 |
---|---|---|
committer | Joakim Bech <joakim.bech@linaro.org> | 2019-04-15 15:30:30 +0700 |
commit | e8e7f1c5d978df640d073de4271ad87bc50b6879 (patch) | |
tree | b470447e59248c912ea4e6dc313955a96762529a /core | |
parent | 7eedcd151e9c7b5eb56ab2f6379ee9c3de77e8c4 (diff) |
tzc380: add region auto configuration function
The tzc_auto_configure() function takes an address, a size, the attribute
and a region as arguments. It calculates the fitting tzc380 region
configuration and applies it to the controller.
Signed-off-by: Rouven Czerwinski <r.czerwinski@pengutronix.de>
Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
Diffstat (limited to 'core')
-rw-r--r-- | core/drivers/tzc380.c | 62 | ||||
-rw-r--r-- | core/include/drivers/tzc380.h | 14 |
2 files changed, 76 insertions, 0 deletions
diff --git a/core/drivers/tzc380.c b/core/drivers/tzc380.c index 2827cfb5..c7d5f2e8 100644 --- a/core/drivers/tzc380.c +++ b/core/drivers/tzc380.c @@ -216,6 +216,68 @@ uint32_t tzc_get_action(void) return tzc_read_action(tzc.base); } +int tzc_auto_configure(vaddr_t addr, vaddr_t size, uint32_t attr, + uint8_t region) +{ + uint64_t sub_region_size = 0; + uint64_t area = 0; + uint8_t lregion = region; + uint64_t region_size = 0; + vaddr_t sub_address = 0; + vaddr_t address = addr; + uint64_t lsize = size; + uint32_t mask = 0; + int i = 0; + uint8_t pow = TZC380_POW; + + while (lsize != 0 && pow > 15) { + region_size = 1ULL << pow; + + /* Case region fits alignment and covers requested area */ + if ((address % region_size == 0) && + ((address + lsize) % region_size == 0)) { + tzc_configure_region(lregion, address, + TZC_ATTR_REGION_SIZE(pow - 1) | + TZC_ATTR_REGION_EN_MASK | + attr); + lregion++; + address += region_size; + lsize -= region_size; + pow--; + continue; + } + + /* Cover area using several subregions */ + sub_region_size = region_size / 8; + if (address % sub_region_size == 0 && + lsize > 2 * sub_region_size) { + sub_address = (address / region_size) * region_size; + mask = 0; + for (i = 0; i < 8; i++) { + area = (i + 1) * sub_region_size; + if (sub_address + area <= address || + sub_address + area > address + lsize) { + mask |= TZC_ATTR_SUBREGION_DIS(i); + } else { + address += sub_region_size; + lsize -= sub_region_size; + } + } + tzc_configure_region(lregion, sub_address, + TZC_ATTR_REGION_SIZE(pow - 1) | + TZC_ATTR_REGION_EN_MASK | + mask | attr); + lregion++; + pow--; + continue; + } + pow--; + } + assert(lsize == 0); + assert(address == addr + size); + return lregion; +} + #if TRACE_LEVEL >= TRACE_DEBUG static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region) diff --git a/core/include/drivers/tzc380.h b/core/include/drivers/tzc380.h index 24708d0c..fed1d92f 100644 --- a/core/include/drivers/tzc380.h +++ b/core/include/drivers/tzc380.h @@ -189,6 +189,12 @@ enum tzc_action { #define TZC_REGION_SIZE_MASK GENMASK_32(6, 1) #define TZC_ATTR_REGION_SIZE(s) ((s) << TZC_REGION_SIZE_SHIFT) +#define TZC_SUBREGION_DIS_SHIFT 8 +#define TZC_SUBREGION_DIS_MASK GENMASK_32(15, 8) +#define TZC_ATTR_SUBREGION_DIS(subreg) \ + (BIT((subreg) + TZC_SUBREGION_DIS_SHIFT) & \ + TZC_SUBREGION_DIS_MASK) + #define TZC_ATTR_REGION_EN_SHIFT 0x0 #define TZC_ATTR_REGION_EN_MASK 0x1 @@ -196,6 +202,12 @@ enum tzc_action { #define TZC_ATTR_REGION_ENABLE 0x1 #define TZC_ATTR_REGION_DISABLE 0x0 +#ifdef CFG_WITH_LPAE +#define TZC380_POW 48 +#else +#define TZC380_POW 34 +#endif + void tzc_init(vaddr_t base); void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr); void tzc_region_enable(uint8_t region); @@ -204,6 +216,8 @@ void tzc_set_action(enum tzc_action action); uint32_t tzc_get_action(void); void tzc_fail_dump(void); void tzc_int_clear(void); +int tzc_auto_configure(vaddr_t addr, vaddr_t rsize, uint32_t attr, + uint8_t region); #if TRACE_LEVEL >= TRACE_DEBUG void tzc_dump_state(void); |