blob: 16bbe42c8e1bca662cc10cf35b2ce1de6f6d88b5 [file] [log] [blame]
Louis Mayencourt6d2b5732019-12-17 13:17:25 +00001/*
2 * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8
9#include <common/debug.h>
10#include <common/fdt_wrappers.h>
11#include <lib/fconf/fconf_dyn_cfg_getter.h>
12#include <lib/object_pool.h>
13#include <libfdt.h>
14
Alexei Fedorov40e7d6c2020-07-13 14:10:00 +010015/* We currently use FW, TB_FW, SOC_FW, TOS_FW, NT_FW and HW configs */
Manish V Badarkhebb533c72020-06-11 22:17:30 +010016#define MAX_DTB_INFO U(6)
Louis Mayencourt6d2b5732019-12-17 13:17:25 +000017
18static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO];
19static OBJECT_POOL_ARRAY(dtb_info_pool, dtb_infos);
Manish V Badarkhe99a8e142020-06-11 22:32:11 +010020
21/*
22 * This function is used to alloc memory for fw config information from
23 * global pool and set fw configuration information.
24 * Specifically used by BL1 to set fw_config information in global array
25 */
26void set_fw_config_info(uintptr_t config_addr, uint32_t config_max_size)
27{
28 struct dyn_cfg_dtb_info_t *dtb_info;
29
30 dtb_info = pool_alloc(&dtb_info_pool);
31 dtb_info->config_addr = config_addr;
32 dtb_info->config_max_size = config_max_size;
33 dtb_info->config_id = FW_CONFIG_ID;
34}
Louis Mayencourt6d2b5732019-12-17 13:17:25 +000035
36struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id)
37{
38 unsigned int index;
39 struct dyn_cfg_dtb_info_t *info;
40
41 /* Positions index to the proper config-id */
42 for (index = 0; index < MAX_DTB_INFO; index++) {
43 if (dtb_infos[index].config_id == config_id) {
44 info = &dtb_infos[index];
45 break;
46 }
47 }
48
49 if (index == MAX_DTB_INFO) {
50 WARN("FCONF: Invalid config id %u\n", config_id);
51 info = NULL;
52 }
53
54 return info;
55}
56
57int fconf_populate_dtb_registry(uintptr_t config)
58{
59 int rc;
60 int node, child;
61 struct dyn_cfg_dtb_info_t *dtb_info;
62
63 /* As libfdt use void *, we can't avoid this cast */
64 const void *dtb = (void *)config;
65
Manish V Badarkhe99a8e142020-06-11 22:32:11 +010066 /*
67 * Compile time assert if FW_CONFIG_ID is 0 which is more
68 * unlikely as 0 is a valid image id for FIP as per the current
69 * code but still to avoid code breakage in case of unlikely
70 * event when image ids gets changed.
71 */
72 CASSERT(FW_CONFIG_ID != 0, assert_invalid_fw_config_id);
73
74 /*
75 * In case of BL1, fw_config dtb information is already
76 * populated in global dtb_infos array by 'set_fw_config_info'
77 * function, Below check is present to avoid re-population of
78 * fw_config information.
79 *
80 * Other BLs, satisfy below check and populate fw_config information
81 * in global dtb_infos array.
82 */
83 if (dtb_infos[0].config_id == 0) {
84 dtb_info = pool_alloc(&dtb_info_pool);
85 dtb_info->config_addr = config;
86 dtb_info->config_max_size = fdt_totalsize(dtb);
87 dtb_info->config_id = FW_CONFIG_ID;
88 }
89
Louis Mayencourtb26fafa2020-04-20 14:17:21 +010090 /* Find the node offset point to "fconf,dyn_cfg-dtb_registry" compatible property */
91 const char *compatible_str = "fconf,dyn_cfg-dtb_registry";
Louis Mayencourt6d2b5732019-12-17 13:17:25 +000092 node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
93 if (node < 0) {
94 ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
95 return node;
96 }
97
98 fdt_for_each_subnode(child, dtb, node) {
Andre Przywarafe5bdf52020-03-26 11:22:37 +000099 uint32_t val32;
100 uint64_t val64;
101
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000102 dtb_info = pool_alloc(&dtb_info_pool);
103
104 /* Read configuration dtb information */
Andre Przywarafe5bdf52020-03-26 11:22:37 +0000105 rc = fdt_read_uint64(dtb, child, "load-address", &val64);
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000106 if (rc < 0) {
107 ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
108 return rc;
109 }
Andre Przywarafe5bdf52020-03-26 11:22:37 +0000110 dtb_info->config_addr = (uintptr_t)val64;
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000111
Andre Przywarafe5bdf52020-03-26 11:22:37 +0000112 rc = fdt_read_uint32(dtb, child, "max-size", &val32);
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000113 if (rc < 0) {
114 ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
115 return rc;
116 }
Andre Przywarafe5bdf52020-03-26 11:22:37 +0000117 dtb_info->config_max_size = val32;
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000118
Andre Przywarafe5bdf52020-03-26 11:22:37 +0000119 rc = fdt_read_uint32(dtb, child, "id", &val32);
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000120 if (rc < 0) {
121 ERROR("FCONF: Incomplete configuration property in dtb-registry.\n");
122 return rc;
123 }
Andre Przywarafe5bdf52020-03-26 11:22:37 +0000124 dtb_info->config_id = val32;
Louis Mayencourt6d2b5732019-12-17 13:17:25 +0000125
126 VERBOSE("FCONF: dyn_cfg.dtb_registry cell found with:\n");
127 VERBOSE("\tload-address = %lx\n", dtb_info->config_addr);
128 VERBOSE("\tmax-size = 0x%zx\n", dtb_info->config_max_size);
129 VERBOSE("\tconfig-id = %u\n", dtb_info->config_id);
130 }
131
132 if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
133 ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
134 return child;
135 }
136
137 return 0;
138}
139
Manish V Badarkhe64616a52020-05-31 08:53:40 +0100140FCONF_REGISTER_POPULATOR(FW_CONFIG, dyn_cfg, fconf_populate_dtb_registry);