blob: e4ed7de850caf0a80b170a9c89f0227ca54301b7 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Maxime Ripard0e31a112016-07-05 10:26:46 +02002/*
3 * Copyright (c) 2016 NextThing Co
4 * Copyright (c) 2016 Free Electrons
Maxime Ripard0e31a112016-07-05 10:26:46 +02005 */
6
Maxime Ripard0e31a112016-07-05 10:26:46 +02007#include <command.h>
8#include <errno.h>
Heinrich Schuchardtb210fc72018-10-11 02:16:46 +02009#include <fdt_support.h>
Simon Glass2dc9c342020-05-10 11:40:01 -060010#include <image.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Maxime Ripard0e31a112016-07-05 10:26:46 +020012#include <malloc.h>
13
14#include <linux/sizes.h>
15
Simon Glass04e76d52025-02-07 11:30:39 -070016#include <test/fdt_overlay.h>
Maxime Ripard0e31a112016-07-05 10:26:46 +020017#include <test/ut.h>
Simon Glass17e99032017-11-25 11:57:30 -070018#include <test/suites.h>
Maxime Ripard0e31a112016-07-05 10:26:46 +020019
20/* 4k ought to be enough for anybody */
21#define FDT_COPY_SIZE (4 * SZ_1K)
22
23extern u32 __dtb_test_fdt_base_begin;
Rasmus Villemoesb0b7e682024-07-10 09:16:10 +020024extern u32 __dtbo_test_fdt_overlay_begin;
25extern u32 __dtbo_test_fdt_overlay_stacked_begin;
Maxime Ripard0e31a112016-07-05 10:26:46 +020026
Heinrich Schuchardta4189002018-12-08 09:53:05 +010027static void *fdt;
28
Simon Glassffbfeac2025-02-07 11:30:44 -070029static int fdt_overlay_init(struct unit_test_state *uts)
30{
31 void *fdt_base = &__dtb_test_fdt_base_begin;
32 void *fdt_overlay = &__dtbo_test_fdt_overlay_begin;
33 void *fdt_overlay_stacked = &__dtbo_test_fdt_overlay_stacked_begin;
34 void *fdt_overlay_copy, *fdt_overlay_stacked_copy;
35
36 ut_assertok(fdt_check_header(fdt_base));
37 ut_assertok(fdt_check_header(fdt_overlay));
38
39 fdt = malloc(FDT_COPY_SIZE);
40 fdt_overlay_copy = malloc(FDT_COPY_SIZE);
41 fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
42 ut_assertnonnull(fdt);
43 ut_assertnonnull(fdt_overlay_copy);
44 ut_assertnonnull(fdt_overlay_stacked_copy);
45
46 /*
47 * Resize the FDT to 4k so that we have room to operate on
48 *
49 * (and relocate it since the memory might be mapped
50 * read-only)
51 */
52 ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
53
54 /*
55 * Resize the overlay to 4k so that we have room to operate on
56 *
57 * (and relocate it since the memory might be mapped
58 * read-only)
59 */
60 ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
61 FDT_COPY_SIZE));
62
63 /*
64 * Resize the stacked overlay to 4k so that we have room to operate on
65 *
66 * (and relocate it since the memory might be mapped
67 * read-only)
68 */
69 ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
70 FDT_COPY_SIZE));
71
72 /* Apply the overlay */
73 ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_copy));
74
75 /* Apply the stacked overlay */
76 ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_stacked_copy));
77
78 free(fdt_overlay_stacked_copy);
79 free(fdt_overlay_copy);
80
81 return 0;
82}
83
Pantelis Antoniou68650022017-09-04 23:12:22 +030084static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path,
Maxime Ripard0e31a112016-07-05 10:26:46 +020085 const char *name, int index,
86 u32 *out)
87{
88 const fdt32_t *val;
89 int node_off;
90 int len;
91
92 node_off = fdt_path_offset(fdt, path);
93 if (node_off < 0)
94 return node_off;
95
96 val = fdt_getprop(fdt, node_off, name, &len);
97 if (!val || (len < (sizeof(uint32_t) * (index + 1))))
98 return -FDT_ERR_NOTFOUND;
99
100 *out = fdt32_to_cpu(*(val + index));
101
102 return 0;
103}
104
Pantelis Antoniou68650022017-09-04 23:12:22 +0300105static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name,
Maxime Ripard0e31a112016-07-05 10:26:46 +0200106 u32 *out)
107{
Pantelis Antoniou68650022017-09-04 23:12:22 +0300108 return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200109}
110
111static int fdt_getprop_str(void *fdt, const char *path, const char *name,
112 const char **out)
113{
114 int node_off;
Simon Glassb0ea7402016-10-02 17:59:28 -0600115 int len;
Maxime Ripard0e31a112016-07-05 10:26:46 +0200116
117 node_off = fdt_path_offset(fdt, path);
118 if (node_off < 0)
119 return node_off;
120
Simon Glassb0ea7402016-10-02 17:59:28 -0600121 *out = fdt_stringlist_get(fdt, node_off, name, 0, &len);
122
123 return len < 0 ? len : 0;
Maxime Ripard0e31a112016-07-05 10:26:46 +0200124}
125
Simon Glass04e76d52025-02-07 11:30:39 -0700126static int fdt_overlay_test_change_int_property(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200127{
Maxime Ripard0e31a112016-07-05 10:26:46 +0200128 u32 val = 0;
129
Pantelis Antoniou68650022017-09-04 23:12:22 +0300130 ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property",
Maxime Ripard0e31a112016-07-05 10:26:46 +0200131 &val));
132 ut_asserteq(43, val);
133
134 return CMD_RET_SUCCESS;
135}
Simon Glass04e76d52025-02-07 11:30:39 -0700136FDT_OVERLAY_TEST(fdt_overlay_test_change_int_property, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200137
Simon Glass04e76d52025-02-07 11:30:39 -0700138static int fdt_overlay_test_change_str_property(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200139{
Maxime Ripard0e31a112016-07-05 10:26:46 +0200140 const char *val = NULL;
141
142 ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property",
143 &val));
144 ut_asserteq_str("foobar", val);
145
146 return CMD_RET_SUCCESS;
147}
Simon Glass04e76d52025-02-07 11:30:39 -0700148FDT_OVERLAY_TEST(fdt_overlay_test_change_str_property, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200149
Simon Glass04e76d52025-02-07 11:30:39 -0700150static int fdt_overlay_test_add_str_property(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200151{
Maxime Ripard0e31a112016-07-05 10:26:46 +0200152 const char *val = NULL;
153
154 ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2",
155 &val));
156 ut_asserteq_str("foobar2", val);
157
158 return CMD_RET_SUCCESS;
159}
Simon Glass04e76d52025-02-07 11:30:39 -0700160FDT_OVERLAY_TEST(fdt_overlay_test_add_str_property, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200161
Simon Glass04e76d52025-02-07 11:30:39 -0700162static int fdt_overlay_test_add_node_by_phandle(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200163{
Maxime Ripard0e31a112016-07-05 10:26:46 +0200164 int off;
165
166 off = fdt_path_offset(fdt, "/test-node/new-node");
167 ut_assert(off >= 0);
168
169 ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
170
171 return CMD_RET_SUCCESS;
172}
Simon Glass04e76d52025-02-07 11:30:39 -0700173FDT_OVERLAY_TEST(fdt_overlay_test_add_node_by_phandle, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200174
Simon Glass04e76d52025-02-07 11:30:39 -0700175static int fdt_overlay_test_add_node_by_path(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200176{
Maxime Ripard0e31a112016-07-05 10:26:46 +0200177 int off;
178
179 off = fdt_path_offset(fdt, "/new-node");
180 ut_assert(off >= 0);
181
182 ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
183
184 return CMD_RET_SUCCESS;
185}
Simon Glass04e76d52025-02-07 11:30:39 -0700186FDT_OVERLAY_TEST(fdt_overlay_test_add_node_by_path, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200187
Simon Glass04e76d52025-02-07 11:30:39 -0700188static int fdt_overlay_test_add_subnode_property(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200189{
Maxime Ripard0e31a112016-07-05 10:26:46 +0200190 int off;
191
192 off = fdt_path_offset(fdt, "/test-node/sub-test-node");
193 ut_assert(off >= 0);
194
195 ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL));
196 ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL));
197
198 return CMD_RET_SUCCESS;
199}
Simon Glass04e76d52025-02-07 11:30:39 -0700200FDT_OVERLAY_TEST(fdt_overlay_test_add_subnode_property, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200201
Simon Glass04e76d52025-02-07 11:30:39 -0700202static int fdt_overlay_test_local_phandle(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200203{
204 uint32_t local_phandle;
Maxime Ripard0e31a112016-07-05 10:26:46 +0200205 u32 val = 0;
206 int off;
207
208 off = fdt_path_offset(fdt, "/new-local-node");
209 ut_assert(off >= 0);
210
211 local_phandle = fdt_get_phandle(fdt, off);
212 ut_assert(local_phandle);
213
Pantelis Antoniou68650022017-09-04 23:12:22 +0300214 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
Maxime Ripard0e31a112016-07-05 10:26:46 +0200215 0, &val));
216 ut_asserteq(local_phandle, val);
217
Pantelis Antoniou68650022017-09-04 23:12:22 +0300218 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
Maxime Ripard0e31a112016-07-05 10:26:46 +0200219 1, &val));
220 ut_asserteq(local_phandle, val);
221
222 return CMD_RET_SUCCESS;
223}
Simon Glass04e76d52025-02-07 11:30:39 -0700224FDT_OVERLAY_TEST(fdt_overlay_test_local_phandle, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200225
Simon Glass04e76d52025-02-07 11:30:39 -0700226static int fdt_overlay_test_local_phandles(struct unit_test_state *uts)
Maxime Ripard0e31a112016-07-05 10:26:46 +0200227{
228 uint32_t local_phandle, test_phandle;
Maxime Ripard0e31a112016-07-05 10:26:46 +0200229 u32 val = 0;
230 int off;
231
232 off = fdt_path_offset(fdt, "/new-local-node");
233 ut_assert(off >= 0);
234
235 local_phandle = fdt_get_phandle(fdt, off);
236 ut_assert(local_phandle);
237
238 off = fdt_path_offset(fdt, "/test-node");
239 ut_assert(off >= 0);
240
241 test_phandle = fdt_get_phandle(fdt, off);
242 ut_assert(test_phandle);
243
Pantelis Antoniou68650022017-09-04 23:12:22 +0300244 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
Maxime Ripard0e31a112016-07-05 10:26:46 +0200245 &val));
246 ut_asserteq(test_phandle, val);
247
Pantelis Antoniou68650022017-09-04 23:12:22 +0300248 ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
Maxime Ripard0e31a112016-07-05 10:26:46 +0200249 &val));
250 ut_asserteq(local_phandle, val);
251
252 return CMD_RET_SUCCESS;
253}
Simon Glass04e76d52025-02-07 11:30:39 -0700254FDT_OVERLAY_TEST(fdt_overlay_test_local_phandles, 0);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200255
Simon Glass04e76d52025-02-07 11:30:39 -0700256static int fdt_overlay_test_stacked(struct unit_test_state *uts)
Pantelis Antoniouccdc28b2017-09-04 23:12:23 +0300257{
Pantelis Antoniouccdc28b2017-09-04 23:12:23 +0300258 u32 val = 0;
259
260 ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node",
261 "stacked-test-int-property", &val));
262 ut_asserteq(43, val);
263
264 return CMD_RET_SUCCESS;
265}
Simon Glass04e76d52025-02-07 11:30:39 -0700266FDT_OVERLAY_TEST(fdt_overlay_test_stacked, 0);
Pantelis Antoniouccdc28b2017-09-04 23:12:23 +0300267
Simon Glass04e76d52025-02-07 11:30:39 -0700268int do_ut_fdt_overlay(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
269 int flag, int argc, char *const argv[])
Maxime Ripard0e31a112016-07-05 10:26:46 +0200270{
Simon Glass04e76d52025-02-07 11:30:39 -0700271 struct unit_test *tests = UNIT_TEST_SUITE_START(fdt_overlay);
272 const int n_ents = UNIT_TEST_SUITE_COUNT(fdt_overlay);
Tom Riniaaa968b2017-09-26 12:43:12 -0400273 int ret = -ENOMEM;
Maxime Ripard0e31a112016-07-05 10:26:46 +0200274
Simon Glassffbfeac2025-02-07 11:30:44 -0700275 ut_assertok(fdt_overlay_init(uts));
Simon Glass04e76d52025-02-07 11:30:39 -0700276 ret = cmd_ut_category(uts, "fdt_overlay", "fdt_overlay_test_", tests,
277 n_ents, argc, argv);
Maxime Ripard0e31a112016-07-05 10:26:46 +0200278
Heinrich Schuchardta4189002018-12-08 09:53:05 +0100279 free(fdt);
Simon Glassffbfeac2025-02-07 11:30:44 -0700280
Tom Riniaaa968b2017-09-26 12:43:12 -0400281 return ret;
Maxime Ripard0e31a112016-07-05 10:26:46 +0200282}