1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Some very basic tests for fdtdec, accessed through test_fdtdec command. 4 * They are easiest to use with sandbox. 5 * 6 * Copyright (c) 2011 The Chromium OS Authors. 7 */ 8 9#include <command.h> 10#include <fdtdec.h> 11#include <linux/libfdt.h> 12#include <malloc.h> 13#include <os.h> 14 15/* The size of our test fdt blob */ 16#define FDT_SIZE (16 * 1024) 17 18#define CHECK(op) ({ \ 19 int err = op; \ 20 if (err < 0) { \ 21 printf("%s: %s: %s\n", __func__, #op, \ 22 fdt_strerror(err)); \ 23 return err; \ 24 } \ 25 \ 26 err; \ 27 }) 28 29#define CHECKVAL(op, expected) ({ \ 30 int err = op; \ 31 if (err != expected) { \ 32 printf("%s: %s: expected %d, but returned %d\n",\ 33 __func__, #op, expected, err); \ 34 return err; \ 35 } \ 36 \ 37 err; \ 38 }) 39 40#define CHECKOK(op) CHECKVAL(op, 0) 41 42/* maximum number of nodes / aliases to generate */ 43#define MAX_NODES 20 44 45/* 46 * Make a test fdt 47 * 48 * @param fdt Device tree pointer 49 * @param size Size of device tree blob 50 * @param aliases Specifies alias assignments. Format is a list of items 51 * separated by space. Items are #a where 52 * # is the alias number 53 * a is the node to point to 54 * @param nodes Specifies nodes to generate (a=0, b=1), upper case 55 * means to create a disabled node 56 */ 57static int make_fdt(void *fdt, int size, const char *aliases, 58 const char *nodes) 59{ 60 char name[20], value[20]; 61 const char *s; 62#if defined(DEBUG) && defined(CONFIG_SANDBOX) 63 int fd; 64#endif 65 66 CHECK(fdt_create(fdt, size)); 67 CHECK(fdt_finish_reservemap(fdt)); 68 CHECK(fdt_begin_node(fdt, "")); 69 70 CHECK(fdt_begin_node(fdt, "aliases")); 71 for (s = aliases; *s;) { 72 sprintf(name, "i2c%c", *s); 73 sprintf(value, "/i2c%d@0", s[1] - 'a'); 74 CHECK(fdt_property_string(fdt, name, value)); 75 s += 2 + (s[2] != '\0'); 76 } 77 CHECK(fdt_end_node(fdt)); 78 79 for (s = nodes; *s; s++) { 80 sprintf(value, "i2c%d@0", (*s & 0xdf) - 'A'); 81 CHECK(fdt_begin_node(fdt, value)); 82 CHECK(fdt_property_string(fdt, "compatible", 83 fdtdec_get_compatible(COMPAT_UNKNOWN))); 84 if (*s <= 'Z') 85 CHECK(fdt_property_string(fdt, "status", "disabled")); 86 CHECK(fdt_end_node(fdt)); 87 } 88 89 CHECK(fdt_end_node(fdt)); 90 CHECK(fdt_finish(fdt)); 91 CHECK(fdt_pack(fdt)); 92#if defined(DEBUG) && defined(CONFIG_SANDBOX) 93 fd = os_open("/tmp/fdtdec-text.dtb", OS_O_CREAT | OS_O_WRONLY); 94 if (fd == -1) { 95 printf("Could not open .dtb file to write\n"); 96 return -1; 97 } 98 os_write(fd, fdt, size); 99 os_close(fd); 100#endif 101 return 0; 102} 103 104static int run_test(const char *aliases, const char *nodes, const char *expect) 105{ 106 int list[MAX_NODES]; 107 const char *s; 108 void *blob; 109 int i; 110 111 blob = malloc(FDT_SIZE); 112 if (!blob) { 113 printf("%s: out of memory\n", __func__); 114 return 1; 115 } 116 117 printf("aliases=%s, nodes=%s, expect=%s: ", aliases, nodes, expect); 118 CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0); 119 CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c", 120 COMPAT_UNKNOWN, 121 list, ARRAY_SIZE(list)), (int)strlen(expect)); 122 123 /* Check we got the right ones */ 124 for (i = 0, s = expect; *s; s++, i++) { 125 int want = *s; 126 const char *name; 127 int got = ' '; 128 129 name = list[i] ? fdt_get_name(blob, list[i], NULL) : NULL; 130 if (name) 131 got = name[3] + 'a' - '0'; 132 133 if (got != want) { 134 printf("Position %d: Expected '%c', got '%c' ('%s')\n", 135 i, want, got, name); 136 return 1; 137 } 138 } 139 140 printf("pass\n"); 141 free(blob); 142 return 0; 143} 144 145static int make_fdt_carveout_device(void *fdt, uint32_t na, uint32_t ns) 146{ 147 const char *basename = "/display"; 148 struct fdt_memory carveout = { 149#ifdef CONFIG_PHYS_64BIT 150 .start = 0x180000000, 151 .end = 0x18fffffff, 152#else 153 .start = 0x80000000, 154 .end = 0x8fffffff, 155#endif 156 }; 157 fdt32_t cells[4], *ptr = cells; 158 uint32_t upper, lower; 159 fdt_size_t size; 160 char name[32]; 161 int offset; 162 163 /* store one or two address cells */ 164 upper = upper_32_bits(carveout.start); 165 lower = lower_32_bits(carveout.start); 166 167 if (na > 1 && upper > 0) 168 snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, 169 lower); 170 else 171 snprintf(name, sizeof(name), "%s@%x", basename, lower); 172 173 if (na > 1) 174 *ptr++ = cpu_to_fdt32(upper); 175 176 *ptr++ = cpu_to_fdt32(lower); 177 178 /* store one or two size cells */ 179 size = carveout.end - carveout.start + 1; 180 upper = upper_32_bits(size); 181 lower = lower_32_bits(size); 182 183 if (ns > 1) 184 *ptr++ = cpu_to_fdt32(upper); 185 186 *ptr++ = cpu_to_fdt32(lower); 187 188 offset = CHECK(fdt_add_subnode(fdt, 0, name + 1)); 189 CHECK(fdt_setprop(fdt, offset, "reg", cells, (na + ns) * sizeof(*cells))); 190 191 return fdtdec_set_carveout(fdt, name, "memory-region", 0, &carveout, 192 "framebuffer", NULL, 0, 0); 193} 194 195static int check_fdt_carveout(void *fdt, uint32_t address_cells, 196 uint32_t size_cells) 197{ 198#ifdef CONFIG_PHYS_64BIT 199 const char *name = "/display@1,80000000"; 200 const struct fdt_memory expected = { 201 .start = 0x180000000, 202 .end = 0x18fffffff, 203 }; 204#else 205 const char *name = "/display@80000000"; 206 const struct fdt_memory expected = { 207 .start = 0x80000000, 208 .end = 0x8fffffff, 209 }; 210#endif 211 struct fdt_memory carveout; 212 213 printf("carveout: %pap-%pap na=%u ns=%u: ", &expected.start, 214 &expected.end, address_cells, size_cells); 215 216 CHECK(fdtdec_get_carveout(fdt, name, "memory-region", 0, &carveout, 217 NULL, NULL, NULL, NULL)); 218 219 if ((carveout.start != expected.start) || 220 (carveout.end != expected.end)) { 221 printf("carveout: %pap-%pap, expected %pap-%pap\n", 222 &carveout.start, &carveout.end, 223 &expected.start, &expected.end); 224 return 1; 225 } 226 227 printf("pass\n"); 228 return 0; 229} 230 231static int make_fdt_carveout(void *fdt, int size, uint32_t address_cells, 232 uint32_t size_cells) 233{ 234 fdt32_t na = cpu_to_fdt32(address_cells); 235 fdt32_t ns = cpu_to_fdt32(size_cells); 236#if defined(DEBUG) && defined(CONFIG_SANDBOX) 237 char filename[512]; 238 int fd; 239#endif 240 int err; 241 242 CHECK(fdt_create(fdt, size)); 243 CHECK(fdt_finish_reservemap(fdt)); 244 CHECK(fdt_begin_node(fdt, "")); 245 CHECK(fdt_property(fdt, "#address-cells", &na, sizeof(na))); 246 CHECK(fdt_property(fdt, "#size-cells", &ns, sizeof(ns))); 247 CHECK(fdt_end_node(fdt)); 248 CHECK(fdt_finish(fdt)); 249 CHECK(fdt_pack(fdt)); 250 251 CHECK(fdt_open_into(fdt, fdt, FDT_SIZE)); 252 253 err = make_fdt_carveout_device(fdt, address_cells, size_cells); 254 255#if defined(DEBUG) && defined(CONFIG_SANDBOX) 256 snprintf(filename, sizeof(filename), "/tmp/fdtdec-carveout-%u-%u.dtb", 257 address_cells, size_cells); 258 259 fd = os_open(filename, OS_O_CREAT | OS_O_WRONLY); 260 if (fd < 0) { 261 printf("could not open .dtb file to write\n"); 262 goto out; 263 } 264 265 os_write(fd, fdt, size); 266 os_close(fd); 267 268out: 269#endif 270 return err; 271} 272 273static int check_carveout(void) 274{ 275 void *fdt; 276 277 fdt = malloc(FDT_SIZE); 278 if (!fdt) { 279 printf("%s: out of memory\n", __func__); 280 return 1; 281 } 282 283#ifndef CONFIG_PHYS_64BIT 284 CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), 0); 285 CHECKOK(check_fdt_carveout(fdt, 1, 1)); 286 CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), 0); 287 CHECKOK(check_fdt_carveout(fdt, 1, 2)); 288#else 289 CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 1), -FDT_ERR_BADVALUE); 290 CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 1, 2), -FDT_ERR_BADVALUE); 291#endif 292 CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 1), 0); 293 CHECKOK(check_fdt_carveout(fdt, 2, 1)); 294 CHECKVAL(make_fdt_carveout(fdt, FDT_SIZE, 2, 2), 0); 295 CHECKOK(check_fdt_carveout(fdt, 2, 2)); 296 297 free(fdt); 298 return 0; 299} 300 301static int do_test_fdtdec(struct cmd_tbl *cmdtp, int flag, int argc, 302 char *const argv[]) 303{ 304 /* basic tests */ 305 CHECKOK(run_test("", "", "")); 306 CHECKOK(run_test("1e 3d", "", "")); 307 308 /* 309 * 'a' represents 0, 'b' represents 1, etc. 310 * The first character is the alias number, the second is the node 311 * number. So the params mean: 312 * 0a 1b : point alias 0 to node 0 (a), alias 1 to node 1(b) 313 * ab : to create nodes 0 and 1 (a and b) 314 * ab : we expect the function to return two nodes, in 315 * the order 0, 1 316 */ 317 CHECKOK(run_test("0a 1b", "ab", "ab")); 318 319 CHECKOK(run_test("0a 1c", "ab", "ab")); 320 CHECKOK(run_test("1c", "ab", "ab")); 321 CHECKOK(run_test("1b", "ab", "ab")); 322 CHECKOK(run_test("0b", "ab", "ba")); 323 CHECKOK(run_test("0b 2d", "dbc", "bcd")); 324 CHECKOK(run_test("0d 3a 1c 2b", "dbac", "dcba")); 325 326 /* things with holes */ 327 CHECKOK(run_test("1b 3d", "dbc", "cb d")); 328 CHECKOK(run_test("1e 3d", "dbc", "bc d")); 329 330 /* no aliases */ 331 CHECKOK(run_test("", "dbac", "dbac")); 332 333 /* disabled nodes */ 334 CHECKOK(run_test("0d 3a 1c 2b", "dBac", "dc a")); 335 CHECKOK(run_test("0b 2d", "DBc", "c")); 336 CHECKOK(run_test("0b 4d 2c", "DBc", " c")); 337 338 /* conflicting aliases - first one gets it */ 339 CHECKOK(run_test("2a 1a 0a", "a", " a")); 340 CHECKOK(run_test("0a 1a 2a", "a", "a")); 341 342 CHECKOK(check_carveout()); 343 344 printf("Test passed\n"); 345 return 0; 346} 347 348U_BOOT_CMD( 349 test_fdtdec, 3, 1, do_test_fdtdec, 350 "test_fdtdec", 351 "Run tests for fdtdec library"); 352