aboutsummaryrefslogtreecommitdiff
path: root/lib/fconf/fconf_dyn_cfg_getter.c
blob: 902c07d955eaa5b1e19d1c0c37471e2445216050 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>

#include <common/debug.h>
#include <common/fdt_wrappers.h>
#include <lib/fconf/fconf_dyn_cfg_getter.h>
#include <lib/object_pool.h>
#include <libfdt.h>

/* We currently use FW, TB_FW, SOC_FW, TOS_FW, NS_fw and HW configs  */
#define MAX_DTB_INFO	U(6)

static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO];
static OBJECT_POOL_ARRAY(dtb_info_pool, dtb_infos);

/*
 * This function is used to alloc memory for fw config information from
 * global pool and set fw configuration information.
 * Specifically used by BL1 to set fw_config information in global array
 */
void set_fw_config_info(uintptr_t config_addr, uint32_t config_max_size)
{
	struct dyn_cfg_dtb_info_t *dtb_info;

	dtb_info = pool_alloc(&dtb_info_pool);
	dtb_info->config_addr = config_addr;
	dtb_info->config_max_size = config_max_size;
	dtb_info->config_id = FW_CONFIG_ID;
}

struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id)
{
	unsigned int index;
	struct dyn_cfg_dtb_info_t *info;

	/* Positions index to the proper config-id */
	for (index = 0; index < MAX_DTB_INFO; index++) {
		if (dtb_infos[index].config_id == config_id) {
			info = &dtb_infos[index];
			break;
		}
	}

	if (index == MAX_DTB_INFO) {
		WARN("FCONF: Invalid config id %u\n", config_id);
		info = NULL;
	}

	return info;
}

int fconf_populate_dtb_registry(uintptr_t config)
{
	int rc;
	int node, child;
	struct dyn_cfg_dtb_info_t *dtb_info;

	/* As libfdt use void *, we can't avoid this cast */
	const void *dtb = (void *)config;

	/*
	 * Compile time assert if FW_CONFIG_ID is 0 which is more
	 * unlikely as 0 is a valid image id for FIP as per the current
	 * code but still to avoid code breakage in case of unlikely
	 * event when image ids gets changed.
	 */
	CASSERT(FW_CONFIG_ID != 0, assert_invalid_fw_config_id);

	/*
	 * In case of BL1, fw_config dtb information is already
	 * populated in global dtb_infos array by 'set_fw_config_info'
	 * function, Below check is present to avoid re-population of
	 * fw_config information.
	 *
	 * Other BLs, satisfy below check and populate fw_config information
	 * in global dtb_infos array.
	 */
	if (dtb_infos[0].config_id == 0) {
		dtb_info = pool_alloc(&dtb_info_pool);
		dtb_info->config_addr = config;
		dtb_info->config_max_size = fdt_totalsize(dtb);
		dtb_info->config_id = FW_CONFIG_ID;
	}

	/* Find the node offset point to "fconf,dyn_cfg-dtb_registry" compatible property */
	const char *compatible_str = "fconf,dyn_cfg-dtb_registry";
	node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
	if (node < 0) {
		ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
		return node;
	}

	fdt_for_each_subnode(child, dtb, node) {
		uint32_t val32;
		uint64_t val64;

		dtb_info = pool_alloc(&dtb_info_pool);

		/* Read configuration dtb information */
		rc = fdt_read_uint64(dtb, child, "load-address", &val64);
		if (rc < 0) {
			ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
			return rc;
		}
		dtb_info->config_addr = (uintptr_t)val64;

		rc = fdt_read_uint32(dtb, child, "max-size", &val32);
		if (rc < 0) {
			ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
			return rc;
		}
		dtb_info->config_max_size = val32;

		rc = fdt_read_uint32(dtb, child, "id", &val32);
		if (rc < 0) {
			ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
			return rc;
		}
		dtb_info->config_id = val32;

		VERBOSE("FCONF: dyn_cfg.dtb_registry cell found with:\n");
		VERBOSE("\tload-address = %lx\n", dtb_info->config_addr);
		VERBOSE("\tmax-size = 0x%zx\n", dtb_info->config_max_size);
		VERBOSE("\tconfig-id = %u\n", dtb_info->config_id);
	}

	if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
		ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
		return child;
	}

	return 0;
}

FCONF_REGISTER_POPULATOR(FW_CONFIG, dyn_cfg, fconf_populate_dtb_registry);