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