Skip to content
Snippets Groups Projects
fdtdec_test.c 5.13 KiB
Newer Older
  • Learn to ignore specific revisions
  • Simon Glass's avatar
    Simon Glass committed
    /*
     * Some very basic tests for fdtdec, accessed through test_fdtdec command.
     * They are easiest to use with sandbox.
     *
     * Copyright (c) 2011 The Chromium OS Authors.
    
     * SPDX-License-Identifier:	GPL-2.0+
    
    Simon Glass's avatar
    Simon Glass committed
     */
    
    #include <common.h>
    #include <fdtdec.h>
    #include <libfdt.h>
    #include <malloc.h>
    #include <os.h>
    
    /* The size of our test fdt blob */
    #define FDT_SIZE	(16 * 1024)
    
    /**
     * Check if an operation failed, and if so, print an error
     *
     * @param oper_name	Name of operation
     * @param err		Error code to check
     *
     * @return 0 if ok, -1 if there was an error
     */
    static int fdt_checkerr(const char *oper_name, int err)
    {
    	if (err) {
    		printf("%s: %s: %s\n", __func__, oper_name, fdt_strerror(err));
    		return -1;
    	}
    
    	return 0;
    }
    
    /**
     * Check the result of an operation and if incorrect, print an error
     *
     * @param oper_name	Name of operation
     * @param expected	Expected value
     * @param value		Actual value
     *
     * @return 0 if ok, -1 if there was an error
     */
    static int checkval(const char *oper_name, int expected, int value)
    {
    	if (expected != value) {
    		printf("%s: %s: expected %d, but returned %d\n", __func__,
    		       oper_name, expected, value);
    		return -1;
    	}
    
    	return 0;
    }
    
    #define CHECK(op)	if (fdt_checkerr(#op, op)) return -1
    #define CHECKVAL(op, expected)	\
    	if (checkval(#op, expected, op)) \
    		return -1
    #define CHECKOK(op)	CHECKVAL(op, 0)
    
    /* maximum number of nodes / aliases to generate */
    #define MAX_NODES	20
    
    /*
     * Make a test fdt
     *
     * @param fdt		Device tree pointer
     * @param size		Size of device tree blob
     * @param aliases	Specifies alias assignments. Format is a list of items
     *			separated by space. Items are #a where
     *				# is the alias number
     *				a is the node to point to
     * @param nodes		Specifies nodes to generate (a=0, b=1), upper case
     *			means to create a disabled node
     */
    static int make_fdt(void *fdt, int size, const char *aliases,
    		    const char *nodes)
    {
    	char name[20], value[20];
    	const char *s;
    	int fd;
    
    	CHECK(fdt_create(fdt, size));
    	CHECK(fdt_finish_reservemap(fdt));
    	CHECK(fdt_begin_node(fdt, ""));
    
    	CHECK(fdt_begin_node(fdt, "aliases"));
    	for (s = aliases; *s;) {
    		sprintf(name, "i2c%c", *s);
    		sprintf(value, "/i2c%d@0", s[1] - 'a');
    		CHECK(fdt_property_string(fdt, name, value));
    		s += 2 + (s[2] != '\0');
    	}
    	CHECK(fdt_end_node(fdt));
    
    	for (s = nodes; *s; s++) {
    		sprintf(value, "i2c%d@0", (*s & 0xdf) - 'A');
    		CHECK(fdt_begin_node(fdt, value));
    		CHECK(fdt_property_string(fdt, "compatible",
    			fdtdec_get_compatible(COMPAT_UNKNOWN)));
    		if (*s <= 'Z')
    			CHECK(fdt_property_string(fdt, "status", "disabled"));
    		CHECK(fdt_end_node(fdt));
    	}
    
    	CHECK(fdt_end_node(fdt));
    	CHECK(fdt_finish(fdt));
    	CHECK(fdt_pack(fdt));
    #if defined(DEBUG) && defined(CONFIG_SANDBOX)
    	fd = os_open("/tmp/fdtdec-text.dtb", OS_O_CREAT | OS_O_WRONLY);
    	if (fd == -1) {
    		printf("Could not open .dtb file to write\n");
    		return -1;
    	}
    	os_write(fd, fdt, size);
    	os_close(fd);
    #endif
    	return 0;
    }
    
    static int run_test(const char *aliases, const char *nodes, const char *expect)
    {
    	int list[MAX_NODES];
    	const char *s;
    	void *blob;
    	int i;
    
    	blob = malloc(FDT_SIZE);
    	if (!blob) {
    		printf("%s: out of memory\n", __func__);
    		return 1;
    	}
    
    	printf("aliases=%s, nodes=%s, expect=%s: ", aliases, nodes, expect);
    	CHECKVAL(make_fdt(blob, FDT_SIZE, aliases, nodes), 0);
    	CHECKVAL(fdtdec_find_aliases_for_id(blob, "i2c",
    			COMPAT_UNKNOWN,
    			list, ARRAY_SIZE(list)), strlen(expect));
    
    	/* Check we got the right ones */
    	for (i = 0, s = expect; *s; s++, i++) {
    		int want = *s;
    		const char *name;
    		int got = ' ';
    
    		name = list[i] ? fdt_get_name(blob, list[i], NULL) : NULL;
    		if (name)
    			got = name[3] + 'a' - '0';
    
    		if (got != want) {
    			printf("Position %d: Expected '%c', got '%c' ('%s')\n",
    			       i, want, got, name);
    			return 1;
    		}
    	}
    
    	printf("pass\n");
    	return 0;
    }
    
    static int do_test_fdtdec(cmd_tbl_t *cmdtp, int flag, int argc,
    			  char * const argv[])
    {
    	/* basic tests */
    	CHECKOK(run_test("", "", ""));
    	CHECKOK(run_test("1e 3d", "", ""));
    
    	/*
    	 * 'a' represents 0, 'b' represents 1, etc.
    	 * The first character is the alias number, the second is the node
    	 * number. So the params mean:
    	 * 0a 1b	: point alias 0 to node 0 (a), alias 1 to node 1(b)
    	 * ab		: to create nodes 0 and 1 (a and b)
    	 * ab		: we expect the function to return two nodes, in
    	 *		  the order 0, 1
    	 */
    	CHECKOK(run_test("0a 1b", "ab", "ab"));
    
    	CHECKOK(run_test("0a 1c", "ab", "ab"));
    	CHECKOK(run_test("1c", "ab", "ab"));
    	CHECKOK(run_test("1b", "ab", "ab"));
    	CHECKOK(run_test("0b", "ab", "ba"));
    	CHECKOK(run_test("0b 2d", "dbc", "bcd"));
    	CHECKOK(run_test("0d 3a 1c 2b", "dbac", "dcba"));
    
    	/* things with holes */
    	CHECKOK(run_test("1b 3d", "dbc", "cb d"));
    	CHECKOK(run_test("1e 3d", "dbc", "bc d"));
    
    	/* no aliases */
    	CHECKOK(run_test("", "dbac", "dbac"));
    
    	/* disabled nodes */
    	CHECKOK(run_test("0d 3a 1c 2b", "dBac", "dc a"));
    	CHECKOK(run_test("0b 2d", "DBc", "c"));
    	CHECKOK(run_test("0b 4d 2c", "DBc", "  c"));
    
    	/* conflicting aliases - first one gets it */
    	CHECKOK(run_test("2a 1a 0a", "a", "  a"));
    	CHECKOK(run_test("0a 1a 2a", "a", "a"));
    
    	printf("Test passed\n");
    	return 0;
    }
    
    U_BOOT_CMD(
    	test_fdtdec, 3, 1, do_test_fdtdec,
    	"test_fdtdec",
    	"Run tests for fdtdec library");