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