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