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