18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Self tests for device tree subsystem
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "### dt-test ### " fmt
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/memblock.h>
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/dma-direct.h> /* to test phys_to_dma/dma_to_phys */
118c2ecf20Sopenharmony_ci#include <linux/err.h>
128c2ecf20Sopenharmony_ci#include <linux/errno.h>
138c2ecf20Sopenharmony_ci#include <linux/hashtable.h>
148c2ecf20Sopenharmony_ci#include <linux/libfdt.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/of_address.h>
178c2ecf20Sopenharmony_ci#include <linux/of_fdt.h>
188c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
198c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
208c2ecf20Sopenharmony_ci#include <linux/list.h>
218c2ecf20Sopenharmony_ci#include <linux/mutex.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/device.h>
248c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/i2c.h>
278c2ecf20Sopenharmony_ci#include <linux/i2c-mux.h>
288c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <linux/bitops.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "of_private.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic struct unittest_results {
358c2ecf20Sopenharmony_ci	int passed;
368c2ecf20Sopenharmony_ci	int failed;
378c2ecf20Sopenharmony_ci} unittest_results;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define unittest(result, fmt, ...) ({ \
408c2ecf20Sopenharmony_ci	bool failed = !(result); \
418c2ecf20Sopenharmony_ci	if (failed) { \
428c2ecf20Sopenharmony_ci		unittest_results.failed++; \
438c2ecf20Sopenharmony_ci		pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
448c2ecf20Sopenharmony_ci	} else { \
458c2ecf20Sopenharmony_ci		unittest_results.passed++; \
468c2ecf20Sopenharmony_ci		pr_debug("pass %s():%i\n", __func__, __LINE__); \
478c2ecf20Sopenharmony_ci	} \
488c2ecf20Sopenharmony_ci	failed; \
498c2ecf20Sopenharmony_ci})
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_KOBJ
528c2ecf20Sopenharmony_ci#define OF_KREF_READ(NODE) kref_read(&(NODE)->kobj.kref)
538c2ecf20Sopenharmony_ci#else
548c2ecf20Sopenharmony_ci#define OF_KREF_READ(NODE) 1
558c2ecf20Sopenharmony_ci#endif
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/*
588c2ecf20Sopenharmony_ci * Expected message may have a message level other than KERN_INFO.
598c2ecf20Sopenharmony_ci * Print the expected message only if the current loglevel will allow
608c2ecf20Sopenharmony_ci * the actual message to print.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * Do not use EXPECT_BEGIN() or EXPECT_END() for messages generated by
638c2ecf20Sopenharmony_ci * pr_debug().
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_ci#define EXPECT_BEGIN(level, fmt, ...) \
668c2ecf20Sopenharmony_ci	printk(level pr_fmt("EXPECT \\ : ") fmt, ##__VA_ARGS__)
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define EXPECT_END(level, fmt, ...) \
698c2ecf20Sopenharmony_ci	printk(level pr_fmt("EXPECT / : ") fmt, ##__VA_ARGS__)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void __init of_unittest_find_node_by_name(void)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct device_node *np;
748c2ecf20Sopenharmony_ci	const char *options, *name;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data");
778c2ecf20Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%pOF", np);
788c2ecf20Sopenharmony_ci	unittest(np && name && !strcmp("/testcase-data", name),
798c2ecf20Sopenharmony_ci		"find /testcase-data failed\n");
808c2ecf20Sopenharmony_ci	of_node_put(np);
818c2ecf20Sopenharmony_ci	kfree(name);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Test if trailing '/' works */
848c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/");
858c2ecf20Sopenharmony_ci	unittest(!np, "trailing '/' on /testcase-data/ should fail\n");
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
888c2ecf20Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%pOF", np);
898c2ecf20Sopenharmony_ci	unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name),
908c2ecf20Sopenharmony_ci		"find /testcase-data/phandle-tests/consumer-a failed\n");
918c2ecf20Sopenharmony_ci	of_node_put(np);
928c2ecf20Sopenharmony_ci	kfree(name);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	np = of_find_node_by_path("testcase-alias");
958c2ecf20Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%pOF", np);
968c2ecf20Sopenharmony_ci	unittest(np && name && !strcmp("/testcase-data", name),
978c2ecf20Sopenharmony_ci		"find testcase-alias failed\n");
988c2ecf20Sopenharmony_ci	of_node_put(np);
998c2ecf20Sopenharmony_ci	kfree(name);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* Test if trailing '/' works on aliases */
1028c2ecf20Sopenharmony_ci	np = of_find_node_by_path("testcase-alias/");
1038c2ecf20Sopenharmony_ci	unittest(!np, "trailing '/' on testcase-alias/ should fail\n");
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a");
1068c2ecf20Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%pOF", np);
1078c2ecf20Sopenharmony_ci	unittest(np && name && !strcmp("/testcase-data/phandle-tests/consumer-a", name),
1088c2ecf20Sopenharmony_ci		"find testcase-alias/phandle-tests/consumer-a failed\n");
1098c2ecf20Sopenharmony_ci	of_node_put(np);
1108c2ecf20Sopenharmony_ci	kfree(name);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/missing-path");
1138c2ecf20Sopenharmony_ci	unittest(!np, "non-existent path returned node %pOF\n", np);
1148c2ecf20Sopenharmony_ci	of_node_put(np);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	np = of_find_node_by_path("missing-alias");
1178c2ecf20Sopenharmony_ci	unittest(!np, "non-existent alias returned node %pOF\n", np);
1188c2ecf20Sopenharmony_ci	of_node_put(np);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	np = of_find_node_by_path("testcase-alias/missing-path");
1218c2ecf20Sopenharmony_ci	unittest(!np, "non-existent alias with relative path returned node %pOF\n", np);
1228c2ecf20Sopenharmony_ci	of_node_put(np);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("/testcase-data:testoption", &options);
1258c2ecf20Sopenharmony_ci	unittest(np && !strcmp("testoption", options),
1268c2ecf20Sopenharmony_ci		 "option path test failed\n");
1278c2ecf20Sopenharmony_ci	of_node_put(np);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("/testcase-data:test/option", &options);
1308c2ecf20Sopenharmony_ci	unittest(np && !strcmp("test/option", options),
1318c2ecf20Sopenharmony_ci		 "option path test, subcase #1 failed\n");
1328c2ecf20Sopenharmony_ci	of_node_put(np);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("/testcase-data/testcase-device1:test/option", &options);
1358c2ecf20Sopenharmony_ci	unittest(np && !strcmp("test/option", options),
1368c2ecf20Sopenharmony_ci		 "option path test, subcase #2 failed\n");
1378c2ecf20Sopenharmony_ci	of_node_put(np);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
1408c2ecf20Sopenharmony_ci	unittest(np, "NULL option path test failed\n");
1418c2ecf20Sopenharmony_ci	of_node_put(np);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("testcase-alias:testaliasoption",
1448c2ecf20Sopenharmony_ci				       &options);
1458c2ecf20Sopenharmony_ci	unittest(np && !strcmp("testaliasoption", options),
1468c2ecf20Sopenharmony_ci		 "option alias path test failed\n");
1478c2ecf20Sopenharmony_ci	of_node_put(np);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("testcase-alias:test/alias/option",
1508c2ecf20Sopenharmony_ci				       &options);
1518c2ecf20Sopenharmony_ci	unittest(np && !strcmp("test/alias/option", options),
1528c2ecf20Sopenharmony_ci		 "option alias path test, subcase #1 failed\n");
1538c2ecf20Sopenharmony_ci	of_node_put(np);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
1568c2ecf20Sopenharmony_ci	unittest(np, "NULL option alias path test failed\n");
1578c2ecf20Sopenharmony_ci	of_node_put(np);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	options = "testoption";
1608c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("testcase-alias", &options);
1618c2ecf20Sopenharmony_ci	unittest(np && !options, "option clearing test failed\n");
1628c2ecf20Sopenharmony_ci	of_node_put(np);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	options = "testoption";
1658c2ecf20Sopenharmony_ci	np = of_find_node_opts_by_path("/", &options);
1668c2ecf20Sopenharmony_ci	unittest(np && !options, "option clearing root node test failed\n");
1678c2ecf20Sopenharmony_ci	of_node_put(np);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void __init of_unittest_dynamic(void)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct device_node *np;
1738c2ecf20Sopenharmony_ci	struct property *prop;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data");
1768c2ecf20Sopenharmony_ci	if (!np) {
1778c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
1788c2ecf20Sopenharmony_ci		return;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* Array of 4 properties for the purpose of testing */
1828c2ecf20Sopenharmony_ci	prop = kcalloc(4, sizeof(*prop), GFP_KERNEL);
1838c2ecf20Sopenharmony_ci	if (!prop) {
1848c2ecf20Sopenharmony_ci		unittest(0, "kzalloc() failed\n");
1858c2ecf20Sopenharmony_ci		return;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/* Add a new property - should pass*/
1898c2ecf20Sopenharmony_ci	prop->name = "new-property";
1908c2ecf20Sopenharmony_ci	prop->value = "new-property-data";
1918c2ecf20Sopenharmony_ci	prop->length = strlen(prop->value) + 1;
1928c2ecf20Sopenharmony_ci	unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n");
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* Try to add an existing property - should fail */
1958c2ecf20Sopenharmony_ci	prop++;
1968c2ecf20Sopenharmony_ci	prop->name = "new-property";
1978c2ecf20Sopenharmony_ci	prop->value = "new-property-data-should-fail";
1988c2ecf20Sopenharmony_ci	prop->length = strlen(prop->value) + 1;
1998c2ecf20Sopenharmony_ci	unittest(of_add_property(np, prop) != 0,
2008c2ecf20Sopenharmony_ci		 "Adding an existing property should have failed\n");
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* Try to modify an existing property - should pass */
2038c2ecf20Sopenharmony_ci	prop->value = "modify-property-data-should-pass";
2048c2ecf20Sopenharmony_ci	prop->length = strlen(prop->value) + 1;
2058c2ecf20Sopenharmony_ci	unittest(of_update_property(np, prop) == 0,
2068c2ecf20Sopenharmony_ci		 "Updating an existing property should have passed\n");
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Try to modify non-existent property - should pass*/
2098c2ecf20Sopenharmony_ci	prop++;
2108c2ecf20Sopenharmony_ci	prop->name = "modify-property";
2118c2ecf20Sopenharmony_ci	prop->value = "modify-missing-property-data-should-pass";
2128c2ecf20Sopenharmony_ci	prop->length = strlen(prop->value) + 1;
2138c2ecf20Sopenharmony_ci	unittest(of_update_property(np, prop) == 0,
2148c2ecf20Sopenharmony_ci		 "Updating a missing property should have passed\n");
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/* Remove property - should pass */
2178c2ecf20Sopenharmony_ci	unittest(of_remove_property(np, prop) == 0,
2188c2ecf20Sopenharmony_ci		 "Removing a property should have passed\n");
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* Adding very large property - should pass */
2218c2ecf20Sopenharmony_ci	prop++;
2228c2ecf20Sopenharmony_ci	prop->name = "large-property-PAGE_SIZEx8";
2238c2ecf20Sopenharmony_ci	prop->length = PAGE_SIZE * 8;
2248c2ecf20Sopenharmony_ci	prop->value = kzalloc(prop->length, GFP_KERNEL);
2258c2ecf20Sopenharmony_ci	unittest(prop->value != NULL, "Unable to allocate large buffer\n");
2268c2ecf20Sopenharmony_ci	if (prop->value)
2278c2ecf20Sopenharmony_ci		unittest(of_add_property(np, prop) == 0,
2288c2ecf20Sopenharmony_ci			 "Adding a large property should have passed\n");
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int __init of_unittest_check_node_linkage(struct device_node *np)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct device_node *child;
2348c2ecf20Sopenharmony_ci	int count = 0, rc;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child) {
2378c2ecf20Sopenharmony_ci		if (child->parent != np) {
2388c2ecf20Sopenharmony_ci			pr_err("Child node %pOFn links to wrong parent %pOFn\n",
2398c2ecf20Sopenharmony_ci				 child, np);
2408c2ecf20Sopenharmony_ci			rc = -EINVAL;
2418c2ecf20Sopenharmony_ci			goto put_child;
2428c2ecf20Sopenharmony_ci		}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		rc = of_unittest_check_node_linkage(child);
2458c2ecf20Sopenharmony_ci		if (rc < 0)
2468c2ecf20Sopenharmony_ci			goto put_child;
2478c2ecf20Sopenharmony_ci		count += rc;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return count + 1;
2518c2ecf20Sopenharmony_ciput_child:
2528c2ecf20Sopenharmony_ci	of_node_put(child);
2538c2ecf20Sopenharmony_ci	return rc;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic void __init of_unittest_check_tree_linkage(void)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct device_node *np;
2598c2ecf20Sopenharmony_ci	int allnode_count = 0, child_count;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (!of_root)
2628c2ecf20Sopenharmony_ci		return;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	for_each_of_allnodes(np)
2658c2ecf20Sopenharmony_ci		allnode_count++;
2668c2ecf20Sopenharmony_ci	child_count = of_unittest_check_node_linkage(of_root);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	unittest(child_count > 0, "Device node data structure is corrupted\n");
2698c2ecf20Sopenharmony_ci	unittest(child_count == allnode_count,
2708c2ecf20Sopenharmony_ci		 "allnodes list size (%i) doesn't match sibling lists size (%i)\n",
2718c2ecf20Sopenharmony_ci		 allnode_count, child_count);
2728c2ecf20Sopenharmony_ci	pr_debug("allnodes list size (%i); sibling lists size (%i)\n", allnode_count, child_count);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic void __init of_unittest_printf_one(struct device_node *np, const char *fmt,
2768c2ecf20Sopenharmony_ci					  const char *expected)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	unsigned char *buf;
2798c2ecf20Sopenharmony_ci	int buf_size;
2808c2ecf20Sopenharmony_ci	int size, i;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	buf_size = strlen(expected) + 10;
2838c2ecf20Sopenharmony_ci	buf = kmalloc(buf_size, GFP_KERNEL);
2848c2ecf20Sopenharmony_ci	if (!buf)
2858c2ecf20Sopenharmony_ci		return;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* Baseline; check conversion with a large size limit */
2888c2ecf20Sopenharmony_ci	memset(buf, 0xff, buf_size);
2898c2ecf20Sopenharmony_ci	size = snprintf(buf, buf_size - 2, fmt, np);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* use strcmp() instead of strncmp() here to be absolutely sure strings match */
2928c2ecf20Sopenharmony_ci	unittest((strcmp(buf, expected) == 0) && (buf[size+1] == 0xff),
2938c2ecf20Sopenharmony_ci		"sprintf failed; fmt='%s' expected='%s' rslt='%s'\n",
2948c2ecf20Sopenharmony_ci		fmt, expected, buf);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Make sure length limits work */
2978c2ecf20Sopenharmony_ci	size++;
2988c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++, size--) {
2998c2ecf20Sopenharmony_ci		/* Clear the buffer, and make sure it works correctly still */
3008c2ecf20Sopenharmony_ci		memset(buf, 0xff, buf_size);
3018c2ecf20Sopenharmony_ci		snprintf(buf, size+1, fmt, np);
3028c2ecf20Sopenharmony_ci		unittest(strncmp(buf, expected, size) == 0 && (buf[size+1] == 0xff),
3038c2ecf20Sopenharmony_ci			"snprintf failed; size=%i fmt='%s' expected='%s' rslt='%s'\n",
3048c2ecf20Sopenharmony_ci			size, fmt, expected, buf);
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci	kfree(buf);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic void __init of_unittest_printf(void)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct device_node *np;
3128c2ecf20Sopenharmony_ci	const char *full_name = "/testcase-data/platform-tests/test-device@1/dev@100";
3138c2ecf20Sopenharmony_ci	char phandle_str[16] = "";
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	np = of_find_node_by_path(full_name);
3168c2ecf20Sopenharmony_ci	if (!np) {
3178c2ecf20Sopenharmony_ci		unittest(np, "testcase data missing\n");
3188c2ecf20Sopenharmony_ci		return;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	num_to_str(phandle_str, sizeof(phandle_str), np->phandle, 0);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOF",  full_name);
3248c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFf", full_name);
3258c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFn", "dev");
3268c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%2pOFn", "dev");
3278c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%5pOFn", "  dev");
3288c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFnc", "dev:test-sub-device");
3298c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFp", phandle_str);
3308c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFP", "dev@100");
3318c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "ABC %pOFP ABC", "ABC dev@100 ABC");
3328c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%10pOFP", "   dev@100");
3338c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%-10pOFP", "dev@100   ");
3348c2ecf20Sopenharmony_ci	of_unittest_printf_one(of_root, "%pOFP", "/");
3358c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFF", "----");
3368c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFPF", "dev@100:----");
3378c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFPFPc", "dev@100:----:dev@100:test-sub-device");
3388c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFc", "test-sub-device");
3398c2ecf20Sopenharmony_ci	of_unittest_printf_one(np, "%pOFC",
3408c2ecf20Sopenharmony_ci			"\"test-sub-device\",\"test-compat2\",\"test-compat3\"");
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistruct node_hash {
3448c2ecf20Sopenharmony_ci	struct hlist_node node;
3458c2ecf20Sopenharmony_ci	struct device_node *np;
3468c2ecf20Sopenharmony_ci};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic DEFINE_HASHTABLE(phandle_ht, 8);
3498c2ecf20Sopenharmony_cistatic void __init of_unittest_check_phandles(void)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct device_node *np;
3528c2ecf20Sopenharmony_ci	struct node_hash *nh;
3538c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
3548c2ecf20Sopenharmony_ci	int i, dup_count = 0, phandle_count = 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	for_each_of_allnodes(np) {
3578c2ecf20Sopenharmony_ci		if (!np->phandle)
3588c2ecf20Sopenharmony_ci			continue;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci		hash_for_each_possible(phandle_ht, nh, node, np->phandle) {
3618c2ecf20Sopenharmony_ci			if (nh->np->phandle == np->phandle) {
3628c2ecf20Sopenharmony_ci				pr_info("Duplicate phandle! %i used by %pOF and %pOF\n",
3638c2ecf20Sopenharmony_ci					np->phandle, nh->np, np);
3648c2ecf20Sopenharmony_ci				dup_count++;
3658c2ecf20Sopenharmony_ci				break;
3668c2ecf20Sopenharmony_ci			}
3678c2ecf20Sopenharmony_ci		}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		nh = kzalloc(sizeof(*nh), GFP_KERNEL);
3708c2ecf20Sopenharmony_ci		if (!nh)
3718c2ecf20Sopenharmony_ci			return;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		nh->np = np;
3748c2ecf20Sopenharmony_ci		hash_add(phandle_ht, &nh->node, np->phandle);
3758c2ecf20Sopenharmony_ci		phandle_count++;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	unittest(dup_count == 0, "Found %i duplicates in %i phandles\n",
3788c2ecf20Sopenharmony_ci		 dup_count, phandle_count);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* Clean up */
3818c2ecf20Sopenharmony_ci	hash_for_each_safe(phandle_ht, i, tmp, nh, node) {
3828c2ecf20Sopenharmony_ci		hash_del(&nh->node);
3838c2ecf20Sopenharmony_ci		kfree(nh);
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_phandle_with_args(void)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct device_node *np;
3908c2ecf20Sopenharmony_ci	struct of_phandle_args args;
3918c2ecf20Sopenharmony_ci	int i, rc;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
3948c2ecf20Sopenharmony_ci	if (!np) {
3958c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
3968c2ecf20Sopenharmony_ci		return;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
4008c2ecf20Sopenharmony_ci	unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
4038c2ecf20Sopenharmony_ci		bool passed = true;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		memset(&args, 0, sizeof(args));
4068c2ecf20Sopenharmony_ci		rc = of_parse_phandle_with_args(np, "phandle-list",
4078c2ecf20Sopenharmony_ci						"#phandle-cells", i, &args);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		/* Test the values from tests-phandle.dtsi */
4108c2ecf20Sopenharmony_ci		switch (i) {
4118c2ecf20Sopenharmony_ci		case 0:
4128c2ecf20Sopenharmony_ci			passed &= !rc;
4138c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
4148c2ecf20Sopenharmony_ci			passed &= (args.args[0] == (i + 1));
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		case 1:
4178c2ecf20Sopenharmony_ci			passed &= !rc;
4188c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
4198c2ecf20Sopenharmony_ci			passed &= (args.args[0] == (i + 1));
4208c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 0);
4218c2ecf20Sopenharmony_ci			break;
4228c2ecf20Sopenharmony_ci		case 2:
4238c2ecf20Sopenharmony_ci			passed &= (rc == -ENOENT);
4248c2ecf20Sopenharmony_ci			break;
4258c2ecf20Sopenharmony_ci		case 3:
4268c2ecf20Sopenharmony_ci			passed &= !rc;
4278c2ecf20Sopenharmony_ci			passed &= (args.args_count == 3);
4288c2ecf20Sopenharmony_ci			passed &= (args.args[0] == (i + 1));
4298c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 4);
4308c2ecf20Sopenharmony_ci			passed &= (args.args[2] == 3);
4318c2ecf20Sopenharmony_ci			break;
4328c2ecf20Sopenharmony_ci		case 4:
4338c2ecf20Sopenharmony_ci			passed &= !rc;
4348c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
4358c2ecf20Sopenharmony_ci			passed &= (args.args[0] == (i + 1));
4368c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 100);
4378c2ecf20Sopenharmony_ci			break;
4388c2ecf20Sopenharmony_ci		case 5:
4398c2ecf20Sopenharmony_ci			passed &= !rc;
4408c2ecf20Sopenharmony_ci			passed &= (args.args_count == 0);
4418c2ecf20Sopenharmony_ci			break;
4428c2ecf20Sopenharmony_ci		case 6:
4438c2ecf20Sopenharmony_ci			passed &= !rc;
4448c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
4458c2ecf20Sopenharmony_ci			passed &= (args.args[0] == (i + 1));
4468c2ecf20Sopenharmony_ci			break;
4478c2ecf20Sopenharmony_ci		case 7:
4488c2ecf20Sopenharmony_ci			passed &= (rc == -ENOENT);
4498c2ecf20Sopenharmony_ci			break;
4508c2ecf20Sopenharmony_ci		default:
4518c2ecf20Sopenharmony_ci			passed = false;
4528c2ecf20Sopenharmony_ci		}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		unittest(passed, "index %i - data error on node %pOF rc=%i\n",
4558c2ecf20Sopenharmony_ci			 i, args.np, rc);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		if (rc == 0)
4588c2ecf20Sopenharmony_ci			of_node_put(args.np);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* Check for missing list property */
4628c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
4638c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args(np, "phandle-list-missing",
4648c2ecf20Sopenharmony_ci					"#phandle-cells", 0, &args);
4658c2ecf20Sopenharmony_ci	unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
4668c2ecf20Sopenharmony_ci	rc = of_count_phandle_with_args(np, "phandle-list-missing",
4678c2ecf20Sopenharmony_ci					"#phandle-cells");
4688c2ecf20Sopenharmony_ci	unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* Check for missing cells property */
4718c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
4748c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args(np, "phandle-list",
4778c2ecf20Sopenharmony_ci					"#phandle-cells-missing", 0, &args);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
4808c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
4858c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	rc = of_count_phandle_with_args(np, "phandle-list",
4888c2ecf20Sopenharmony_ci					"#phandle-cells-missing");
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
4918c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-a: could not get #phandle-cells-missing for /testcase-data/phandle-tests/provider1");
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/* Check for bad phandle in list */
4968c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
4998c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
5028c2ecf20Sopenharmony_ci					"#phandle-cells", 0, &args);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
5058c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
5108c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	rc = of_count_phandle_with_args(np, "phandle-list-bad-phandle",
5138c2ecf20Sopenharmony_ci					"#phandle-cells");
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
5168c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-a: could not find phandle");
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	/* Check for incorrectly formed argument list */
5218c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
5248c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
5278c2ecf20Sopenharmony_ci					"#phandle-cells", 1, &args);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
5308c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
5358c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	rc = of_count_phandle_with_args(np, "phandle-list-bad-args",
5388c2ecf20Sopenharmony_ci					"#phandle-cells");
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
5418c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-a: #phandle-cells = 3 found -1");
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_phandle_with_args_map(void)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct device_node *np, *p[6] = {};
5498c2ecf20Sopenharmony_ci	struct of_phandle_args args;
5508c2ecf20Sopenharmony_ci	unsigned int prefs[6];
5518c2ecf20Sopenharmony_ci	int i, rc;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b");
5548c2ecf20Sopenharmony_ci	if (!np) {
5558c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
5568c2ecf20Sopenharmony_ci		return;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	p[0] = of_find_node_by_path("/testcase-data/phandle-tests/provider0");
5608c2ecf20Sopenharmony_ci	p[1] = of_find_node_by_path("/testcase-data/phandle-tests/provider1");
5618c2ecf20Sopenharmony_ci	p[2] = of_find_node_by_path("/testcase-data/phandle-tests/provider2");
5628c2ecf20Sopenharmony_ci	p[3] = of_find_node_by_path("/testcase-data/phandle-tests/provider3");
5638c2ecf20Sopenharmony_ci	p[4] = of_find_node_by_path("/testcase-data/phandle-tests/provider4");
5648c2ecf20Sopenharmony_ci	p[5] = of_find_node_by_path("/testcase-data/phandle-tests/provider5");
5658c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p); ++i) {
5668c2ecf20Sopenharmony_ci		if (!p[i]) {
5678c2ecf20Sopenharmony_ci			pr_err("missing testcase data\n");
5688c2ecf20Sopenharmony_ci			return;
5698c2ecf20Sopenharmony_ci		}
5708c2ecf20Sopenharmony_ci		prefs[i] = OF_KREF_READ(p[i]);
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
5748c2ecf20Sopenharmony_ci	unittest(rc == 8, "of_count_phandle_with_args() returned %i, expected 8\n", rc);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	for (i = 0; i < 9; i++) {
5778c2ecf20Sopenharmony_ci		bool passed = true;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		memset(&args, 0, sizeof(args));
5808c2ecf20Sopenharmony_ci		rc = of_parse_phandle_with_args_map(np, "phandle-list",
5818c2ecf20Sopenharmony_ci						    "phandle", i, &args);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		/* Test the values from tests-phandle.dtsi */
5848c2ecf20Sopenharmony_ci		switch (i) {
5858c2ecf20Sopenharmony_ci		case 0:
5868c2ecf20Sopenharmony_ci			passed &= !rc;
5878c2ecf20Sopenharmony_ci			passed &= (args.np == p[1]);
5888c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
5898c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 1);
5908c2ecf20Sopenharmony_ci			break;
5918c2ecf20Sopenharmony_ci		case 1:
5928c2ecf20Sopenharmony_ci			passed &= !rc;
5938c2ecf20Sopenharmony_ci			passed &= (args.np == p[3]);
5948c2ecf20Sopenharmony_ci			passed &= (args.args_count == 3);
5958c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 2);
5968c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 5);
5978c2ecf20Sopenharmony_ci			passed &= (args.args[2] == 3);
5988c2ecf20Sopenharmony_ci			break;
5998c2ecf20Sopenharmony_ci		case 2:
6008c2ecf20Sopenharmony_ci			passed &= (rc == -ENOENT);
6018c2ecf20Sopenharmony_ci			break;
6028c2ecf20Sopenharmony_ci		case 3:
6038c2ecf20Sopenharmony_ci			passed &= !rc;
6048c2ecf20Sopenharmony_ci			passed &= (args.np == p[0]);
6058c2ecf20Sopenharmony_ci			passed &= (args.args_count == 0);
6068c2ecf20Sopenharmony_ci			break;
6078c2ecf20Sopenharmony_ci		case 4:
6088c2ecf20Sopenharmony_ci			passed &= !rc;
6098c2ecf20Sopenharmony_ci			passed &= (args.np == p[1]);
6108c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
6118c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 3);
6128c2ecf20Sopenharmony_ci			break;
6138c2ecf20Sopenharmony_ci		case 5:
6148c2ecf20Sopenharmony_ci			passed &= !rc;
6158c2ecf20Sopenharmony_ci			passed &= (args.np == p[0]);
6168c2ecf20Sopenharmony_ci			passed &= (args.args_count == 0);
6178c2ecf20Sopenharmony_ci			break;
6188c2ecf20Sopenharmony_ci		case 6:
6198c2ecf20Sopenharmony_ci			passed &= !rc;
6208c2ecf20Sopenharmony_ci			passed &= (args.np == p[2]);
6218c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
6228c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 15);
6238c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 0x20);
6248c2ecf20Sopenharmony_ci			break;
6258c2ecf20Sopenharmony_ci		case 7:
6268c2ecf20Sopenharmony_ci			passed &= !rc;
6278c2ecf20Sopenharmony_ci			passed &= (args.np == p[3]);
6288c2ecf20Sopenharmony_ci			passed &= (args.args_count == 3);
6298c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 2);
6308c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 5);
6318c2ecf20Sopenharmony_ci			passed &= (args.args[2] == 3);
6328c2ecf20Sopenharmony_ci			break;
6338c2ecf20Sopenharmony_ci		case 8:
6348c2ecf20Sopenharmony_ci			passed &= (rc == -ENOENT);
6358c2ecf20Sopenharmony_ci			break;
6368c2ecf20Sopenharmony_ci		default:
6378c2ecf20Sopenharmony_ci			passed = false;
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		unittest(passed, "index %i - data error on node %s rc=%i\n",
6418c2ecf20Sopenharmony_ci			 i, args.np->full_name, rc);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		if (rc == 0)
6448c2ecf20Sopenharmony_ci			of_node_put(args.np);
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	/* Check for missing list property */
6488c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
6498c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args_map(np, "phandle-list-missing",
6508c2ecf20Sopenharmony_ci					    "phandle", 0, &args);
6518c2ecf20Sopenharmony_ci	unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	/* Check for missing cells,map,mask property */
6548c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
6578c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-b: could not get #phandle-missing-cells for /testcase-data/phandle-tests/provider1");
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args_map(np, "phandle-list",
6608c2ecf20Sopenharmony_ci					    "phandle-missing", 0, &args);
6618c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
6628c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-b: could not get #phandle-missing-cells for /testcase-data/phandle-tests/provider1");
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	/* Check for bad phandle in list */
6678c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
6708c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle");
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle",
6738c2ecf20Sopenharmony_ci					    "phandle", 0, &args);
6748c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
6758c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-b: could not find phandle");
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* Check for incorrectly formed argument list */
6808c2ecf20Sopenharmony_ci	memset(&args, 0, sizeof(args));
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
6838c2ecf20Sopenharmony_ci		     "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found -1");
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args",
6868c2ecf20Sopenharmony_ci					    "phandle", 1, &args);
6878c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
6888c2ecf20Sopenharmony_ci		   "OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found -1");
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p); ++i) {
6938c2ecf20Sopenharmony_ci		unittest(prefs[i] == OF_KREF_READ(p[i]),
6948c2ecf20Sopenharmony_ci			 "provider%d: expected:%d got:%d\n",
6958c2ecf20Sopenharmony_ci			 i, prefs[i], OF_KREF_READ(p[i]));
6968c2ecf20Sopenharmony_ci		of_node_put(p[i]);
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic void __init of_unittest_property_string(void)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	const char *strings[4];
7038c2ecf20Sopenharmony_ci	struct device_node *np;
7048c2ecf20Sopenharmony_ci	int rc;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
7078c2ecf20Sopenharmony_ci	if (!np) {
7088c2ecf20Sopenharmony_ci		pr_err("No testcase data in device tree\n");
7098c2ecf20Sopenharmony_ci		return;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "phandle-list-names", "first");
7138c2ecf20Sopenharmony_ci	unittest(rc == 0, "first expected:0 got:%i\n", rc);
7148c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "phandle-list-names", "second");
7158c2ecf20Sopenharmony_ci	unittest(rc == 1, "second expected:1 got:%i\n", rc);
7168c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "phandle-list-names", "third");
7178c2ecf20Sopenharmony_ci	unittest(rc == 2, "third expected:2 got:%i\n", rc);
7188c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "phandle-list-names", "fourth");
7198c2ecf20Sopenharmony_ci	unittest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
7208c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "missing-property", "blah");
7218c2ecf20Sopenharmony_ci	unittest(rc == -EINVAL, "missing property; rc=%i\n", rc);
7228c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "empty-property", "blah");
7238c2ecf20Sopenharmony_ci	unittest(rc == -ENODATA, "empty property; rc=%i\n", rc);
7248c2ecf20Sopenharmony_ci	rc = of_property_match_string(np, "unterminated-string", "blah");
7258c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	/* of_property_count_strings() tests */
7288c2ecf20Sopenharmony_ci	rc = of_property_count_strings(np, "string-property");
7298c2ecf20Sopenharmony_ci	unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
7308c2ecf20Sopenharmony_ci	rc = of_property_count_strings(np, "phandle-list-names");
7318c2ecf20Sopenharmony_ci	unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
7328c2ecf20Sopenharmony_ci	rc = of_property_count_strings(np, "unterminated-string");
7338c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
7348c2ecf20Sopenharmony_ci	rc = of_property_count_strings(np, "unterminated-string-list");
7358c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	/* of_property_read_string_index() tests */
7388c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "string-property", 0, strings);
7398c2ecf20Sopenharmony_ci	unittest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
7408c2ecf20Sopenharmony_ci	strings[0] = NULL;
7418c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "string-property", 1, strings);
7428c2ecf20Sopenharmony_ci	unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
7438c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "phandle-list-names", 0, strings);
7448c2ecf20Sopenharmony_ci	unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
7458c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "phandle-list-names", 1, strings);
7468c2ecf20Sopenharmony_ci	unittest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
7478c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "phandle-list-names", 2, strings);
7488c2ecf20Sopenharmony_ci	unittest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
7498c2ecf20Sopenharmony_ci	strings[0] = NULL;
7508c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "phandle-list-names", 3, strings);
7518c2ecf20Sopenharmony_ci	unittest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
7528c2ecf20Sopenharmony_ci	strings[0] = NULL;
7538c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "unterminated-string", 0, strings);
7548c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
7558c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings);
7568c2ecf20Sopenharmony_ci	unittest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
7578c2ecf20Sopenharmony_ci	strings[0] = NULL;
7588c2ecf20Sopenharmony_ci	rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */
7598c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
7608c2ecf20Sopenharmony_ci	strings[1] = NULL;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* of_property_read_string_array() tests */
7638c2ecf20Sopenharmony_ci	rc = of_property_read_string_array(np, "string-property", strings, 4);
7648c2ecf20Sopenharmony_ci	unittest(rc == 1, "Incorrect string count; rc=%i\n", rc);
7658c2ecf20Sopenharmony_ci	rc = of_property_read_string_array(np, "phandle-list-names", strings, 4);
7668c2ecf20Sopenharmony_ci	unittest(rc == 3, "Incorrect string count; rc=%i\n", rc);
7678c2ecf20Sopenharmony_ci	rc = of_property_read_string_array(np, "unterminated-string", strings, 4);
7688c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
7698c2ecf20Sopenharmony_ci	/* -- An incorrectly formed string should cause a failure */
7708c2ecf20Sopenharmony_ci	rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4);
7718c2ecf20Sopenharmony_ci	unittest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
7728c2ecf20Sopenharmony_ci	/* -- parsing the correctly formed strings should still work: */
7738c2ecf20Sopenharmony_ci	strings[2] = NULL;
7748c2ecf20Sopenharmony_ci	rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2);
7758c2ecf20Sopenharmony_ci	unittest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
7768c2ecf20Sopenharmony_ci	strings[1] = NULL;
7778c2ecf20Sopenharmony_ci	rc = of_property_read_string_array(np, "phandle-list-names", strings, 1);
7788c2ecf20Sopenharmony_ci	unittest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci#define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
7828c2ecf20Sopenharmony_ci			(p1)->value && (p2)->value && \
7838c2ecf20Sopenharmony_ci			!memcmp((p1)->value, (p2)->value, (p1)->length) && \
7848c2ecf20Sopenharmony_ci			!strcmp((p1)->name, (p2)->name))
7858c2ecf20Sopenharmony_cistatic void __init of_unittest_property_copy(void)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_DYNAMIC
7888c2ecf20Sopenharmony_ci	struct property p1 = { .name = "p1", .length = 0, .value = "" };
7898c2ecf20Sopenharmony_ci	struct property p2 = { .name = "p2", .length = 5, .value = "abcd" };
7908c2ecf20Sopenharmony_ci	struct property *new;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	new = __of_prop_dup(&p1, GFP_KERNEL);
7938c2ecf20Sopenharmony_ci	unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
7948c2ecf20Sopenharmony_ci	kfree(new->value);
7958c2ecf20Sopenharmony_ci	kfree(new->name);
7968c2ecf20Sopenharmony_ci	kfree(new);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	new = __of_prop_dup(&p2, GFP_KERNEL);
7998c2ecf20Sopenharmony_ci	unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
8008c2ecf20Sopenharmony_ci	kfree(new->value);
8018c2ecf20Sopenharmony_ci	kfree(new->name);
8028c2ecf20Sopenharmony_ci	kfree(new);
8038c2ecf20Sopenharmony_ci#endif
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic void __init of_unittest_changeset(void)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_DYNAMIC
8098c2ecf20Sopenharmony_ci	struct property *ppadd, padd = { .name = "prop-add", .length = 1, .value = "" };
8108c2ecf20Sopenharmony_ci	struct property *ppname_n1,  pname_n1  = { .name = "name", .length = 3, .value = "n1"  };
8118c2ecf20Sopenharmony_ci	struct property *ppname_n2,  pname_n2  = { .name = "name", .length = 3, .value = "n2"  };
8128c2ecf20Sopenharmony_ci	struct property *ppname_n21, pname_n21 = { .name = "name", .length = 3, .value = "n21" };
8138c2ecf20Sopenharmony_ci	struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
8148c2ecf20Sopenharmony_ci	struct property *ppremove;
8158c2ecf20Sopenharmony_ci	struct device_node *n1, *n2, *n21, *nchangeset, *nremove, *parent, *np;
8168c2ecf20Sopenharmony_ci	struct of_changeset chgset;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	n1 = __of_node_dup(NULL, "n1");
8198c2ecf20Sopenharmony_ci	unittest(n1, "testcase setup failure\n");
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	n2 = __of_node_dup(NULL, "n2");
8228c2ecf20Sopenharmony_ci	unittest(n2, "testcase setup failure\n");
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	n21 = __of_node_dup(NULL, "n21");
8258c2ecf20Sopenharmony_ci	unittest(n21, "testcase setup failure %p\n", n21);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	nchangeset = of_find_node_by_path("/testcase-data/changeset");
8288c2ecf20Sopenharmony_ci	nremove = of_get_child_by_name(nchangeset, "node-remove");
8298c2ecf20Sopenharmony_ci	unittest(nremove, "testcase setup failure\n");
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	ppadd = __of_prop_dup(&padd, GFP_KERNEL);
8328c2ecf20Sopenharmony_ci	unittest(ppadd, "testcase setup failure\n");
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	ppname_n1  = __of_prop_dup(&pname_n1, GFP_KERNEL);
8358c2ecf20Sopenharmony_ci	unittest(ppname_n1, "testcase setup failure\n");
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	ppname_n2  = __of_prop_dup(&pname_n2, GFP_KERNEL);
8388c2ecf20Sopenharmony_ci	unittest(ppname_n2, "testcase setup failure\n");
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	ppname_n21 = __of_prop_dup(&pname_n21, GFP_KERNEL);
8418c2ecf20Sopenharmony_ci	unittest(ppname_n21, "testcase setup failure\n");
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL);
8448c2ecf20Sopenharmony_ci	unittest(ppupdate, "testcase setup failure\n");
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	parent = nchangeset;
8478c2ecf20Sopenharmony_ci	n1->parent = parent;
8488c2ecf20Sopenharmony_ci	n2->parent = parent;
8498c2ecf20Sopenharmony_ci	n21->parent = n2;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	ppremove = of_find_property(parent, "prop-remove", NULL);
8528c2ecf20Sopenharmony_ci	unittest(ppremove, "failed to find removal prop");
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	of_changeset_init(&chgset);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	unittest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
8578c2ecf20Sopenharmony_ci	unittest(!of_changeset_add_property(&chgset, n1, ppname_n1), "fail add prop name\n");
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	unittest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
8608c2ecf20Sopenharmony_ci	unittest(!of_changeset_add_property(&chgset, n2, ppname_n2), "fail add prop name\n");
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	unittest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
8638c2ecf20Sopenharmony_ci	unittest(!of_changeset_add_property(&chgset, n21, ppname_n21), "fail add prop name\n");
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	unittest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop prop-add\n");
8688c2ecf20Sopenharmony_ci	unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
8698c2ecf20Sopenharmony_ci	unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	unittest(!of_changeset_apply(&chgset), "apply failed\n");
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	of_node_put(nchangeset);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	/* Make sure node names are constructed correctly */
8768c2ecf20Sopenharmony_ci	unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
8778c2ecf20Sopenharmony_ci		 "'%pOF' not added\n", n21);
8788c2ecf20Sopenharmony_ci	of_node_put(np);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	unittest(!of_changeset_revert(&chgset), "revert failed\n");
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	of_changeset_destroy(&chgset);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	of_node_put(n1);
8858c2ecf20Sopenharmony_ci	of_node_put(n2);
8868c2ecf20Sopenharmony_ci	of_node_put(n21);
8878c2ecf20Sopenharmony_ci#endif
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic void __init of_unittest_dma_get_max_cpu_address(void)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct device_node *np;
8938c2ecf20Sopenharmony_ci	phys_addr_t cpu_addr;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_OF_ADDRESS))
8968c2ecf20Sopenharmony_ci		return;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/address-tests");
8998c2ecf20Sopenharmony_ci	if (!np) {
9008c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
9018c2ecf20Sopenharmony_ci		return;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	cpu_addr = of_dma_get_max_cpu_address(np);
9058c2ecf20Sopenharmony_ci	unittest(cpu_addr == 0x4fffffff,
9068c2ecf20Sopenharmony_ci		 "of_dma_get_max_cpu_address: wrong CPU addr %pad (expecting %x)\n",
9078c2ecf20Sopenharmony_ci		 &cpu_addr, 0x4fffffff);
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic void __init of_unittest_dma_ranges_one(const char *path,
9118c2ecf20Sopenharmony_ci		u64 expect_dma_addr, u64 expect_paddr)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci#ifdef CONFIG_HAS_DMA
9148c2ecf20Sopenharmony_ci	struct device_node *np;
9158c2ecf20Sopenharmony_ci	const struct bus_dma_region *map = NULL;
9168c2ecf20Sopenharmony_ci	int rc;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	np = of_find_node_by_path(path);
9198c2ecf20Sopenharmony_ci	if (!np) {
9208c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
9218c2ecf20Sopenharmony_ci		return;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	rc = of_dma_get_range(np, &map);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	unittest(!rc, "of_dma_get_range failed on node %pOF rc=%i\n", np, rc);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	if (!rc) {
9298c2ecf20Sopenharmony_ci		phys_addr_t	paddr;
9308c2ecf20Sopenharmony_ci		dma_addr_t	dma_addr;
9318c2ecf20Sopenharmony_ci		struct device	*dev_bogus;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci		dev_bogus = kzalloc(sizeof(struct device), GFP_KERNEL);
9348c2ecf20Sopenharmony_ci		if (!dev_bogus) {
9358c2ecf20Sopenharmony_ci			unittest(0, "kzalloc() failed\n");
9368c2ecf20Sopenharmony_ci			kfree(map);
9378c2ecf20Sopenharmony_ci			return;
9388c2ecf20Sopenharmony_ci		}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci		dev_bogus->dma_range_map = map;
9418c2ecf20Sopenharmony_ci		paddr = dma_to_phys(dev_bogus, expect_dma_addr);
9428c2ecf20Sopenharmony_ci		dma_addr = phys_to_dma(dev_bogus, expect_paddr);
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		unittest(paddr == expect_paddr,
9458c2ecf20Sopenharmony_ci			 "of_dma_get_range: wrong phys addr %pap (expecting %llx) on node %pOF\n",
9468c2ecf20Sopenharmony_ci			 &paddr, expect_paddr, np);
9478c2ecf20Sopenharmony_ci		unittest(dma_addr == expect_dma_addr,
9488c2ecf20Sopenharmony_ci			 "of_dma_get_range: wrong DMA addr %pad (expecting %llx) on node %pOF\n",
9498c2ecf20Sopenharmony_ci			 &dma_addr, expect_dma_addr, np);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci		kfree(map);
9528c2ecf20Sopenharmony_ci		kfree(dev_bogus);
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci	of_node_put(np);
9558c2ecf20Sopenharmony_ci#endif
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_dma_ranges(void)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	of_unittest_dma_ranges_one("/testcase-data/address-tests/device@70000000",
9618c2ecf20Sopenharmony_ci		0x0, 0x20000000);
9628c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
9638c2ecf20Sopenharmony_ci		of_unittest_dma_ranges_one("/testcase-data/address-tests/bus@80000000/device@1000",
9648c2ecf20Sopenharmony_ci			0x100000000, 0x20000000);
9658c2ecf20Sopenharmony_ci	of_unittest_dma_ranges_one("/testcase-data/address-tests/pci@90000000",
9668c2ecf20Sopenharmony_ci		0x80000000, 0x20000000);
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic void __init of_unittest_pci_dma_ranges(void)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	struct device_node *np;
9728c2ecf20Sopenharmony_ci	struct of_pci_range range;
9738c2ecf20Sopenharmony_ci	struct of_pci_range_parser parser;
9748c2ecf20Sopenharmony_ci	int i = 0;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PCI))
9778c2ecf20Sopenharmony_ci		return;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/address-tests/pci@90000000");
9808c2ecf20Sopenharmony_ci	if (!np) {
9818c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
9828c2ecf20Sopenharmony_ci		return;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (of_pci_dma_range_parser_init(&parser, np)) {
9868c2ecf20Sopenharmony_ci		pr_err("missing dma-ranges property\n");
9878c2ecf20Sopenharmony_ci		return;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	/*
9918c2ecf20Sopenharmony_ci	 * Get the dma-ranges from the device tree
9928c2ecf20Sopenharmony_ci	 */
9938c2ecf20Sopenharmony_ci	for_each_of_pci_range(&parser, &range) {
9948c2ecf20Sopenharmony_ci		if (!i) {
9958c2ecf20Sopenharmony_ci			unittest(range.size == 0x10000000,
9968c2ecf20Sopenharmony_ci				 "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
9978c2ecf20Sopenharmony_ci				 np, range.size);
9988c2ecf20Sopenharmony_ci			unittest(range.cpu_addr == 0x20000000,
9998c2ecf20Sopenharmony_ci				 "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
10008c2ecf20Sopenharmony_ci				 range.cpu_addr, np);
10018c2ecf20Sopenharmony_ci			unittest(range.pci_addr == 0x80000000,
10028c2ecf20Sopenharmony_ci				 "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
10038c2ecf20Sopenharmony_ci				 range.pci_addr, np);
10048c2ecf20Sopenharmony_ci		} else {
10058c2ecf20Sopenharmony_ci			unittest(range.size == 0x10000000,
10068c2ecf20Sopenharmony_ci				 "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
10078c2ecf20Sopenharmony_ci				 np, range.size);
10088c2ecf20Sopenharmony_ci			unittest(range.cpu_addr == 0x40000000,
10098c2ecf20Sopenharmony_ci				 "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
10108c2ecf20Sopenharmony_ci				 range.cpu_addr, np);
10118c2ecf20Sopenharmony_ci			unittest(range.pci_addr == 0xc0000000,
10128c2ecf20Sopenharmony_ci				 "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
10138c2ecf20Sopenharmony_ci				 range.pci_addr, np);
10148c2ecf20Sopenharmony_ci		}
10158c2ecf20Sopenharmony_ci		i++;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	of_node_put(np);
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_interrupts(void)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct device_node *np;
10248c2ecf20Sopenharmony_ci	struct of_phandle_args args;
10258c2ecf20Sopenharmony_ci	int i, rc;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
10288c2ecf20Sopenharmony_ci		return;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/interrupts/interrupts0");
10318c2ecf20Sopenharmony_ci	if (!np) {
10328c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
10338c2ecf20Sopenharmony_ci		return;
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
10378c2ecf20Sopenharmony_ci		bool passed = true;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci		memset(&args, 0, sizeof(args));
10408c2ecf20Sopenharmony_ci		rc = of_irq_parse_one(np, i, &args);
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci		passed &= !rc;
10438c2ecf20Sopenharmony_ci		passed &= (args.args_count == 1);
10448c2ecf20Sopenharmony_ci		passed &= (args.args[0] == (i + 1));
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci		unittest(passed, "index %i - data error on node %pOF rc=%i\n",
10478c2ecf20Sopenharmony_ci			 i, args.np, rc);
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci	of_node_put(np);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/interrupts/interrupts1");
10528c2ecf20Sopenharmony_ci	if (!np) {
10538c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
10548c2ecf20Sopenharmony_ci		return;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
10588c2ecf20Sopenharmony_ci		bool passed = true;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci		memset(&args, 0, sizeof(args));
10618c2ecf20Sopenharmony_ci		rc = of_irq_parse_one(np, i, &args);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci		/* Test the values from tests-phandle.dtsi */
10648c2ecf20Sopenharmony_ci		switch (i) {
10658c2ecf20Sopenharmony_ci		case 0:
10668c2ecf20Sopenharmony_ci			passed &= !rc;
10678c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
10688c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 9);
10698c2ecf20Sopenharmony_ci			break;
10708c2ecf20Sopenharmony_ci		case 1:
10718c2ecf20Sopenharmony_ci			passed &= !rc;
10728c2ecf20Sopenharmony_ci			passed &= (args.args_count == 3);
10738c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 10);
10748c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 11);
10758c2ecf20Sopenharmony_ci			passed &= (args.args[2] == 12);
10768c2ecf20Sopenharmony_ci			break;
10778c2ecf20Sopenharmony_ci		case 2:
10788c2ecf20Sopenharmony_ci			passed &= !rc;
10798c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
10808c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 13);
10818c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 14);
10828c2ecf20Sopenharmony_ci			break;
10838c2ecf20Sopenharmony_ci		case 3:
10848c2ecf20Sopenharmony_ci			passed &= !rc;
10858c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
10868c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 15);
10878c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 16);
10888c2ecf20Sopenharmony_ci			break;
10898c2ecf20Sopenharmony_ci		default:
10908c2ecf20Sopenharmony_ci			passed = false;
10918c2ecf20Sopenharmony_ci		}
10928c2ecf20Sopenharmony_ci		unittest(passed, "index %i - data error on node %pOF rc=%i\n",
10938c2ecf20Sopenharmony_ci			 i, args.np, rc);
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci	of_node_put(np);
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic void __init of_unittest_parse_interrupts_extended(void)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	struct device_node *np;
11018c2ecf20Sopenharmony_ci	struct of_phandle_args args;
11028c2ecf20Sopenharmony_ci	int i, rc;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
11058c2ecf20Sopenharmony_ci		return;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0");
11088c2ecf20Sopenharmony_ci	if (!np) {
11098c2ecf20Sopenharmony_ci		pr_err("missing testcase data\n");
11108c2ecf20Sopenharmony_ci		return;
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	for (i = 0; i < 7; i++) {
11148c2ecf20Sopenharmony_ci		bool passed = true;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci		memset(&args, 0, sizeof(args));
11178c2ecf20Sopenharmony_ci		rc = of_irq_parse_one(np, i, &args);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci		/* Test the values from tests-phandle.dtsi */
11208c2ecf20Sopenharmony_ci		switch (i) {
11218c2ecf20Sopenharmony_ci		case 0:
11228c2ecf20Sopenharmony_ci			passed &= !rc;
11238c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
11248c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 1);
11258c2ecf20Sopenharmony_ci			break;
11268c2ecf20Sopenharmony_ci		case 1:
11278c2ecf20Sopenharmony_ci			passed &= !rc;
11288c2ecf20Sopenharmony_ci			passed &= (args.args_count == 3);
11298c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 2);
11308c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 3);
11318c2ecf20Sopenharmony_ci			passed &= (args.args[2] == 4);
11328c2ecf20Sopenharmony_ci			break;
11338c2ecf20Sopenharmony_ci		case 2:
11348c2ecf20Sopenharmony_ci			passed &= !rc;
11358c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
11368c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 5);
11378c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 6);
11388c2ecf20Sopenharmony_ci			break;
11398c2ecf20Sopenharmony_ci		case 3:
11408c2ecf20Sopenharmony_ci			passed &= !rc;
11418c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
11428c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 9);
11438c2ecf20Sopenharmony_ci			break;
11448c2ecf20Sopenharmony_ci		case 4:
11458c2ecf20Sopenharmony_ci			passed &= !rc;
11468c2ecf20Sopenharmony_ci			passed &= (args.args_count == 3);
11478c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 10);
11488c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 11);
11498c2ecf20Sopenharmony_ci			passed &= (args.args[2] == 12);
11508c2ecf20Sopenharmony_ci			break;
11518c2ecf20Sopenharmony_ci		case 5:
11528c2ecf20Sopenharmony_ci			passed &= !rc;
11538c2ecf20Sopenharmony_ci			passed &= (args.args_count == 2);
11548c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 13);
11558c2ecf20Sopenharmony_ci			passed &= (args.args[1] == 14);
11568c2ecf20Sopenharmony_ci			break;
11578c2ecf20Sopenharmony_ci		case 6:
11588c2ecf20Sopenharmony_ci			passed &= !rc;
11598c2ecf20Sopenharmony_ci			passed &= (args.args_count == 1);
11608c2ecf20Sopenharmony_ci			passed &= (args.args[0] == 15);
11618c2ecf20Sopenharmony_ci			break;
11628c2ecf20Sopenharmony_ci		default:
11638c2ecf20Sopenharmony_ci			passed = false;
11648c2ecf20Sopenharmony_ci		}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		unittest(passed, "index %i - data error on node %pOF rc=%i\n",
11678c2ecf20Sopenharmony_ci			 i, args.np, rc);
11688c2ecf20Sopenharmony_ci	}
11698c2ecf20Sopenharmony_ci	of_node_put(np);
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic const struct of_device_id match_node_table[] = {
11738c2ecf20Sopenharmony_ci	{ .data = "A", .name = "name0", }, /* Name alone is lowest priority */
11748c2ecf20Sopenharmony_ci	{ .data = "B", .type = "type1", }, /* followed by type alone */
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	{ .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
11778c2ecf20Sopenharmony_ci	{ .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
11788c2ecf20Sopenharmony_ci	{ .data = "Cc", .name = "name2", .type = "type2", },
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	{ .data = "E", .compatible = "compat3" },
11818c2ecf20Sopenharmony_ci	{ .data = "G", .compatible = "compat2", },
11828c2ecf20Sopenharmony_ci	{ .data = "H", .compatible = "compat2", .name = "name5", },
11838c2ecf20Sopenharmony_ci	{ .data = "I", .compatible = "compat2", .type = "type1", },
11848c2ecf20Sopenharmony_ci	{ .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
11858c2ecf20Sopenharmony_ci	{ .data = "K", .compatible = "compat2", .name = "name9", },
11868c2ecf20Sopenharmony_ci	{}
11878c2ecf20Sopenharmony_ci};
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic struct {
11908c2ecf20Sopenharmony_ci	const char *path;
11918c2ecf20Sopenharmony_ci	const char *data;
11928c2ecf20Sopenharmony_ci} match_node_tests[] = {
11938c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name0", .data = "A", },
11948c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name1", .data = "B", },
11958c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
11968c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
11978c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
11988c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name3", .data = "E", },
11998c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name4", .data = "G", },
12008c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name5", .data = "H", },
12018c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name6", .data = "G", },
12028c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name7", .data = "I", },
12038c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name8", .data = "J", },
12048c2ecf20Sopenharmony_ci	{ .path = "/testcase-data/match-node/name9", .data = "K", },
12058c2ecf20Sopenharmony_ci};
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_cistatic void __init of_unittest_match_node(void)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	struct device_node *np;
12108c2ecf20Sopenharmony_ci	const struct of_device_id *match;
12118c2ecf20Sopenharmony_ci	int i;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
12148c2ecf20Sopenharmony_ci		np = of_find_node_by_path(match_node_tests[i].path);
12158c2ecf20Sopenharmony_ci		if (!np) {
12168c2ecf20Sopenharmony_ci			unittest(0, "missing testcase node %s\n",
12178c2ecf20Sopenharmony_ci				match_node_tests[i].path);
12188c2ecf20Sopenharmony_ci			continue;
12198c2ecf20Sopenharmony_ci		}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci		match = of_match_node(match_node_table, np);
12228c2ecf20Sopenharmony_ci		if (!match) {
12238c2ecf20Sopenharmony_ci			unittest(0, "%s didn't match anything\n",
12248c2ecf20Sopenharmony_ci				match_node_tests[i].path);
12258c2ecf20Sopenharmony_ci			continue;
12268c2ecf20Sopenharmony_ci		}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci		if (strcmp(match->data, match_node_tests[i].data) != 0) {
12298c2ecf20Sopenharmony_ci			unittest(0, "%s got wrong match. expected %s, got %s\n",
12308c2ecf20Sopenharmony_ci				match_node_tests[i].path, match_node_tests[i].data,
12318c2ecf20Sopenharmony_ci				(const char *)match->data);
12328c2ecf20Sopenharmony_ci			continue;
12338c2ecf20Sopenharmony_ci		}
12348c2ecf20Sopenharmony_ci		unittest(1, "passed");
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_cistatic struct resource test_bus_res = {
12398c2ecf20Sopenharmony_ci	.start = 0xfffffff8,
12408c2ecf20Sopenharmony_ci	.end = 0xfffffff9,
12418c2ecf20Sopenharmony_ci	.flags = IORESOURCE_MEM,
12428c2ecf20Sopenharmony_ci};
12438c2ecf20Sopenharmony_cistatic const struct platform_device_info test_bus_info = {
12448c2ecf20Sopenharmony_ci	.name = "unittest-bus",
12458c2ecf20Sopenharmony_ci};
12468c2ecf20Sopenharmony_cistatic void __init of_unittest_platform_populate(void)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	int irq, rc;
12498c2ecf20Sopenharmony_ci	struct device_node *np, *child, *grandchild;
12508c2ecf20Sopenharmony_ci	struct platform_device *pdev, *test_bus;
12518c2ecf20Sopenharmony_ci	const struct of_device_id match[] = {
12528c2ecf20Sopenharmony_ci		{ .compatible = "test-device", },
12538c2ecf20Sopenharmony_ci		{}
12548c2ecf20Sopenharmony_ci	};
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data");
12578c2ecf20Sopenharmony_ci	of_platform_default_populate(np, NULL, NULL);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* Test that a missing irq domain returns -EPROBE_DEFER */
12608c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/testcase-device1");
12618c2ecf20Sopenharmony_ci	pdev = of_find_device_by_node(np);
12628c2ecf20Sopenharmony_ci	unittest(pdev, "device 1 creation failed\n");
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) {
12658c2ecf20Sopenharmony_ci		irq = platform_get_irq(pdev, 0);
12668c2ecf20Sopenharmony_ci		unittest(irq == -EPROBE_DEFER,
12678c2ecf20Sopenharmony_ci			 "device deferred probe failed - %d\n", irq);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci		/* Test that a parsing failure does not return -EPROBE_DEFER */
12708c2ecf20Sopenharmony_ci		np = of_find_node_by_path("/testcase-data/testcase-device2");
12718c2ecf20Sopenharmony_ci		pdev = of_find_device_by_node(np);
12728c2ecf20Sopenharmony_ci		unittest(pdev, "device 2 creation failed\n");
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci		EXPECT_BEGIN(KERN_INFO,
12758c2ecf20Sopenharmony_ci			     "platform testcase-data:testcase-device2: IRQ index 0 not found");
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci		irq = platform_get_irq(pdev, 0);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci		EXPECT_END(KERN_INFO,
12808c2ecf20Sopenharmony_ci			   "platform testcase-data:testcase-device2: IRQ index 0 not found");
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci		unittest(irq < 0 && irq != -EPROBE_DEFER,
12838c2ecf20Sopenharmony_ci			 "device parsing error failed - %d\n", irq);
12848c2ecf20Sopenharmony_ci	}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/platform-tests");
12878c2ecf20Sopenharmony_ci	unittest(np, "No testcase data in device tree\n");
12888c2ecf20Sopenharmony_ci	if (!np)
12898c2ecf20Sopenharmony_ci		return;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	test_bus = platform_device_register_full(&test_bus_info);
12928c2ecf20Sopenharmony_ci	rc = PTR_ERR_OR_ZERO(test_bus);
12938c2ecf20Sopenharmony_ci	unittest(!rc, "testbus registration failed; rc=%i\n", rc);
12948c2ecf20Sopenharmony_ci	if (rc) {
12958c2ecf20Sopenharmony_ci		of_node_put(np);
12968c2ecf20Sopenharmony_ci		return;
12978c2ecf20Sopenharmony_ci	}
12988c2ecf20Sopenharmony_ci	test_bus->dev.of_node = np;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	/*
13018c2ecf20Sopenharmony_ci	 * Add a dummy resource to the test bus node after it is
13028c2ecf20Sopenharmony_ci	 * registered to catch problems with un-inserted resources. The
13038c2ecf20Sopenharmony_ci	 * DT code doesn't insert the resources, and it has caused the
13048c2ecf20Sopenharmony_ci	 * kernel to oops in the past. This makes sure the same bug
13058c2ecf20Sopenharmony_ci	 * doesn't crop up again.
13068c2ecf20Sopenharmony_ci	 */
13078c2ecf20Sopenharmony_ci	platform_device_add_resources(test_bus, &test_bus_res, 1);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	of_platform_populate(np, match, NULL, &test_bus->dev);
13108c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child) {
13118c2ecf20Sopenharmony_ci		for_each_child_of_node(child, grandchild) {
13128c2ecf20Sopenharmony_ci			pdev = of_find_device_by_node(grandchild);
13138c2ecf20Sopenharmony_ci			unittest(pdev,
13148c2ecf20Sopenharmony_ci				 "Could not create device for node '%pOFn'\n",
13158c2ecf20Sopenharmony_ci				 grandchild);
13168c2ecf20Sopenharmony_ci			of_dev_put(pdev);
13178c2ecf20Sopenharmony_ci		}
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	of_platform_depopulate(&test_bus->dev);
13218c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child) {
13228c2ecf20Sopenharmony_ci		for_each_child_of_node(child, grandchild)
13238c2ecf20Sopenharmony_ci			unittest(!of_find_device_by_node(grandchild),
13248c2ecf20Sopenharmony_ci				 "device didn't get destroyed '%pOFn'\n",
13258c2ecf20Sopenharmony_ci				 grandchild);
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	platform_device_unregister(test_bus);
13298c2ecf20Sopenharmony_ci	of_node_put(np);
13308c2ecf20Sopenharmony_ci}
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci/**
13338c2ecf20Sopenharmony_ci *	update_node_properties - adds the properties
13348c2ecf20Sopenharmony_ci *	of np into dup node (present in live tree) and
13358c2ecf20Sopenharmony_ci *	updates parent of children of np to dup.
13368c2ecf20Sopenharmony_ci *
13378c2ecf20Sopenharmony_ci *	@np:	node whose properties are being added to the live tree
13388c2ecf20Sopenharmony_ci *	@dup:	node present in live tree to be updated
13398c2ecf20Sopenharmony_ci */
13408c2ecf20Sopenharmony_cistatic void update_node_properties(struct device_node *np,
13418c2ecf20Sopenharmony_ci					struct device_node *dup)
13428c2ecf20Sopenharmony_ci{
13438c2ecf20Sopenharmony_ci	struct property *prop;
13448c2ecf20Sopenharmony_ci	struct property *save_next;
13458c2ecf20Sopenharmony_ci	struct device_node *child;
13468c2ecf20Sopenharmony_ci	int ret;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child)
13498c2ecf20Sopenharmony_ci		child->parent = dup;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	/*
13528c2ecf20Sopenharmony_ci	 * "unittest internal error: unable to add testdata property"
13538c2ecf20Sopenharmony_ci	 *
13548c2ecf20Sopenharmony_ci	 *    If this message reports a property in node '/__symbols__' then
13558c2ecf20Sopenharmony_ci	 *    the respective unittest overlay contains a label that has the
13568c2ecf20Sopenharmony_ci	 *    same name as a label in the live devicetree.  The label will
13578c2ecf20Sopenharmony_ci	 *    be in the live devicetree only if the devicetree source was
13588c2ecf20Sopenharmony_ci	 *    compiled with the '-@' option.  If you encounter this error,
13598c2ecf20Sopenharmony_ci	 *    please consider renaming __all__ of the labels in the unittest
13608c2ecf20Sopenharmony_ci	 *    overlay dts files with an odd prefix that is unlikely to be
13618c2ecf20Sopenharmony_ci	 *    used in a real devicetree.
13628c2ecf20Sopenharmony_ci	 */
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/*
13658c2ecf20Sopenharmony_ci	 * open code for_each_property_of_node() because of_add_property()
13668c2ecf20Sopenharmony_ci	 * sets prop->next to NULL
13678c2ecf20Sopenharmony_ci	 */
13688c2ecf20Sopenharmony_ci	for (prop = np->properties; prop != NULL; prop = save_next) {
13698c2ecf20Sopenharmony_ci		save_next = prop->next;
13708c2ecf20Sopenharmony_ci		ret = of_add_property(dup, prop);
13718c2ecf20Sopenharmony_ci		if (ret) {
13728c2ecf20Sopenharmony_ci			if (ret == -EEXIST && !strcmp(prop->name, "name"))
13738c2ecf20Sopenharmony_ci				continue;
13748c2ecf20Sopenharmony_ci			pr_err("unittest internal error: unable to add testdata property %pOF/%s",
13758c2ecf20Sopenharmony_ci			       np, prop->name);
13768c2ecf20Sopenharmony_ci		}
13778c2ecf20Sopenharmony_ci	}
13788c2ecf20Sopenharmony_ci}
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci/**
13818c2ecf20Sopenharmony_ci *	attach_node_and_children - attaches nodes
13828c2ecf20Sopenharmony_ci *	and its children to live tree.
13838c2ecf20Sopenharmony_ci *	CAUTION: misleading function name - if node @np already exists in
13848c2ecf20Sopenharmony_ci *	the live tree then children of @np are *not* attached to the live
13858c2ecf20Sopenharmony_ci *	tree.  This works for the current test devicetree nodes because such
13868c2ecf20Sopenharmony_ci *	nodes do not have child nodes.
13878c2ecf20Sopenharmony_ci *
13888c2ecf20Sopenharmony_ci *	@np:	Node to attach to live tree
13898c2ecf20Sopenharmony_ci */
13908c2ecf20Sopenharmony_cistatic void attach_node_and_children(struct device_node *np)
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	struct device_node *next, *dup, *child;
13938c2ecf20Sopenharmony_ci	unsigned long flags;
13948c2ecf20Sopenharmony_ci	const char *full_name;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	full_name = kasprintf(GFP_KERNEL, "%pOF", np);
13978c2ecf20Sopenharmony_ci	if (!full_name)
13988c2ecf20Sopenharmony_ci		return;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	if (!strcmp(full_name, "/__local_fixups__") ||
14018c2ecf20Sopenharmony_ci	    !strcmp(full_name, "/__fixups__")) {
14028c2ecf20Sopenharmony_ci		kfree(full_name);
14038c2ecf20Sopenharmony_ci		return;
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	dup = of_find_node_by_path(full_name);
14078c2ecf20Sopenharmony_ci	kfree(full_name);
14088c2ecf20Sopenharmony_ci	if (dup) {
14098c2ecf20Sopenharmony_ci		update_node_properties(np, dup);
14108c2ecf20Sopenharmony_ci		return;
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	child = np->child;
14148c2ecf20Sopenharmony_ci	np->child = NULL;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	mutex_lock(&of_mutex);
14178c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&devtree_lock, flags);
14188c2ecf20Sopenharmony_ci	np->sibling = np->parent->child;
14198c2ecf20Sopenharmony_ci	np->parent->child = np;
14208c2ecf20Sopenharmony_ci	of_node_clear_flag(np, OF_DETACHED);
14218c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&devtree_lock, flags);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	__of_attach_node_sysfs(np);
14248c2ecf20Sopenharmony_ci	mutex_unlock(&of_mutex);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	while (child) {
14278c2ecf20Sopenharmony_ci		next = child->sibling;
14288c2ecf20Sopenharmony_ci		attach_node_and_children(child);
14298c2ecf20Sopenharmony_ci		child = next;
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci}
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci/**
14348c2ecf20Sopenharmony_ci *	unittest_data_add - Reads, copies data from
14358c2ecf20Sopenharmony_ci *	linked tree and attaches it to the live tree
14368c2ecf20Sopenharmony_ci */
14378c2ecf20Sopenharmony_cistatic int __init unittest_data_add(void)
14388c2ecf20Sopenharmony_ci{
14398c2ecf20Sopenharmony_ci	void *unittest_data;
14408c2ecf20Sopenharmony_ci	struct device_node *unittest_data_node, *np;
14418c2ecf20Sopenharmony_ci	/*
14428c2ecf20Sopenharmony_ci	 * __dtb_testcases_begin[] and __dtb_testcases_end[] are magically
14438c2ecf20Sopenharmony_ci	 * created by cmd_dt_S_dtb in scripts/Makefile.lib
14448c2ecf20Sopenharmony_ci	 */
14458c2ecf20Sopenharmony_ci	extern uint8_t __dtb_testcases_begin[];
14468c2ecf20Sopenharmony_ci	extern uint8_t __dtb_testcases_end[];
14478c2ecf20Sopenharmony_ci	const int size = __dtb_testcases_end - __dtb_testcases_begin;
14488c2ecf20Sopenharmony_ci	int rc;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	if (!size) {
14518c2ecf20Sopenharmony_ci		pr_warn("%s: No testcase data to attach; not running tests\n",
14528c2ecf20Sopenharmony_ci			__func__);
14538c2ecf20Sopenharmony_ci		return -ENODATA;
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	/* creating copy */
14578c2ecf20Sopenharmony_ci	unittest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL);
14588c2ecf20Sopenharmony_ci	if (!unittest_data)
14598c2ecf20Sopenharmony_ci		return -ENOMEM;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	of_fdt_unflatten_tree(unittest_data, NULL, &unittest_data_node);
14628c2ecf20Sopenharmony_ci	if (!unittest_data_node) {
14638c2ecf20Sopenharmony_ci		pr_warn("%s: No tree to attach; not running tests\n", __func__);
14648c2ecf20Sopenharmony_ci		kfree(unittest_data);
14658c2ecf20Sopenharmony_ci		return -ENODATA;
14668c2ecf20Sopenharmony_ci	}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	/*
14698c2ecf20Sopenharmony_ci	 * This lock normally encloses of_resolve_phandles()
14708c2ecf20Sopenharmony_ci	 */
14718c2ecf20Sopenharmony_ci	of_overlay_mutex_lock();
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	rc = of_resolve_phandles(unittest_data_node);
14748c2ecf20Sopenharmony_ci	if (rc) {
14758c2ecf20Sopenharmony_ci		pr_err("%s: Failed to resolve phandles (rc=%i)\n", __func__, rc);
14768c2ecf20Sopenharmony_ci		of_overlay_mutex_unlock();
14778c2ecf20Sopenharmony_ci		return -EINVAL;
14788c2ecf20Sopenharmony_ci	}
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	if (!of_root) {
14818c2ecf20Sopenharmony_ci		of_root = unittest_data_node;
14828c2ecf20Sopenharmony_ci		for_each_of_allnodes(np)
14838c2ecf20Sopenharmony_ci			__of_attach_node_sysfs(np);
14848c2ecf20Sopenharmony_ci		of_aliases = of_find_node_by_path("/aliases");
14858c2ecf20Sopenharmony_ci		of_chosen = of_find_node_by_path("/chosen");
14868c2ecf20Sopenharmony_ci		of_overlay_mutex_unlock();
14878c2ecf20Sopenharmony_ci		return 0;
14888c2ecf20Sopenharmony_ci	}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
14918c2ecf20Sopenharmony_ci		     "Duplicate name in testcase-data, renamed to \"duplicate-name#1\"");
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	/* attach the sub-tree to live tree */
14948c2ecf20Sopenharmony_ci	np = unittest_data_node->child;
14958c2ecf20Sopenharmony_ci	while (np) {
14968c2ecf20Sopenharmony_ci		struct device_node *next = np->sibling;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci		np->parent = of_root;
14998c2ecf20Sopenharmony_ci		attach_node_and_children(np);
15008c2ecf20Sopenharmony_ci		np = next;
15018c2ecf20Sopenharmony_ci	}
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
15048c2ecf20Sopenharmony_ci		   "Duplicate name in testcase-data, renamed to \"duplicate-name#1\"");
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	of_overlay_mutex_unlock();
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	return 0;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_OVERLAY
15128c2ecf20Sopenharmony_cistatic int __init overlay_data_apply(const char *overlay_name, int *overlay_id);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cistatic int unittest_probe(struct platform_device *pdev)
15158c2ecf20Sopenharmony_ci{
15168c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
15178c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	if (np == NULL) {
15208c2ecf20Sopenharmony_ci		dev_err(dev, "No OF data for device\n");
15218c2ecf20Sopenharmony_ci		return -EINVAL;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	of_platform_populate(np, NULL, NULL, &pdev->dev);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	return 0;
15308c2ecf20Sopenharmony_ci}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_cistatic int unittest_remove(struct platform_device *pdev)
15338c2ecf20Sopenharmony_ci{
15348c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
15358c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
15388c2ecf20Sopenharmony_ci	return 0;
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic const struct of_device_id unittest_match[] = {
15428c2ecf20Sopenharmony_ci	{ .compatible = "unittest", },
15438c2ecf20Sopenharmony_ci	{},
15448c2ecf20Sopenharmony_ci};
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_cistatic struct platform_driver unittest_driver = {
15478c2ecf20Sopenharmony_ci	.probe			= unittest_probe,
15488c2ecf20Sopenharmony_ci	.remove			= unittest_remove,
15498c2ecf20Sopenharmony_ci	.driver = {
15508c2ecf20Sopenharmony_ci		.name		= "unittest",
15518c2ecf20Sopenharmony_ci		.of_match_table	= of_match_ptr(unittest_match),
15528c2ecf20Sopenharmony_ci	},
15538c2ecf20Sopenharmony_ci};
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci/* get the platform device instantiated at the path */
15568c2ecf20Sopenharmony_cistatic struct platform_device *of_path_to_platform_device(const char *path)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	struct device_node *np;
15598c2ecf20Sopenharmony_ci	struct platform_device *pdev;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	np = of_find_node_by_path(path);
15628c2ecf20Sopenharmony_ci	if (np == NULL)
15638c2ecf20Sopenharmony_ci		return NULL;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	pdev = of_find_device_by_node(np);
15668c2ecf20Sopenharmony_ci	of_node_put(np);
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	return pdev;
15698c2ecf20Sopenharmony_ci}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci/* find out if a platform device exists at that path */
15728c2ecf20Sopenharmony_cistatic int of_path_platform_device_exists(const char *path)
15738c2ecf20Sopenharmony_ci{
15748c2ecf20Sopenharmony_ci	struct platform_device *pdev;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	pdev = of_path_to_platform_device(path);
15778c2ecf20Sopenharmony_ci	platform_device_put(pdev);
15788c2ecf20Sopenharmony_ci	return pdev != NULL;
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_GPIO
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cistruct unittest_gpio_dev {
15848c2ecf20Sopenharmony_ci	struct gpio_chip chip;
15858c2ecf20Sopenharmony_ci};
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_cistatic int unittest_gpio_chip_request_count;
15888c2ecf20Sopenharmony_cistatic int unittest_gpio_probe_count;
15898c2ecf20Sopenharmony_cistatic int unittest_gpio_probe_pass_count;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_cistatic int unittest_gpio_chip_request(struct gpio_chip *chip, unsigned int offset)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	unittest_gpio_chip_request_count++;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	pr_debug("%s(): %s %d %d\n", __func__, chip->label, offset,
15968c2ecf20Sopenharmony_ci		 unittest_gpio_chip_request_count);
15978c2ecf20Sopenharmony_ci	return 0;
15988c2ecf20Sopenharmony_ci}
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_cistatic int unittest_gpio_probe(struct platform_device *pdev)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	struct unittest_gpio_dev *devptr;
16038c2ecf20Sopenharmony_ci	int ret;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	unittest_gpio_probe_count++;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	devptr = kzalloc(sizeof(*devptr), GFP_KERNEL);
16088c2ecf20Sopenharmony_ci	if (!devptr)
16098c2ecf20Sopenharmony_ci		return -ENOMEM;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, devptr);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	devptr->chip.of_node = pdev->dev.of_node;
16148c2ecf20Sopenharmony_ci	devptr->chip.label = "of-unittest-gpio";
16158c2ecf20Sopenharmony_ci	devptr->chip.base = -1; /* dynamic allocation */
16168c2ecf20Sopenharmony_ci	devptr->chip.ngpio = 5;
16178c2ecf20Sopenharmony_ci	devptr->chip.request = unittest_gpio_chip_request;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	ret = gpiochip_add_data(&devptr->chip, NULL);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	unittest(!ret,
16228c2ecf20Sopenharmony_ci		 "gpiochip_add_data() for node @%pOF failed, ret = %d\n", devptr->chip.of_node, ret);
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	if (!ret)
16258c2ecf20Sopenharmony_ci		unittest_gpio_probe_pass_count++;
16268c2ecf20Sopenharmony_ci	return ret;
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic int unittest_gpio_remove(struct platform_device *pdev)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	struct unittest_gpio_dev *gdev = platform_get_drvdata(pdev);
16328c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
16338c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	if (!gdev)
16388c2ecf20Sopenharmony_ci		return -EINVAL;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	if (gdev->chip.base != -1)
16418c2ecf20Sopenharmony_ci		gpiochip_remove(&gdev->chip);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, NULL);
16448c2ecf20Sopenharmony_ci	kfree(gdev);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	return 0;
16478c2ecf20Sopenharmony_ci}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_cistatic const struct of_device_id unittest_gpio_id[] = {
16508c2ecf20Sopenharmony_ci	{ .compatible = "unittest-gpio", },
16518c2ecf20Sopenharmony_ci	{}
16528c2ecf20Sopenharmony_ci};
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_cistatic struct platform_driver unittest_gpio_driver = {
16558c2ecf20Sopenharmony_ci	.probe	= unittest_gpio_probe,
16568c2ecf20Sopenharmony_ci	.remove	= unittest_gpio_remove,
16578c2ecf20Sopenharmony_ci	.driver	= {
16588c2ecf20Sopenharmony_ci		.name		= "unittest-gpio",
16598c2ecf20Sopenharmony_ci		.of_match_table	= of_match_ptr(unittest_gpio_id),
16608c2ecf20Sopenharmony_ci	},
16618c2ecf20Sopenharmony_ci};
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_gpio(void)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	int chip_request_count;
16668c2ecf20Sopenharmony_ci	int probe_pass_count;
16678c2ecf20Sopenharmony_ci	int ret;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	/*
16708c2ecf20Sopenharmony_ci	 * tests: apply overlays before registering driver
16718c2ecf20Sopenharmony_ci	 * Similar to installing a driver as a module, the
16728c2ecf20Sopenharmony_ci	 * driver is registered after applying the overlays.
16738c2ecf20Sopenharmony_ci	 *
16748c2ecf20Sopenharmony_ci	 * The overlays are applied by overlay_data_apply()
16758c2ecf20Sopenharmony_ci	 * instead of of_unittest_apply_overlay() so that they
16768c2ecf20Sopenharmony_ci	 * will not be tracked.  Thus they will not be removed
16778c2ecf20Sopenharmony_ci	 * by of_unittest_destroy_tracked_overlays().
16788c2ecf20Sopenharmony_ci	 *
16798c2ecf20Sopenharmony_ci	 * - apply overlay_gpio_01
16808c2ecf20Sopenharmony_ci	 * - apply overlay_gpio_02a
16818c2ecf20Sopenharmony_ci	 * - apply overlay_gpio_02b
16828c2ecf20Sopenharmony_ci	 * - register driver
16838c2ecf20Sopenharmony_ci	 *
16848c2ecf20Sopenharmony_ci	 * register driver will result in
16858c2ecf20Sopenharmony_ci	 *   - probe and processing gpio hog for overlay_gpio_01
16868c2ecf20Sopenharmony_ci	 *   - probe for overlay_gpio_02a
16878c2ecf20Sopenharmony_ci	 *   - processing gpio for overlay_gpio_02b
16888c2ecf20Sopenharmony_ci	 */
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	probe_pass_count = unittest_gpio_probe_pass_count;
16918c2ecf20Sopenharmony_ci	chip_request_count = unittest_gpio_chip_request_count;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	/*
16948c2ecf20Sopenharmony_ci	 * overlay_gpio_01 contains gpio node and child gpio hog node
16958c2ecf20Sopenharmony_ci	 * overlay_gpio_02a contains gpio node
16968c2ecf20Sopenharmony_ci	 * overlay_gpio_02b contains child gpio hog node
16978c2ecf20Sopenharmony_ci	 */
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_gpio_01", NULL),
17008c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_gpio_01' failed\n");
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_gpio_02a", NULL),
17038c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_gpio_02a' failed\n");
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_gpio_02b", NULL),
17068c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_gpio_02b' failed\n");
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	/*
17098c2ecf20Sopenharmony_ci	 * messages are the result of the probes, after the
17108c2ecf20Sopenharmony_ci	 * driver is registered
17118c2ecf20Sopenharmony_ci	 */
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
17148c2ecf20Sopenharmony_ci		     "gpio-<<int>> (line-B-input): hogged as input\n");
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
17178c2ecf20Sopenharmony_ci		     "gpio-<<int>> (line-A-input): hogged as input\n");
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	ret = platform_driver_register(&unittest_gpio_driver);
17208c2ecf20Sopenharmony_ci	if (unittest(ret == 0, "could not register unittest gpio driver\n"))
17218c2ecf20Sopenharmony_ci		return;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
17248c2ecf20Sopenharmony_ci		   "gpio-<<int>> (line-A-input): hogged as input\n");
17258c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
17268c2ecf20Sopenharmony_ci		   "gpio-<<int>> (line-B-input): hogged as input\n");
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	unittest(probe_pass_count + 2 == unittest_gpio_probe_pass_count,
17298c2ecf20Sopenharmony_ci		 "unittest_gpio_probe() failed or not called\n");
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	unittest(chip_request_count + 2 == unittest_gpio_chip_request_count,
17328c2ecf20Sopenharmony_ci		 "unittest_gpio_chip_request() called %d times (expected 1 time)\n",
17338c2ecf20Sopenharmony_ci		 unittest_gpio_chip_request_count - chip_request_count);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	/*
17368c2ecf20Sopenharmony_ci	 * tests: apply overlays after registering driver
17378c2ecf20Sopenharmony_ci	 *
17388c2ecf20Sopenharmony_ci	 * Similar to a driver built-in to the kernel, the
17398c2ecf20Sopenharmony_ci	 * driver is registered before applying the overlays.
17408c2ecf20Sopenharmony_ci	 *
17418c2ecf20Sopenharmony_ci	 * overlay_gpio_03 contains gpio node and child gpio hog node
17428c2ecf20Sopenharmony_ci	 *
17438c2ecf20Sopenharmony_ci	 * - apply overlay_gpio_03
17448c2ecf20Sopenharmony_ci	 *
17458c2ecf20Sopenharmony_ci	 * apply overlay will result in
17468c2ecf20Sopenharmony_ci	 *   - probe and processing gpio hog.
17478c2ecf20Sopenharmony_ci	 */
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	probe_pass_count = unittest_gpio_probe_pass_count;
17508c2ecf20Sopenharmony_ci	chip_request_count = unittest_gpio_chip_request_count;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
17538c2ecf20Sopenharmony_ci		     "gpio-<<int>> (line-D-input): hogged as input\n");
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	/* overlay_gpio_03 contains gpio node and child gpio hog node */
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_gpio_03", NULL),
17588c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_gpio_03' failed\n");
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
17618c2ecf20Sopenharmony_ci		   "gpio-<<int>> (line-D-input): hogged as input\n");
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci	unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count,
17648c2ecf20Sopenharmony_ci		 "unittest_gpio_probe() failed or not called\n");
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	unittest(chip_request_count + 1 == unittest_gpio_chip_request_count,
17678c2ecf20Sopenharmony_ci		 "unittest_gpio_chip_request() called %d times (expected 1 time)\n",
17688c2ecf20Sopenharmony_ci		 unittest_gpio_chip_request_count - chip_request_count);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	/*
17718c2ecf20Sopenharmony_ci	 * overlay_gpio_04a contains gpio node
17728c2ecf20Sopenharmony_ci	 *
17738c2ecf20Sopenharmony_ci	 * - apply overlay_gpio_04a
17748c2ecf20Sopenharmony_ci	 *
17758c2ecf20Sopenharmony_ci	 * apply the overlay will result in
17768c2ecf20Sopenharmony_ci	 *   - probe for overlay_gpio_04a
17778c2ecf20Sopenharmony_ci	 */
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	probe_pass_count = unittest_gpio_probe_pass_count;
17808c2ecf20Sopenharmony_ci	chip_request_count = unittest_gpio_chip_request_count;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	/* overlay_gpio_04a contains gpio node */
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_gpio_04a", NULL),
17858c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_gpio_04a' failed\n");
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count,
17888c2ecf20Sopenharmony_ci		 "unittest_gpio_probe() failed or not called\n");
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	/*
17918c2ecf20Sopenharmony_ci	 * overlay_gpio_04b contains child gpio hog node
17928c2ecf20Sopenharmony_ci	 *
17938c2ecf20Sopenharmony_ci	 * - apply overlay_gpio_04b
17948c2ecf20Sopenharmony_ci	 *
17958c2ecf20Sopenharmony_ci	 * apply the overlay will result in
17968c2ecf20Sopenharmony_ci	 *   - processing gpio for overlay_gpio_04b
17978c2ecf20Sopenharmony_ci	 */
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
18008c2ecf20Sopenharmony_ci		     "gpio-<<int>> (line-C-input): hogged as input\n");
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	/* overlay_gpio_04b contains child gpio hog node */
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_gpio_04b", NULL),
18058c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_gpio_04b' failed\n");
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
18088c2ecf20Sopenharmony_ci		   "gpio-<<int>> (line-C-input): hogged as input\n");
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	unittest(chip_request_count + 1 == unittest_gpio_chip_request_count,
18118c2ecf20Sopenharmony_ci		 "unittest_gpio_chip_request() called %d times (expected 1 time)\n",
18128c2ecf20Sopenharmony_ci		 unittest_gpio_chip_request_count - chip_request_count);
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci#else
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_gpio(void)
18188c2ecf20Sopenharmony_ci{
18198c2ecf20Sopenharmony_ci	/* skip tests */
18208c2ecf20Sopenharmony_ci}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci#endif
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C)
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci/* get the i2c client device instantiated at the path */
18278c2ecf20Sopenharmony_cistatic struct i2c_client *of_path_to_i2c_client(const char *path)
18288c2ecf20Sopenharmony_ci{
18298c2ecf20Sopenharmony_ci	struct device_node *np;
18308c2ecf20Sopenharmony_ci	struct i2c_client *client;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	np = of_find_node_by_path(path);
18338c2ecf20Sopenharmony_ci	if (np == NULL)
18348c2ecf20Sopenharmony_ci		return NULL;
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	client = of_find_i2c_device_by_node(np);
18378c2ecf20Sopenharmony_ci	of_node_put(np);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	return client;
18408c2ecf20Sopenharmony_ci}
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci/* find out if a i2c client device exists at that path */
18438c2ecf20Sopenharmony_cistatic int of_path_i2c_client_exists(const char *path)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	struct i2c_client *client;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	client = of_path_to_i2c_client(path);
18488c2ecf20Sopenharmony_ci	if (client)
18498c2ecf20Sopenharmony_ci		put_device(&client->dev);
18508c2ecf20Sopenharmony_ci	return client != NULL;
18518c2ecf20Sopenharmony_ci}
18528c2ecf20Sopenharmony_ci#else
18538c2ecf20Sopenharmony_cistatic int of_path_i2c_client_exists(const char *path)
18548c2ecf20Sopenharmony_ci{
18558c2ecf20Sopenharmony_ci	return 0;
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci#endif
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_cienum overlay_type {
18608c2ecf20Sopenharmony_ci	PDEV_OVERLAY,
18618c2ecf20Sopenharmony_ci	I2C_OVERLAY
18628c2ecf20Sopenharmony_ci};
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_cistatic int of_path_device_type_exists(const char *path,
18658c2ecf20Sopenharmony_ci		enum overlay_type ovtype)
18668c2ecf20Sopenharmony_ci{
18678c2ecf20Sopenharmony_ci	switch (ovtype) {
18688c2ecf20Sopenharmony_ci	case PDEV_OVERLAY:
18698c2ecf20Sopenharmony_ci		return of_path_platform_device_exists(path);
18708c2ecf20Sopenharmony_ci	case I2C_OVERLAY:
18718c2ecf20Sopenharmony_ci		return of_path_i2c_client_exists(path);
18728c2ecf20Sopenharmony_ci	}
18738c2ecf20Sopenharmony_ci	return 0;
18748c2ecf20Sopenharmony_ci}
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_cistatic const char *unittest_path(int nr, enum overlay_type ovtype)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	const char *base;
18798c2ecf20Sopenharmony_ci	static char buf[256];
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	switch (ovtype) {
18828c2ecf20Sopenharmony_ci	case PDEV_OVERLAY:
18838c2ecf20Sopenharmony_ci		base = "/testcase-data/overlay-node/test-bus";
18848c2ecf20Sopenharmony_ci		break;
18858c2ecf20Sopenharmony_ci	case I2C_OVERLAY:
18868c2ecf20Sopenharmony_ci		base = "/testcase-data/overlay-node/test-bus/i2c-test-bus";
18878c2ecf20Sopenharmony_ci		break;
18888c2ecf20Sopenharmony_ci	default:
18898c2ecf20Sopenharmony_ci		buf[0] = '\0';
18908c2ecf20Sopenharmony_ci		return buf;
18918c2ecf20Sopenharmony_ci	}
18928c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf) - 1, "%s/test-unittest%d", base, nr);
18938c2ecf20Sopenharmony_ci	buf[sizeof(buf) - 1] = '\0';
18948c2ecf20Sopenharmony_ci	return buf;
18958c2ecf20Sopenharmony_ci}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_cistatic int of_unittest_device_exists(int unittest_nr, enum overlay_type ovtype)
18988c2ecf20Sopenharmony_ci{
18998c2ecf20Sopenharmony_ci	const char *path;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	path = unittest_path(unittest_nr, ovtype);
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	switch (ovtype) {
19048c2ecf20Sopenharmony_ci	case PDEV_OVERLAY:
19058c2ecf20Sopenharmony_ci		return of_path_platform_device_exists(path);
19068c2ecf20Sopenharmony_ci	case I2C_OVERLAY:
19078c2ecf20Sopenharmony_ci		return of_path_i2c_client_exists(path);
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci	return 0;
19108c2ecf20Sopenharmony_ci}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_cistatic const char *overlay_name_from_nr(int nr)
19138c2ecf20Sopenharmony_ci{
19148c2ecf20Sopenharmony_ci	static char buf[256];
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	snprintf(buf, sizeof(buf) - 1,
19178c2ecf20Sopenharmony_ci		"overlay_%d", nr);
19188c2ecf20Sopenharmony_ci	buf[sizeof(buf) - 1] = '\0';
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	return buf;
19218c2ecf20Sopenharmony_ci}
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_cistatic const char *bus_path = "/testcase-data/overlay-node/test-bus";
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci/* FIXME: it is NOT guaranteed that overlay ids are assigned in sequence */
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci#define MAX_UNITTEST_OVERLAYS	256
19288c2ecf20Sopenharmony_cistatic unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_UNITTEST_OVERLAYS)];
19298c2ecf20Sopenharmony_cistatic int overlay_first_id = -1;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_cistatic long of_unittest_overlay_tracked(int id)
19328c2ecf20Sopenharmony_ci{
19338c2ecf20Sopenharmony_ci	if (WARN_ON(id >= MAX_UNITTEST_OVERLAYS))
19348c2ecf20Sopenharmony_ci		return 0;
19358c2ecf20Sopenharmony_ci	return overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id);
19368c2ecf20Sopenharmony_ci}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_cistatic void of_unittest_track_overlay(int id)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	if (overlay_first_id < 0)
19418c2ecf20Sopenharmony_ci		overlay_first_id = id;
19428c2ecf20Sopenharmony_ci	id -= overlay_first_id;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	if (WARN_ON(id >= MAX_UNITTEST_OVERLAYS))
19458c2ecf20Sopenharmony_ci		return;
19468c2ecf20Sopenharmony_ci	overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id);
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic void of_unittest_untrack_overlay(int id)
19508c2ecf20Sopenharmony_ci{
19518c2ecf20Sopenharmony_ci	if (overlay_first_id < 0)
19528c2ecf20Sopenharmony_ci		return;
19538c2ecf20Sopenharmony_ci	id -= overlay_first_id;
19548c2ecf20Sopenharmony_ci	if (WARN_ON(id >= MAX_UNITTEST_OVERLAYS))
19558c2ecf20Sopenharmony_ci		return;
19568c2ecf20Sopenharmony_ci	overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_cistatic void of_unittest_destroy_tracked_overlays(void)
19608c2ecf20Sopenharmony_ci{
19618c2ecf20Sopenharmony_ci	int id, ret, defers, ovcs_id;
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	if (overlay_first_id < 0)
19648c2ecf20Sopenharmony_ci		return;
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	/* try until no defers */
19678c2ecf20Sopenharmony_ci	do {
19688c2ecf20Sopenharmony_ci		defers = 0;
19698c2ecf20Sopenharmony_ci		/* remove in reverse order */
19708c2ecf20Sopenharmony_ci		for (id = MAX_UNITTEST_OVERLAYS - 1; id >= 0; id--) {
19718c2ecf20Sopenharmony_ci			if (!of_unittest_overlay_tracked(id))
19728c2ecf20Sopenharmony_ci				continue;
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci			ovcs_id = id + overlay_first_id;
19758c2ecf20Sopenharmony_ci			ret = of_overlay_remove(&ovcs_id);
19768c2ecf20Sopenharmony_ci			if (ret == -ENODEV) {
19778c2ecf20Sopenharmony_ci				pr_warn("%s: no overlay to destroy for #%d\n",
19788c2ecf20Sopenharmony_ci					__func__, id + overlay_first_id);
19798c2ecf20Sopenharmony_ci				continue;
19808c2ecf20Sopenharmony_ci			}
19818c2ecf20Sopenharmony_ci			if (ret != 0) {
19828c2ecf20Sopenharmony_ci				defers++;
19838c2ecf20Sopenharmony_ci				pr_warn("%s: overlay destroy failed for #%d\n",
19848c2ecf20Sopenharmony_ci					__func__, id + overlay_first_id);
19858c2ecf20Sopenharmony_ci				continue;
19868c2ecf20Sopenharmony_ci			}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci			of_unittest_untrack_overlay(id);
19898c2ecf20Sopenharmony_ci		}
19908c2ecf20Sopenharmony_ci	} while (defers > 0);
19918c2ecf20Sopenharmony_ci}
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_cistatic int __init of_unittest_apply_overlay(int overlay_nr, int *overlay_id)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	const char *overlay_name;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	overlay_name = overlay_name_from_nr(overlay_nr);
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	if (!overlay_data_apply(overlay_name, overlay_id)) {
20008c2ecf20Sopenharmony_ci		unittest(0, "could not apply overlay \"%s\"\n",
20018c2ecf20Sopenharmony_ci				overlay_name);
20028c2ecf20Sopenharmony_ci		return -EFAULT;
20038c2ecf20Sopenharmony_ci	}
20048c2ecf20Sopenharmony_ci	of_unittest_track_overlay(*overlay_id);
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	return 0;
20078c2ecf20Sopenharmony_ci}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci/* apply an overlay while checking before and after states */
20108c2ecf20Sopenharmony_cistatic int __init of_unittest_apply_overlay_check(int overlay_nr,
20118c2ecf20Sopenharmony_ci		int unittest_nr, int before, int after,
20128c2ecf20Sopenharmony_ci		enum overlay_type ovtype)
20138c2ecf20Sopenharmony_ci{
20148c2ecf20Sopenharmony_ci	int ret, ovcs_id;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	/* unittest device must not be in before state */
20178c2ecf20Sopenharmony_ci	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
20188c2ecf20Sopenharmony_ci		unittest(0, "%s with device @\"%s\" %s\n",
20198c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr),
20208c2ecf20Sopenharmony_ci				unittest_path(unittest_nr, ovtype),
20218c2ecf20Sopenharmony_ci				!before ? "enabled" : "disabled");
20228c2ecf20Sopenharmony_ci		return -EINVAL;
20238c2ecf20Sopenharmony_ci	}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	ovcs_id = 0;
20268c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay(overlay_nr, &ovcs_id);
20278c2ecf20Sopenharmony_ci	if (ret != 0) {
20288c2ecf20Sopenharmony_ci		/* of_unittest_apply_overlay already called unittest() */
20298c2ecf20Sopenharmony_ci		return ret;
20308c2ecf20Sopenharmony_ci	}
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	/* unittest device must be to set to after state */
20338c2ecf20Sopenharmony_ci	if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
20348c2ecf20Sopenharmony_ci		unittest(0, "%s failed to create @\"%s\" %s\n",
20358c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr),
20368c2ecf20Sopenharmony_ci				unittest_path(unittest_nr, ovtype),
20378c2ecf20Sopenharmony_ci				!after ? "enabled" : "disabled");
20388c2ecf20Sopenharmony_ci		return -EINVAL;
20398c2ecf20Sopenharmony_ci	}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	return 0;
20428c2ecf20Sopenharmony_ci}
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci/* apply an overlay and then revert it while checking before, after states */
20458c2ecf20Sopenharmony_cistatic int __init of_unittest_apply_revert_overlay_check(int overlay_nr,
20468c2ecf20Sopenharmony_ci		int unittest_nr, int before, int after,
20478c2ecf20Sopenharmony_ci		enum overlay_type ovtype)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	int ret, ovcs_id, save_id;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	/* unittest device must be in before state */
20528c2ecf20Sopenharmony_ci	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
20538c2ecf20Sopenharmony_ci		unittest(0, "%s with device @\"%s\" %s\n",
20548c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr),
20558c2ecf20Sopenharmony_ci				unittest_path(unittest_nr, ovtype),
20568c2ecf20Sopenharmony_ci				!before ? "enabled" : "disabled");
20578c2ecf20Sopenharmony_ci		return -EINVAL;
20588c2ecf20Sopenharmony_ci	}
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	/* apply the overlay */
20618c2ecf20Sopenharmony_ci	ovcs_id = 0;
20628c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay(overlay_nr, &ovcs_id);
20638c2ecf20Sopenharmony_ci	if (ret != 0) {
20648c2ecf20Sopenharmony_ci		/* of_unittest_apply_overlay already called unittest() */
20658c2ecf20Sopenharmony_ci		return ret;
20668c2ecf20Sopenharmony_ci	}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	/* unittest device must be in after state */
20698c2ecf20Sopenharmony_ci	if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
20708c2ecf20Sopenharmony_ci		unittest(0, "%s failed to create @\"%s\" %s\n",
20718c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr),
20728c2ecf20Sopenharmony_ci				unittest_path(unittest_nr, ovtype),
20738c2ecf20Sopenharmony_ci				!after ? "enabled" : "disabled");
20748c2ecf20Sopenharmony_ci		return -EINVAL;
20758c2ecf20Sopenharmony_ci	}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	save_id = ovcs_id;
20788c2ecf20Sopenharmony_ci	ret = of_overlay_remove(&ovcs_id);
20798c2ecf20Sopenharmony_ci	if (ret != 0) {
20808c2ecf20Sopenharmony_ci		unittest(0, "%s failed to be destroyed @\"%s\"\n",
20818c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr),
20828c2ecf20Sopenharmony_ci				unittest_path(unittest_nr, ovtype));
20838c2ecf20Sopenharmony_ci		return ret;
20848c2ecf20Sopenharmony_ci	}
20858c2ecf20Sopenharmony_ci	of_unittest_untrack_overlay(save_id);
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	/* unittest device must be again in before state */
20888c2ecf20Sopenharmony_ci	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
20898c2ecf20Sopenharmony_ci		unittest(0, "%s with device @\"%s\" %s\n",
20908c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr),
20918c2ecf20Sopenharmony_ci				unittest_path(unittest_nr, ovtype),
20928c2ecf20Sopenharmony_ci				!before ? "enabled" : "disabled");
20938c2ecf20Sopenharmony_ci		return -EINVAL;
20948c2ecf20Sopenharmony_ci	}
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	return 0;
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci/* test activation of device */
21008c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_0(void)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	int ret;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
21058c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest0/status");
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	/* device should enable */
21088c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY);
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
21118c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest0/status");
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	if (ret)
21148c2ecf20Sopenharmony_ci		return;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 0);
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci/* test deactivation of device */
21208c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_1(void)
21218c2ecf20Sopenharmony_ci{
21228c2ecf20Sopenharmony_ci	int ret;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
21258c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest1/status");
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	/* device should disable */
21288c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
21318c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest1/status");
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	if (ret)
21348c2ecf20Sopenharmony_ci		return;
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 1);
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci}
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci/* test activation of device */
21418c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_2(void)
21428c2ecf20Sopenharmony_ci{
21438c2ecf20Sopenharmony_ci	int ret;
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
21468c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest2/status");
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	/* device should enable */
21498c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY);
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
21528c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest2/status");
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	if (ret)
21558c2ecf20Sopenharmony_ci		return;
21568c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 2);
21578c2ecf20Sopenharmony_ci}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci/* test deactivation of device */
21608c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_3(void)
21618c2ecf20Sopenharmony_ci{
21628c2ecf20Sopenharmony_ci	int ret;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
21658c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest3/status");
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	/* device should disable */
21688c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY);
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
21718c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest3/status");
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	if (ret)
21748c2ecf20Sopenharmony_ci		return;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 3);
21778c2ecf20Sopenharmony_ci}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci/* test activation of a full device node */
21808c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_4(void)
21818c2ecf20Sopenharmony_ci{
21828c2ecf20Sopenharmony_ci	/* device should disable */
21838c2ecf20Sopenharmony_ci	if (of_unittest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY))
21848c2ecf20Sopenharmony_ci		return;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 4);
21878c2ecf20Sopenharmony_ci}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci/* test overlay apply/revert sequence */
21908c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_5(void)
21918c2ecf20Sopenharmony_ci{
21928c2ecf20Sopenharmony_ci	int ret;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
21958c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest5/status");
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	/* device should disable */
21988c2ecf20Sopenharmony_ci	ret = of_unittest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
22018c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest5/status");
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	if (ret)
22048c2ecf20Sopenharmony_ci		return;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 5);
22078c2ecf20Sopenharmony_ci}
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci/* test overlay application in sequence */
22108c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_6(void)
22118c2ecf20Sopenharmony_ci{
22128c2ecf20Sopenharmony_ci	int i, ov_id[2], ovcs_id;
22138c2ecf20Sopenharmony_ci	int overlay_nr = 6, unittest_nr = 6;
22148c2ecf20Sopenharmony_ci	int before = 0, after = 1;
22158c2ecf20Sopenharmony_ci	const char *overlay_name;
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci	int ret;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	/* unittest device must be in before state */
22208c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
22218c2ecf20Sopenharmony_ci		if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
22228c2ecf20Sopenharmony_ci				!= before) {
22238c2ecf20Sopenharmony_ci			unittest(0, "%s with device @\"%s\" %s\n",
22248c2ecf20Sopenharmony_ci					overlay_name_from_nr(overlay_nr + i),
22258c2ecf20Sopenharmony_ci					unittest_path(unittest_nr + i,
22268c2ecf20Sopenharmony_ci						PDEV_OVERLAY),
22278c2ecf20Sopenharmony_ci					!before ? "enabled" : "disabled");
22288c2ecf20Sopenharmony_ci			return;
22298c2ecf20Sopenharmony_ci		}
22308c2ecf20Sopenharmony_ci	}
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	/* apply the overlays */
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
22358c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest6/status");
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	overlay_name = overlay_name_from_nr(overlay_nr + 0);
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	ret = overlay_data_apply(overlay_name, &ovcs_id);
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	if (!ret) {
22428c2ecf20Sopenharmony_ci		unittest(0, "could not apply overlay \"%s\"\n", overlay_name);
22438c2ecf20Sopenharmony_ci			return;
22448c2ecf20Sopenharmony_ci	}
22458c2ecf20Sopenharmony_ci	ov_id[0] = ovcs_id;
22468c2ecf20Sopenharmony_ci	of_unittest_track_overlay(ov_id[0]);
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
22498c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest6/status");
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
22528c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest7/status");
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	overlay_name = overlay_name_from_nr(overlay_nr + 1);
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	ret = overlay_data_apply(overlay_name, &ovcs_id);
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci	if (!ret) {
22598c2ecf20Sopenharmony_ci		unittest(0, "could not apply overlay \"%s\"\n", overlay_name);
22608c2ecf20Sopenharmony_ci			return;
22618c2ecf20Sopenharmony_ci	}
22628c2ecf20Sopenharmony_ci	ov_id[1] = ovcs_id;
22638c2ecf20Sopenharmony_ci	of_unittest_track_overlay(ov_id[1]);
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
22668c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest7/status");
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci
22698c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
22708c2ecf20Sopenharmony_ci		/* unittest device must be in after state */
22718c2ecf20Sopenharmony_ci		if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
22728c2ecf20Sopenharmony_ci				!= after) {
22738c2ecf20Sopenharmony_ci			unittest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
22748c2ecf20Sopenharmony_ci					overlay_name_from_nr(overlay_nr + i),
22758c2ecf20Sopenharmony_ci					unittest_path(unittest_nr + i,
22768c2ecf20Sopenharmony_ci						PDEV_OVERLAY),
22778c2ecf20Sopenharmony_ci					!after ? "enabled" : "disabled");
22788c2ecf20Sopenharmony_ci			return;
22798c2ecf20Sopenharmony_ci		}
22808c2ecf20Sopenharmony_ci	}
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	for (i = 1; i >= 0; i--) {
22838c2ecf20Sopenharmony_ci		ovcs_id = ov_id[i];
22848c2ecf20Sopenharmony_ci		if (of_overlay_remove(&ovcs_id)) {
22858c2ecf20Sopenharmony_ci			unittest(0, "%s failed destroy @\"%s\"\n",
22868c2ecf20Sopenharmony_ci					overlay_name_from_nr(overlay_nr + i),
22878c2ecf20Sopenharmony_ci					unittest_path(unittest_nr + i,
22888c2ecf20Sopenharmony_ci						PDEV_OVERLAY));
22898c2ecf20Sopenharmony_ci			return;
22908c2ecf20Sopenharmony_ci		}
22918c2ecf20Sopenharmony_ci		of_unittest_untrack_overlay(ov_id[i]);
22928c2ecf20Sopenharmony_ci	}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
22958c2ecf20Sopenharmony_ci		/* unittest device must be again in before state */
22968c2ecf20Sopenharmony_ci		if (of_unittest_device_exists(unittest_nr + i, PDEV_OVERLAY)
22978c2ecf20Sopenharmony_ci				!= before) {
22988c2ecf20Sopenharmony_ci			unittest(0, "%s with device @\"%s\" %s\n",
22998c2ecf20Sopenharmony_ci					overlay_name_from_nr(overlay_nr + i),
23008c2ecf20Sopenharmony_ci					unittest_path(unittest_nr + i,
23018c2ecf20Sopenharmony_ci						PDEV_OVERLAY),
23028c2ecf20Sopenharmony_ci					!before ? "enabled" : "disabled");
23038c2ecf20Sopenharmony_ci			return;
23048c2ecf20Sopenharmony_ci		}
23058c2ecf20Sopenharmony_ci	}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 6);
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci/* test overlay application in sequence */
23128c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_8(void)
23138c2ecf20Sopenharmony_ci{
23148c2ecf20Sopenharmony_ci	int i, ov_id[2], ovcs_id;
23158c2ecf20Sopenharmony_ci	int overlay_nr = 8, unittest_nr = 8;
23168c2ecf20Sopenharmony_ci	const char *overlay_name;
23178c2ecf20Sopenharmony_ci	int ret;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	/* we don't care about device state in this test */
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
23228c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/status");
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	overlay_name = overlay_name_from_nr(overlay_nr + 0);
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	ret = overlay_data_apply(overlay_name, &ovcs_id);
23278c2ecf20Sopenharmony_ci	if (!ret)
23288c2ecf20Sopenharmony_ci		unittest(0, "could not apply overlay \"%s\"\n", overlay_name);
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
23318c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/status");
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	if (!ret)
23348c2ecf20Sopenharmony_ci		return;
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	ov_id[0] = ovcs_id;
23378c2ecf20Sopenharmony_ci	of_unittest_track_overlay(ov_id[0]);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	overlay_name = overlay_name_from_nr(overlay_nr + 1);
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
23428c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/property-foo");
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	/* apply the overlays */
23458c2ecf20Sopenharmony_ci	ret = overlay_data_apply(overlay_name, &ovcs_id);
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
23488c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/test-unittest8/property-foo");
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	if (!ret) {
23518c2ecf20Sopenharmony_ci		unittest(0, "could not apply overlay \"%s\"\n", overlay_name);
23528c2ecf20Sopenharmony_ci		return;
23538c2ecf20Sopenharmony_ci	}
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	ov_id[1] = ovcs_id;
23568c2ecf20Sopenharmony_ci	of_unittest_track_overlay(ov_id[1]);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	/* now try to remove first overlay (it should fail) */
23598c2ecf20Sopenharmony_ci	ovcs_id = ov_id[0];
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
23628c2ecf20Sopenharmony_ci		     "OF: overlay: node_overlaps_later_cs: #6 overlaps with #7 @/testcase-data/overlay-node/test-bus/test-unittest8");
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
23658c2ecf20Sopenharmony_ci		     "OF: overlay: overlay #6 is not topmost");
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	ret = of_overlay_remove(&ovcs_id);
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
23708c2ecf20Sopenharmony_ci		   "OF: overlay: overlay #6 is not topmost");
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
23738c2ecf20Sopenharmony_ci		   "OF: overlay: node_overlaps_later_cs: #6 overlaps with #7 @/testcase-data/overlay-node/test-bus/test-unittest8");
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	if (!ret) {
23768c2ecf20Sopenharmony_ci		unittest(0, "%s was destroyed @\"%s\"\n",
23778c2ecf20Sopenharmony_ci				overlay_name_from_nr(overlay_nr + 0),
23788c2ecf20Sopenharmony_ci				unittest_path(unittest_nr,
23798c2ecf20Sopenharmony_ci					PDEV_OVERLAY));
23808c2ecf20Sopenharmony_ci		return;
23818c2ecf20Sopenharmony_ci	}
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	/* removing them in order should work */
23848c2ecf20Sopenharmony_ci	for (i = 1; i >= 0; i--) {
23858c2ecf20Sopenharmony_ci		ovcs_id = ov_id[i];
23868c2ecf20Sopenharmony_ci		if (of_overlay_remove(&ovcs_id)) {
23878c2ecf20Sopenharmony_ci			unittest(0, "%s not destroyed @\"%s\"\n",
23888c2ecf20Sopenharmony_ci					overlay_name_from_nr(overlay_nr + i),
23898c2ecf20Sopenharmony_ci					unittest_path(unittest_nr,
23908c2ecf20Sopenharmony_ci						PDEV_OVERLAY));
23918c2ecf20Sopenharmony_ci			return;
23928c2ecf20Sopenharmony_ci		}
23938c2ecf20Sopenharmony_ci		of_unittest_untrack_overlay(ov_id[i]);
23948c2ecf20Sopenharmony_ci	}
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 8);
23978c2ecf20Sopenharmony_ci}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci/* test insertion of a bus with parent devices */
24008c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_10(void)
24018c2ecf20Sopenharmony_ci{
24028c2ecf20Sopenharmony_ci	int ret;
24038c2ecf20Sopenharmony_ci	char *child_path;
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	/* device should disable */
24068c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY);
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	if (unittest(ret == 0,
24098c2ecf20Sopenharmony_ci			"overlay test %d failed; overlay application\n", 10))
24108c2ecf20Sopenharmony_ci		return;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	child_path = kasprintf(GFP_KERNEL, "%s/test-unittest101",
24138c2ecf20Sopenharmony_ci			unittest_path(10, PDEV_OVERLAY));
24148c2ecf20Sopenharmony_ci	if (unittest(child_path, "overlay test %d failed; kasprintf\n", 10))
24158c2ecf20Sopenharmony_ci		return;
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	ret = of_path_device_type_exists(child_path, PDEV_OVERLAY);
24188c2ecf20Sopenharmony_ci	kfree(child_path);
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	unittest(ret, "overlay test %d failed; no child device\n", 10);
24218c2ecf20Sopenharmony_ci}
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci/* test insertion of a bus with parent devices (and revert) */
24248c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_11(void)
24258c2ecf20Sopenharmony_ci{
24268c2ecf20Sopenharmony_ci	int ret;
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	/* device should disable */
24298c2ecf20Sopenharmony_ci	ret = of_unittest_apply_revert_overlay_check(11, 11, 0, 1,
24308c2ecf20Sopenharmony_ci			PDEV_OVERLAY);
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	unittest(ret == 0, "overlay test %d failed; overlay apply\n", 11);
24338c2ecf20Sopenharmony_ci}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_cistruct unittest_i2c_bus_data {
24388c2ecf20Sopenharmony_ci	struct platform_device	*pdev;
24398c2ecf20Sopenharmony_ci	struct i2c_adapter	adap;
24408c2ecf20Sopenharmony_ci};
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_cistatic int unittest_i2c_master_xfer(struct i2c_adapter *adap,
24438c2ecf20Sopenharmony_ci		struct i2c_msg *msgs, int num)
24448c2ecf20Sopenharmony_ci{
24458c2ecf20Sopenharmony_ci	struct unittest_i2c_bus_data *std = i2c_get_adapdata(adap);
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	(void)std;
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	return num;
24508c2ecf20Sopenharmony_ci}
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_cistatic u32 unittest_i2c_functionality(struct i2c_adapter *adap)
24538c2ecf20Sopenharmony_ci{
24548c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
24558c2ecf20Sopenharmony_ci}
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_cistatic const struct i2c_algorithm unittest_i2c_algo = {
24588c2ecf20Sopenharmony_ci	.master_xfer	= unittest_i2c_master_xfer,
24598c2ecf20Sopenharmony_ci	.functionality	= unittest_i2c_functionality,
24608c2ecf20Sopenharmony_ci};
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_cistatic int unittest_i2c_bus_probe(struct platform_device *pdev)
24638c2ecf20Sopenharmony_ci{
24648c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
24658c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
24668c2ecf20Sopenharmony_ci	struct unittest_i2c_bus_data *std;
24678c2ecf20Sopenharmony_ci	struct i2c_adapter *adap;
24688c2ecf20Sopenharmony_ci	int ret;
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci	if (np == NULL) {
24718c2ecf20Sopenharmony_ci		dev_err(dev, "No OF data for device\n");
24728c2ecf20Sopenharmony_ci		return -EINVAL;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	}
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	std = devm_kzalloc(dev, sizeof(*std), GFP_KERNEL);
24798c2ecf20Sopenharmony_ci	if (!std)
24808c2ecf20Sopenharmony_ci		return -ENOMEM;
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	/* link them together */
24838c2ecf20Sopenharmony_ci	std->pdev = pdev;
24848c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, std);
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	adap = &std->adap;
24878c2ecf20Sopenharmony_ci	i2c_set_adapdata(adap, std);
24888c2ecf20Sopenharmony_ci	adap->nr = -1;
24898c2ecf20Sopenharmony_ci	strlcpy(adap->name, pdev->name, sizeof(adap->name));
24908c2ecf20Sopenharmony_ci	adap->class = I2C_CLASS_DEPRECATED;
24918c2ecf20Sopenharmony_ci	adap->algo = &unittest_i2c_algo;
24928c2ecf20Sopenharmony_ci	adap->dev.parent = dev;
24938c2ecf20Sopenharmony_ci	adap->dev.of_node = dev->of_node;
24948c2ecf20Sopenharmony_ci	adap->timeout = 5 * HZ;
24958c2ecf20Sopenharmony_ci	adap->retries = 3;
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	ret = i2c_add_numbered_adapter(adap);
24988c2ecf20Sopenharmony_ci	if (ret != 0) {
24998c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to add I2C adapter\n");
25008c2ecf20Sopenharmony_ci		return ret;
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	return 0;
25048c2ecf20Sopenharmony_ci}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_cistatic int unittest_i2c_bus_remove(struct platform_device *pdev)
25078c2ecf20Sopenharmony_ci{
25088c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
25098c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
25108c2ecf20Sopenharmony_ci	struct unittest_i2c_bus_data *std = platform_get_drvdata(pdev);
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
25138c2ecf20Sopenharmony_ci	i2c_del_adapter(&std->adap);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	return 0;
25168c2ecf20Sopenharmony_ci}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_cistatic const struct of_device_id unittest_i2c_bus_match[] = {
25198c2ecf20Sopenharmony_ci	{ .compatible = "unittest-i2c-bus", },
25208c2ecf20Sopenharmony_ci	{},
25218c2ecf20Sopenharmony_ci};
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_cistatic struct platform_driver unittest_i2c_bus_driver = {
25248c2ecf20Sopenharmony_ci	.probe			= unittest_i2c_bus_probe,
25258c2ecf20Sopenharmony_ci	.remove			= unittest_i2c_bus_remove,
25268c2ecf20Sopenharmony_ci	.driver = {
25278c2ecf20Sopenharmony_ci		.name		= "unittest-i2c-bus",
25288c2ecf20Sopenharmony_ci		.of_match_table	= of_match_ptr(unittest_i2c_bus_match),
25298c2ecf20Sopenharmony_ci	},
25308c2ecf20Sopenharmony_ci};
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_cistatic int unittest_i2c_dev_probe(struct i2c_client *client,
25338c2ecf20Sopenharmony_ci		const struct i2c_device_id *id)
25348c2ecf20Sopenharmony_ci{
25358c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
25368c2ecf20Sopenharmony_ci	struct device_node *np = client->dev.of_node;
25378c2ecf20Sopenharmony_ci
25388c2ecf20Sopenharmony_ci	if (!np) {
25398c2ecf20Sopenharmony_ci		dev_err(dev, "No OF node\n");
25408c2ecf20Sopenharmony_ci		return -EINVAL;
25418c2ecf20Sopenharmony_ci	}
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	return 0;
25468c2ecf20Sopenharmony_ci};
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_cistatic int unittest_i2c_dev_remove(struct i2c_client *client)
25498c2ecf20Sopenharmony_ci{
25508c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
25518c2ecf20Sopenharmony_ci	struct device_node *np = client->dev.of_node;
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
25548c2ecf20Sopenharmony_ci	return 0;
25558c2ecf20Sopenharmony_ci}
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_cistatic const struct i2c_device_id unittest_i2c_dev_id[] = {
25588c2ecf20Sopenharmony_ci	{ .name = "unittest-i2c-dev" },
25598c2ecf20Sopenharmony_ci	{ }
25608c2ecf20Sopenharmony_ci};
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_cistatic struct i2c_driver unittest_i2c_dev_driver = {
25638c2ecf20Sopenharmony_ci	.driver = {
25648c2ecf20Sopenharmony_ci		.name = "unittest-i2c-dev",
25658c2ecf20Sopenharmony_ci	},
25668c2ecf20Sopenharmony_ci	.probe = unittest_i2c_dev_probe,
25678c2ecf20Sopenharmony_ci	.remove = unittest_i2c_dev_remove,
25688c2ecf20Sopenharmony_ci	.id_table = unittest_i2c_dev_id,
25698c2ecf20Sopenharmony_ci};
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C_MUX)
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_cistatic int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
25748c2ecf20Sopenharmony_ci{
25758c2ecf20Sopenharmony_ci	return 0;
25768c2ecf20Sopenharmony_ci}
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_cistatic int unittest_i2c_mux_probe(struct i2c_client *client,
25798c2ecf20Sopenharmony_ci		const struct i2c_device_id *id)
25808c2ecf20Sopenharmony_ci{
25818c2ecf20Sopenharmony_ci	int i, nchans;
25828c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
25838c2ecf20Sopenharmony_ci	struct i2c_adapter *adap = client->adapter;
25848c2ecf20Sopenharmony_ci	struct device_node *np = client->dev.of_node, *child;
25858c2ecf20Sopenharmony_ci	struct i2c_mux_core *muxc;
25868c2ecf20Sopenharmony_ci	u32 reg, max_reg;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci	if (!np) {
25918c2ecf20Sopenharmony_ci		dev_err(dev, "No OF node\n");
25928c2ecf20Sopenharmony_ci		return -EINVAL;
25938c2ecf20Sopenharmony_ci	}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	max_reg = (u32)-1;
25968c2ecf20Sopenharmony_ci	for_each_child_of_node(np, child) {
25978c2ecf20Sopenharmony_ci		if (of_property_read_u32(child, "reg", &reg))
25988c2ecf20Sopenharmony_ci			continue;
25998c2ecf20Sopenharmony_ci		if (max_reg == (u32)-1 || reg > max_reg)
26008c2ecf20Sopenharmony_ci			max_reg = reg;
26018c2ecf20Sopenharmony_ci	}
26028c2ecf20Sopenharmony_ci	nchans = max_reg == (u32)-1 ? 0 : max_reg + 1;
26038c2ecf20Sopenharmony_ci	if (nchans == 0) {
26048c2ecf20Sopenharmony_ci		dev_err(dev, "No channels\n");
26058c2ecf20Sopenharmony_ci		return -EINVAL;
26068c2ecf20Sopenharmony_ci	}
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	muxc = i2c_mux_alloc(adap, dev, nchans, 0, 0,
26098c2ecf20Sopenharmony_ci			     unittest_i2c_mux_select_chan, NULL);
26108c2ecf20Sopenharmony_ci	if (!muxc)
26118c2ecf20Sopenharmony_ci		return -ENOMEM;
26128c2ecf20Sopenharmony_ci	for (i = 0; i < nchans; i++) {
26138c2ecf20Sopenharmony_ci		if (i2c_mux_add_adapter(muxc, 0, i, 0)) {
26148c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to register mux #%d\n", i);
26158c2ecf20Sopenharmony_ci			i2c_mux_del_adapters(muxc);
26168c2ecf20Sopenharmony_ci			return -ENODEV;
26178c2ecf20Sopenharmony_ci		}
26188c2ecf20Sopenharmony_ci	}
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, muxc);
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	return 0;
26238c2ecf20Sopenharmony_ci};
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_cistatic int unittest_i2c_mux_remove(struct i2c_client *client)
26268c2ecf20Sopenharmony_ci{
26278c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
26288c2ecf20Sopenharmony_ci	struct device_node *np = client->dev.of_node;
26298c2ecf20Sopenharmony_ci	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s for node @%pOF\n", __func__, np);
26328c2ecf20Sopenharmony_ci	i2c_mux_del_adapters(muxc);
26338c2ecf20Sopenharmony_ci	return 0;
26348c2ecf20Sopenharmony_ci}
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_cistatic const struct i2c_device_id unittest_i2c_mux_id[] = {
26378c2ecf20Sopenharmony_ci	{ .name = "unittest-i2c-mux" },
26388c2ecf20Sopenharmony_ci	{ }
26398c2ecf20Sopenharmony_ci};
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_cistatic struct i2c_driver unittest_i2c_mux_driver = {
26428c2ecf20Sopenharmony_ci	.driver = {
26438c2ecf20Sopenharmony_ci		.name = "unittest-i2c-mux",
26448c2ecf20Sopenharmony_ci	},
26458c2ecf20Sopenharmony_ci	.probe = unittest_i2c_mux_probe,
26468c2ecf20Sopenharmony_ci	.remove = unittest_i2c_mux_remove,
26478c2ecf20Sopenharmony_ci	.id_table = unittest_i2c_mux_id,
26488c2ecf20Sopenharmony_ci};
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci#endif
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_cistatic int of_unittest_overlay_i2c_init(void)
26538c2ecf20Sopenharmony_ci{
26548c2ecf20Sopenharmony_ci	int ret;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	ret = i2c_add_driver(&unittest_i2c_dev_driver);
26578c2ecf20Sopenharmony_ci	if (unittest(ret == 0,
26588c2ecf20Sopenharmony_ci			"could not register unittest i2c device driver\n"))
26598c2ecf20Sopenharmony_ci		return ret;
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci	ret = platform_driver_register(&unittest_i2c_bus_driver);
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	if (unittest(ret == 0,
26648c2ecf20Sopenharmony_ci			"could not register unittest i2c bus driver\n"))
26658c2ecf20Sopenharmony_ci		return ret;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C_MUX)
26688c2ecf20Sopenharmony_ci
26698c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
26708c2ecf20Sopenharmony_ci		     "i2c i2c-1: Added multiplexed i2c bus 2");
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_ci	ret = i2c_add_driver(&unittest_i2c_mux_driver);
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
26758c2ecf20Sopenharmony_ci		   "i2c i2c-1: Added multiplexed i2c bus 2");
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci	if (unittest(ret == 0,
26788c2ecf20Sopenharmony_ci			"could not register unittest i2c mux driver\n"))
26798c2ecf20Sopenharmony_ci		return ret;
26808c2ecf20Sopenharmony_ci#endif
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci	return 0;
26838c2ecf20Sopenharmony_ci}
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_cistatic void of_unittest_overlay_i2c_cleanup(void)
26868c2ecf20Sopenharmony_ci{
26878c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C_MUX)
26888c2ecf20Sopenharmony_ci	i2c_del_driver(&unittest_i2c_mux_driver);
26898c2ecf20Sopenharmony_ci#endif
26908c2ecf20Sopenharmony_ci	platform_driver_unregister(&unittest_i2c_bus_driver);
26918c2ecf20Sopenharmony_ci	i2c_del_driver(&unittest_i2c_dev_driver);
26928c2ecf20Sopenharmony_ci}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_i2c_12(void)
26958c2ecf20Sopenharmony_ci{
26968c2ecf20Sopenharmony_ci	int ret;
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_ci	/* device should enable */
26998c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
27008c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12/status");
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY);
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
27058c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest12/status");
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	if (ret)
27088c2ecf20Sopenharmony_ci		return;
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 12);
27118c2ecf20Sopenharmony_ci}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci/* test deactivation of device */
27148c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_i2c_13(void)
27158c2ecf20Sopenharmony_ci{
27168c2ecf20Sopenharmony_ci	int ret;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
27198c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13/status");
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	/* device should disable */
27228c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY);
27238c2ecf20Sopenharmony_ci
27248c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
27258c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data/overlay-node/test-bus/i2c-test-bus/test-unittest13/status");
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_ci	if (ret)
27288c2ecf20Sopenharmony_ci		return;
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 13);
27318c2ecf20Sopenharmony_ci}
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci/* just check for i2c mux existence */
27348c2ecf20Sopenharmony_cistatic void of_unittest_overlay_i2c_14(void)
27358c2ecf20Sopenharmony_ci{
27368c2ecf20Sopenharmony_ci}
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay_i2c_15(void)
27398c2ecf20Sopenharmony_ci{
27408c2ecf20Sopenharmony_ci	int ret;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci	/* device should enable */
27438c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_INFO,
27448c2ecf20Sopenharmony_ci		     "i2c i2c-1: Added multiplexed i2c bus 3");
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	ret = of_unittest_apply_overlay_check(15, 15, 0, 1, I2C_OVERLAY);
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	EXPECT_END(KERN_INFO,
27498c2ecf20Sopenharmony_ci		   "i2c i2c-1: Added multiplexed i2c bus 3");
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci	if (ret)
27528c2ecf20Sopenharmony_ci		return;
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci	unittest(1, "overlay test %d passed\n", 15);
27558c2ecf20Sopenharmony_ci}
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci#else
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_cistatic inline void of_unittest_overlay_i2c_14(void) { }
27608c2ecf20Sopenharmony_cistatic inline void of_unittest_overlay_i2c_15(void) { }
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci#endif
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_cistatic void __init of_unittest_overlay(void)
27658c2ecf20Sopenharmony_ci{
27668c2ecf20Sopenharmony_ci	struct device_node *bus_np = NULL;
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci	if (platform_driver_register(&unittest_driver)) {
27698c2ecf20Sopenharmony_ci		unittest(0, "could not register unittest driver\n");
27708c2ecf20Sopenharmony_ci		goto out;
27718c2ecf20Sopenharmony_ci	}
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	bus_np = of_find_node_by_path(bus_path);
27748c2ecf20Sopenharmony_ci	if (bus_np == NULL) {
27758c2ecf20Sopenharmony_ci		unittest(0, "could not find bus_path \"%s\"\n", bus_path);
27768c2ecf20Sopenharmony_ci		goto out;
27778c2ecf20Sopenharmony_ci	}
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci	if (of_platform_default_populate(bus_np, NULL, NULL)) {
27808c2ecf20Sopenharmony_ci		unittest(0, "could not populate bus @ \"%s\"\n", bus_path);
27818c2ecf20Sopenharmony_ci		goto out;
27828c2ecf20Sopenharmony_ci	}
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ci	if (!of_unittest_device_exists(100, PDEV_OVERLAY)) {
27858c2ecf20Sopenharmony_ci		unittest(0, "could not find unittest0 @ \"%s\"\n",
27868c2ecf20Sopenharmony_ci				unittest_path(100, PDEV_OVERLAY));
27878c2ecf20Sopenharmony_ci		goto out;
27888c2ecf20Sopenharmony_ci	}
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	if (of_unittest_device_exists(101, PDEV_OVERLAY)) {
27918c2ecf20Sopenharmony_ci		unittest(0, "unittest1 @ \"%s\" should not exist\n",
27928c2ecf20Sopenharmony_ci				unittest_path(101, PDEV_OVERLAY));
27938c2ecf20Sopenharmony_ci		goto out;
27948c2ecf20Sopenharmony_ci	}
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	unittest(1, "basic infrastructure of overlays passed");
27978c2ecf20Sopenharmony_ci
27988c2ecf20Sopenharmony_ci	/* tests in sequence */
27998c2ecf20Sopenharmony_ci	of_unittest_overlay_0();
28008c2ecf20Sopenharmony_ci	of_unittest_overlay_1();
28018c2ecf20Sopenharmony_ci	of_unittest_overlay_2();
28028c2ecf20Sopenharmony_ci	of_unittest_overlay_3();
28038c2ecf20Sopenharmony_ci	of_unittest_overlay_4();
28048c2ecf20Sopenharmony_ci	of_unittest_overlay_5();
28058c2ecf20Sopenharmony_ci	of_unittest_overlay_6();
28068c2ecf20Sopenharmony_ci	of_unittest_overlay_8();
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci	of_unittest_overlay_10();
28098c2ecf20Sopenharmony_ci	of_unittest_overlay_11();
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_ci#if IS_BUILTIN(CONFIG_I2C)
28128c2ecf20Sopenharmony_ci	if (unittest(of_unittest_overlay_i2c_init() == 0, "i2c init failed\n"))
28138c2ecf20Sopenharmony_ci		goto out;
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_ci	of_unittest_overlay_i2c_12();
28168c2ecf20Sopenharmony_ci	of_unittest_overlay_i2c_13();
28178c2ecf20Sopenharmony_ci	of_unittest_overlay_i2c_14();
28188c2ecf20Sopenharmony_ci	of_unittest_overlay_i2c_15();
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	of_unittest_overlay_i2c_cleanup();
28218c2ecf20Sopenharmony_ci#endif
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	of_unittest_overlay_gpio();
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	of_unittest_destroy_tracked_overlays();
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ciout:
28288c2ecf20Sopenharmony_ci	of_node_put(bus_np);
28298c2ecf20Sopenharmony_ci}
28308c2ecf20Sopenharmony_ci
28318c2ecf20Sopenharmony_ci#else
28328c2ecf20Sopenharmony_cistatic inline void __init of_unittest_overlay(void) { }
28338c2ecf20Sopenharmony_ci#endif
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci#ifdef CONFIG_OF_OVERLAY
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci/*
28388c2ecf20Sopenharmony_ci * __dtb_ot_begin[] and __dtb_ot_end[] are created by cmd_dt_S_dtb
28398c2ecf20Sopenharmony_ci * in scripts/Makefile.lib
28408c2ecf20Sopenharmony_ci */
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci#define OVERLAY_INFO_EXTERN(name) \
28438c2ecf20Sopenharmony_ci	extern uint8_t __dtb_##name##_begin[]; \
28448c2ecf20Sopenharmony_ci	extern uint8_t __dtb_##name##_end[]
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci#define OVERLAY_INFO(overlay_name, expected)             \
28478c2ecf20Sopenharmony_ci{	.dtb_begin       = __dtb_##overlay_name##_begin, \
28488c2ecf20Sopenharmony_ci	.dtb_end         = __dtb_##overlay_name##_end,   \
28498c2ecf20Sopenharmony_ci	.expected_result = expected,                     \
28508c2ecf20Sopenharmony_ci	.name            = #overlay_name,                \
28518c2ecf20Sopenharmony_ci}
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_cistruct overlay_info {
28548c2ecf20Sopenharmony_ci	uint8_t		*dtb_begin;
28558c2ecf20Sopenharmony_ci	uint8_t		*dtb_end;
28568c2ecf20Sopenharmony_ci	int		expected_result;
28578c2ecf20Sopenharmony_ci	int		overlay_id;
28588c2ecf20Sopenharmony_ci	char		*name;
28598c2ecf20Sopenharmony_ci};
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_base);
28628c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay);
28638c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_0);
28648c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_1);
28658c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_2);
28668c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_3);
28678c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_4);
28688c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_5);
28698c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_6);
28708c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_7);
28718c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_8);
28728c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_9);
28738c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_10);
28748c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_11);
28758c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_12);
28768c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_13);
28778c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_15);
28788c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_01);
28798c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_02a);
28808c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_02b);
28818c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_03);
28828c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_04a);
28838c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_gpio_04b);
28848c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_add_dup_node);
28858c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop);
28868c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_phandle);
28878c2ecf20Sopenharmony_ciOVERLAY_INFO_EXTERN(overlay_bad_symbol);
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci/* entries found by name */
28908c2ecf20Sopenharmony_cistatic struct overlay_info overlays[] = {
28918c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_base, -9999),
28928c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay, 0),
28938c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_0, 0),
28948c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_1, 0),
28958c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_2, 0),
28968c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_3, 0),
28978c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_4, 0),
28988c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_5, 0),
28998c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_6, 0),
29008c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_7, 0),
29018c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_8, 0),
29028c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_9, 0),
29038c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_10, 0),
29048c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_11, 0),
29058c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_12, 0),
29068c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_13, 0),
29078c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_15, 0),
29088c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_gpio_01, 0),
29098c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_gpio_02a, 0),
29108c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_gpio_02b, 0),
29118c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_gpio_03, 0),
29128c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_gpio_04a, 0),
29138c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_gpio_04b, 0),
29148c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL),
29158c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL),
29168c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
29178c2ecf20Sopenharmony_ci	OVERLAY_INFO(overlay_bad_symbol, -EINVAL),
29188c2ecf20Sopenharmony_ci	/* end marker */
29198c2ecf20Sopenharmony_ci	{.dtb_begin = NULL, .dtb_end = NULL, .expected_result = 0, .name = NULL}
29208c2ecf20Sopenharmony_ci};
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_cistatic struct device_node *overlay_base_root;
29238c2ecf20Sopenharmony_ci
29248c2ecf20Sopenharmony_cistatic void * __init dt_alloc_memory(u64 size, u64 align)
29258c2ecf20Sopenharmony_ci{
29268c2ecf20Sopenharmony_ci	void *ptr = memblock_alloc(size, align);
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	if (!ptr)
29298c2ecf20Sopenharmony_ci		panic("%s: Failed to allocate %llu bytes align=0x%llx\n",
29308c2ecf20Sopenharmony_ci		      __func__, size, align);
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci	return ptr;
29338c2ecf20Sopenharmony_ci}
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci/*
29368c2ecf20Sopenharmony_ci * Create base device tree for the overlay unittest.
29378c2ecf20Sopenharmony_ci *
29388c2ecf20Sopenharmony_ci * This is called from very early boot code.
29398c2ecf20Sopenharmony_ci *
29408c2ecf20Sopenharmony_ci * Do as much as possible the same way as done in __unflatten_device_tree
29418c2ecf20Sopenharmony_ci * and other early boot steps for the normal FDT so that the overlay base
29428c2ecf20Sopenharmony_ci * unflattened tree will have the same characteristics as the real tree
29438c2ecf20Sopenharmony_ci * (such as having memory allocated by the early allocator).  The goal
29448c2ecf20Sopenharmony_ci * is to test "the real thing" as much as possible, and test "test setup
29458c2ecf20Sopenharmony_ci * code" as little as possible.
29468c2ecf20Sopenharmony_ci *
29478c2ecf20Sopenharmony_ci * Have to stop before resolving phandles, because that uses kmalloc.
29488c2ecf20Sopenharmony_ci */
29498c2ecf20Sopenharmony_civoid __init unittest_unflatten_overlay_base(void)
29508c2ecf20Sopenharmony_ci{
29518c2ecf20Sopenharmony_ci	struct overlay_info *info;
29528c2ecf20Sopenharmony_ci	u32 data_size;
29538c2ecf20Sopenharmony_ci	void *new_fdt;
29548c2ecf20Sopenharmony_ci	u32 size;
29558c2ecf20Sopenharmony_ci	int found = 0;
29568c2ecf20Sopenharmony_ci	const char *overlay_name = "overlay_base";
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	for (info = overlays; info && info->name; info++) {
29598c2ecf20Sopenharmony_ci		if (!strcmp(overlay_name, info->name)) {
29608c2ecf20Sopenharmony_ci			found = 1;
29618c2ecf20Sopenharmony_ci			break;
29628c2ecf20Sopenharmony_ci		}
29638c2ecf20Sopenharmony_ci	}
29648c2ecf20Sopenharmony_ci	if (!found) {
29658c2ecf20Sopenharmony_ci		pr_err("no overlay data for %s\n", overlay_name);
29668c2ecf20Sopenharmony_ci		return;
29678c2ecf20Sopenharmony_ci	}
29688c2ecf20Sopenharmony_ci
29698c2ecf20Sopenharmony_ci	info = &overlays[0];
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	if (info->expected_result != -9999) {
29728c2ecf20Sopenharmony_ci		pr_err("No dtb 'overlay_base' to attach\n");
29738c2ecf20Sopenharmony_ci		return;
29748c2ecf20Sopenharmony_ci	}
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	data_size = info->dtb_end - info->dtb_begin;
29778c2ecf20Sopenharmony_ci	if (!data_size) {
29788c2ecf20Sopenharmony_ci		pr_err("No dtb 'overlay_base' to attach\n");
29798c2ecf20Sopenharmony_ci		return;
29808c2ecf20Sopenharmony_ci	}
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	size = fdt_totalsize(info->dtb_begin);
29838c2ecf20Sopenharmony_ci	if (size != data_size) {
29848c2ecf20Sopenharmony_ci		pr_err("dtb 'overlay_base' header totalsize != actual size");
29858c2ecf20Sopenharmony_ci		return;
29868c2ecf20Sopenharmony_ci	}
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	new_fdt = dt_alloc_memory(size, roundup_pow_of_two(FDT_V17_SIZE));
29898c2ecf20Sopenharmony_ci	if (!new_fdt) {
29908c2ecf20Sopenharmony_ci		pr_err("alloc for dtb 'overlay_base' failed");
29918c2ecf20Sopenharmony_ci		return;
29928c2ecf20Sopenharmony_ci	}
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	memcpy(new_fdt, info->dtb_begin, size);
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	__unflatten_device_tree(new_fdt, NULL, &overlay_base_root,
29978c2ecf20Sopenharmony_ci				dt_alloc_memory, true);
29988c2ecf20Sopenharmony_ci}
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci/*
30018c2ecf20Sopenharmony_ci * The purpose of of_unittest_overlay_data_add is to add an
30028c2ecf20Sopenharmony_ci * overlay in the normal fashion.  This is a test of the whole
30038c2ecf20Sopenharmony_ci * picture, instead of testing individual elements.
30048c2ecf20Sopenharmony_ci *
30058c2ecf20Sopenharmony_ci * A secondary purpose is to be able to verify that the contents of
30068c2ecf20Sopenharmony_ci * /proc/device-tree/ contains the updated structure and values from
30078c2ecf20Sopenharmony_ci * the overlay.  That must be verified separately in user space.
30088c2ecf20Sopenharmony_ci *
30098c2ecf20Sopenharmony_ci * Return 0 on unexpected error.
30108c2ecf20Sopenharmony_ci */
30118c2ecf20Sopenharmony_cistatic int __init overlay_data_apply(const char *overlay_name, int *overlay_id)
30128c2ecf20Sopenharmony_ci{
30138c2ecf20Sopenharmony_ci	struct overlay_info *info;
30148c2ecf20Sopenharmony_ci	int found = 0;
30158c2ecf20Sopenharmony_ci	int ret;
30168c2ecf20Sopenharmony_ci	u32 size;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	for (info = overlays; info && info->name; info++) {
30198c2ecf20Sopenharmony_ci		if (!strcmp(overlay_name, info->name)) {
30208c2ecf20Sopenharmony_ci			found = 1;
30218c2ecf20Sopenharmony_ci			break;
30228c2ecf20Sopenharmony_ci		}
30238c2ecf20Sopenharmony_ci	}
30248c2ecf20Sopenharmony_ci	if (!found) {
30258c2ecf20Sopenharmony_ci		pr_err("no overlay data for %s\n", overlay_name);
30268c2ecf20Sopenharmony_ci		return 0;
30278c2ecf20Sopenharmony_ci	}
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci	size = info->dtb_end - info->dtb_begin;
30308c2ecf20Sopenharmony_ci	if (!size)
30318c2ecf20Sopenharmony_ci		pr_err("no overlay data for %s\n", overlay_name);
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	ret = of_overlay_fdt_apply(info->dtb_begin, size, &info->overlay_id);
30348c2ecf20Sopenharmony_ci	if (overlay_id)
30358c2ecf20Sopenharmony_ci		*overlay_id = info->overlay_id;
30368c2ecf20Sopenharmony_ci	if (ret < 0)
30378c2ecf20Sopenharmony_ci		goto out;
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci	pr_debug("%s applied\n", overlay_name);
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ciout:
30428c2ecf20Sopenharmony_ci	if (ret != info->expected_result)
30438c2ecf20Sopenharmony_ci		pr_err("of_overlay_fdt_apply() expected %d, ret=%d, %s\n",
30448c2ecf20Sopenharmony_ci		       info->expected_result, ret, overlay_name);
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_ci	return (ret == info->expected_result);
30478c2ecf20Sopenharmony_ci}
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_ci/*
30508c2ecf20Sopenharmony_ci * The purpose of of_unittest_overlay_high_level is to add an overlay
30518c2ecf20Sopenharmony_ci * in the normal fashion.  This is a test of the whole picture,
30528c2ecf20Sopenharmony_ci * instead of individual elements.
30538c2ecf20Sopenharmony_ci *
30548c2ecf20Sopenharmony_ci * The first part of the function is _not_ normal overlay usage; it is
30558c2ecf20Sopenharmony_ci * finishing splicing the base overlay device tree into the live tree.
30568c2ecf20Sopenharmony_ci */
30578c2ecf20Sopenharmony_cistatic __init void of_unittest_overlay_high_level(void)
30588c2ecf20Sopenharmony_ci{
30598c2ecf20Sopenharmony_ci	struct device_node *last_sibling;
30608c2ecf20Sopenharmony_ci	struct device_node *np;
30618c2ecf20Sopenharmony_ci	struct device_node *of_symbols;
30628c2ecf20Sopenharmony_ci	struct device_node *overlay_base_symbols;
30638c2ecf20Sopenharmony_ci	struct device_node **pprev;
30648c2ecf20Sopenharmony_ci	struct property *prop;
30658c2ecf20Sopenharmony_ci	int ret;
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	if (!overlay_base_root) {
30688c2ecf20Sopenharmony_ci		unittest(0, "overlay_base_root not initialized\n");
30698c2ecf20Sopenharmony_ci		return;
30708c2ecf20Sopenharmony_ci	}
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	/*
30738c2ecf20Sopenharmony_ci	 * Could not fixup phandles in unittest_unflatten_overlay_base()
30748c2ecf20Sopenharmony_ci	 * because kmalloc() was not yet available.
30758c2ecf20Sopenharmony_ci	 */
30768c2ecf20Sopenharmony_ci	of_overlay_mutex_lock();
30778c2ecf20Sopenharmony_ci	of_resolve_phandles(overlay_base_root);
30788c2ecf20Sopenharmony_ci	of_overlay_mutex_unlock();
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ci	/*
30828c2ecf20Sopenharmony_ci	 * do not allow overlay_base to duplicate any node already in
30838c2ecf20Sopenharmony_ci	 * tree, this greatly simplifies the code
30848c2ecf20Sopenharmony_ci	 */
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	/*
30878c2ecf20Sopenharmony_ci	 * remove overlay_base_root node "__local_fixups", after
30888c2ecf20Sopenharmony_ci	 * being used by of_resolve_phandles()
30898c2ecf20Sopenharmony_ci	 */
30908c2ecf20Sopenharmony_ci	pprev = &overlay_base_root->child;
30918c2ecf20Sopenharmony_ci	for (np = overlay_base_root->child; np; np = np->sibling) {
30928c2ecf20Sopenharmony_ci		if (of_node_name_eq(np, "__local_fixups__")) {
30938c2ecf20Sopenharmony_ci			*pprev = np->sibling;
30948c2ecf20Sopenharmony_ci			break;
30958c2ecf20Sopenharmony_ci		}
30968c2ecf20Sopenharmony_ci		pprev = &np->sibling;
30978c2ecf20Sopenharmony_ci	}
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	/* remove overlay_base_root node "__symbols__" if in live tree */
31008c2ecf20Sopenharmony_ci	of_symbols = of_get_child_by_name(of_root, "__symbols__");
31018c2ecf20Sopenharmony_ci	if (of_symbols) {
31028c2ecf20Sopenharmony_ci		/* will have to graft properties from node into live tree */
31038c2ecf20Sopenharmony_ci		pprev = &overlay_base_root->child;
31048c2ecf20Sopenharmony_ci		for (np = overlay_base_root->child; np; np = np->sibling) {
31058c2ecf20Sopenharmony_ci			if (of_node_name_eq(np, "__symbols__")) {
31068c2ecf20Sopenharmony_ci				overlay_base_symbols = np;
31078c2ecf20Sopenharmony_ci				*pprev = np->sibling;
31088c2ecf20Sopenharmony_ci				break;
31098c2ecf20Sopenharmony_ci			}
31108c2ecf20Sopenharmony_ci			pprev = &np->sibling;
31118c2ecf20Sopenharmony_ci		}
31128c2ecf20Sopenharmony_ci	}
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_ci	for_each_child_of_node(overlay_base_root, np) {
31158c2ecf20Sopenharmony_ci		struct device_node *base_child;
31168c2ecf20Sopenharmony_ci		for_each_child_of_node(of_root, base_child) {
31178c2ecf20Sopenharmony_ci			if (!strcmp(np->full_name, base_child->full_name)) {
31188c2ecf20Sopenharmony_ci				unittest(0, "illegal node name in overlay_base %pOFn",
31198c2ecf20Sopenharmony_ci					 np);
31208c2ecf20Sopenharmony_ci				return;
31218c2ecf20Sopenharmony_ci			}
31228c2ecf20Sopenharmony_ci		}
31238c2ecf20Sopenharmony_ci	}
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci	/*
31268c2ecf20Sopenharmony_ci	 * overlay 'overlay_base' is not allowed to have root
31278c2ecf20Sopenharmony_ci	 * properties, so only need to splice nodes into main device tree.
31288c2ecf20Sopenharmony_ci	 *
31298c2ecf20Sopenharmony_ci	 * root node of *overlay_base_root will not be freed, it is lost
31308c2ecf20Sopenharmony_ci	 * memory.
31318c2ecf20Sopenharmony_ci	 */
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	for (np = overlay_base_root->child; np; np = np->sibling)
31348c2ecf20Sopenharmony_ci		np->parent = of_root;
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci	mutex_lock(&of_mutex);
31378c2ecf20Sopenharmony_ci
31388c2ecf20Sopenharmony_ci	for (last_sibling = np = of_root->child; np; np = np->sibling)
31398c2ecf20Sopenharmony_ci		last_sibling = np;
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci	if (last_sibling)
31428c2ecf20Sopenharmony_ci		last_sibling->sibling = overlay_base_root->child;
31438c2ecf20Sopenharmony_ci	else
31448c2ecf20Sopenharmony_ci		of_root->child = overlay_base_root->child;
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_ci	for_each_of_allnodes_from(overlay_base_root, np)
31478c2ecf20Sopenharmony_ci		__of_attach_node_sysfs(np);
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	if (of_symbols) {
31508c2ecf20Sopenharmony_ci		struct property *new_prop;
31518c2ecf20Sopenharmony_ci		for_each_property_of_node(overlay_base_symbols, prop) {
31528c2ecf20Sopenharmony_ci
31538c2ecf20Sopenharmony_ci			new_prop = __of_prop_dup(prop, GFP_KERNEL);
31548c2ecf20Sopenharmony_ci			if (!new_prop) {
31558c2ecf20Sopenharmony_ci				unittest(0, "__of_prop_dup() of '%s' from overlay_base node __symbols__",
31568c2ecf20Sopenharmony_ci					 prop->name);
31578c2ecf20Sopenharmony_ci				goto err_unlock;
31588c2ecf20Sopenharmony_ci			}
31598c2ecf20Sopenharmony_ci			if (__of_add_property(of_symbols, new_prop)) {
31608c2ecf20Sopenharmony_ci				kfree(new_prop->name);
31618c2ecf20Sopenharmony_ci				kfree(new_prop->value);
31628c2ecf20Sopenharmony_ci				kfree(new_prop);
31638c2ecf20Sopenharmony_ci				/* "name" auto-generated by unflatten */
31648c2ecf20Sopenharmony_ci				if (!strcmp(prop->name, "name"))
31658c2ecf20Sopenharmony_ci					continue;
31668c2ecf20Sopenharmony_ci				unittest(0, "duplicate property '%s' in overlay_base node __symbols__",
31678c2ecf20Sopenharmony_ci					 prop->name);
31688c2ecf20Sopenharmony_ci				goto err_unlock;
31698c2ecf20Sopenharmony_ci			}
31708c2ecf20Sopenharmony_ci			if (__of_add_property_sysfs(of_symbols, new_prop)) {
31718c2ecf20Sopenharmony_ci				unittest(0, "unable to add property '%s' in overlay_base node __symbols__ to sysfs",
31728c2ecf20Sopenharmony_ci					 prop->name);
31738c2ecf20Sopenharmony_ci				goto err_unlock;
31748c2ecf20Sopenharmony_ci			}
31758c2ecf20Sopenharmony_ci		}
31768c2ecf20Sopenharmony_ci	}
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_ci	mutex_unlock(&of_mutex);
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci	/* now do the normal overlay usage test */
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31848c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/substation@100/status");
31858c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31868c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/status");
31878c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31888c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@30/incline-up");
31898c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31908c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@40/incline-up");
31918c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31928c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/status");
31938c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31948c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/color");
31958c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31968c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/rate");
31978c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
31988c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/hvac_2");
31998c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32008c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200");
32018c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32028c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_left");
32038c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32048c2ecf20Sopenharmony_ci		     "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_right");
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	ret = overlay_data_apply("overlay", NULL);
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32098c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_right");
32108c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32118c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200_left");
32128c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32138c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/ride_200");
32148c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32158c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /__symbols__/hvac_2");
32168c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32178c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/rate");
32188c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32198c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/color");
32208c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32218c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/lights@40000/status");
32228c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32238c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@40/incline-up");
32248c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32258c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/ride@100/track@30/incline-up");
32268c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32278c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/fairway-1/status");
32288c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32298c2ecf20Sopenharmony_ci		   "OF: overlay: WARNING: memory leak will occur if overlay removed, property: /testcase-data-2/substation@100/status");
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci	unittest(ret, "Adding overlay 'overlay' failed\n");
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32348c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/controller");
32358c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32368c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/controller/name");
32378c2ecf20Sopenharmony_ci
32388c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_bad_add_dup_node", NULL),
32398c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_bad_add_dup_node' failed\n");
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32428c2ecf20Sopenharmony_ci		   "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/controller/name");
32438c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32448c2ecf20Sopenharmony_ci		   "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/controller");
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32478c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/electric");
32488c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32498c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/rpm_avail");
32508c2ecf20Sopenharmony_ci	EXPECT_BEGIN(KERN_ERR,
32518c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/name");
32528c2ecf20Sopenharmony_ci
32538c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_bad_add_dup_prop", NULL),
32548c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_bad_add_dup_prop' failed\n");
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32578c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/name");
32588c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32598c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/electric/rpm_avail");
32608c2ecf20Sopenharmony_ci	EXPECT_END(KERN_ERR,
32618c2ecf20Sopenharmony_ci		     "OF: overlay: ERROR: multiple fragments add and/or delete node /testcase-data-2/substation@100/motor-1/electric");
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_bad_phandle", NULL),
32648c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_bad_phandle' failed\n");
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	unittest(overlay_data_apply("overlay_bad_symbol", NULL),
32678c2ecf20Sopenharmony_ci		 "Adding overlay 'overlay_bad_symbol' failed\n");
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_ci	return;
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_cierr_unlock:
32728c2ecf20Sopenharmony_ci	mutex_unlock(&of_mutex);
32738c2ecf20Sopenharmony_ci}
32748c2ecf20Sopenharmony_ci
32758c2ecf20Sopenharmony_ci#else
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_cistatic inline __init void of_unittest_overlay_high_level(void) {}
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci#endif
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_cistatic int __init of_unittest(void)
32828c2ecf20Sopenharmony_ci{
32838c2ecf20Sopenharmony_ci	struct device_node *np;
32848c2ecf20Sopenharmony_ci	int res;
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_ci	pr_info("start of unittest - you will see error messages\n");
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci	/* adding data for unittest */
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_UML))
32918c2ecf20Sopenharmony_ci		unittest_unflatten_overlay_base();
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	res = unittest_data_add();
32948c2ecf20Sopenharmony_ci	if (res)
32958c2ecf20Sopenharmony_ci		return res;
32968c2ecf20Sopenharmony_ci	if (!of_aliases)
32978c2ecf20Sopenharmony_ci		of_aliases = of_find_node_by_path("/aliases");
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
33008c2ecf20Sopenharmony_ci	if (!np) {
33018c2ecf20Sopenharmony_ci		pr_info("No testcase data in device tree; not running tests\n");
33028c2ecf20Sopenharmony_ci		return 0;
33038c2ecf20Sopenharmony_ci	}
33048c2ecf20Sopenharmony_ci	of_node_put(np);
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	of_unittest_check_tree_linkage();
33078c2ecf20Sopenharmony_ci	of_unittest_check_phandles();
33088c2ecf20Sopenharmony_ci	of_unittest_find_node_by_name();
33098c2ecf20Sopenharmony_ci	of_unittest_dynamic();
33108c2ecf20Sopenharmony_ci	of_unittest_parse_phandle_with_args();
33118c2ecf20Sopenharmony_ci	of_unittest_parse_phandle_with_args_map();
33128c2ecf20Sopenharmony_ci	of_unittest_printf();
33138c2ecf20Sopenharmony_ci	of_unittest_property_string();
33148c2ecf20Sopenharmony_ci	of_unittest_property_copy();
33158c2ecf20Sopenharmony_ci	of_unittest_changeset();
33168c2ecf20Sopenharmony_ci	of_unittest_parse_interrupts();
33178c2ecf20Sopenharmony_ci	of_unittest_parse_interrupts_extended();
33188c2ecf20Sopenharmony_ci	of_unittest_dma_get_max_cpu_address();
33198c2ecf20Sopenharmony_ci	of_unittest_parse_dma_ranges();
33208c2ecf20Sopenharmony_ci	of_unittest_pci_dma_ranges();
33218c2ecf20Sopenharmony_ci	of_unittest_match_node();
33228c2ecf20Sopenharmony_ci	of_unittest_platform_populate();
33238c2ecf20Sopenharmony_ci	of_unittest_overlay();
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci	/* Double check linkage after removing testcase data */
33268c2ecf20Sopenharmony_ci	of_unittest_check_tree_linkage();
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci	of_unittest_overlay_high_level();
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	pr_info("end of unittest - %i passed, %i failed\n",
33318c2ecf20Sopenharmony_ci		unittest_results.passed, unittest_results.failed);
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci	return 0;
33348c2ecf20Sopenharmony_ci}
33358c2ecf20Sopenharmony_cilate_initcall(of_unittest);
3336