blob: c2bed3e0c1fb61aaac5bf0502e9b4f9a6d8f6f29 [file] [log] [blame]
Peng Fan47466162019-08-26 08:11:56 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 NXP
4 */
5
6#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Peng Fan2e0644a2023-04-28 12:08:09 +08008#include <firmware/imx/sci/sci.h>
Peng Fan429c9ac2019-08-26 08:12:06 +00009#include <asm/arch/sys_proto.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060010#include <asm/global_data.h>
Peng Fan47466162019-08-26 08:11:56 +000011#include <dm/ofnode.h>
12#include <fdt_support.h>
Peng Fanae617972020-05-05 20:28:37 +080013#include <linux/libfdt.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060014#include <linux/printk.h>
Peng Fan47466162019-08-26 08:11:56 +000015
16DECLARE_GLOBAL_DATA_PTR;
17
18static bool check_owned_resource(sc_rsrc_t rsrc_id)
19{
20 bool owned;
21
22 owned = sc_rm_is_resource_owned(-1, rsrc_id);
23
24 return owned;
25}
26
27static int disable_fdt_node(void *blob, int nodeoffset)
28{
29 int rc, ret;
30 const char *status = "disabled";
31
32 do {
33 rc = fdt_setprop(blob, nodeoffset, "status", status,
34 strlen(status) + 1);
35 if (rc) {
36 if (rc == -FDT_ERR_NOSPACE) {
37 ret = fdt_increase_size(blob, 512);
38 if (ret)
39 return ret;
40 }
41 }
42 } while (rc == -FDT_ERR_NOSPACE);
43
44 return rc;
45}
46
47static void update_fdt_with_owned_resources(void *blob)
48{
49 /*
50 * Traverses the fdt nodes, check its power domain and use
51 * the resource id in the power domain for checking whether
52 * it is owned by current partition
53 */
54 struct fdtdec_phandle_args args;
55 int offset = 0, depth = 0;
56 u32 rsrc_id;
57 int rc, i;
58
59 for (offset = fdt_next_node(blob, offset, &depth); offset > 0;
60 offset = fdt_next_node(blob, offset, &depth)) {
61 debug("Node name: %s, depth %d\n",
62 fdt_get_name(blob, offset, NULL), depth);
63
64 if (!fdt_get_property(blob, offset, "power-domains", NULL)) {
65 debug(" - ignoring node %s\n",
66 fdt_get_name(blob, offset, NULL));
67 continue;
68 }
69
70 if (!fdtdec_get_is_enabled(blob, offset)) {
71 debug(" - ignoring node %s\n",
72 fdt_get_name(blob, offset, NULL));
73 continue;
74 }
75
76 i = 0;
77 while (true) {
78 rc = fdtdec_parse_phandle_with_args(blob, offset,
79 "power-domains",
80 "#power-domain-cells",
81 0, i++, &args);
82 if (rc == -ENOENT) {
83 break;
84 } else if (rc) {
85 printf("Parse power-domains of %s wrong: %d\n",
86 fdt_get_name(blob, offset, NULL), rc);
87 continue;
88 }
89
90 rsrc_id = args.args[0];
91
92 if (!check_owned_resource(rsrc_id)) {
93 rc = disable_fdt_node(blob, offset);
94 if (!rc) {
95 printf("Disable %s rsrc %u not owned\n",
96 fdt_get_name(blob, offset, NULL),
97 rsrc_id);
98 } else {
99 printf("Unable to disable %s, err=%s\n",
100 fdt_get_name(blob, offset, NULL),
101 fdt_strerror(rc));
102 }
103 }
104 }
105 }
106}
107
Peng Fan429c9ac2019-08-26 08:12:06 +0000108static int config_smmu_resource_sid(int rsrc, int sid)
109{
110 int err;
111
Peng Fan429c9ac2019-08-26 08:12:06 +0000112 err = sc_rm_set_master_sid(-1, rsrc, sid);
113 debug("set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
Peng Fan25b7eb42023-06-15 18:08:58 +0800114 if (err) {
Peng Fan5bc54482020-05-05 20:28:46 +0800115 if (!check_owned_resource(rsrc)) {
116 printf("%s rsrc[%d] not owned\n", __func__, rsrc);
117 return -1;
118 }
Peng Fan429c9ac2019-08-26 08:12:06 +0000119 pr_err("fail set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
120 return -EINVAL;
121 }
122
123 return 0;
124}
125
126static int config_smmu_fdt_device_sid(void *blob, int device_offset, int sid)
127{
128 const char *name = fdt_get_name(blob, device_offset, NULL);
129 struct fdtdec_phandle_args args;
130 int rsrc, ret;
131 int proplen;
132 const fdt32_t *prop;
133 int i;
134
135 prop = fdt_getprop(blob, device_offset, "fsl,sc_rsrc_id", &proplen);
136 if (prop) {
137 int i;
138
139 debug("configure node %s sid 0x%x for %d resources\n",
140 name, sid, (int)(proplen / sizeof(fdt32_t)));
141 for (i = 0; i < proplen / sizeof(fdt32_t); ++i) {
142 ret = config_smmu_resource_sid(fdt32_to_cpu(prop[i]),
143 sid);
144 if (ret)
145 return ret;
146 }
147
148 return 0;
149 }
150
151 i = 0;
152 while (true) {
153 ret = fdtdec_parse_phandle_with_args(blob, device_offset,
154 "power-domains",
155 "#power-domain-cells",
156 0, i++, &args);
157 if (ret == -ENOENT) {
158 break;
159 } else if (ret) {
160 printf("Parse power-domains of node %s wrong: %d\n",
161 fdt_get_name(blob, device_offset, NULL), ret);
162 continue;
163 }
164
165 debug("configure node %s sid 0x%x rsrc=%d\n",
166 name, sid, rsrc);
167 rsrc = args.args[0];
168
169 ret = config_smmu_resource_sid(rsrc, sid);
170 if (ret)
171 break;
172 }
173
174 return ret;
175}
176
177static int config_smmu_fdt(void *blob)
178{
179 int offset, proplen, i, ret;
180 const fdt32_t *prop;
181 const char *name;
182
183 /* Legacy smmu bindings, still used by xen. */
184 offset = fdt_node_offset_by_compatible(blob, 0, "arm,mmu-500");
185 prop = fdt_getprop(blob, offset, "mmu-masters", &proplen);
186 if (offset > 0 && prop) {
187 debug("found legacy mmu-masters property\n");
188
189 for (i = 0; i < proplen / 8; ++i) {
190 u32 phandle = fdt32_to_cpu(prop[2 * i]);
191 int sid = fdt32_to_cpu(prop[2 * i + 1]);
192 int device_offset;
193
194 device_offset = fdt_node_offset_by_phandle(blob,
195 phandle);
196 if (device_offset < 0) {
197 pr_err("Not find device from mmu_masters: %d",
198 device_offset);
199 continue;
200 }
201 ret = config_smmu_fdt_device_sid(blob, device_offset,
202 sid);
203 if (ret)
204 return ret;
205 }
206
207 /* Ignore new bindings if old bindings found, just like linux. */
208 return 0;
209 }
210
211 /* Generic smmu bindings */
212 offset = 0;
213 while ((offset = fdt_next_node(blob, offset, NULL)) > 0) {
214 name = fdt_get_name(blob, offset, NULL);
215 prop = fdt_getprop(blob, offset, "iommus", &proplen);
216 if (!prop)
217 continue;
218 debug("node %s iommus proplen %d\n", name, proplen);
219
220 if (proplen == 12) {
221 int sid = fdt32_to_cpu(prop[1]);
222
223 config_smmu_fdt_device_sid(blob, offset, sid);
224 } else if (proplen != 4) {
225 debug("node %s ignore unexpected iommus proplen=%d\n",
226 name, proplen);
227 }
228 }
229
230 return 0;
231}
232
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900233static int ft_add_optee_node(void *fdt, struct bd_info *bd)
Peng Fan064fe832019-08-26 08:12:13 +0000234{
235 const char *path, *subpath;
236 int offs;
237
238 /*
239 * No TEE space allocated indicating no TEE running, so no
240 * need to add optee node in dts
241 */
242 if (!boot_pointer[1])
243 return 0;
244
245 offs = fdt_increase_size(fdt, 512);
246 if (offs) {
247 printf("No Space for dtb\n");
248 return 1;
249 }
250
251 path = "/firmware";
252 offs = fdt_path_offset(fdt, path);
253 if (offs < 0) {
254 path = "/";
255 offs = fdt_path_offset(fdt, path);
256
257 if (offs < 0) {
258 printf("Could not find root node.\n");
259 return offs;
260 }
261
262 subpath = "firmware";
263 offs = fdt_add_subnode(fdt, offs, subpath);
264 if (offs < 0) {
265 printf("Could not create %s node.\n", subpath);
266 return offs;
267 }
268 }
269
270 subpath = "optee";
271 offs = fdt_add_subnode(fdt, offs, subpath);
272 if (offs < 0) {
273 printf("Could not create %s node.\n", subpath);
274 return offs;
275 }
276
277 fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz");
278 fdt_setprop_string(fdt, offs, "method", "smc");
279
280 return 0;
281}
282
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900283int ft_system_setup(void *blob, struct bd_info *bd)
Peng Fan47466162019-08-26 08:11:56 +0000284{
Peng Fan429c9ac2019-08-26 08:12:06 +0000285 int ret;
Peng Fanae617972020-05-05 20:28:37 +0800286 int off;
287
288 if (CONFIG_BOOTAUX_RESERVED_MEM_BASE) {
289 off = fdt_add_mem_rsv(blob, CONFIG_BOOTAUX_RESERVED_MEM_BASE,
290 CONFIG_BOOTAUX_RESERVED_MEM_SIZE);
291 if (off < 0)
292 printf("Failed to reserve memory for bootaux: %s\n",
293 fdt_strerror(off));
294 }
Peng Fan429c9ac2019-08-26 08:12:06 +0000295
Peng Fan47466162019-08-26 08:11:56 +0000296 update_fdt_with_owned_resources(blob);
297
Peng Fan429c9ac2019-08-26 08:12:06 +0000298 if (is_imx8qm()) {
299 ret = config_smmu_fdt(blob);
300 if (ret)
301 return ret;
302 }
303
Peng Fan064fe832019-08-26 08:12:13 +0000304 return ft_add_optee_node(blob, bd);
Peng Fan47466162019-08-26 08:11:56 +0000305}