1 /*
2 * Copyright (c) 2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdint.h>
11
12 #include "device_definition.h"
13 #include "host_base_address.h"
14 #include "host_system.h"
15 #include "tfm_hal_device_header.h"
16 #include "tfm_plat_otp.h"
17 #ifdef RD_SYSCTRL_NI_TOWER
18 #include "ni_tower_lib.h"
19
20 #define NI_TOWER_SYSCTRL_SYSTOP_PARENT_TYPE NI_TOWER_VD
21 #define NI_TOWER_SYSCTRL_SYSTOP_PARENT_ID (0)
22 #define NI_TOWER_SYSCTRL_SYSTOP_IDX (1)
23 #endif
24
25 static struct host_system_t host_system_data = {0};
26
27 #if defined(RD_SYSCTRL_NI_TOWER) || defined(RD_PERIPH_NI_TOWER)
28 /*
29 * Initializes the ATU region before configuring the NI-Tower. This function
30 * maps the physical base address of the NI-Tower instance received as the
31 * parameter to a logical address HOST_NI_TOWER_BASE.
32 */
ni_tower_pre_init(uint64_t ni_tower_phys_address)33 static int ni_tower_pre_init(uint64_t ni_tower_phys_address)
34 {
35 enum atu_error_t atu_err;
36 enum atu_roba_t roba_value;
37
38 atu_err = atu_initialize_region(
39 &ATU_DEV_S,
40 HOST_NI_TOWER_ATU_ID,
41 HOST_NI_TOWER_BASE,
42 ni_tower_phys_address,
43 HOST_NI_TOWER_SIZE);
44 if (atu_err != ATU_ERR_NONE) {
45 return -1;
46 }
47
48 roba_value = ATU_ROBA_SET_1;
49 atu_err = set_axnsc(&ATU_DEV_S, roba_value, HOST_NI_TOWER_ATU_ID);
50 if (atu_err != ATU_ERR_NONE) {
51 return -1;
52 }
53
54 roba_value = ATU_ROBA_SET_0;
55 atu_err = set_axprot1(&ATU_DEV_S, roba_value, HOST_NI_TOWER_ATU_ID);
56 if (atu_err != ATU_ERR_NONE) {
57 return -1;
58 }
59
60 return 0;
61 }
62
63 /* Un-initializes the ATU region after configuring the NI-Tower */
ni_tower_post_init(void)64 static int ni_tower_post_init(void)
65 {
66 enum atu_error_t atu_err;
67
68 atu_err = atu_uninitialize_region(&ATU_DEV_S, HOST_NI_TOWER_ATU_ID);
69 if (atu_err != ATU_ERR_NONE) {
70 return -1;
71 }
72
73 return 0;
74 }
75 #endif
76
77 #ifdef RD_SYSCTRL_NI_TOWER
78 /* Voltage domain - 0 is the parent node of SYSTOP Power domain */
79 const struct ni_tower_component_node systop_parent_node = {
80 .type = NI_TOWER_SYSCTRL_SYSTOP_PARENT_TYPE,
81 .id = NI_TOWER_SYSCTRL_SYSTOP_PARENT_ID,
82 };
83
84 /* List of node data to be skipped during AON discovery */
85 const struct ni_tower_skip_component_discovery_node_data
86 skip_aon_discovery_data[] = {
87 /*
88 * Skip discovery of SYSTOP power domain node since the node is
89 * undiscoverable during AON initialisation.
90 * CFG_NODE - 0
91 * |
92 * +--> VD - 0
93 * |
94 * +--> PD - 0 (AON) ...
95 * |
96 * +--> PD - 1 (SYSTOP) ...
97 *
98 */
99 {
100 .parent_node = &systop_parent_node,
101 .node_idx = NI_TOWER_SYSCTRL_SYSTOP_IDX,
102 },
103 };
104
105 /*
106 * Programs the System control NI-Tower for nodes under Always-On (AON) domain.
107 */
ni_tower_sysctrl_aon_init(void)108 static int ni_tower_sysctrl_aon_init(void)
109 {
110 int err;
111
112 err = ni_tower_pre_init(host_system_data.info.chip_ap_phys_base +
113 HOST_SYSCTRL_NI_TOWER_PHYS_BASE);
114 if (err != 0) {
115 return err;
116 }
117
118 SYSCTRL_NI_TOWER_DEV.skip_discovery_list =
119 &(struct ni_tower_skip_component_discovery_list ){
120 .skip_node_data = skip_aon_discovery_data,
121 .skip_node_count = ARRAY_SIZE(skip_aon_discovery_data),
122 };
123
124 SYSCTRL_NI_TOWER_DEV.chip_addr_offset =
125 host_system_data.info.chip_ap_phys_base;
126 err = program_sysctrl_ni_tower_aon(host_system_data.info.chip_id);
127 if (err != 0) {
128 return err;
129 }
130
131 SYSCTRL_NI_TOWER_DEV.skip_discovery_list = NULL;
132
133 err = ni_tower_post_init();
134 if (err != 0) {
135 return err;
136 }
137
138 return 0;
139 }
140
141 /*
142 * Programs the System control NI-Tower for nodes under SYSTOP domain.
143 */
ni_tower_sysctrl_systop_init(void)144 static int ni_tower_sysctrl_systop_init(void)
145 {
146 int err;
147
148 err = ni_tower_pre_init(host_system_data.info.chip_ap_phys_base +
149 HOST_SYSCTRL_NI_TOWER_PHYS_BASE);
150 if (err != 0) {
151 return err;
152 }
153
154 SYSCTRL_NI_TOWER_DEV.chip_addr_offset =
155 host_system_data.info.chip_ap_phys_base;
156 err = program_sysctrl_ni_tower_systop();
157 if (err != 0) {
158 return err;
159 }
160
161 err = ni_tower_post_init();
162 if (err != 0) {
163 return err;
164 }
165
166 return 0;
167 }
168 #endif
169
170 #ifdef RD_PERIPH_NI_TOWER
171 /*
172 * Programs the Peripheral NI-Tower.
173 */
ni_tower_periph_init(void)174 static int ni_tower_periph_init(void)
175 {
176 int err;
177
178 err = ni_tower_pre_init(host_system_data.info.chip_ap_phys_base +
179 HOST_PERIPH_NI_TOWER_PHYS_BASE);
180 if (err != 0) {
181 return err;
182 }
183
184 PERIPH_NI_TOWER_DEV.chip_addr_offset =
185 host_system_data.info.chip_ap_phys_base;
186 err = program_periph_ni_tower();
187 if (err != 0) {
188 return err;
189 }
190
191 err = ni_tower_post_init();
192 if (err != 0) {
193 return err;
194 }
195
196 return 0;
197 }
198
199 /*
200 * Programs the Peripheral NI-Tower for ram_axim AP_BL1_RO region.
201 */
ni_tower_periph_init_ap_bl1_post_load(void)202 static int32_t ni_tower_periph_init_ap_bl1_post_load(void)
203 {
204 int32_t err;
205
206 err = ni_tower_pre_init(host_system_data.info.chip_ap_phys_base +
207 HOST_PERIPH_NI_TOWER_PHYS_BASE);
208 if (err != 0) {
209 return err;
210 }
211
212 PERIPH_NI_TOWER_DEV.chip_addr_offset =
213 host_system_data.info.chip_ap_phys_base;
214 err = program_periph_ni_tower_post_ap_bl1_load();
215 if (err != 0) {
216 return err;
217 }
218
219 err = ni_tower_post_init();
220 if (err != 0) {
221 return err;
222 }
223
224 return 0;
225 }
226 #endif
227
228 #ifdef HOST_SMMU
229 /*
230 * Initialize and bypass Granule Protection Check (GPC) to allow RSE and SCP
231 * to access HOST AP peripheral regions.
232 */
sysctrl_smmu_init(void)233 static int32_t sysctrl_smmu_init(void)
234 {
235 enum atu_roba_t roba_value;
236 enum atu_error_t atu_err;
237 enum smmu_error_t smmu_err;
238
239 atu_err = atu_initialize_region(&ATU_DEV_S,
240 HOST_SYSCTRL_SMMU_ATU_ID,
241 HOST_SYSCTRL_SMMU_BASE,
242 (host_system_data.info.chip_ap_phys_base +
243 HOST_SYSCTRL_SMMU_PHYS_BASE),
244 HOST_SYSCTRL_SMMU_SIZE);
245 if (atu_err != ATU_ERR_NONE) {
246 return -1;
247 }
248
249 roba_value = ATU_ROBA_SET_1;
250 atu_err = set_axnsc(&ATU_DEV_S, roba_value, HOST_SYSCTRL_SMMU_ATU_ID);
251 if (atu_err != ATU_ERR_NONE) {
252 return -1;
253 }
254
255 roba_value = ATU_ROBA_SET_0;
256 atu_err = set_axprot1(&ATU_DEV_S, roba_value, HOST_SYSCTRL_SMMU_ATU_ID);
257 if (atu_err != ATU_ERR_NONE) {
258 return -1;
259 }
260
261 /* Disable GPC */
262 smmu_err = smmu_gpc_disable(&HOST_SYSCTRL_SMMU_DEV);
263 if (smmu_err != SMMU_ERR_NONE){
264 return -1;
265 }
266
267 /* Allow Access via SMMU */
268 smmu_err = smmu_access_enable(&HOST_SYSCTRL_SMMU_DEV);
269 if (smmu_err != SMMU_ERR_NONE){
270 return -1;
271 }
272
273 atu_err = atu_uninitialize_region(&ATU_DEV_S, HOST_SYSCTRL_SMMU_ATU_ID);
274 if (atu_err != ATU_ERR_NONE) {
275 return -1;
276 }
277 return 0;
278 }
279 #endif
280
281 /* Read Chip ID from OTP */
read_chip_id(uint32_t * chip_id)282 static int read_chip_id(uint32_t *chip_id)
283 {
284 int err;
285 uint32_t otp_chip_id;
286
287 err = tfm_plat_otp_read(PLAT_OTP_ID_RSE_ID,
288 sizeof(otp_chip_id),
289 (uint8_t*)&otp_chip_id);
290 if (err != 0)
291 return err;
292
293 *chip_id = otp_chip_id;
294 return 0;
295 }
296
297 /* Initialize host system by collecting fixed data about the host system */
host_system_init(void)298 int host_system_init(void)
299 {
300 int res;
301
302 res = read_chip_id(&host_system_data.info.chip_id);
303 if (res != 0) {
304 host_system_data.info.chip_id = 0;
305 return res;
306 }
307 host_system_data.info.chip_ap_phys_base =
308 HOST_AP_CHIP_N_PHYS_BASE(host_system_data.info.chip_id);
309
310 host_system_data.initialized = true;
311 return 0;
312 }
313
314 /* Get info struct containing fixed data about the host system */
host_system_get_info(struct host_system_info_t ** info)315 int host_system_get_info(struct host_system_info_t **info)
316 {
317 if (info == NULL) {
318 return -1;
319 }
320
321 if (host_system_data.initialized == false) {
322 return -1;
323 }
324
325 *info = &host_system_data.info;
326 return 0;
327 }
328
host_system_prepare_mscp_access(void)329 int host_system_prepare_mscp_access(void)
330 {
331 #ifdef RD_SYSCTRL_NI_TOWER
332 int res;
333
334 /* Configure System Control NI-Tower for nodes under AON power domain */
335 res = ni_tower_sysctrl_aon_init();
336 if (res != 0) {
337 return res;
338 }
339 #endif
340 return 0;
341 }
342
host_system_prepare_ap_access(void)343 int host_system_prepare_ap_access(void)
344 {
345 int res;
346
347 (void)res;
348
349 /*
350 * AP cannot be accessed until SCP setup is complete so wait for signal
351 * from SCP.
352 */
353 while (host_system_data.status.scp_systop_ready == false) {
354 __WFE();
355 }
356
357 #ifdef RD_SYSCTRL_NI_TOWER
358 /* Configure System Control NI-Tower for nodes under SYSTOP power domain */
359 res = ni_tower_sysctrl_systop_init();
360 if (res != 0) {
361 return 1;
362 }
363 #endif
364
365 #ifdef HOST_SMMU
366 /* Initialize the SYSCTRL SMMU for boot time */
367 res = sysctrl_smmu_init();
368 if (res != 0) {
369 return 1;
370 }
371 #endif
372
373 #ifdef RD_PERIPH_NI_TOWER
374 /* Configure Peripheral NI-Tower */
375 res = ni_tower_periph_init();
376 if (res != 0) {
377 return 1;
378 }
379 #endif
380
381 return 0;
382 }
383
host_system_scp_signal_ap_ready(void)384 void host_system_scp_signal_ap_ready(void)
385 {
386 host_system_data.status.scp_systop_ready = true;
387 }
388
host_system_finish(void)389 int host_system_finish(void)
390 {
391 int res;
392
393 (void)res;
394
395 #ifdef RD_PERIPH_NI_TOWER
396 /* Limit AP BL1 load region to read-only and lock the APU region */
397 res = ni_tower_periph_init_ap_bl1_post_load();
398 if (res != 0) {
399 return 1;
400 }
401 #endif
402
403 return 0;
404 }
405