1dc254f38SSimon Glass /*
2dc254f38SSimon Glass * Some very basic tests for fdtdec, accessed through test_fdtdec command.
3dc254f38SSimon Glass * They are easiest to use with sandbox.
4dc254f38SSimon Glass *
5dc254f38SSimon Glass * Copyright (c) 2011 The Chromium OS Authors.
61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
7dc254f38SSimon Glass */
8dc254f38SSimon Glass
9dc254f38SSimon Glass #include <common.h>
10dc254f38SSimon Glass #include <fdtdec.h>
11*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
12dc254f38SSimon Glass #include <malloc.h>
13dc254f38SSimon Glass #include <os.h>
14dc254f38SSimon Glass
15dc254f38SSimon Glass /* The size of our test fdt blob */
16dc254f38SSimon Glass #define FDT_SIZE (16 * 1024)
17dc254f38SSimon Glass
18dc254f38SSimon Glass /**
19dc254f38SSimon Glass * Check if an operation failed, and if so, print an error
20dc254f38SSimon Glass *
21dc254f38SSimon Glass * @param oper_name Name of operation
22dc254f38SSimon Glass * @param err Error code to check
23dc254f38SSimon Glass *
24dc254f38SSimon Glass * @return 0 if ok, -1 if there was an error
25dc254f38SSimon Glass */
fdt_checkerr(const char * oper_name,int err)26dc254f38SSimon Glass static int fdt_checkerr(const char *oper_name, int err)
27dc254f38SSimon Glass {
28dc254f38SSimon Glass if (err) {
29dc254f38SSimon Glass printf("%s: %s: %s\n", __func__, oper_name, fdt_strerror(err));
30dc254f38SSimon Glass return -1;
31dc254f38SSimon Glass }
32dc254f38SSimon Glass
33dc254f38SSimon Glass return 0;
34dc254f38SSimon Glass }
35dc254f38SSimon Glass
36dc254f38SSimon Glass /**
37dc254f38SSimon Glass * Check the result of an operation and if incorrect, print an error
38dc254f38SSimon Glass *
39dc254f38SSimon Glass * @param oper_name Name of operation
40dc254f38SSimon Glass * @param expected Expected value
41dc254f38SSimon Glass * @param value Actual value
42dc254f38SSimon Glass *
43dc254f38SSimon Glass * @return 0 if ok, -1 if there was an error
44dc254f38SSimon Glass */
checkval(const char * oper_name,int expected,int value)45dc254f38SSimon Glass static int checkval(const char *oper_name, int expected, int value)
46dc254f38SSimon Glass {
47dc254f38SSimon Glass if (expected != value) {
48dc254f38SSimon Glass printf("%s: %s: expected %d, but returned %d\n", __func__,
49dc254f38SSimon Glass oper_name, expected, value);
50dc254f38SSimon Glass return -1;
51dc254f38SSimon Glass }
52dc254f38SSimon Glass
53dc254f38SSimon Glass return 0;
54dc254f38SSimon Glass }
55dc254f38SSimon Glass
56dc254f38SSimon Glass #define CHECK(op) if (fdt_checkerr(#op, op)) return -1
57dc254f38SSimon Glass #define CHECKVAL(op, expected) \
58dc254f38SSimon Glass if (checkval(#op, expected, op)) \
59dc254f38SSimon Glass return -1
60dc254f38SSimon Glass #define CHECKOK(op) CHECKVAL(op, 0)
61dc254f38SSimon Glass
62dc254f38SSimon Glass /* maximum number of nodes / aliases to generate */
63dc254f38SSimon Glass #define MAX_NODES 20
64dc254f38SSimon Glass
65dc254f38SSimon Glass /*
66dc254f38SSimon Glass * Make a test fdt
67dc254f38SSimon Glass *
68dc254f38SSimon Glass * @param fdt Device tree pointer
69dc254f38SSimon Glass * @param size Size of device tree blob
70dc254f38SSimon Glass * @param aliases Specifies alias assignments. Format is a list of items
71dc254f38SSimon Glass * separated by space. Items are #a where
72dc254f38SSimon Glass * # is the alias number
73dc254f38SSimon Glass * a is the node to point to
74dc254f38SSimon Glass * @param nodes Specifies nodes to generate (a=0, b=1), upper case
75dc254f38SSimon Glass * means to create a disabled node
76dc254f38SSimon Glass */
make_fdt(void * fdt,int size,const char * aliases,const char * nodes)77dc254f38SSimon Glass static int make_fdt(void *fdt, int size, const char *aliases,
78dc254f38SSimon Glass const char *nodes)
79dc254f38SSimon Glass {
80dc254f38SSimon Glass char name[20], value[20];
81dc254f38SSimon Glass const char *s;
82dc254f38SSimon Glass int fd;
83dc254f38SSimon Glass
84dc254f38SSimon Glass CHECK(fdt_create(fdt, size));
85dc254f38SSimon Glass CHECK(fdt_finish_reservemap(fdt));
86dc254f38SSimon Glass CHECK(fdt_begin_node(fdt, ""));
87dc254f38SSimon Glass
88dc254f38SSimon Glass CHECK(fdt_begin_node(fdt, "aliases"));
89dc254f38SSimon Glass for (s = aliases; *s;) {
90dc254f38SSimon Glass sprintf(name, "i2c%c", *s);
91dc254f38SSimon Glass sprintf(value, "/i2c%d@0", s[1] - 'a');
92dc254f38SSimon Glass CHECK(fdt_property_string(fdt, name, value));
93dc254f38SSimon Glass s += 2 + (s[2] != '\0');
94dc254f38SSimon Glass }
95dc254f38SSimon Glass CHECK(fdt_end_node(fdt));
96dc254f38SSimon Glass
97dc254f38SSimon Glass for (s = nodes; *s; s++) {
98dc254f38SSimon Glass sprintf(value, "i2c%d@0", (*s & 0xdf) - 'A');
99dc254f38SSimon Glass CHECK(fdt_begin_node(fdt, value));
100dc254f38SSimon Glass CHECK(fdt_property_string(fdt, "compatible",
101dc254f38SSimon Glass fdtdec_get_compatible(COMPAT_UNKNOWN)));
102dc254f38SSimon Glass if (*s <= 'Z')
103dc254f38SSimon Glass CHECK(fdt_property_string(fdt, "status", "disabled"));
104dc254f38SSimon Glass CHECK(fdt_end_node(fdt));
105dc254f38SSimon Glass }
106dc254f38SSimon Glass
107dc254f38SSimon Glass CHECK(fdt_end_node(fdt));
108dc254f38SSimon Glass CHECK(fdt_finish(fdt));
109dc254f38SSimon Glass CHECK(fdt_pack(fdt));
110dc254f38SSimon Glass #if defined(DEBUG) && defined(CONFIG_SANDBOX)
111dc254f38SSimon Glass fd = os_open("/tmp/fdtdec-text.dtb", OS_O_CREAT | OS_O_WRONLY);
112dc254f38SSimon Glass if (fd == -1) {
113dc254f38SSimon Glass printf("Could not open .dtb file to write\n");
114dc254f38SSimon Glass return -1;
115dc254f38SSimon Glass }
116dc254f38SSimon Glass os_write(fd, fdt, size);
117dc254f38SSimon Glass os_close(fd);
118dc254f38SSimon Glass #endif
119dc254f38SSimon Glass return 0;
120dc254f38SSimon Glass }
121dc254f38SSimon Glass
run_test(const char * aliases,const char * nodes,const char * expect)122dc254f38SSimon Glass static int run_test(const char *aliases, const char *nodes, const char *expect)
123dc254f38SSimon Glass {
124dc254f38SSimon Glass int list[MAX_NODES];
125dc254f38SSimon Glass const char *s;
126dc254f38SSimon Glass void *blob;
127dc254f38SSimon Glass int i;
128dc254f38SSimon Glass
129dc254f38SSimon Glass blob = malloc(FDT_SIZE);
130dc254f38SSimon Glass if (!blob) {
131dc254f38SSimon Glass printf("%s: out of memory\n", __func__);
132dc254f38SSimon Glass return 1;
133dc254f38SSimon Glass }
134dc254f38SSimon Glass
135dc254f38SSimon Glass printf("aliases=%s, nodes=%s, expect=%s: ", aliases, nodes, expect);
136dc254f38SSimon Glass CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0);
137dc254f38SSimon Glass CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c",
138dc254f38SSimon Glass COMPAT_UNKNOWN,
139dc254f38SSimon Glass list, ARRAY_SIZE(list)), strlen(expect));
140dc254f38SSimon Glass
141dc254f38SSimon Glass /* Check we got the right ones */
142dc254f38SSimon Glass for (i = 0, s = expect; *s; s++, i++) {
143dc254f38SSimon Glass int want = *s;
144dc254f38SSimon Glass const char *name;
145dc254f38SSimon Glass int got = ' ';
146dc254f38SSimon Glass
147dc254f38SSimon Glass name = list[i] ? fdt_get_name(blob, list[i], NULL) : NULL;
148dc254f38SSimon Glass if (name)
149dc254f38SSimon Glass got = name[3] + 'a' - '0';
150dc254f38SSimon Glass
151dc254f38SSimon Glass if (got != want) {
152dc254f38SSimon Glass printf("Position %d: Expected '%c', got '%c' ('%s')\n",
153dc254f38SSimon Glass i, want, got, name);
154dc254f38SSimon Glass return 1;
155dc254f38SSimon Glass }
156dc254f38SSimon Glass }
157dc254f38SSimon Glass
158dc254f38SSimon Glass printf("pass\n");
159dc254f38SSimon Glass return 0;
160dc254f38SSimon Glass }
161dc254f38SSimon Glass
do_test_fdtdec(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])162dc254f38SSimon Glass static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc,
163dc254f38SSimon Glass char * const argv[])
164dc254f38SSimon Glass {
165dc254f38SSimon Glass /* basic tests */
166dc254f38SSimon Glass CHECKOK(run_test("", "", ""));
167dc254f38SSimon Glass CHECKOK(run_test("1e 3d", "", ""));
168dc254f38SSimon Glass
169dc254f38SSimon Glass /*
170dc254f38SSimon Glass * 'a' represents 0, 'b' represents 1, etc.
171dc254f38SSimon Glass * The first character is the alias number, the second is the node
172dc254f38SSimon Glass * number. So the params mean:
173dc254f38SSimon Glass * 0a 1b : point alias 0 to node 0 (a), alias 1 to node 1(b)
174dc254f38SSimon Glass * ab : to create nodes 0 and 1 (a and b)
175dc254f38SSimon Glass * ab : we expect the function to return two nodes, in
176dc254f38SSimon Glass * the order 0, 1
177dc254f38SSimon Glass */
178dc254f38SSimon Glass CHECKOK(run_test("0a 1b", "ab", "ab"));
179dc254f38SSimon Glass
180dc254f38SSimon Glass CHECKOK(run_test("0a 1c", "ab", "ab"));
181dc254f38SSimon Glass CHECKOK(run_test("1c", "ab", "ab"));
182dc254f38SSimon Glass CHECKOK(run_test("1b", "ab", "ab"));
183dc254f38SSimon Glass CHECKOK(run_test("0b", "ab", "ba"));
184dc254f38SSimon Glass CHECKOK(run_test("0b 2d", "dbc", "bcd"));
185dc254f38SSimon Glass CHECKOK(run_test("0d 3a 1c 2b", "dbac", "dcba"));
186dc254f38SSimon Glass
187dc254f38SSimon Glass /* things with holes */
188dc254f38SSimon Glass CHECKOK(run_test("1b 3d", "dbc", "cb d"));
189dc254f38SSimon Glass CHECKOK(run_test("1e 3d", "dbc", "bc d"));
190dc254f38SSimon Glass
191dc254f38SSimon Glass /* no aliases */
192dc254f38SSimon Glass CHECKOK(run_test("", "dbac", "dbac"));
193dc254f38SSimon Glass
194dc254f38SSimon Glass /* disabled nodes */
195dc254f38SSimon Glass CHECKOK(run_test("0d 3a 1c 2b", "dBac", "dc a"));
196dc254f38SSimon Glass CHECKOK(run_test("0b 2d", "DBc", "c"));
197dc254f38SSimon Glass CHECKOK(run_test("0b 4d 2c", "DBc", " c"));
198dc254f38SSimon Glass
199dc254f38SSimon Glass /* conflicting aliases - first one gets it */
200dc254f38SSimon Glass CHECKOK(run_test("2a 1a 0a", "a", " a"));
201dc254f38SSimon Glass CHECKOK(run_test("0a 1a 2a", "a", "a"));
202dc254f38SSimon Glass
203dc254f38SSimon Glass printf("Test passed\n");
204dc254f38SSimon Glass return 0;
205dc254f38SSimon Glass }
206dc254f38SSimon Glass
207dc254f38SSimon Glass U_BOOT_CMD(
208dc254f38SSimon Glass test_fdtdec, 3, 1, do_test_fdtdec,
209dc254f38SSimon Glass "test_fdtdec",
210dc254f38SSimon Glass "Run tests for fdtdec library");
211