19d3b191aSVijayenthiran Subramaniam /* 29d3b191aSVijayenthiran Subramaniam * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 39d3b191aSVijayenthiran Subramaniam * 49d3b191aSVijayenthiran Subramaniam * SPDX-License-Identifier: BSD-3-Clause 59d3b191aSVijayenthiran Subramaniam */ 69d3b191aSVijayenthiran Subramaniam 79d3b191aSVijayenthiran Subramaniam #include <assert.h> 8*09d40e0eSAntonio Nino Diaz 9*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 10*09d40e0eSAntonio Nino Diaz #include <drivers/arm/tzc_dmc620.h> 11*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 129d3b191aSVijayenthiran Subramaniam 139d3b191aSVijayenthiran Subramaniam /* Mask to extract bit 31 to 16 */ 149d3b191aSVijayenthiran Subramaniam #define MASK_31_16 UINT64_C(0x0000ffff0000) 159d3b191aSVijayenthiran Subramaniam /* Mask to extract bit 47 to 32 */ 169d3b191aSVijayenthiran Subramaniam #define MASK_47_32 UINT64_C(0xffff00000000) 179d3b191aSVijayenthiran Subramaniam 189d3b191aSVijayenthiran Subramaniam /* Helper macro for getting dmc_base addr of a dmc_inst */ 199d3b191aSVijayenthiran Subramaniam #define DMC_BASE(plat_data, dmc_inst) \ 209d3b191aSVijayenthiran Subramaniam ((uintptr_t)(plat_data->dmc_base[dmc_inst])) 219d3b191aSVijayenthiran Subramaniam 229d3b191aSVijayenthiran Subramaniam /* Pointer to the tzc_dmc620_config_data structure populated by the platform */ 239d3b191aSVijayenthiran Subramaniam static const tzc_dmc620_config_data_t *g_plat_config_data; 249d3b191aSVijayenthiran Subramaniam 259d3b191aSVijayenthiran Subramaniam #if ENABLE_ASSERTIONS 269d3b191aSVijayenthiran Subramaniam /* 279d3b191aSVijayenthiran Subramaniam * Helper function to check if the DMC-620 instance is present at the 289d3b191aSVijayenthiran Subramaniam * base address provided by the platform and also check if at least 299d3b191aSVijayenthiran Subramaniam * one dmc instance is present. 309d3b191aSVijayenthiran Subramaniam */ 319d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_validate_plat_driver_data( 329d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data) 339d3b191aSVijayenthiran Subramaniam { 349d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 359d3b191aSVijayenthiran Subramaniam unsigned int dmc_id; 369d3b191aSVijayenthiran Subramaniam uintptr_t base; 379d3b191aSVijayenthiran Subramaniam 389d3b191aSVijayenthiran Subramaniam assert(plat_driver_data != NULL); 399d3b191aSVijayenthiran Subramaniam 409d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 419d3b191aSVijayenthiran Subramaniam assert(dmc_count > 0U); 429d3b191aSVijayenthiran Subramaniam 439d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 449d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 459d3b191aSVijayenthiran Subramaniam dmc_id = mmio_read_32(base + DMC620_PERIPHERAL_ID_0); 469d3b191aSVijayenthiran Subramaniam assert(dmc_id == DMC620_PERIPHERAL_ID_0_VALUE); 479d3b191aSVijayenthiran Subramaniam } 489d3b191aSVijayenthiran Subramaniam } 499d3b191aSVijayenthiran Subramaniam #endif 509d3b191aSVijayenthiran Subramaniam 519d3b191aSVijayenthiran Subramaniam /* 529d3b191aSVijayenthiran Subramaniam * Program a region with region base and region top addresses of all 539d3b191aSVijayenthiran Subramaniam * DMC-620 instances. 549d3b191aSVijayenthiran Subramaniam */ 559d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_configure_region(int region_no, 569d3b191aSVijayenthiran Subramaniam unsigned long long region_base, 579d3b191aSVijayenthiran Subramaniam unsigned long long region_top, 589d3b191aSVijayenthiran Subramaniam unsigned int sec_attr) 599d3b191aSVijayenthiran Subramaniam { 609d3b191aSVijayenthiran Subramaniam uint32_t min_31_00, min_47_32; 619d3b191aSVijayenthiran Subramaniam uint32_t max_31_00, max_47_32; 629d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 639d3b191aSVijayenthiran Subramaniam uintptr_t base; 649d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data; 659d3b191aSVijayenthiran Subramaniam 669d3b191aSVijayenthiran Subramaniam plat_driver_data = g_plat_config_data->plat_drv_data; 679d3b191aSVijayenthiran Subramaniam assert(plat_driver_data != NULL); 689d3b191aSVijayenthiran Subramaniam 699d3b191aSVijayenthiran Subramaniam /* Do range checks on regions. */ 709d3b191aSVijayenthiran Subramaniam assert((region_no >= 0U) && (region_no <= DMC620_ACC_ADDR_COUNT)); 719d3b191aSVijayenthiran Subramaniam 729d3b191aSVijayenthiran Subramaniam /* region_base and (region_top + 1) must be 4KB aligned */ 739d3b191aSVijayenthiran Subramaniam assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); 749d3b191aSVijayenthiran Subramaniam 759d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 769d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 779d3b191aSVijayenthiran Subramaniam min_31_00 = (region_base & MASK_31_16) | sec_attr; 789d3b191aSVijayenthiran Subramaniam min_47_32 = (region_base & MASK_47_32) 799d3b191aSVijayenthiran Subramaniam >> DMC620_ACC_ADDR_WIDTH; 809d3b191aSVijayenthiran Subramaniam max_31_00 = (region_top & MASK_31_16); 819d3b191aSVijayenthiran Subramaniam max_47_32 = (region_top & MASK_47_32) 829d3b191aSVijayenthiran Subramaniam >> DMC620_ACC_ADDR_WIDTH; 839d3b191aSVijayenthiran Subramaniam 849d3b191aSVijayenthiran Subramaniam /* Extract the base address of the DMC-620 instance */ 859d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 869d3b191aSVijayenthiran Subramaniam /* Configure access address region registers */ 879d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no), 889d3b191aSVijayenthiran Subramaniam min_31_00); 899d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no), 909d3b191aSVijayenthiran Subramaniam min_47_32); 919d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no), 929d3b191aSVijayenthiran Subramaniam max_31_00); 939d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no), 949d3b191aSVijayenthiran Subramaniam max_47_32); 959d3b191aSVijayenthiran Subramaniam } 969d3b191aSVijayenthiran Subramaniam } 979d3b191aSVijayenthiran Subramaniam 989d3b191aSVijayenthiran Subramaniam /* 999d3b191aSVijayenthiran Subramaniam * Set the action value for all the DMC-620 instances. 1009d3b191aSVijayenthiran Subramaniam */ 1019d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_set_action(void) 1029d3b191aSVijayenthiran Subramaniam { 1039d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 1049d3b191aSVijayenthiran Subramaniam uintptr_t base; 1059d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data; 1069d3b191aSVijayenthiran Subramaniam 1079d3b191aSVijayenthiran Subramaniam plat_driver_data = g_plat_config_data->plat_drv_data; 1089d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 1099d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 1109d3b191aSVijayenthiran Subramaniam /* Extract the base address of the DMC-620 instance */ 1119d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 1129d3b191aSVijayenthiran Subramaniam /* Switch to READY */ 1139d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_GO); 1149d3b191aSVijayenthiran Subramaniam mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_EXECUTE); 1159d3b191aSVijayenthiran Subramaniam } 1169d3b191aSVijayenthiran Subramaniam } 1179d3b191aSVijayenthiran Subramaniam 1189d3b191aSVijayenthiran Subramaniam /* 1199d3b191aSVijayenthiran Subramaniam * Verify whether the DMC-620 configuration is complete by reading back 1209d3b191aSVijayenthiran Subramaniam * configuration registers and comparing it with the configured value. If 1219d3b191aSVijayenthiran Subramaniam * configuration is incomplete, loop till the configured value is reflected in 1229d3b191aSVijayenthiran Subramaniam * the register. 1239d3b191aSVijayenthiran Subramaniam */ 1249d3b191aSVijayenthiran Subramaniam static void tzc_dmc620_verify_complete(void) 1259d3b191aSVijayenthiran Subramaniam { 1269d3b191aSVijayenthiran Subramaniam uint8_t dmc_inst, dmc_count; 1279d3b191aSVijayenthiran Subramaniam uintptr_t base; 1289d3b191aSVijayenthiran Subramaniam const tzc_dmc620_driver_data_t *plat_driver_data; 1299d3b191aSVijayenthiran Subramaniam 1309d3b191aSVijayenthiran Subramaniam plat_driver_data = g_plat_config_data->plat_drv_data; 1319d3b191aSVijayenthiran Subramaniam dmc_count = plat_driver_data->dmc_count; 1329d3b191aSVijayenthiran Subramaniam for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { 1339d3b191aSVijayenthiran Subramaniam /* Extract the base address of the DMC-620 instance */ 1349d3b191aSVijayenthiran Subramaniam base = DMC_BASE(plat_driver_data, dmc_inst); 1359d3b191aSVijayenthiran Subramaniam while ((mmio_read_32(base + DMC620_MEMC_STATUS) & 1369d3b191aSVijayenthiran Subramaniam DMC620_MEMC_CMD_MASK) != DMC620_MEMC_CMD_GO) 1379d3b191aSVijayenthiran Subramaniam continue; 1389d3b191aSVijayenthiran Subramaniam } 1399d3b191aSVijayenthiran Subramaniam } 1409d3b191aSVijayenthiran Subramaniam 1419d3b191aSVijayenthiran Subramaniam /* 1429d3b191aSVijayenthiran Subramaniam * Initialize the DMC-620 TrustZone Controller using the region configuration 1439d3b191aSVijayenthiran Subramaniam * supplied by the platform. The DMC620 controller should be enabled elsewhere 1449d3b191aSVijayenthiran Subramaniam * before invoking this function. 1459d3b191aSVijayenthiran Subramaniam */ 1469d3b191aSVijayenthiran Subramaniam void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data) 1479d3b191aSVijayenthiran Subramaniam { 1489d3b191aSVijayenthiran Subramaniam int i; 1499d3b191aSVijayenthiran Subramaniam 1509d3b191aSVijayenthiran Subramaniam /* Check if valid pointer is passed */ 1519d3b191aSVijayenthiran Subramaniam assert(plat_config_data != NULL); 1529d3b191aSVijayenthiran Subramaniam 1539d3b191aSVijayenthiran Subramaniam /* 1549d3b191aSVijayenthiran Subramaniam * Check if access address count passed by the platform is less than or 1559d3b191aSVijayenthiran Subramaniam * equal to DMC620's access address count 1569d3b191aSVijayenthiran Subramaniam */ 1579d3b191aSVijayenthiran Subramaniam assert(plat_config_data->acc_addr_count <= DMC620_ACC_ADDR_COUNT); 1589d3b191aSVijayenthiran Subramaniam 1599d3b191aSVijayenthiran Subramaniam #if ENABLE_ASSERTIONS 1609d3b191aSVijayenthiran Subramaniam /* Validates the information passed by platform */ 1619d3b191aSVijayenthiran Subramaniam tzc_dmc620_validate_plat_driver_data(plat_config_data->plat_drv_data); 1629d3b191aSVijayenthiran Subramaniam #endif 1639d3b191aSVijayenthiran Subramaniam 1649d3b191aSVijayenthiran Subramaniam g_plat_config_data = plat_config_data; 1659d3b191aSVijayenthiran Subramaniam 1669d3b191aSVijayenthiran Subramaniam INFO("Configuring DMC-620 TZC settings\n"); 1679d3b191aSVijayenthiran Subramaniam for (i = 0U; i < g_plat_config_data->acc_addr_count; i++) 1689d3b191aSVijayenthiran Subramaniam tzc_dmc620_configure_region(i, 1699d3b191aSVijayenthiran Subramaniam g_plat_config_data->plat_acc_addr_data[i].region_base, 1709d3b191aSVijayenthiran Subramaniam g_plat_config_data->plat_acc_addr_data[i].region_top, 1719d3b191aSVijayenthiran Subramaniam g_plat_config_data->plat_acc_addr_data[i].sec_attr); 1729d3b191aSVijayenthiran Subramaniam 1739d3b191aSVijayenthiran Subramaniam tzc_dmc620_set_action(); 1749d3b191aSVijayenthiran Subramaniam tzc_dmc620_verify_complete(); 1759d3b191aSVijayenthiran Subramaniam INFO("DMC-620 TZC setup completed\n"); 1769d3b191aSVijayenthiran Subramaniam } 177