blob: 7e307ee5041b8f85a32faf9896538216e8d7bca3 [file] [log] [blame]
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +05301/*
Alexei Fedorov69f93c82020-07-27 15:04:14 +01002 * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +05303 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
9#include <common/debug.h>
10#include <drivers/arm/tzc_dmc620.h>
11#include <lib/mmio.h>
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +053012
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) \
Alexei Fedorov69f93c82020-07-27 15:04:14 +010020 ((uintptr_t)((plat_data)->dmc_base[(dmc_inst)]))
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +053021
22/* Pointer to the tzc_dmc620_config_data structure populated by the platform */
23static 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 */
31static void tzc_dmc620_validate_plat_driver_data(
32 const tzc_dmc620_driver_data_t *plat_driver_data)
33{
Alexei Fedorov69f93c82020-07-27 15:04:14 +010034 unsigned int dmc_inst, dmc_count, dmc_id;
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +053035 uintptr_t base;
36
37 assert(plat_driver_data != NULL);
38
39 dmc_count = plat_driver_data->dmc_count;
40 assert(dmc_count > 0U);
41
42 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
43 base = DMC_BASE(plat_driver_data, dmc_inst);
44 dmc_id = mmio_read_32(base + DMC620_PERIPHERAL_ID_0);
45 assert(dmc_id == DMC620_PERIPHERAL_ID_0_VALUE);
46 }
47}
48#endif
49
50/*
51 * Program a region with region base and region top addresses of all
52 * DMC-620 instances.
53 */
54static void tzc_dmc620_configure_region(int region_no,
55 unsigned long long region_base,
56 unsigned long long region_top,
57 unsigned int sec_attr)
58{
59 uint32_t min_31_00, min_47_32;
60 uint32_t max_31_00, max_47_32;
Alexei Fedorov69f93c82020-07-27 15:04:14 +010061 unsigned int dmc_inst, dmc_count;
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +053062 uintptr_t base;
63 const tzc_dmc620_driver_data_t *plat_driver_data;
64
65 plat_driver_data = g_plat_config_data->plat_drv_data;
66 assert(plat_driver_data != NULL);
67
68 /* Do range checks on regions. */
Alexei Fedorov69f93c82020-07-27 15:04:14 +010069 assert((region_no >= 0) && (region_no <= DMC620_ACC_ADDR_COUNT));
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +053070
71 /* region_base and (region_top + 1) must be 4KB aligned */
72 assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U);
73
74 dmc_count = plat_driver_data->dmc_count;
75 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
Alexei Fedorov69f93c82020-07-27 15:04:14 +010076 min_31_00 = (uint32_t)((region_base & MASK_31_16) | sec_attr);
77 min_47_32 = (uint32_t)((region_base & MASK_47_32)
78 >> DMC620_ACC_ADDR_WIDTH);
79 max_31_00 = (uint32_t)(region_top & MASK_31_16);
80 max_47_32 = (uint32_t)((region_top & MASK_47_32)
81 >> DMC620_ACC_ADDR_WIDTH);
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +053082
83 /* Extract the base address of the DMC-620 instance */
84 base = DMC_BASE(plat_driver_data, dmc_inst);
85 /* Configure access address region registers */
86 mmio_write_32(base + DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no),
87 min_31_00);
88 mmio_write_32(base + DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no),
89 min_47_32);
90 mmio_write_32(base + DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no),
91 max_31_00);
92 mmio_write_32(base + DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no),
93 max_47_32);
94 }
95}
96
97/*
98 * Set the action value for all the DMC-620 instances.
99 */
100static void tzc_dmc620_set_action(void)
101{
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100102 unsigned int dmc_inst, dmc_count;
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530103 uintptr_t base;
104 const tzc_dmc620_driver_data_t *plat_driver_data;
105
106 plat_driver_data = g_plat_config_data->plat_drv_data;
107 dmc_count = plat_driver_data->dmc_count;
108 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
109 /* Extract the base address of the DMC-620 instance */
110 base = DMC_BASE(plat_driver_data, dmc_inst);
111 /* Switch to READY */
112 mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_GO);
113 mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_EXECUTE);
114 }
115}
116
117/*
118 * Verify whether the DMC-620 configuration is complete by reading back
119 * configuration registers and comparing it with the configured value. If
120 * configuration is incomplete, loop till the configured value is reflected in
121 * the register.
122 */
123static void tzc_dmc620_verify_complete(void)
124{
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100125 unsigned int dmc_inst, dmc_count;
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530126 uintptr_t base;
127 const tzc_dmc620_driver_data_t *plat_driver_data;
128
129 plat_driver_data = g_plat_config_data->plat_drv_data;
130 dmc_count = plat_driver_data->dmc_count;
131 for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
132 /* Extract the base address of the DMC-620 instance */
133 base = DMC_BASE(plat_driver_data, dmc_inst);
134 while ((mmio_read_32(base + DMC620_MEMC_STATUS) &
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100135 DMC620_MEMC_CMD_MASK) != DMC620_MEMC_CMD_GO) {
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530136 continue;
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100137 }
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530138 }
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 */
146void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data)
147{
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100148 uint8_t i;
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530149
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");
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100167 for (i = 0U; i < g_plat_config_data->acc_addr_count; i++) {
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530168 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);
Alexei Fedorov69f93c82020-07-27 15:04:14 +0100172 }
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +0530173
174 tzc_dmc620_set_action();
175 tzc_dmc620_verify_complete();
176 INFO("DMC-620 TZC setup completed\n");
177}