1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <common/debug.h> 10*91f16700Schasinglulu #include <drivers/arm/tzc_dmc500.h> 11*91f16700Schasinglulu #include <drivers/arm/tzc_common.h> 12*91f16700Schasinglulu #include <lib/mmio.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #include "tzc_common_private.h" 15*91f16700Schasinglulu 16*91f16700Schasinglulu /* 17*91f16700Schasinglulu * Macros which will be used by common core functions. 18*91f16700Schasinglulu */ 19*91f16700Schasinglulu #define TZC_DMC500_REGION_BASE_LOW_0_OFFSET 0x054 20*91f16700Schasinglulu #define TZC_DMC500_REGION_BASE_HIGH_0_OFFSET 0x058 21*91f16700Schasinglulu #define TZC_DMC500_REGION_TOP_LOW_0_OFFSET 0x05C 22*91f16700Schasinglulu #define TZC_DMC500_REGION_TOP_HIGH_0_OFFSET 0x060 23*91f16700Schasinglulu #define TZC_DMC500_REGION_ATTR_0_OFFSET 0x064 24*91f16700Schasinglulu #define TZC_DMC500_REGION_ID_ACCESS_0_OFFSET 0x068 25*91f16700Schasinglulu 26*91f16700Schasinglulu #define TZC_DMC500_ACTION_OFF 0x50 27*91f16700Schasinglulu 28*91f16700Schasinglulu /* Pointer to the tzc_dmc500_driver_data structure populated by the platform */ 29*91f16700Schasinglulu static const tzc_dmc500_driver_data_t *g_driver_data; 30*91f16700Schasinglulu static unsigned int g_sys_if_count; 31*91f16700Schasinglulu 32*91f16700Schasinglulu #define verify_region_attr(region, attr) \ 33*91f16700Schasinglulu ((g_conf_regions[(region)].sec_attr == \ 34*91f16700Schasinglulu ((attr) >> TZC_REGION_ATTR_SEC_SHIFT)) \ 35*91f16700Schasinglulu && ((attr) & (0x1 << TZC_REGION_ATTR_F_EN_SHIFT))) 36*91f16700Schasinglulu 37*91f16700Schasinglulu /* 38*91f16700Schasinglulu * Structure for configured regions attributes in DMC500. 39*91f16700Schasinglulu */ 40*91f16700Schasinglulu typedef struct tzc_dmc500_regions { 41*91f16700Schasinglulu unsigned int sec_attr; 42*91f16700Schasinglulu int is_enabled; 43*91f16700Schasinglulu } tzc_dmc500_regions_t; 44*91f16700Schasinglulu 45*91f16700Schasinglulu /* 46*91f16700Schasinglulu * Array storing the attributes of the configured regions. This array 47*91f16700Schasinglulu * will be used by the `tzc_dmc500_verify_complete` to verify the flush 48*91f16700Schasinglulu * completion. 49*91f16700Schasinglulu */ 50*91f16700Schasinglulu static tzc_dmc500_regions_t g_conf_regions[MAX_REGION_VAL + 1]; 51*91f16700Schasinglulu 52*91f16700Schasinglulu /* Helper Macros for making the code readable */ 53*91f16700Schasinglulu #define DMC_INST_BASE_ADDR(instance) (g_driver_data->dmc_base[instance]) 54*91f16700Schasinglulu #define DMC_INST_SI_BASE(instance, interface) \ 55*91f16700Schasinglulu (DMC_INST_BASE_ADDR(instance) + IFACE_OFFSET(interface)) 56*91f16700Schasinglulu 57*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_ACTION(_dmc500, DMC500) 58*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_BASE(_dmc500, DMC500) 59*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_TOP(_dmc500, DMC500) 60*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(_dmc500, DMC500) 61*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(_dmc500, DMC500) 62*91f16700Schasinglulu 63*91f16700Schasinglulu DEFINE_TZC_COMMON_CONFIGURE_REGION0(_dmc500) 64*91f16700Schasinglulu DEFINE_TZC_COMMON_CONFIGURE_REGION(_dmc500) 65*91f16700Schasinglulu 66*91f16700Schasinglulu static inline unsigned int _tzc_dmc500_read_region_attr_0( 67*91f16700Schasinglulu uintptr_t dmc_si_base, 68*91f16700Schasinglulu unsigned int region_no) 69*91f16700Schasinglulu { 70*91f16700Schasinglulu return mmio_read_32(dmc_si_base + 71*91f16700Schasinglulu TZC_REGION_OFFSET(TZC_DMC500_REGION_SIZE, region_no) + 72*91f16700Schasinglulu TZC_DMC500_REGION_ATTR_0_OFFSET); 73*91f16700Schasinglulu } 74*91f16700Schasinglulu 75*91f16700Schasinglulu static inline void _tzc_dmc500_write_flush_control(uintptr_t dmc_si_base) 76*91f16700Schasinglulu { 77*91f16700Schasinglulu mmio_write_32(dmc_si_base + SI_FLUSH_CTRL_OFFSET, 1); 78*91f16700Schasinglulu } 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* 81*91f16700Schasinglulu * Sets the Flush controls for all the DMC Instances and System Interfaces. 82*91f16700Schasinglulu * This initiates the flush of configuration settings from the shadow 83*91f16700Schasinglulu * registers to the actual configuration register. The caller should poll 84*91f16700Schasinglulu * changed register to confirm update. 85*91f16700Schasinglulu */ 86*91f16700Schasinglulu void tzc_dmc500_config_complete(void) 87*91f16700Schasinglulu { 88*91f16700Schasinglulu int dmc_inst, sys_if; 89*91f16700Schasinglulu 90*91f16700Schasinglulu assert(g_driver_data); 91*91f16700Schasinglulu 92*91f16700Schasinglulu for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { 93*91f16700Schasinglulu assert(DMC_INST_BASE_ADDR(dmc_inst)); 94*91f16700Schasinglulu for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) 95*91f16700Schasinglulu _tzc_dmc500_write_flush_control( 96*91f16700Schasinglulu DMC_INST_SI_BASE(dmc_inst, sys_if)); 97*91f16700Schasinglulu } 98*91f16700Schasinglulu } 99*91f16700Schasinglulu 100*91f16700Schasinglulu /* 101*91f16700Schasinglulu * This function reads back the secure attributes from the configuration 102*91f16700Schasinglulu * register for each DMC Instance and System Interface and compares it with 103*91f16700Schasinglulu * the configured value. The successful verification of the region attributes 104*91f16700Schasinglulu * confirms that the flush operation has completed. 105*91f16700Schasinglulu * If the verification fails, the caller is expected to invoke this API again 106*91f16700Schasinglulu * till it succeeds. 107*91f16700Schasinglulu * Returns 0 on success and 1 on failure. 108*91f16700Schasinglulu */ 109*91f16700Schasinglulu int tzc_dmc500_verify_complete(void) 110*91f16700Schasinglulu { 111*91f16700Schasinglulu int dmc_inst, sys_if, region_no; 112*91f16700Schasinglulu unsigned int attr; 113*91f16700Schasinglulu 114*91f16700Schasinglulu assert(g_driver_data); 115*91f16700Schasinglulu /* Region 0 must be configured */ 116*91f16700Schasinglulu assert(g_conf_regions[0].is_enabled); 117*91f16700Schasinglulu 118*91f16700Schasinglulu /* Iterate over all configured regions */ 119*91f16700Schasinglulu for (region_no = 0; region_no <= MAX_REGION_VAL; region_no++) { 120*91f16700Schasinglulu if (!g_conf_regions[region_no].is_enabled) 121*91f16700Schasinglulu continue; 122*91f16700Schasinglulu for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; 123*91f16700Schasinglulu dmc_inst++) { 124*91f16700Schasinglulu assert(DMC_INST_BASE_ADDR(dmc_inst)); 125*91f16700Schasinglulu for (sys_if = 0; sys_if < g_sys_if_count; 126*91f16700Schasinglulu sys_if++) { 127*91f16700Schasinglulu attr = _tzc_dmc500_read_region_attr_0( 128*91f16700Schasinglulu DMC_INST_SI_BASE(dmc_inst, sys_if), 129*91f16700Schasinglulu region_no); 130*91f16700Schasinglulu VERBOSE("Verifying DMC500 region:%d" 131*91f16700Schasinglulu " dmc_inst:%d sys_if:%d attr:%x\n", 132*91f16700Schasinglulu region_no, dmc_inst, sys_if, attr); 133*91f16700Schasinglulu if (!verify_region_attr(region_no, attr)) 134*91f16700Schasinglulu return 1; 135*91f16700Schasinglulu } 136*91f16700Schasinglulu } 137*91f16700Schasinglulu } 138*91f16700Schasinglulu 139*91f16700Schasinglulu return 0; 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu /* 143*91f16700Schasinglulu * `tzc_dmc500_configure_region0` is used to program region 0 in both the 144*91f16700Schasinglulu * system interfaces of all the DMC-500 instances. Region 0 covers the whole 145*91f16700Schasinglulu * address space that is not mapped to any other region for a system interface, 146*91f16700Schasinglulu * and is always enabled; this cannot be changed. This function only changes 147*91f16700Schasinglulu * the access permissions. 148*91f16700Schasinglulu */ 149*91f16700Schasinglulu void tzc_dmc500_configure_region0(unsigned int sec_attr, 150*91f16700Schasinglulu unsigned int nsaid_permissions) 151*91f16700Schasinglulu { 152*91f16700Schasinglulu int dmc_inst, sys_if; 153*91f16700Schasinglulu 154*91f16700Schasinglulu /* Assert if DMC-500 is not initialized */ 155*91f16700Schasinglulu assert(g_driver_data); 156*91f16700Schasinglulu 157*91f16700Schasinglulu /* Configure region_0 in all DMC instances */ 158*91f16700Schasinglulu for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { 159*91f16700Schasinglulu assert(DMC_INST_BASE_ADDR(dmc_inst)); 160*91f16700Schasinglulu for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) 161*91f16700Schasinglulu _tzc_dmc500_configure_region0( 162*91f16700Schasinglulu DMC_INST_SI_BASE(dmc_inst, sys_if), 163*91f16700Schasinglulu sec_attr, nsaid_permissions); 164*91f16700Schasinglulu } 165*91f16700Schasinglulu 166*91f16700Schasinglulu g_conf_regions[0].sec_attr = sec_attr; 167*91f16700Schasinglulu g_conf_regions[0].is_enabled = 1; 168*91f16700Schasinglulu } 169*91f16700Schasinglulu 170*91f16700Schasinglulu /* 171*91f16700Schasinglulu * `tzc_dmc500_configure_region` is used to program a region into all system 172*91f16700Schasinglulu * interfaces of all the DMC instances. 173*91f16700Schasinglulu * NOTE: 174*91f16700Schasinglulu * Region 0 is special; it is preferable to use tzc_dmc500_configure_region0 175*91f16700Schasinglulu * for this region (see comment for that function). 176*91f16700Schasinglulu */ 177*91f16700Schasinglulu void tzc_dmc500_configure_region(unsigned int region_no, 178*91f16700Schasinglulu unsigned long long region_base, 179*91f16700Schasinglulu unsigned long long region_top, 180*91f16700Schasinglulu unsigned int sec_attr, 181*91f16700Schasinglulu unsigned int nsaid_permissions) 182*91f16700Schasinglulu { 183*91f16700Schasinglulu int dmc_inst, sys_if; 184*91f16700Schasinglulu 185*91f16700Schasinglulu assert(g_driver_data); 186*91f16700Schasinglulu /* Do range checks on regions. */ 187*91f16700Schasinglulu assert((region_no >= 0U) && (region_no <= MAX_REGION_VAL)); 188*91f16700Schasinglulu 189*91f16700Schasinglulu /* 190*91f16700Schasinglulu * Do address range check based on DMC-TZ configuration. A 43bit address 191*91f16700Schasinglulu * is the max and expected case. 192*91f16700Schasinglulu */ 193*91f16700Schasinglulu assert(((region_top <= (UINT64_MAX >> (64U - 43U))) && 194*91f16700Schasinglulu (region_base < region_top))); 195*91f16700Schasinglulu 196*91f16700Schasinglulu /* region_base and (region_top + 1) must be 4KB aligned */ 197*91f16700Schasinglulu assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); 198*91f16700Schasinglulu 199*91f16700Schasinglulu for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { 200*91f16700Schasinglulu assert(DMC_INST_BASE_ADDR(dmc_inst)); 201*91f16700Schasinglulu for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) 202*91f16700Schasinglulu _tzc_dmc500_configure_region( 203*91f16700Schasinglulu DMC_INST_SI_BASE(dmc_inst, sys_if), 204*91f16700Schasinglulu TZC_DMC500_REGION_ATTR_F_EN_MASK, 205*91f16700Schasinglulu region_no, region_base, region_top, 206*91f16700Schasinglulu sec_attr, nsaid_permissions); 207*91f16700Schasinglulu } 208*91f16700Schasinglulu 209*91f16700Schasinglulu g_conf_regions[region_no].sec_attr = sec_attr; 210*91f16700Schasinglulu g_conf_regions[region_no].is_enabled = 1; 211*91f16700Schasinglulu } 212*91f16700Schasinglulu 213*91f16700Schasinglulu /* Sets the action value for all the DMC instances */ 214*91f16700Schasinglulu void tzc_dmc500_set_action(unsigned int action) 215*91f16700Schasinglulu { 216*91f16700Schasinglulu int dmc_inst; 217*91f16700Schasinglulu 218*91f16700Schasinglulu assert(g_driver_data); 219*91f16700Schasinglulu 220*91f16700Schasinglulu for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { 221*91f16700Schasinglulu assert(DMC_INST_BASE_ADDR(dmc_inst)); 222*91f16700Schasinglulu /* 223*91f16700Schasinglulu * - Currently no handler is provided to trap an error via 224*91f16700Schasinglulu * interrupt or exception. 225*91f16700Schasinglulu * - The interrupt action has not been tested. 226*91f16700Schasinglulu */ 227*91f16700Schasinglulu _tzc_dmc500_write_action(DMC_INST_BASE_ADDR(dmc_inst), action); 228*91f16700Schasinglulu } 229*91f16700Schasinglulu } 230*91f16700Schasinglulu 231*91f16700Schasinglulu /* 232*91f16700Schasinglulu * A DMC-500 instance must be present at each base address provided by the 233*91f16700Schasinglulu * platform. It also expects platform to pass at least one instance of 234*91f16700Schasinglulu * DMC-500. 235*91f16700Schasinglulu */ 236*91f16700Schasinglulu static void validate_plat_driver_data( 237*91f16700Schasinglulu const tzc_dmc500_driver_data_t *plat_driver_data) 238*91f16700Schasinglulu { 239*91f16700Schasinglulu #if ENABLE_ASSERTIONS 240*91f16700Schasinglulu int i; 241*91f16700Schasinglulu unsigned int dmc_id; 242*91f16700Schasinglulu uintptr_t dmc_base; 243*91f16700Schasinglulu 244*91f16700Schasinglulu assert(plat_driver_data); 245*91f16700Schasinglulu assert(plat_driver_data->dmc_count > 0 && 246*91f16700Schasinglulu (plat_driver_data->dmc_count <= MAX_DMC_COUNT)); 247*91f16700Schasinglulu 248*91f16700Schasinglulu for (i = 0; i < plat_driver_data->dmc_count; i++) { 249*91f16700Schasinglulu dmc_base = plat_driver_data->dmc_base[i]; 250*91f16700Schasinglulu assert(dmc_base); 251*91f16700Schasinglulu 252*91f16700Schasinglulu dmc_id = _tzc_read_peripheral_id(dmc_base); 253*91f16700Schasinglulu assert(dmc_id == DMC500_PERIPHERAL_ID); 254*91f16700Schasinglulu } 255*91f16700Schasinglulu #endif /* ENABLE_ASSERTIONS */ 256*91f16700Schasinglulu } 257*91f16700Schasinglulu 258*91f16700Schasinglulu 259*91f16700Schasinglulu /* 260*91f16700Schasinglulu * Initializes the base address and count of DMC instances. 261*91f16700Schasinglulu * 262*91f16700Schasinglulu * Note : Only pointer to plat_driver_data is saved, so it is caller's 263*91f16700Schasinglulu * responsibility to keep it valid until the driver is used. 264*91f16700Schasinglulu */ 265*91f16700Schasinglulu void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data) 266*91f16700Schasinglulu { 267*91f16700Schasinglulu /* Check valid pointer is passed */ 268*91f16700Schasinglulu assert(plat_driver_data); 269*91f16700Schasinglulu 270*91f16700Schasinglulu /* 271*91f16700Schasinglulu * NOTE: This driver expects the DMC-500 controller is already in 272*91f16700Schasinglulu * READY state. Hence, it uses the reconfiguration method for 273*91f16700Schasinglulu * programming TrustZone regions 274*91f16700Schasinglulu */ 275*91f16700Schasinglulu /* Validates the information passed by platform */ 276*91f16700Schasinglulu validate_plat_driver_data(plat_driver_data); 277*91f16700Schasinglulu g_driver_data = plat_driver_data; 278*91f16700Schasinglulu 279*91f16700Schasinglulu /* Check valid system interface count */ 280*91f16700Schasinglulu assert(g_driver_data->sys_if_count <= MAX_SYS_IF_COUNT); 281*91f16700Schasinglulu 282*91f16700Schasinglulu g_sys_if_count = g_driver_data->sys_if_count; 283*91f16700Schasinglulu 284*91f16700Schasinglulu /* If interface count is not present then assume max */ 285*91f16700Schasinglulu if (g_sys_if_count == 0U) 286*91f16700Schasinglulu g_sys_if_count = MAX_SYS_IF_COUNT; 287*91f16700Schasinglulu } 288