aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorRouven Czerwinski <r.czerwinski@pengutronix.de>2019-03-18 10:46:55 +0100
committerJoakim Bech <joakim.bech@linaro.org>2019-04-15 15:30:30 +0700
commite8e7f1c5d978df640d073de4271ad87bc50b6879 (patch)
treeb470447e59248c912ea4e6dc313955a96762529a /core
parent7eedcd151e9c7b5eb56ab2f6379ee9c3de77e8c4 (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.c62
-rw-r--r--core/include/drivers/tzc380.h14
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);