11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 24c56bf5fSPeng Fan /* 34c56bf5fSPeng Fan * Copyright 2017 NXP 44c56bf5fSPeng Fan * All rights reserved. 54c56bf5fSPeng Fan * 64c56bf5fSPeng Fan * Peng Fan <peng.fan@nxp.com> 74c56bf5fSPeng Fan * 84c56bf5fSPeng Fan * Redistribution and use in source and binary forms, with or without 94c56bf5fSPeng Fan * modification, are permitted provided that the following conditions are met: 104c56bf5fSPeng Fan * 114c56bf5fSPeng Fan * 1. Redistributions of source code must retain the above copyright notice, 124c56bf5fSPeng Fan * this list of conditions and the following disclaimer. 134c56bf5fSPeng Fan * 144c56bf5fSPeng Fan * 2. Redistributions in binary form must reproduce the above copyright notice, 154c56bf5fSPeng Fan * this list of conditions and the following disclaimer in the documentation 164c56bf5fSPeng Fan * and/or other materials provided with the distribution. 174c56bf5fSPeng Fan * 184c56bf5fSPeng Fan * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 194c56bf5fSPeng Fan * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 204c56bf5fSPeng Fan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 214c56bf5fSPeng Fan * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 224c56bf5fSPeng Fan * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 234c56bf5fSPeng Fan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 244c56bf5fSPeng Fan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 254c56bf5fSPeng Fan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 264c56bf5fSPeng Fan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 274c56bf5fSPeng Fan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 284c56bf5fSPeng Fan * POSSIBILITY OF SUCH DAMAGE. 294c56bf5fSPeng Fan */ 304c56bf5fSPeng Fan 314c56bf5fSPeng Fan #include <assert.h> 324c56bf5fSPeng Fan #include <drivers/tzc380.h> 334c56bf5fSPeng Fan #include <io.h> 344c56bf5fSPeng Fan #include <kernel/panic.h> 35*343c1571SPeng Fan #include <mm/core_memprot.h> 36*343c1571SPeng Fan #include <mm/core_mmu.h> 374c56bf5fSPeng Fan #include <stddef.h> 384c56bf5fSPeng Fan #include <trace.h> 394c56bf5fSPeng Fan #include <util.h> 404c56bf5fSPeng Fan 414c56bf5fSPeng Fan /* 424c56bf5fSPeng Fan * Implementation defined values used to validate inputs later. 434c56bf5fSPeng Fan * Filters : max of 4 ; 0 to 3 444c56bf5fSPeng Fan * Regions : max of 9 ; 0 to 8 454c56bf5fSPeng Fan * Address width : Values between 32 to 64 464c56bf5fSPeng Fan */ 474c56bf5fSPeng Fan struct tzc_instance { 484c56bf5fSPeng Fan vaddr_t base; 494c56bf5fSPeng Fan uint8_t addr_width; 504c56bf5fSPeng Fan uint8_t num_regions; 514c56bf5fSPeng Fan }; 524c56bf5fSPeng Fan 534c56bf5fSPeng Fan static struct tzc_instance tzc; 544c56bf5fSPeng Fan 554c56bf5fSPeng Fan static uint32_t tzc_read_build_config(vaddr_t base) 564c56bf5fSPeng Fan { 574c56bf5fSPeng Fan return read32(base + BUILD_CONFIG_OFF); 584c56bf5fSPeng Fan } 594c56bf5fSPeng Fan 604c56bf5fSPeng Fan static void tzc_write_action(vaddr_t base, enum tzc_action action) 614c56bf5fSPeng Fan { 624c56bf5fSPeng Fan write32(action, base + ACTION_OFF); 634c56bf5fSPeng Fan } 644c56bf5fSPeng Fan 654c56bf5fSPeng Fan static void tzc_write_region_base_low(vaddr_t base, uint32_t region, 664c56bf5fSPeng Fan uint32_t val) 674c56bf5fSPeng Fan { 684c56bf5fSPeng Fan write32(val, base + REGION_SETUP_LOW_OFF(region)); 694c56bf5fSPeng Fan } 704c56bf5fSPeng Fan 714c56bf5fSPeng Fan static void tzc_write_region_base_high(vaddr_t base, uint32_t region, 724c56bf5fSPeng Fan uint32_t val) 734c56bf5fSPeng Fan { 744c56bf5fSPeng Fan write32(val, base + REGION_SETUP_HIGH_OFF(region)); 754c56bf5fSPeng Fan } 764c56bf5fSPeng Fan 77*343c1571SPeng Fan static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region) 78*343c1571SPeng Fan { 79*343c1571SPeng Fan return read32(base + REGION_ATTRIBUTES_OFF(region)); 80*343c1571SPeng Fan } 81*343c1571SPeng Fan 824c56bf5fSPeng Fan static void tzc_write_region_attributes(vaddr_t base, uint32_t region, 834c56bf5fSPeng Fan uint32_t val) 844c56bf5fSPeng Fan { 854c56bf5fSPeng Fan write32(val, base + REGION_ATTRIBUTES_OFF(region)); 864c56bf5fSPeng Fan } 874c56bf5fSPeng Fan 884c56bf5fSPeng Fan void tzc_init(vaddr_t base) 894c56bf5fSPeng Fan { 904c56bf5fSPeng Fan uint32_t tzc_build; 914c56bf5fSPeng Fan 924c56bf5fSPeng Fan assert(base); 934c56bf5fSPeng Fan tzc.base = base; 944c56bf5fSPeng Fan 954c56bf5fSPeng Fan /* Save values we will use later. */ 964c56bf5fSPeng Fan tzc_build = tzc_read_build_config(tzc.base); 974c56bf5fSPeng Fan tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & 984c56bf5fSPeng Fan BUILD_CONFIG_AW_MASK) + 1; 994c56bf5fSPeng Fan tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & 1004c56bf5fSPeng Fan BUILD_CONFIG_NR_MASK) + 1; 1014c56bf5fSPeng Fan } 1024c56bf5fSPeng Fan 103*343c1571SPeng Fan /* 104*343c1571SPeng Fan * There are two modes of operation for the region security 105*343c1571SPeng Fan * permissions, with or without security inversion. 106*343c1571SPeng Fan * Check TZC380 "2.2.5 Region security permissions" for 107*343c1571SPeng Fan * more details. 108*343c1571SPeng Fan */ 109*343c1571SPeng Fan void tzc_security_inversion_en(vaddr_t base) 110*343c1571SPeng Fan { 111*343c1571SPeng Fan write32(1, base + SECURITY_INV_EN_OFF); 112*343c1571SPeng Fan } 113*343c1571SPeng Fan 114*343c1571SPeng Fan /* 115*343c1571SPeng Fan * Enable a single region. Sometimes we could not use tzc_configure_region 116*343c1571SPeng Fan * to enable the region, when security inversion is on. 117*343c1571SPeng Fan * When need security inversion, we need to first configure 118*343c1571SPeng Fan * region address and attribute, then configure security inversion, 119*343c1571SPeng Fan * then enable the regions. 120*343c1571SPeng Fan */ 121*343c1571SPeng Fan void tzc_region_enable(uint8_t region) 122*343c1571SPeng Fan { 123*343c1571SPeng Fan uint32_t val; 124*343c1571SPeng Fan 125*343c1571SPeng Fan val = tzc_read_region_attributes(tzc.base, region); 126*343c1571SPeng Fan val |= TZC_ATTR_REGION_EN_MASK; 127*343c1571SPeng Fan tzc_write_region_attributes(tzc.base, region, val); 128*343c1571SPeng Fan } 129*343c1571SPeng Fan 130*343c1571SPeng Fan /* 131*343c1571SPeng Fan * Dump info when TZC380 catchs an unallowed access with TZC 132*343c1571SPeng Fan * interrupt enabled. 133*343c1571SPeng Fan */ 134*343c1571SPeng Fan void tzc_fail_dump(void) 135*343c1571SPeng Fan { 136*343c1571SPeng Fan vaddr_t base __maybe_unused = core_mmu_get_va(tzc.base, 137*343c1571SPeng Fan MEM_AREA_IO_SEC); 138*343c1571SPeng Fan 139*343c1571SPeng Fan EMSG("Fail address Low 0x%" PRIx32, 140*343c1571SPeng Fan read32(base + FAIL_ADDRESS_LOW_OFF)); 141*343c1571SPeng Fan EMSG("Fail address High 0x%" PRIx32, 142*343c1571SPeng Fan read32(base + FAIL_ADDRESS_HIGH_OFF)); 143*343c1571SPeng Fan EMSG("Fail Control 0x%" PRIx32, read32(base + FAIL_CONTROL_OFF)); 144*343c1571SPeng Fan EMSG("Fail Id 0x%" PRIx32, read32(base + FAIL_ID)); 145*343c1571SPeng Fan } 146*343c1571SPeng Fan 147*343c1571SPeng Fan void tzc_int_clear(void) 148*343c1571SPeng Fan { 149*343c1571SPeng Fan vaddr_t base = core_mmu_get_va(tzc.base, MEM_AREA_IO_SEC); 150*343c1571SPeng Fan 151*343c1571SPeng Fan write32(0, base + INT_CLEAR); 152*343c1571SPeng Fan } 153*343c1571SPeng Fan 1544c56bf5fSPeng Fan static uint32_t addr_low(vaddr_t addr) 1554c56bf5fSPeng Fan { 1564c56bf5fSPeng Fan return (uint32_t)addr; 1574c56bf5fSPeng Fan } 1584c56bf5fSPeng Fan 1594c56bf5fSPeng Fan static uint32_t addr_high(vaddr_t addr __maybe_unused) 1604c56bf5fSPeng Fan { 1614c56bf5fSPeng Fan #if (UINTPTR_MAX == UINT64_MAX) 1624c56bf5fSPeng Fan return addr >> 32; 1634c56bf5fSPeng Fan #else 1644c56bf5fSPeng Fan return 0; 1654c56bf5fSPeng Fan #endif 1664c56bf5fSPeng Fan } 1674c56bf5fSPeng Fan 1684c56bf5fSPeng Fan 1694c56bf5fSPeng Fan /* 1704c56bf5fSPeng Fan * `tzc_configure_region` is used to program regions into the TrustZone 1714c56bf5fSPeng Fan * controller. 1724c56bf5fSPeng Fan */ 1734c56bf5fSPeng Fan void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr) 1744c56bf5fSPeng Fan { 1754c56bf5fSPeng Fan assert(tzc.base); 1764c56bf5fSPeng Fan 1774c56bf5fSPeng Fan assert(region < tzc.num_regions); 1784c56bf5fSPeng Fan 179fe1404daSPeng Fan /* 180fe1404daSPeng Fan * For region 0, this high/low/size/en field is Read Only (RO). 181fe1404daSPeng Fan * So should not configure those field for region 0. 182fe1404daSPeng Fan */ 183fe1404daSPeng Fan if (region) { 184fe1404daSPeng Fan tzc_write_region_base_low(tzc.base, region, 185fe1404daSPeng Fan addr_low(region_base)); 186fe1404daSPeng Fan tzc_write_region_base_high(tzc.base, region, 187fe1404daSPeng Fan addr_high(region_base)); 1884c56bf5fSPeng Fan tzc_write_region_attributes(tzc.base, region, attr); 189fe1404daSPeng Fan } else { 190fe1404daSPeng Fan tzc_write_region_attributes(tzc.base, region, 191fe1404daSPeng Fan attr & TZC_ATTR_SP_MASK); 192fe1404daSPeng Fan } 1934c56bf5fSPeng Fan } 1944c56bf5fSPeng Fan 1954c56bf5fSPeng Fan void tzc_set_action(enum tzc_action action) 1964c56bf5fSPeng Fan { 1974c56bf5fSPeng Fan assert(tzc.base); 1984c56bf5fSPeng Fan 1994c56bf5fSPeng Fan /* 2004c56bf5fSPeng Fan * - Currently no handler is provided to trap an error via interrupt 2014c56bf5fSPeng Fan * or exception. 2024c56bf5fSPeng Fan * - The interrupt action has not been tested. 2034c56bf5fSPeng Fan */ 2044c56bf5fSPeng Fan tzc_write_action(tzc.base, action); 2054c56bf5fSPeng Fan } 2064c56bf5fSPeng Fan 2074c56bf5fSPeng Fan #if TRACE_LEVEL >= TRACE_DEBUG 2084c56bf5fSPeng Fan 2094c56bf5fSPeng Fan static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region) 2104c56bf5fSPeng Fan { 2114c56bf5fSPeng Fan return read32(base + REGION_SETUP_LOW_OFF(region)); 2124c56bf5fSPeng Fan } 2134c56bf5fSPeng Fan 2144c56bf5fSPeng Fan static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region) 2154c56bf5fSPeng Fan { 2164c56bf5fSPeng Fan return read32(base + REGION_SETUP_HIGH_OFF(region)); 2174c56bf5fSPeng Fan } 2184c56bf5fSPeng Fan 2194c56bf5fSPeng Fan #define REGION_MAX 16 2204c56bf5fSPeng Fan void tzc_dump_state(void) 2214c56bf5fSPeng Fan { 2224c56bf5fSPeng Fan uint32_t n; 2234c56bf5fSPeng Fan uint32_t temp_32reg, temp_32reg_h; 2244c56bf5fSPeng Fan 2254c56bf5fSPeng Fan DMSG("enter"); 2264c56bf5fSPeng Fan DMSG("security_inversion_en %x\n", 2274c56bf5fSPeng Fan read32(tzc.base + SECURITY_INV_EN_OFF)); 2284c56bf5fSPeng Fan for (n = 0; n <= REGION_MAX; n++) { 2294c56bf5fSPeng Fan temp_32reg = tzc_read_region_attributes(tzc.base, n); 2304c56bf5fSPeng Fan if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK)) 2314c56bf5fSPeng Fan continue; 2324c56bf5fSPeng Fan 2334c56bf5fSPeng Fan DMSG("\n"); 2344c56bf5fSPeng Fan DMSG("region %d", n); 2354c56bf5fSPeng Fan temp_32reg = tzc_read_region_base_low(tzc.base, n); 2364c56bf5fSPeng Fan temp_32reg_h = tzc_read_region_base_high(tzc.base, n); 2374c56bf5fSPeng Fan DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg); 2384c56bf5fSPeng Fan temp_32reg = tzc_read_region_attributes(tzc.base, n); 2394c56bf5fSPeng Fan DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT); 2404c56bf5fSPeng Fan DMSG("region size: %x\n", (temp_32reg & TZC_REGION_SIZE_MASK) >> 2414c56bf5fSPeng Fan TZC_REGION_SIZE_SHIFT); 2424c56bf5fSPeng Fan } 2434c56bf5fSPeng Fan DMSG("exit"); 2444c56bf5fSPeng Fan } 2454c56bf5fSPeng Fan 2464c56bf5fSPeng Fan #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */ 247