xref: /openbmc/u-boot/test/overlay/cmd_ut_overlay.c (revision 277b06684ddf5231ce1e684ee2860aedacb32b3c)
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