1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2019-2023, Arm Limited. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <common/debug.h> 10*91f16700Schasinglulu #include <common/fdt_wrappers.h> 11*91f16700Schasinglulu #include <lib/fconf/fconf_dyn_cfg_getter.h> 12*91f16700Schasinglulu #include <lib/object_pool.h> 13*91f16700Schasinglulu #include <libfdt.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include <platform_def.h> 16*91f16700Schasinglulu 17*91f16700Schasinglulu /* We currently use FW, TB_FW, SOC_FW, TOS_FW, NT_FW and HW configs */ 18*91f16700Schasinglulu #define MAX_DTB_INFO U(6) 19*91f16700Schasinglulu /* 20*91f16700Schasinglulu * Compile time assert if FW_CONFIG_ID is 0 which is more 21*91f16700Schasinglulu * unlikely as 0 is a valid image ID for FIP as per the current 22*91f16700Schasinglulu * code but still to avoid code breakage in case of unlikely 23*91f16700Schasinglulu * event when image IDs get changed. 24*91f16700Schasinglulu */ 25*91f16700Schasinglulu CASSERT(FW_CONFIG_ID != U(0), assert_invalid_fw_config_id); 26*91f16700Schasinglulu 27*91f16700Schasinglulu static struct dyn_cfg_dtb_info_t dtb_infos[MAX_DTB_INFO]; 28*91f16700Schasinglulu static OBJECT_POOL_ARRAY(dtb_info_pool, dtb_infos); 29*91f16700Schasinglulu 30*91f16700Schasinglulu /* 31*91f16700Schasinglulu * This function is used to alloc memory for config information from 32*91f16700Schasinglulu * global pool and set the configuration information. 33*91f16700Schasinglulu */ 34*91f16700Schasinglulu void set_config_info(uintptr_t config_addr, uintptr_t secondary_config_addr, 35*91f16700Schasinglulu uint32_t config_max_size, 36*91f16700Schasinglulu unsigned int config_id) 37*91f16700Schasinglulu { 38*91f16700Schasinglulu struct dyn_cfg_dtb_info_t *dtb_info; 39*91f16700Schasinglulu 40*91f16700Schasinglulu dtb_info = pool_alloc(&dtb_info_pool); 41*91f16700Schasinglulu dtb_info->config_addr = config_addr; 42*91f16700Schasinglulu dtb_info->secondary_config_addr = secondary_config_addr; 43*91f16700Schasinglulu dtb_info->config_max_size = config_max_size; 44*91f16700Schasinglulu dtb_info->config_id = config_id; 45*91f16700Schasinglulu } 46*91f16700Schasinglulu 47*91f16700Schasinglulu /* Get index of the config_id image */ 48*91f16700Schasinglulu unsigned int dyn_cfg_dtb_info_get_index(unsigned int config_id) 49*91f16700Schasinglulu { 50*91f16700Schasinglulu unsigned int index; 51*91f16700Schasinglulu 52*91f16700Schasinglulu /* Positions index to the proper config-id */ 53*91f16700Schasinglulu for (index = 0U; index < MAX_DTB_INFO; index++) { 54*91f16700Schasinglulu if (dtb_infos[index].config_id == config_id) { 55*91f16700Schasinglulu return index; 56*91f16700Schasinglulu } 57*91f16700Schasinglulu } 58*91f16700Schasinglulu 59*91f16700Schasinglulu return FCONF_INVALID_IDX; 60*91f16700Schasinglulu } 61*91f16700Schasinglulu 62*91f16700Schasinglulu struct dyn_cfg_dtb_info_t *dyn_cfg_dtb_info_getter(unsigned int config_id) 63*91f16700Schasinglulu { 64*91f16700Schasinglulu /* Positions index to the proper config-id */ 65*91f16700Schasinglulu unsigned int index = dyn_cfg_dtb_info_get_index(config_id); 66*91f16700Schasinglulu 67*91f16700Schasinglulu if (index < MAX_DTB_INFO) { 68*91f16700Schasinglulu return &dtb_infos[index]; 69*91f16700Schasinglulu } 70*91f16700Schasinglulu 71*91f16700Schasinglulu WARN("FCONF: Invalid config id %u\n", config_id); 72*91f16700Schasinglulu 73*91f16700Schasinglulu return NULL; 74*91f16700Schasinglulu } 75*91f16700Schasinglulu 76*91f16700Schasinglulu int fconf_populate_dtb_registry(uintptr_t config) 77*91f16700Schasinglulu { 78*91f16700Schasinglulu int rc; 79*91f16700Schasinglulu int node, child; 80*91f16700Schasinglulu 81*91f16700Schasinglulu /* As libfdt use void *, we can't avoid this cast */ 82*91f16700Schasinglulu const void *dtb = (void *)config; 83*91f16700Schasinglulu 84*91f16700Schasinglulu /* 85*91f16700Schasinglulu * In case of BL1, fw_config dtb information is already 86*91f16700Schasinglulu * populated in global dtb_infos array by 'set_config_info' 87*91f16700Schasinglulu * function, Below check is present to avoid re-population of 88*91f16700Schasinglulu * fw_config information. 89*91f16700Schasinglulu * 90*91f16700Schasinglulu * Other BLs, satisfy below check and populate fw_config information 91*91f16700Schasinglulu * in global dtb_infos array. 92*91f16700Schasinglulu */ 93*91f16700Schasinglulu if (dtb_infos[0].config_id == 0U) { 94*91f16700Schasinglulu uint32_t config_max_size = fdt_totalsize(dtb); 95*91f16700Schasinglulu set_config_info(config, ~0UL, config_max_size, FW_CONFIG_ID); 96*91f16700Schasinglulu } 97*91f16700Schasinglulu 98*91f16700Schasinglulu /* Find the node offset point to "fconf,dyn_cfg-dtb_registry" compatible property */ 99*91f16700Schasinglulu const char *compatible_str = "fconf,dyn_cfg-dtb_registry"; 100*91f16700Schasinglulu node = fdt_node_offset_by_compatible(dtb, -1, compatible_str); 101*91f16700Schasinglulu if (node < 0) { 102*91f16700Schasinglulu ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str); 103*91f16700Schasinglulu return node; 104*91f16700Schasinglulu } 105*91f16700Schasinglulu 106*91f16700Schasinglulu fdt_for_each_subnode(child, dtb, node) { 107*91f16700Schasinglulu uint32_t config_max_size, config_id; 108*91f16700Schasinglulu uintptr_t config_addr; 109*91f16700Schasinglulu uintptr_t secondary_config_addr = ~0UL; 110*91f16700Schasinglulu uint64_t val64; 111*91f16700Schasinglulu 112*91f16700Schasinglulu /* Read configuration dtb information */ 113*91f16700Schasinglulu rc = fdt_read_uint64(dtb, child, "load-address", &val64); 114*91f16700Schasinglulu if (rc < 0) { 115*91f16700Schasinglulu ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); 116*91f16700Schasinglulu return rc; 117*91f16700Schasinglulu } 118*91f16700Schasinglulu config_addr = (uintptr_t)val64; 119*91f16700Schasinglulu 120*91f16700Schasinglulu rc = fdt_read_uint32(dtb, child, "max-size", &config_max_size); 121*91f16700Schasinglulu if (rc < 0) { 122*91f16700Schasinglulu ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); 123*91f16700Schasinglulu return rc; 124*91f16700Schasinglulu } 125*91f16700Schasinglulu 126*91f16700Schasinglulu rc = fdt_read_uint32(dtb, child, "id", &config_id); 127*91f16700Schasinglulu if (rc < 0) { 128*91f16700Schasinglulu ERROR("FCONF: Incomplete configuration property in dtb-registry.\n"); 129*91f16700Schasinglulu return rc; 130*91f16700Schasinglulu } 131*91f16700Schasinglulu 132*91f16700Schasinglulu VERBOSE("FCONF: dyn_cfg.dtb_registry cell found with:\n"); 133*91f16700Schasinglulu VERBOSE("\tload-address = %lx\n", config_addr); 134*91f16700Schasinglulu VERBOSE("\tmax-size = 0x%x\n", config_max_size); 135*91f16700Schasinglulu VERBOSE("\tconfig-id = %u\n", config_id); 136*91f16700Schasinglulu 137*91f16700Schasinglulu rc = fdt_read_uint64(dtb, child, "secondary-load-address", 138*91f16700Schasinglulu &val64); 139*91f16700Schasinglulu if (rc == 0) { 140*91f16700Schasinglulu secondary_config_addr = (uintptr_t)val64; 141*91f16700Schasinglulu VERBOSE("\tsecondary-load-address = %lx\n", 142*91f16700Schasinglulu secondary_config_addr); 143*91f16700Schasinglulu } 144*91f16700Schasinglulu 145*91f16700Schasinglulu set_config_info(config_addr, secondary_config_addr, 146*91f16700Schasinglulu config_max_size, config_id); 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) { 150*91f16700Schasinglulu ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node); 151*91f16700Schasinglulu return child; 152*91f16700Schasinglulu } 153*91f16700Schasinglulu 154*91f16700Schasinglulu return 0; 155*91f16700Schasinglulu } 156*91f16700Schasinglulu 157*91f16700Schasinglulu FCONF_REGISTER_POPULATOR(FW_CONFIG, dyn_cfg, fconf_populate_dtb_registry); 158