1 /* 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 15 /* We currently use FW, TB_FW, SOC_FW, TOS_FW, NS_fw and HW configs */ 16 #define MAX_DTB_INFO U(6) 17 18 #ifdef IMAGE_BL1 19 static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO] = { 20 [0] = { 21 .config_addr = ARM_FW_CONFIG_BASE, 22 .config_max_size = (uint32_t) 23 (ARM_FW_CONFIG_LIMIT - ARM_FW_CONFIG_BASE), 24 .config_id = FW_CONFIG_ID 25 }, 26 }; 27 /* Create an object pool starting at the second element */ 28 static OBJECT_POOL(dtb_info_pool, &dtb_infos[1], 29 sizeof(struct dyn_cfg_dtb_info_t), MAX_DTB_INFO-1); 30 #else 31 static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO]; 32 static OBJECT_POOL_ARRAY(dtb_info_pool, dtb_infos); 33 #endif 34 35 struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id) 36 { 37 unsigned int index; 38 struct dyn_cfg_dtb_info_t *info; 39 40 /* Positions index to the proper config-id */ 41 for (index = 0; index < MAX_DTB_INFO; index++) { 42 if (dtb_infos[index].config_id == config_id) { 43 info = &dtb_infos[index]; 44 break; 45 } 46 } 47 48 if (index == MAX_DTB_INFO) { 49 WARN("FCONF: Invalid config id %u\n", config_id); 50 info = NULL; 51 } 52 53 return info; 54 } 55 56 int fconf_populate_dtb_registry(uintptr_t config) 57 { 58 int rc; 59 int node, child; 60 struct dyn_cfg_dtb_info_t *dtb_info; 61 62 /* As libfdt use void *, we can't avoid this cast */ 63 const void *dtb = (void *)config; 64 65 /* Find the node offset point to "fconf,dyn_cfg-dtb_registry" compatible property */ 66 const char *compatible_str = "fconf,dyn_cfg-dtb_registry"; 67 node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); 68 if (node < 0) { 69 ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str); 70 return node; 71 } 72 73 #ifndef IMAGE_BL1 74 /* Save config dtb information */ 75 dtb_info = pool_alloc(&dtb_info_pool); 76 77 dtb_info->config_addr = config; 78 dtb_info->config_max_size = fdt_totalsize(dtb); 79 dtb_info->config_id = FW_CONFIG_ID; 80 #endif 81 82 fdt_for_each_subnode(child, dtb, node) { 83 uint32_t val32; 84 uint64_t val64; 85 86 dtb_info = pool_alloc(&dtb_info_pool); 87 88 /* Read configuration dtb information */ 89 rc = fdt_read_uint64(dtb, child, "load-address", &val64); 90 if (rc < 0) { 91 ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); 92 return rc; 93 } 94 dtb_info->config_addr = (uintptr_t)val64; 95 96 rc = fdt_read_uint32(dtb, child, "max-size", &val32); 97 if (rc < 0) { 98 ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); 99 return rc; 100 } 101 dtb_info->config_max_size = val32; 102 103 rc = fdt_read_uint32(dtb, child, "id", &val32); 104 if (rc < 0) { 105 ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); 106 return rc; 107 } 108 dtb_info->config_id = val32; 109 110 VERBOSE("FCONF: dyn_cfg.dtb_registry cell found with:\n"); 111 VERBOSE("\tload-address = %lx\n", dtb_info->config_addr); 112 VERBOSE("\tmax-size = 0x%zx\n", dtb_info->config_max_size); 113 VERBOSE("\tconfig-id = %u\n", dtb_info->config_id); 114 } 115 116 if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) { 117 ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node); 118 return child; 119 } 120 121 return 0; 122 } 123 124 FCONF_REGISTER_POPULATOR(FW_CONFIG, dyn_cfg, fconf_populate_dtb_registry); 125