1*9d3b191aSVijayenthiran Subramaniam /* 2*9d3b191aSVijayenthiran Subramaniam * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3*9d3b191aSVijayenthiran Subramaniam * 4*9d3b191aSVijayenthiran Subramaniam * SPDX-License-Identifier: BSD-3-Clause 5*9d3b191aSVijayenthiran Subramaniam */ 6*9d3b191aSVijayenthiran Subramaniam 7*9d3b191aSVijayenthiran Subramaniam #include <assert.h> 8*9d3b191aSVijayenthiran Subramaniam #include <debug.h> 9*9d3b191aSVijayenthiran Subramaniam #include <mmio.h> 10*9d3b191aSVijayenthiran Subramaniam #include <tzc_dmc620.h> 11*9d3b191aSVijayenthiran Subramaniam 12*9d3b191aSVijayenthiran Subramaniam /* Mask to extract bit 31 to 16 */ 13*9d3b191aSVijayenthiran Subramaniam #define MASK_31_16 UINT64_C(0x0000ffff0000) 14*9d3b191aSVijayenthiran Subramaniam /* Mask to extract bit 47 to 32 */ 15*9d3b191aSVijayenthiran Subramaniam #define MASK_47_32 UINT64_C(0xffff00000000) 16*9d3b191aSVijayenthiran Subramaniam 17*9d3b191aSVijayenthiran Subramaniam /* Helper macro for getting dmc_base addr of a dmc_inst */ 18*9d3b191aSVijayenthiran Subramaniam #define DMC_BASE(plat_data, dmc_inst) \ 19*9d3b191aSVijayenthiran Subramaniam ((uintptr_t)(plat_data->dmc_base[dmc_inst])) 20*9d3b191aSVijayenthiran Subramaniam 21*9d3b191aSVijayenthiran Subramaniam /* Pointer to the tzc_dmc620_config_data structure populated by the platform */ 22*9d3b191aSVijayenthiran Subramaniam static const tzc_dmc620_config_data_t *g_plat_config_data; 23*9d3b191aSVijayenthiran Subramaniam 24*9d3b191aSVijayenthiran Subramaniam #if ENABLE_ASSERTIONS 25*9d3b191aSVijayenthiran Subramaniam /* 26*9d3b191aSVijayenthiran Subramaniam * Helper function to check if the DMC-620 instance is present at the 27*9d3b191aSVijayenthiran Subramaniam * base address provided by the platform and also check if at least 28*9d3b191aSVijayenthiran Subramaniam * one dmc instance is present. 29*9d3b191aSVijayenthiran Subramaniam */ 30*9d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_validate_plat_driver_data( 31*9d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data) 32*9d3b191aSVijayenthiran Subramaniam { 33*9d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 34*9d3b191aSVijayenthiran Subramaniam unsigned int dmc_id; 35*9d3b191aSVijayenthiran Subramaniam uintptr_t base; 36*9d3b191aSVijayenthiran Subramaniam 37*9d3b191aSVijayenthiran Subramaniam assert(plat_driver_data != NULL); 38*9d3b191aSVijayenthiran Subramaniam 39*9d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 40*9d3b191aSVijayenthiran Subramaniam assert(dmc_count > 0U); 41*9d3b191aSVijayenthiran Subramaniam 42*9d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 43*9d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 44*9d3b191aSVijayenthiran Subramaniam dmc_id = mmio_read_32(base + DMC620_PERIPHERAL_ID_0); 45*9d3b191aSVijayenthiran Subramaniam assert(dmc_id == DMC620_PERIPHERAL_ID_0_VALUE); 46*9d3b191aSVijayenthiran Subramaniam } 47*9d3b191aSVijayenthiran Subramaniam } 48*9d3b191aSVijayenthiran Subramaniam #endif 49*9d3b191aSVijayenthiran Subramaniam 50*9d3b191aSVijayenthiran Subramaniam /* 51*9d3b191aSVijayenthiran Subramaniam * Program a region with region base and region top addresses of all 52*9d3b191aSVijayenthiran Subramaniam * DMC-620 instances. 53*9d3b191aSVijayenthiran Subramaniam */ 54*9d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_configure_region(int region_no, 55*9d3b191aSVijayenthiran Subramaniam unsigned long long region_base, 56*9d3b191aSVijayenthiran Subramaniam unsigned long long region_top, 57*9d3b191aSVijayenthiran Subramaniam unsigned int sec_attr) 58*9d3b191aSVijayenthiran Subramaniam { 59*9d3b191aSVijayenthiran Subramaniam uint32_t min_31_00, min_47_32; 60*9d3b191aSVijayenthiran Subramaniam uint32_t max_31_00, max_47_32; 61*9d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 62*9d3b191aSVijayenthiran Subramaniam uintptr_t base; 63*9d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data; 64*9d3b191aSVijayenthiran Subramaniam 65*9d3b191aSVijayenthiran Subramaniam plat_driver_data = g_plat_config_data->plat_drv_data; 66*9d3b191aSVijayenthiran Subramaniam assert(plat_driver_data != NULL); 67*9d3b191aSVijayenthiran Subramaniam 68*9d3b191aSVijayenthiran Subramaniam /* Do range checks on regions. */ 69*9d3b191aSVijayenthiran Subramaniam assert((region_no >= 0U) && (region_no <= DMC620_ACC_ADDR_COUNT)); 70*9d3b191aSVijayenthiran Subramaniam 71*9d3b191aSVijayenthiran Subramaniam /* region_base and (region_top + 1) must be 4KB aligned */ 72*9d3b191aSVijayenthiran Subramaniam assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); 73*9d3b191aSVijayenthiran Subramaniam 74*9d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 75*9d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 76*9d3b191aSVijayenthiran Subramaniam min_31_00 = (region_base & MASK_31_16) | sec_attr; 77*9d3b191aSVijayenthiran Subramaniam min_47_32 = (region_base & MASK_47_32) 78*9d3b191aSVijayenthiran Subramaniam >> DMC620_ACC_ADDR_WIDTH; 79*9d3b191aSVijayenthiran Subramaniam max_31_00 = (region_top & MASK_31_16); 80*9d3b191aSVijayenthiran Subramaniam max_47_32 = (region_top & MASK_47_32) 81*9d3b191aSVijayenthiran Subramaniam >> DMC620_ACC_ADDR_WIDTH; 82*9d3b191aSVijayenthiran Subramaniam 83*9d3b191aSVijayenthiran Subramaniam /* Extract the base address of the DMC-620 instance */ 84*9d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 85*9d3b191aSVijayenthiran Subramaniam /* Configure access address region registers */ 86*9d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no), 87*9d3b191aSVijayenthiran Subramaniam min_31_00); 88*9d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no), 89*9d3b191aSVijayenthiran Subramaniam min_47_32); 90*9d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no), 91*9d3b191aSVijayenthiran Subramaniam max_31_00); 92*9d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no), 93*9d3b191aSVijayenthiran Subramaniam max_47_32); 94*9d3b191aSVijayenthiran Subramaniam } 95*9d3b191aSVijayenthiran Subramaniam } 96*9d3b191aSVijayenthiran Subramaniam 97*9d3b191aSVijayenthiran Subramaniam /* 98*9d3b191aSVijayenthiran Subramaniam * Set the action value for all the DMC-620 instances. 99*9d3b191aSVijayenthiran Subramaniam */ 100*9d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_set_action(void) 101*9d3b191aSVijayenthiran Subramaniam { 102*9d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 103*9d3b191aSVijayenthiran Subramaniam uintptr_t base; 104*9d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data; 105*9d3b191aSVijayenthiran Subramaniam 106*9d3b191aSVijayenthiran Subramaniam plat_driver_data = g_plat_config_data->plat_drv_data; 107*9d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 108*9d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 109*9d3b191aSVijayenthiran Subramaniam /* Extract the base address of the DMC-620 instance */ 110*9d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 111*9d3b191aSVijayenthiran Subramaniam /* Switch to READY */ 112*9d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_GO); 113*9d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_EXECUTE); 114*9d3b191aSVijayenthiran Subramaniam } 115*9d3b191aSVijayenthiran Subramaniam } 116*9d3b191aSVijayenthiran Subramaniam 117*9d3b191aSVijayenthiran Subramaniam /* 118*9d3b191aSVijayenthiran Subramaniam * Verify whether the DMC-620 configuration is complete by reading back 119*9d3b191aSVijayenthiran Subramaniam * configuration registers and comparing it with the configured value. If 120*9d3b191aSVijayenthiran Subramaniam * configuration is incomplete, loop till the configured value is reflected in 121*9d3b191aSVijayenthiran Subramaniam * the register. 122*9d3b191aSVijayenthiran Subramaniam */ 123*9d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_verify_complete(void) 124*9d3b191aSVijayenthiran Subramaniam { 125*9d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 126*9d3b191aSVijayenthiran Subramaniam uintptr_t base; 127*9d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data; 128*9d3b191aSVijayenthiran Subramaniam 129*9d3b191aSVijayenthiran Subramaniam plat_driver_data = g_plat_config_data->plat_drv_data; 130*9d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 131*9d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 132*9d3b191aSVijayenthiran Subramaniam /* Extract the base address of the DMC-620 instance */ 133*9d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 134*9d3b191aSVijayenthiran Subramaniam while ((mmio_read_32(base + DMC620_MEMC_STATUS) & 135*9d3b191aSVijayenthiran Subramaniam DMC620_MEMC_CMD_MASK) != DMC620_MEMC_CMD_GO) 136*9d3b191aSVijayenthiran Subramaniam continue; 137*9d3b191aSVijayenthiran Subramaniam } 138*9d3b191aSVijayenthiran Subramaniam } 139*9d3b191aSVijayenthiran Subramaniam 140*9d3b191aSVijayenthiran Subramaniam /* 141*9d3b191aSVijayenthiran Subramaniam * Initialize the DMC-620 TrustZone Controller using the region configuration 142*9d3b191aSVijayenthiran Subramaniam * supplied by the platform. The DMC620 controller should be enabled elsewhere 143*9d3b191aSVijayenthiran Subramaniam * before invoking this function. 144*9d3b191aSVijayenthiran Subramaniam */ 145*9d3b191aSVijayenthiran Subramaniam void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data) 146*9d3b191aSVijayenthiran Subramaniam { 147*9d3b191aSVijayenthiran Subramaniam int i; 148*9d3b191aSVijayenthiran Subramaniam 149*9d3b191aSVijayenthiran Subramaniam /* Check if valid pointer is passed */ 150*9d3b191aSVijayenthiran Subramaniam assert(plat_config_data != NULL); 151*9d3b191aSVijayenthiran Subramaniam 152*9d3b191aSVijayenthiran Subramaniam /* 153*9d3b191aSVijayenthiran Subramaniam * Check if access address count passed by the platform is less than or 154*9d3b191aSVijayenthiran Subramaniam * equal to DMC620's access address count 155*9d3b191aSVijayenthiran Subramaniam */ 156*9d3b191aSVijayenthiran Subramaniam assert(plat_config_data->acc_addr_count <= DMC620_ACC_ADDR_COUNT); 157*9d3b191aSVijayenthiran Subramaniam 158*9d3b191aSVijayenthiran Subramaniam #if ENABLE_ASSERTIONS 159*9d3b191aSVijayenthiran Subramaniam /* Validates the information passed by platform */ 160*9d3b191aSVijayenthiran Subramaniam tzc_dmc620_validate_plat_driver_data(plat_config_data->plat_drv_data); 161*9d3b191aSVijayenthiran Subramaniam #endif 162*9d3b191aSVijayenthiran Subramaniam 163*9d3b191aSVijayenthiran Subramaniam g_plat_config_data = plat_config_data; 164*9d3b191aSVijayenthiran Subramaniam 165*9d3b191aSVijayenthiran Subramaniam INFO("Configuring DMC-620 TZC settings\n"); 166*9d3b191aSVijayenthiran Subramaniam for (i = 0U; i < g_plat_config_data->acc_addr_count; i++) 167*9d3b191aSVijayenthiran Subramaniam tzc_dmc620_configure_region(i, 168*9d3b191aSVijayenthiran Subramaniam g_plat_config_data->plat_acc_addr_data[i].region_base, 169*9d3b191aSVijayenthiran Subramaniam g_plat_config_data->plat_acc_addr_data[i].region_top, 170*9d3b191aSVijayenthiran Subramaniam g_plat_config_data->plat_acc_addr_data[i].sec_attr); 171*9d3b191aSVijayenthiran Subramaniam 172*9d3b191aSVijayenthiran Subramaniam tzc_dmc620_set_action(); 173*9d3b191aSVijayenthiran Subramaniam tzc_dmc620_verify_complete(); 174*9d3b191aSVijayenthiran Subramaniam INFO("DMC-620 TZC setup completed\n"); 175*9d3b191aSVijayenthiran Subramaniam } 176