xref: /rk3399_ARM-atf/drivers/arm/tzc/tzc_dmc620.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
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