1 /* 2 * Copyright (c) 2018, 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 uint8_t dmc_inst, dmc_count; 35 unsigned int dmc_id; 36 uintptr_t base; 37 38 assert(plat_driver_data != NULL); 39 40 dmc_count = plat_driver_data->dmc_count; 41 assert(dmc_count > 0U); 42 43 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 44 base = DMC_BASE(plat_driver_data, dmc_inst); 45 dmc_id = mmio_read_32(base + DMC620_PERIPHERAL_ID_0); 46 assert(dmc_id == DMC620_PERIPHERAL_ID_0_VALUE); 47 } 48 } 49 #endif 50 51 /* 52 * Program a region with region base and region top addresses of all 53 * DMC-620 instances. 54 */ 55 static void tzc_dmc620_configure_region(int region_no, 56 unsigned long long region_base, 57 unsigned long long region_top, 58 unsigned int sec_attr) 59 { 60 uint32_t min_31_00, min_47_32; 61 uint32_t max_31_00, max_47_32; 62 uint8_t dmc_inst, dmc_count; 63 uintptr_t base; 64 const tzc_dmc620_driver_data_t *plat_driver_data; 65 66 plat_driver_data = g_plat_config_data->plat_drv_data; 67 assert(plat_driver_data != NULL); 68 69 /* Do range checks on regions. */ 70 assert((region_no >= 0U) && (region_no <= DMC620_ACC_ADDR_COUNT)); 71 72 /* region_base and (region_top + 1) must be 4KB aligned */ 73 assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); 74 75 dmc_count = plat_driver_data->dmc_count; 76 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 77 min_31_00 = (region_base & MASK_31_16) | sec_attr; 78 min_47_32 = (region_base & MASK_47_32) 79 >> DMC620_ACC_ADDR_WIDTH; 80 max_31_00 = (region_top & MASK_31_16); 81 max_47_32 = (region_top & MASK_47_32) 82 >> DMC620_ACC_ADDR_WIDTH; 83 84 /* Extract the base address of the DMC-620 instance */ 85 base = DMC_BASE(plat_driver_data, dmc_inst); 86 /* Configure access address region registers */ 87 mmio_write_32(base + DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no), 88 min_31_00); 89 mmio_write_32(base + DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no), 90 min_47_32); 91 mmio_write_32(base + DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no), 92 max_31_00); 93 mmio_write_32(base + DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no), 94 max_47_32); 95 } 96 } 97 98 /* 99 * Set the action value for all the DMC-620 instances. 100 */ 101 static void tzc_dmc620_set_action(void) 102 { 103 uint8_t dmc_inst, dmc_count; 104 uintptr_t base; 105 const tzc_dmc620_driver_data_t *plat_driver_data; 106 107 plat_driver_data = g_plat_config_data->plat_drv_data; 108 dmc_count = plat_driver_data->dmc_count; 109 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 110 /* Extract the base address of the DMC-620 instance */ 111 base = DMC_BASE(plat_driver_data, dmc_inst); 112 /* Switch to READY */ 113 mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_GO); 114 mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_EXECUTE); 115 } 116 } 117 118 /* 119 * Verify whether the DMC-620 configuration is complete by reading back 120 * configuration registers and comparing it with the configured value. If 121 * configuration is incomplete, loop till the configured value is reflected in 122 * the register. 123 */ 124 static void tzc_dmc620_verify_complete(void) 125 { 126 uint8_t dmc_inst, dmc_count; 127 uintptr_t base; 128 const tzc_dmc620_driver_data_t *plat_driver_data; 129 130 plat_driver_data = g_plat_config_data->plat_drv_data; 131 dmc_count = plat_driver_data->dmc_count; 132 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 133 /* Extract the base address of the DMC-620 instance */ 134 base = DMC_BASE(plat_driver_data, dmc_inst); 135 while ((mmio_read_32(base + DMC620_MEMC_STATUS) & 136 DMC620_MEMC_CMD_MASK) != DMC620_MEMC_CMD_GO) 137 continue; 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 int 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 tzc_dmc620_set_action(); 174 tzc_dmc620_verify_complete(); 175 INFO("DMC-620 TZC setup completed\n"); 176 } 177