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> 35343c1571SPeng Fan #include <mm/core_memprot.h> 36343c1571SPeng 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 { 57918bb3a5SEtienne Carriere return io_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 { 62918bb3a5SEtienne Carriere io_write32(base + ACTION_OFF, action); 634c56bf5fSPeng Fan } 644c56bf5fSPeng Fan 65*7eedcd15SRouven Czerwinski static uint32_t tzc_read_action(vaddr_t base) 66*7eedcd15SRouven Czerwinski { 67*7eedcd15SRouven Czerwinski return io_read32(base + ACTION_OFF); 68*7eedcd15SRouven Czerwinski } 69*7eedcd15SRouven Czerwinski 704c56bf5fSPeng Fan static void tzc_write_region_base_low(vaddr_t base, uint32_t region, 714c56bf5fSPeng Fan uint32_t val) 724c56bf5fSPeng Fan { 73918bb3a5SEtienne Carriere io_write32(base + REGION_SETUP_LOW_OFF(region), val); 744c56bf5fSPeng Fan } 754c56bf5fSPeng Fan 764c56bf5fSPeng Fan static void tzc_write_region_base_high(vaddr_t base, uint32_t region, 774c56bf5fSPeng Fan uint32_t val) 784c56bf5fSPeng Fan { 79918bb3a5SEtienne Carriere io_write32(base + REGION_SETUP_HIGH_OFF(region), val); 804c56bf5fSPeng Fan } 814c56bf5fSPeng Fan 82343c1571SPeng Fan static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region) 83343c1571SPeng Fan { 84918bb3a5SEtienne Carriere return io_read32(base + REGION_ATTRIBUTES_OFF(region)); 85343c1571SPeng Fan } 86343c1571SPeng Fan 874c56bf5fSPeng Fan static void tzc_write_region_attributes(vaddr_t base, uint32_t region, 884c56bf5fSPeng Fan uint32_t val) 894c56bf5fSPeng Fan { 90918bb3a5SEtienne Carriere io_write32(base + REGION_ATTRIBUTES_OFF(region), val); 914c56bf5fSPeng Fan } 924c56bf5fSPeng Fan 934c56bf5fSPeng Fan void tzc_init(vaddr_t base) 944c56bf5fSPeng Fan { 954c56bf5fSPeng Fan uint32_t tzc_build; 964c56bf5fSPeng Fan 974c56bf5fSPeng Fan assert(base); 984c56bf5fSPeng Fan tzc.base = base; 994c56bf5fSPeng Fan 1004c56bf5fSPeng Fan /* Save values we will use later. */ 1014c56bf5fSPeng Fan tzc_build = tzc_read_build_config(tzc.base); 1024c56bf5fSPeng Fan tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & 1034c56bf5fSPeng Fan BUILD_CONFIG_AW_MASK) + 1; 1044c56bf5fSPeng Fan tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & 1054c56bf5fSPeng Fan BUILD_CONFIG_NR_MASK) + 1; 1064c56bf5fSPeng Fan } 1074c56bf5fSPeng Fan 108343c1571SPeng Fan /* 109343c1571SPeng Fan * There are two modes of operation for the region security 110343c1571SPeng Fan * permissions, with or without security inversion. 111343c1571SPeng Fan * Check TZC380 "2.2.5 Region security permissions" for 112343c1571SPeng Fan * more details. 113343c1571SPeng Fan */ 114343c1571SPeng Fan void tzc_security_inversion_en(vaddr_t base) 115343c1571SPeng Fan { 116918bb3a5SEtienne Carriere io_write32(base + SECURITY_INV_EN_OFF, 1); 117343c1571SPeng Fan } 118343c1571SPeng Fan 119343c1571SPeng Fan /* 120343c1571SPeng Fan * Enable a single region. Sometimes we could not use tzc_configure_region 121343c1571SPeng Fan * to enable the region, when security inversion is on. 122343c1571SPeng Fan * When need security inversion, we need to first configure 123343c1571SPeng Fan * region address and attribute, then configure security inversion, 124343c1571SPeng Fan * then enable the regions. 125343c1571SPeng Fan */ 126343c1571SPeng Fan void tzc_region_enable(uint8_t region) 127343c1571SPeng Fan { 128343c1571SPeng Fan uint32_t val; 129343c1571SPeng Fan 130343c1571SPeng Fan val = tzc_read_region_attributes(tzc.base, region); 131343c1571SPeng Fan val |= TZC_ATTR_REGION_EN_MASK; 132343c1571SPeng Fan tzc_write_region_attributes(tzc.base, region, val); 133343c1571SPeng Fan } 134343c1571SPeng Fan 135343c1571SPeng Fan /* 136343c1571SPeng Fan * Dump info when TZC380 catchs an unallowed access with TZC 137343c1571SPeng Fan * interrupt enabled. 138343c1571SPeng Fan */ 139343c1571SPeng Fan void tzc_fail_dump(void) 140343c1571SPeng Fan { 141343c1571SPeng Fan vaddr_t base __maybe_unused = core_mmu_get_va(tzc.base, 142343c1571SPeng Fan MEM_AREA_IO_SEC); 143343c1571SPeng Fan 144343c1571SPeng Fan EMSG("Fail address Low 0x%" PRIx32, 145918bb3a5SEtienne Carriere io_read32(base + FAIL_ADDRESS_LOW_OFF)); 146343c1571SPeng Fan EMSG("Fail address High 0x%" PRIx32, 147918bb3a5SEtienne Carriere io_read32(base + FAIL_ADDRESS_HIGH_OFF)); 148918bb3a5SEtienne Carriere EMSG("Fail Control 0x%" PRIx32, io_read32(base + FAIL_CONTROL_OFF)); 149918bb3a5SEtienne Carriere EMSG("Fail Id 0x%" PRIx32, io_read32(base + FAIL_ID)); 150343c1571SPeng Fan } 151343c1571SPeng Fan 152343c1571SPeng Fan void tzc_int_clear(void) 153343c1571SPeng Fan { 154343c1571SPeng Fan vaddr_t base = core_mmu_get_va(tzc.base, MEM_AREA_IO_SEC); 155343c1571SPeng Fan 156918bb3a5SEtienne Carriere io_write32(base + INT_CLEAR, 0); 157343c1571SPeng Fan } 158343c1571SPeng Fan 1594c56bf5fSPeng Fan static uint32_t addr_low(vaddr_t addr) 1604c56bf5fSPeng Fan { 1614c56bf5fSPeng Fan return (uint32_t)addr; 1624c56bf5fSPeng Fan } 1634c56bf5fSPeng Fan 1644c56bf5fSPeng Fan static uint32_t addr_high(vaddr_t addr __maybe_unused) 1654c56bf5fSPeng Fan { 1664c56bf5fSPeng Fan #if (UINTPTR_MAX == UINT64_MAX) 1674c56bf5fSPeng Fan return addr >> 32; 1684c56bf5fSPeng Fan #else 1694c56bf5fSPeng Fan return 0; 1704c56bf5fSPeng Fan #endif 1714c56bf5fSPeng Fan } 1724c56bf5fSPeng Fan 1734c56bf5fSPeng Fan 1744c56bf5fSPeng Fan /* 1754c56bf5fSPeng Fan * `tzc_configure_region` is used to program regions into the TrustZone 1764c56bf5fSPeng Fan * controller. 1774c56bf5fSPeng Fan */ 1784c56bf5fSPeng Fan void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr) 1794c56bf5fSPeng Fan { 1804c56bf5fSPeng Fan assert(tzc.base); 1814c56bf5fSPeng Fan 1824c56bf5fSPeng Fan assert(region < tzc.num_regions); 1834c56bf5fSPeng Fan 184fe1404daSPeng Fan /* 185fe1404daSPeng Fan * For region 0, this high/low/size/en field is Read Only (RO). 186fe1404daSPeng Fan * So should not configure those field for region 0. 187fe1404daSPeng Fan */ 188fe1404daSPeng Fan if (region) { 189fe1404daSPeng Fan tzc_write_region_base_low(tzc.base, region, 190fe1404daSPeng Fan addr_low(region_base)); 191fe1404daSPeng Fan tzc_write_region_base_high(tzc.base, region, 192fe1404daSPeng Fan addr_high(region_base)); 1934c56bf5fSPeng Fan tzc_write_region_attributes(tzc.base, region, attr); 194fe1404daSPeng Fan } else { 195fe1404daSPeng Fan tzc_write_region_attributes(tzc.base, region, 196fe1404daSPeng Fan attr & TZC_ATTR_SP_MASK); 197fe1404daSPeng Fan } 1984c56bf5fSPeng Fan } 1994c56bf5fSPeng Fan 2004c56bf5fSPeng Fan void tzc_set_action(enum tzc_action action) 2014c56bf5fSPeng Fan { 2024c56bf5fSPeng Fan assert(tzc.base); 2034c56bf5fSPeng Fan 2044c56bf5fSPeng Fan /* 2054c56bf5fSPeng Fan * - Currently no handler is provided to trap an error via interrupt 2064c56bf5fSPeng Fan * or exception. 2074c56bf5fSPeng Fan * - The interrupt action has not been tested. 2084c56bf5fSPeng Fan */ 2094c56bf5fSPeng Fan tzc_write_action(tzc.base, action); 2104c56bf5fSPeng Fan } 2114c56bf5fSPeng Fan 212*7eedcd15SRouven Czerwinski uint32_t tzc_get_action(void) 213*7eedcd15SRouven Czerwinski { 214*7eedcd15SRouven Czerwinski assert(tzc.base); 215*7eedcd15SRouven Czerwinski 216*7eedcd15SRouven Czerwinski return tzc_read_action(tzc.base); 217*7eedcd15SRouven Czerwinski } 218*7eedcd15SRouven Czerwinski 2194c56bf5fSPeng Fan #if TRACE_LEVEL >= TRACE_DEBUG 2204c56bf5fSPeng Fan 2214c56bf5fSPeng Fan static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region) 2224c56bf5fSPeng Fan { 223918bb3a5SEtienne Carriere return io_read32(base + REGION_SETUP_LOW_OFF(region)); 2244c56bf5fSPeng Fan } 2254c56bf5fSPeng Fan 2264c56bf5fSPeng Fan static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region) 2274c56bf5fSPeng Fan { 228918bb3a5SEtienne Carriere return io_read32(base + REGION_SETUP_HIGH_OFF(region)); 2294c56bf5fSPeng Fan } 2304c56bf5fSPeng Fan 2314c56bf5fSPeng Fan #define REGION_MAX 16 2324c56bf5fSPeng Fan void tzc_dump_state(void) 2334c56bf5fSPeng Fan { 2344c56bf5fSPeng Fan uint32_t n; 2354c56bf5fSPeng Fan uint32_t temp_32reg, temp_32reg_h; 2364c56bf5fSPeng Fan 2374c56bf5fSPeng Fan DMSG("enter"); 23865fe41dbSEtienne Carriere DMSG("security_inversion_en %x", 239918bb3a5SEtienne Carriere io_read32(tzc.base + SECURITY_INV_EN_OFF)); 2404c56bf5fSPeng Fan for (n = 0; n <= REGION_MAX; n++) { 2414c56bf5fSPeng Fan temp_32reg = tzc_read_region_attributes(tzc.base, n); 2424c56bf5fSPeng Fan if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK)) 2434c56bf5fSPeng Fan continue; 2444c56bf5fSPeng Fan 24565fe41dbSEtienne Carriere DMSG(""); 2464c56bf5fSPeng Fan DMSG("region %d", n); 2474c56bf5fSPeng Fan temp_32reg = tzc_read_region_base_low(tzc.base, n); 2484c56bf5fSPeng Fan temp_32reg_h = tzc_read_region_base_high(tzc.base, n); 2494c56bf5fSPeng Fan DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg); 2504c56bf5fSPeng Fan temp_32reg = tzc_read_region_attributes(tzc.base, n); 2514c56bf5fSPeng Fan DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT); 25265fe41dbSEtienne Carriere DMSG("region size: %x", (temp_32reg & TZC_REGION_SIZE_MASK) >> 2534c56bf5fSPeng Fan TZC_REGION_SIZE_SHIFT); 2544c56bf5fSPeng Fan } 2554c56bf5fSPeng Fan DMSG("exit"); 2564c56bf5fSPeng Fan } 2574c56bf5fSPeng Fan 2584c56bf5fSPeng Fan #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */ 259