183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f2a9942fSMaxime Ripard /*
3f2a9942fSMaxime Ripard * Copyright (c) 2016 NextThing Co
4f2a9942fSMaxime Ripard * Copyright (c) 2016 Free Electrons
5f2a9942fSMaxime Ripard */
6f2a9942fSMaxime Ripard
7f2a9942fSMaxime Ripard #include <common.h>
8f2a9942fSMaxime Ripard #include <command.h>
9f2a9942fSMaxime Ripard #include <errno.h>
10d796735cSHeinrich Schuchardt #include <fdt_support.h>
11f2a9942fSMaxime Ripard #include <malloc.h>
12f2a9942fSMaxime Ripard
13f2a9942fSMaxime Ripard #include <linux/sizes.h>
14f2a9942fSMaxime Ripard
15f2a9942fSMaxime Ripard #include <test/ut.h>
16f2a9942fSMaxime Ripard #include <test/overlay.h>
17e93232e1SSimon Glass #include <test/suites.h>
18f2a9942fSMaxime Ripard
19f2a9942fSMaxime Ripard /* 4k ought to be enough for anybody */
20f2a9942fSMaxime Ripard #define FDT_COPY_SIZE (4 * SZ_1K)
21f2a9942fSMaxime Ripard
22f2a9942fSMaxime Ripard extern u32 __dtb_test_fdt_base_begin;
23f2a9942fSMaxime Ripard extern u32 __dtb_test_fdt_overlay_begin;
24ea28e488SPantelis Antoniou extern u32 __dtb_test_fdt_overlay_stacked_begin;
25f2a9942fSMaxime Ripard
26*3cc13761SHeinrich Schuchardt static void *fdt;
27*3cc13761SHeinrich Schuchardt
ut_fdt_getprop_u32_by_index(void * fdt,const char * path,const char * name,int index,u32 * out)28706708d3SPantelis Antoniou static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path,
29f2a9942fSMaxime Ripard const char *name, int index,
30f2a9942fSMaxime Ripard u32 *out)
31f2a9942fSMaxime Ripard {
32f2a9942fSMaxime Ripard const fdt32_t *val;
33f2a9942fSMaxime Ripard int node_off;
34f2a9942fSMaxime Ripard int len;
35f2a9942fSMaxime Ripard
36f2a9942fSMaxime Ripard node_off = fdt_path_offset(fdt, path);
37f2a9942fSMaxime Ripard if (node_off < 0)
38f2a9942fSMaxime Ripard return node_off;
39f2a9942fSMaxime Ripard
40f2a9942fSMaxime Ripard val = fdt_getprop(fdt, node_off, name, &len);
41f2a9942fSMaxime Ripard if (!val || (len < (sizeof(uint32_t) * (index + 1))))
42f2a9942fSMaxime Ripard return -FDT_ERR_NOTFOUND;
43f2a9942fSMaxime Ripard
44f2a9942fSMaxime Ripard *out = fdt32_to_cpu(*(val + index));
45f2a9942fSMaxime Ripard
46f2a9942fSMaxime Ripard return 0;
47f2a9942fSMaxime Ripard }
48f2a9942fSMaxime Ripard
ut_fdt_getprop_u32(void * fdt,const char * path,const char * name,u32 * out)49706708d3SPantelis Antoniou static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name,
50f2a9942fSMaxime Ripard u32 *out)
51f2a9942fSMaxime Ripard {
52706708d3SPantelis Antoniou return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out);
53f2a9942fSMaxime Ripard }
54f2a9942fSMaxime Ripard
fdt_getprop_str(void * fdt,const char * path,const char * name,const char ** out)55f2a9942fSMaxime Ripard static int fdt_getprop_str(void *fdt, const char *path, const char *name,
56f2a9942fSMaxime Ripard const char **out)
57f2a9942fSMaxime Ripard {
58f2a9942fSMaxime Ripard int node_off;
59b02e4044SSimon Glass int len;
60f2a9942fSMaxime Ripard
61f2a9942fSMaxime Ripard node_off = fdt_path_offset(fdt, path);
62f2a9942fSMaxime Ripard if (node_off < 0)
63f2a9942fSMaxime Ripard return node_off;
64f2a9942fSMaxime Ripard
65b02e4044SSimon Glass *out = fdt_stringlist_get(fdt, node_off, name, 0, &len);
66b02e4044SSimon Glass
67b02e4044SSimon Glass return len < 0 ? len : 0;
68f2a9942fSMaxime Ripard }
69f2a9942fSMaxime Ripard
fdt_overlay_change_int_property(struct unit_test_state * uts)70f2a9942fSMaxime Ripard static int fdt_overlay_change_int_property(struct unit_test_state *uts)
71f2a9942fSMaxime Ripard {
72f2a9942fSMaxime Ripard u32 val = 0;
73f2a9942fSMaxime Ripard
74706708d3SPantelis Antoniou ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property",
75f2a9942fSMaxime Ripard &val));
76f2a9942fSMaxime Ripard ut_asserteq(43, val);
77f2a9942fSMaxime Ripard
78f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
79f2a9942fSMaxime Ripard }
80f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_change_int_property, 0);
81f2a9942fSMaxime Ripard
fdt_overlay_change_str_property(struct unit_test_state * uts)82f2a9942fSMaxime Ripard static int fdt_overlay_change_str_property(struct unit_test_state *uts)
83f2a9942fSMaxime Ripard {
84f2a9942fSMaxime Ripard const char *val = NULL;
85f2a9942fSMaxime Ripard
86f2a9942fSMaxime Ripard ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property",
87f2a9942fSMaxime Ripard &val));
88f2a9942fSMaxime Ripard ut_asserteq_str("foobar", val);
89f2a9942fSMaxime Ripard
90f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
91f2a9942fSMaxime Ripard }
92f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_change_str_property, 0);
93f2a9942fSMaxime Ripard
fdt_overlay_add_str_property(struct unit_test_state * uts)94f2a9942fSMaxime Ripard static int fdt_overlay_add_str_property(struct unit_test_state *uts)
95f2a9942fSMaxime Ripard {
96f2a9942fSMaxime Ripard const char *val = NULL;
97f2a9942fSMaxime Ripard
98f2a9942fSMaxime Ripard ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2",
99f2a9942fSMaxime Ripard &val));
100f2a9942fSMaxime Ripard ut_asserteq_str("foobar2", val);
101f2a9942fSMaxime Ripard
102f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
103f2a9942fSMaxime Ripard }
104f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_add_str_property, 0);
105f2a9942fSMaxime Ripard
fdt_overlay_add_node_by_phandle(struct unit_test_state * uts)106f2a9942fSMaxime Ripard static int fdt_overlay_add_node_by_phandle(struct unit_test_state *uts)
107f2a9942fSMaxime Ripard {
108f2a9942fSMaxime Ripard int off;
109f2a9942fSMaxime Ripard
110f2a9942fSMaxime Ripard off = fdt_path_offset(fdt, "/test-node/new-node");
111f2a9942fSMaxime Ripard ut_assert(off >= 0);
112f2a9942fSMaxime Ripard
113f2a9942fSMaxime Ripard ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
114f2a9942fSMaxime Ripard
115f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
116f2a9942fSMaxime Ripard }
117f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_add_node_by_phandle, 0);
118f2a9942fSMaxime Ripard
fdt_overlay_add_node_by_path(struct unit_test_state * uts)119f2a9942fSMaxime Ripard static int fdt_overlay_add_node_by_path(struct unit_test_state *uts)
120f2a9942fSMaxime Ripard {
121f2a9942fSMaxime Ripard int off;
122f2a9942fSMaxime Ripard
123f2a9942fSMaxime Ripard off = fdt_path_offset(fdt, "/new-node");
124f2a9942fSMaxime Ripard ut_assert(off >= 0);
125f2a9942fSMaxime Ripard
126f2a9942fSMaxime Ripard ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
127f2a9942fSMaxime Ripard
128f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
129f2a9942fSMaxime Ripard }
130f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_add_node_by_path, 0);
131f2a9942fSMaxime Ripard
fdt_overlay_add_subnode_property(struct unit_test_state * uts)132f2a9942fSMaxime Ripard static int fdt_overlay_add_subnode_property(struct unit_test_state *uts)
133f2a9942fSMaxime Ripard {
134f2a9942fSMaxime Ripard int off;
135f2a9942fSMaxime Ripard
136f2a9942fSMaxime Ripard off = fdt_path_offset(fdt, "/test-node/sub-test-node");
137f2a9942fSMaxime Ripard ut_assert(off >= 0);
138f2a9942fSMaxime Ripard
139f2a9942fSMaxime Ripard ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL));
140f2a9942fSMaxime Ripard ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL));
141f2a9942fSMaxime Ripard
142f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
143f2a9942fSMaxime Ripard }
144f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_add_subnode_property, 0);
145f2a9942fSMaxime Ripard
fdt_overlay_local_phandle(struct unit_test_state * uts)146f2a9942fSMaxime Ripard static int fdt_overlay_local_phandle(struct unit_test_state *uts)
147f2a9942fSMaxime Ripard {
148f2a9942fSMaxime Ripard uint32_t local_phandle;
149f2a9942fSMaxime Ripard u32 val = 0;
150f2a9942fSMaxime Ripard int off;
151f2a9942fSMaxime Ripard
152f2a9942fSMaxime Ripard off = fdt_path_offset(fdt, "/new-local-node");
153f2a9942fSMaxime Ripard ut_assert(off >= 0);
154f2a9942fSMaxime Ripard
155f2a9942fSMaxime Ripard local_phandle = fdt_get_phandle(fdt, off);
156f2a9942fSMaxime Ripard ut_assert(local_phandle);
157f2a9942fSMaxime Ripard
158706708d3SPantelis Antoniou ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
159f2a9942fSMaxime Ripard 0, &val));
160f2a9942fSMaxime Ripard ut_asserteq(local_phandle, val);
161f2a9942fSMaxime Ripard
162706708d3SPantelis Antoniou ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
163f2a9942fSMaxime Ripard 1, &val));
164f2a9942fSMaxime Ripard ut_asserteq(local_phandle, val);
165f2a9942fSMaxime Ripard
166f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
167f2a9942fSMaxime Ripard }
168f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_local_phandle, 0);
169f2a9942fSMaxime Ripard
fdt_overlay_local_phandles(struct unit_test_state * uts)170f2a9942fSMaxime Ripard static int fdt_overlay_local_phandles(struct unit_test_state *uts)
171f2a9942fSMaxime Ripard {
172f2a9942fSMaxime Ripard uint32_t local_phandle, test_phandle;
173f2a9942fSMaxime Ripard u32 val = 0;
174f2a9942fSMaxime Ripard int off;
175f2a9942fSMaxime Ripard
176f2a9942fSMaxime Ripard off = fdt_path_offset(fdt, "/new-local-node");
177f2a9942fSMaxime Ripard ut_assert(off >= 0);
178f2a9942fSMaxime Ripard
179f2a9942fSMaxime Ripard local_phandle = fdt_get_phandle(fdt, off);
180f2a9942fSMaxime Ripard ut_assert(local_phandle);
181f2a9942fSMaxime Ripard
182f2a9942fSMaxime Ripard off = fdt_path_offset(fdt, "/test-node");
183f2a9942fSMaxime Ripard ut_assert(off >= 0);
184f2a9942fSMaxime Ripard
185f2a9942fSMaxime Ripard test_phandle = fdt_get_phandle(fdt, off);
186f2a9942fSMaxime Ripard ut_assert(test_phandle);
187f2a9942fSMaxime Ripard
188706708d3SPantelis Antoniou ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
189f2a9942fSMaxime Ripard &val));
190f2a9942fSMaxime Ripard ut_asserteq(test_phandle, val);
191f2a9942fSMaxime Ripard
192706708d3SPantelis Antoniou ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
193f2a9942fSMaxime Ripard &val));
194f2a9942fSMaxime Ripard ut_asserteq(local_phandle, val);
195f2a9942fSMaxime Ripard
196f2a9942fSMaxime Ripard return CMD_RET_SUCCESS;
197f2a9942fSMaxime Ripard }
198f2a9942fSMaxime Ripard OVERLAY_TEST(fdt_overlay_local_phandles, 0);
199f2a9942fSMaxime Ripard
fdt_overlay_stacked(struct unit_test_state * uts)200ea28e488SPantelis Antoniou static int fdt_overlay_stacked(struct unit_test_state *uts)
201ea28e488SPantelis Antoniou {
202ea28e488SPantelis Antoniou u32 val = 0;
203ea28e488SPantelis Antoniou
204ea28e488SPantelis Antoniou ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node",
205ea28e488SPantelis Antoniou "stacked-test-int-property", &val));
206ea28e488SPantelis Antoniou ut_asserteq(43, val);
207ea28e488SPantelis Antoniou
208ea28e488SPantelis Antoniou return CMD_RET_SUCCESS;
209ea28e488SPantelis Antoniou }
210ea28e488SPantelis Antoniou OVERLAY_TEST(fdt_overlay_stacked, 0);
211ea28e488SPantelis Antoniou
do_ut_overlay(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])212f2a9942fSMaxime Ripard int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
213f2a9942fSMaxime Ripard {
214f2a9942fSMaxime Ripard struct unit_test *tests = ll_entry_start(struct unit_test,
215f2a9942fSMaxime Ripard overlay_test);
216f2a9942fSMaxime Ripard const int n_ents = ll_entry_count(struct unit_test, overlay_test);
217f2a9942fSMaxime Ripard struct unit_test_state *uts;
218f2a9942fSMaxime Ripard void *fdt_base = &__dtb_test_fdt_base_begin;
219f2a9942fSMaxime Ripard void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
220ea28e488SPantelis Antoniou void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin;
221*3cc13761SHeinrich Schuchardt void *fdt_overlay_copy, *fdt_overlay_stacked_copy;
222d91062c4STom Rini int ret = -ENOMEM;
223f2a9942fSMaxime Ripard
224f2a9942fSMaxime Ripard uts = calloc(1, sizeof(*uts));
225f2a9942fSMaxime Ripard if (!uts)
226f2a9942fSMaxime Ripard return -ENOMEM;
227f2a9942fSMaxime Ripard
228f2a9942fSMaxime Ripard ut_assertok(fdt_check_header(fdt_base));
229f2a9942fSMaxime Ripard ut_assertok(fdt_check_header(fdt_overlay));
230f2a9942fSMaxime Ripard
231*3cc13761SHeinrich Schuchardt fdt = malloc(FDT_COPY_SIZE);
232*3cc13761SHeinrich Schuchardt if (!fdt)
233d91062c4STom Rini goto err1;
234f2a9942fSMaxime Ripard
235f2a9942fSMaxime Ripard fdt_overlay_copy = malloc(FDT_COPY_SIZE);
236f2a9942fSMaxime Ripard if (!fdt_overlay_copy)
237d91062c4STom Rini goto err2;
238f2a9942fSMaxime Ripard
239ea28e488SPantelis Antoniou fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
240ea28e488SPantelis Antoniou if (!fdt_overlay_stacked_copy)
241d91062c4STom Rini goto err3;
242ea28e488SPantelis Antoniou
243f2a9942fSMaxime Ripard /*
244f2a9942fSMaxime Ripard * Resize the FDT to 4k so that we have room to operate on
245f2a9942fSMaxime Ripard *
246f2a9942fSMaxime Ripard * (and relocate it since the memory might be mapped
247f2a9942fSMaxime Ripard * read-only)
248f2a9942fSMaxime Ripard */
249*3cc13761SHeinrich Schuchardt ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
250f2a9942fSMaxime Ripard
251f2a9942fSMaxime Ripard /*
252f2a9942fSMaxime Ripard * Resize the overlay to 4k so that we have room to operate on
253f2a9942fSMaxime Ripard *
254f2a9942fSMaxime Ripard * (and relocate it since the memory might be mapped
255f2a9942fSMaxime Ripard * read-only)
256f2a9942fSMaxime Ripard */
257f2a9942fSMaxime Ripard ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
258f2a9942fSMaxime Ripard FDT_COPY_SIZE));
259f2a9942fSMaxime Ripard
260ea28e488SPantelis Antoniou /*
261ea28e488SPantelis Antoniou * Resize the stacked overlay to 4k so that we have room to operate on
262ea28e488SPantelis Antoniou *
263ea28e488SPantelis Antoniou * (and relocate it since the memory might be mapped
264ea28e488SPantelis Antoniou * read-only)
265ea28e488SPantelis Antoniou */
266ea28e488SPantelis Antoniou ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
267ea28e488SPantelis Antoniou FDT_COPY_SIZE));
268ea28e488SPantelis Antoniou
269f2a9942fSMaxime Ripard /* Apply the overlay */
270*3cc13761SHeinrich Schuchardt ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_copy));
271f2a9942fSMaxime Ripard
272ea28e488SPantelis Antoniou /* Apply the stacked overlay */
273*3cc13761SHeinrich Schuchardt ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_stacked_copy));
274ea28e488SPantelis Antoniou
275e93232e1SSimon Glass ret = cmd_ut_category("overlay", tests, n_ents, argc, argv);
276f2a9942fSMaxime Ripard
277ea28e488SPantelis Antoniou free(fdt_overlay_stacked_copy);
278d91062c4STom Rini err3:
279f2a9942fSMaxime Ripard free(fdt_overlay_copy);
280d91062c4STom Rini err2:
281*3cc13761SHeinrich Schuchardt free(fdt);
282d91062c4STom Rini err1:
283d91062c4STom Rini return ret;
284f2a9942fSMaxime Ripard }
285