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