1 /*
2 * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <libfdt.h>
8
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <common/desc_image_load.h>
12 #include <drivers/arm/css/sds.h>
13 #include <lib/fconf/fconf.h>
14 #include <lib/fconf/fconf_dyn_cfg_getter.h>
15 #include <plat/arm/common/plat_arm.h>
16 #include <plat/common/platform.h>
17 #include <platform_def.h>
18
19 #include <nrd_variant.h>
20
21 /*
22 * Information about the isolated CPUs obtained from SDS.
23 */
24 struct isolated_cpu_mpid_list {
25 uint64_t num_entries; /* Number of entries in the list */
26 uint64_t mpid_list[PLATFORM_CORE_COUNT]; /* List of isolated CPU MPIDs */
27 };
28
29 /* Function to read isolated CPU MPID list from SDS. */
plat_arm_nrd_get_isolated_cpu_list(struct isolated_cpu_mpid_list * list)30 void plat_arm_nrd_get_isolated_cpu_list(struct isolated_cpu_mpid_list *list)
31 {
32 int ret;
33
34 ret = sds_init(SDS_SCP_AP_REGION_ID);
35 if (ret != SDS_OK) {
36 ERROR("SDS initialization failed, error: %d\n", ret);
37 panic();
38 }
39
40 ret = sds_struct_read(SDS_SCP_AP_REGION_ID,
41 SDS_ISOLATED_CPU_LIST_ID, 0, &list->num_entries,
42 sizeof(list->num_entries), SDS_ACCESS_MODE_CACHED);
43 if (ret != SDS_OK) {
44 INFO("SDS CPU num elements read failed, error: %d\n", ret);
45 list->num_entries = 0;
46 return;
47 }
48
49 if (list->num_entries > PLATFORM_CORE_COUNT) {
50 ERROR("Isolated CPU list count %ld greater than max"
51 " number supported %d\n",
52 list->num_entries, PLATFORM_CORE_COUNT);
53 panic();
54 } else if (list->num_entries == 0) {
55 INFO("SDS isolated CPU list is empty\n");
56 return;
57 }
58
59 ret = sds_struct_read(SDS_SCP_AP_REGION_ID,
60 SDS_ISOLATED_CPU_LIST_ID,
61 sizeof(list->num_entries),
62 &list->mpid_list,
63 sizeof(list->mpid_list[0]) * list->num_entries,
64 SDS_ACCESS_MODE_CACHED);
65 if (ret != SDS_OK) {
66 ERROR("SDS CPU list read failed. error: %d\n", ret);
67 panic();
68 }
69 }
70
71 /*******************************************************************************
72 * This function inserts Platform information via device tree nodes as,
73 * system-id {
74 * platform-id = <0>;
75 * config-id = <0>;
76 * isolated-cpu-list = <0>
77 * }
78 ******************************************************************************/
plat_nrd_append_config_node(void)79 static int plat_nrd_append_config_node(void)
80 {
81 bl_mem_params_node_t *mem_params;
82 void *fdt;
83 int nodeoffset, err;
84 unsigned int platid = 0, platcfg = 0;
85 struct isolated_cpu_mpid_list cpu_mpid_list = {0};
86
87 mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
88 if (mem_params == NULL) {
89 ERROR("NT_FW CONFIG base address is NULL");
90 return -1;
91 }
92
93 fdt = (void *)(mem_params->image_info.image_base);
94
95 /* Check the validity of the fdt */
96 if (fdt_check_header(fdt) != 0) {
97 ERROR("Invalid NT_FW_CONFIG DTB passed\n");
98 return -1;
99 }
100
101 nodeoffset = fdt_subnode_offset(fdt, 0, "system-id");
102 if (nodeoffset < 0) {
103 ERROR("Failed to get system-id node offset\n");
104 return -1;
105 }
106
107 platid = plat_arm_nrd_get_platform_id();
108 err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid);
109 if (err < 0) {
110 ERROR("Failed to set platform-id\n");
111 return -1;
112 }
113
114 platcfg = plat_arm_nrd_get_config_id();
115 err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg);
116 if (err < 0) {
117 ERROR("Failed to set config-id\n");
118 return -1;
119 }
120
121 platcfg = plat_arm_nrd_get_multi_chip_mode();
122 err = fdt_setprop_u32(fdt, nodeoffset, "multi-chip-mode", platcfg);
123 if (err < 0) {
124 ERROR("Failed to set multi-chip-mode\n");
125 return -1;
126 }
127
128 plat_arm_nrd_get_isolated_cpu_list(&cpu_mpid_list);
129 if (cpu_mpid_list.num_entries > 0) {
130 err = fdt_setprop(fdt, nodeoffset, "isolated-cpu-list",
131 &cpu_mpid_list,
132 (sizeof(cpu_mpid_list.num_entries) *
133 (cpu_mpid_list.num_entries + 1)));
134 if (err < 0) {
135 ERROR("Failed to set isolated-cpu-list, error: %d\n",
136 err);
137 }
138 }
139
140 flush_dcache_range((uintptr_t)fdt, mem_params->image_info.image_size);
141
142 return 0;
143 }
144
145 /*******************************************************************************
146 * This function returns the list of executable images.
147 ******************************************************************************/
plat_get_next_bl_params(void)148 bl_params_t *plat_get_next_bl_params(void)
149 {
150 struct bl_params *arm_bl_params;
151 int ret;
152
153 ret = plat_nrd_append_config_node();
154 if (ret != 0)
155 panic();
156
157 arm_bl_params = arm_get_next_bl_params();
158
159 #if !EL3_PAYLOAD_BASE
160 const struct dyn_cfg_dtb_info_t *fw_config_info;
161 bl_mem_params_node_t *param_node;
162 uintptr_t fw_config_base = 0UL;
163
164 /* Get BL31 image node */
165 param_node = get_bl_mem_params_node(BL31_IMAGE_ID);
166 assert(param_node != NULL);
167
168 /* Get fw_config load address */
169 fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
170 assert(fw_config_info != NULL);
171
172 fw_config_base = fw_config_info->config_addr;
173 assert(fw_config_base != 0UL);
174
175 /*
176 * Get the entry point info of next executable image and override
177 * arg1 of entry point info with fw_config base address
178 */
179 param_node->ep_info.args.arg1 = (uint64_t)fw_config_base;
180
181 #endif
182 return arm_bl_params;
183 }
184