blob: 64ec5abee736d68f9dac8381b3a548a6276c490a [file] [log] [blame]
Vijayenthiran Subramaniam03bb12f2018-10-22 18:36:35 +05301/*
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>
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) \
20 ((uintptr_t)(plat_data->dmc_base[dmc_inst]))
21
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{
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 */
55static 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 */
101static 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 */
124static 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 */
146void 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}