1260684Skaiw// SPDX-License-Identifier: GPL-2.0+
2260684Skaiw/*
3276371Semaste * Copyright (C) 2016 Google, Inc
4260684Skaiw * Written by Simon Glass <sjg@chromium.org>
5260684Skaiw */
6260684Skaiw
7260684Skaiw#include <common.h>
8260684Skaiw#include <errno.h>
9260684Skaiw#include <image.h>
10260684Skaiw#include <log.h>
11260684Skaiw#include <linux/libfdt.h>
12260684Skaiw
13260684Skaiwulong fdt_getprop_u32(const void *fdt, int node, const char *prop)
14260684Skaiw{
15260684Skaiw	const u32 *cell;
16260684Skaiw	int len;
17260684Skaiw
18260684Skaiw	cell = fdt_getprop(fdt, node, prop, &len);
19260684Skaiw	if (!cell || len != sizeof(*cell))
20260684Skaiw		return FDT_ERROR;
21260684Skaiw
22260684Skaiw	return fdt32_to_cpu(*cell);
23260684Skaiw}
24260684Skaiw
25260684Skaiw__weak int board_fit_config_name_match(const char *name)
26260684Skaiw{
27260684Skaiw	return -EINVAL;
28260684Skaiw}
29260684Skaiw
30276371Semaste/*
31260684Skaiw * Iterate over all /configurations subnodes and call a platform specific
32260684Skaiw * function to find the matching configuration.
33260684Skaiw * Returns the node offset or a negative error number.
34260684Skaiw */
35260684Skaiwint fit_find_config_node(const void *fdt)
36276371Semaste{
37260684Skaiw	const char *name;
38260684Skaiw	int conf, node, len;
39260684Skaiw	const char *dflt_conf_name;
40260684Skaiw	const char *dflt_conf_desc = NULL;
41260684Skaiw	int dflt_conf_node = -ENOENT;
42260684Skaiw
43260684Skaiw	conf = fdt_path_offset(fdt, FIT_CONFS_PATH);
44260684Skaiw	if (conf < 0) {
45260684Skaiw		debug("%s: Cannot find /configurations node: %d\n", __func__,
46260684Skaiw		      conf);
47260684Skaiw		return -EINVAL;
48260854Skaiw	}
49260684Skaiw
50260684Skaiw	dflt_conf_name = fdt_getprop(fdt, conf, "default", &len);
51260684Skaiw
52276371Semaste	for (node = fdt_first_subnode(fdt, conf);
53276371Semaste	     node >= 0;
54276371Semaste	     node = fdt_next_subnode(fdt, node)) {
55260684Skaiw		name = fdt_getprop(fdt, node, "description", &len);
56260684Skaiw		if (!name) {
57260684Skaiw#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
58260684Skaiw			printf("%s: Missing FDT description in DTB\n",
59260684Skaiw			       __func__);
60260684Skaiw#endif
61260684Skaiw			return -EINVAL;
62260684Skaiw		}
63260684Skaiw
64260684Skaiw		if (dflt_conf_name) {
65260684Skaiw			const char *node_name = fdt_get_name(fdt, node, NULL);
66276371Semaste			if (strcmp(dflt_conf_name, node_name) == 0) {
67276371Semaste				dflt_conf_node = node;
68260684Skaiw				dflt_conf_desc = name;
69260684Skaiw			}
70260684Skaiw		}
71276371Semaste
72260684Skaiw		if (board_fit_config_name_match(name))
73260684Skaiw			continue;
74260684Skaiw
75260684Skaiw		debug("Selecting config '%s'\n", name);
76260684Skaiw
77260684Skaiw		return node;
78260684Skaiw	}
79260684Skaiw
80276371Semaste	if (dflt_conf_node != -ENOENT) {
81276371Semaste		debug("Selecting default config '%s'\n", dflt_conf_desc);
82276371Semaste		return dflt_conf_node;
83276371Semaste	}
84260684Skaiw
85260684Skaiw	return -ENOENT;
86260684Skaiw}
87260684Skaiw