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