1 /* 2 * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 9 #include <libfdt.h> 10 11 #include <common/bl_common.h> 12 #include <common/debug.h> 13 #include <drivers/arm/css/css_mhu_doorbell.h> 14 #include <drivers/arm/css/scmi.h> 15 #include <drivers/generic_delay_timer.h> 16 #include <lib/fconf/fconf.h> 17 #include <lib/fconf/fconf_dyn_cfg_getter.h> 18 #include <plat/arm/common/plat_arm.h> 19 #include <plat/arm/css/common/css_pm.h> 20 #include <plat/common/platform.h> 21 22 #include <nrd_ras.h> 23 #include <nrd_variant.h> 24 25 nrd_platform_info_t nrd_plat_info; 26 27 static scmi_channel_plat_info_t plat_rd_scmi_info[] = { 28 { 29 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, 30 .db_reg_addr = PLAT_CSS_MHU_BASE + SENDER_REG_SET(0), 31 .db_preserve_mask = 0xfffffffe, 32 .db_modify_mask = 0x1, 33 .ring_doorbell = &mhuv2_ring_doorbell, 34 }, 35 #if (NRD_CHIP_COUNT > 1) 36 { 37 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE + 38 NRD_REMOTE_CHIP_MEM_OFFSET(1), 39 .db_reg_addr = PLAT_CSS_MHU_BASE 40 + NRD_REMOTE_CHIP_MEM_OFFSET(1) + SENDER_REG_SET(0), 41 .db_preserve_mask = 0xfffffffe, 42 .db_modify_mask = 0x1, 43 .ring_doorbell = &mhuv2_ring_doorbell, 44 }, 45 #endif 46 #if (NRD_CHIP_COUNT > 2) 47 { 48 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE + 49 NRD_REMOTE_CHIP_MEM_OFFSET(2), 50 .db_reg_addr = PLAT_CSS_MHU_BASE + 51 NRD_REMOTE_CHIP_MEM_OFFSET(2) + SENDER_REG_SET(0), 52 .db_preserve_mask = 0xfffffffe, 53 .db_modify_mask = 0x1, 54 .ring_doorbell = &mhuv2_ring_doorbell, 55 }, 56 #endif 57 #if (NRD_CHIP_COUNT > 3) 58 { 59 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE + 60 NRD_REMOTE_CHIP_MEM_OFFSET(3), 61 .db_reg_addr = PLAT_CSS_MHU_BASE + 62 NRD_REMOTE_CHIP_MEM_OFFSET(3) + SENDER_REG_SET(0), 63 .db_preserve_mask = 0xfffffffe, 64 .db_modify_mask = 0x1, 65 .ring_doorbell = &mhuv2_ring_doorbell, 66 }, 67 #endif 68 }; 69 70 static scmi_channel_plat_info_t plat3_rd_scmi_info[] = { 71 { 72 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, 73 .db_reg_addr = PLAT_CSS_MHU_BASE + MHU_V3_SENDER_REG_SET(0), 74 .db_preserve_mask = 0xfffffffe, 75 .db_modify_mask = 0x1, 76 .ring_doorbell = &mhu_ring_doorbell, 77 }, 78 #if (NRD_CHIP_COUNT > 1) 79 { 80 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE + 81 NRD_REMOTE_CHIP_MEM_OFFSET(1), 82 .db_reg_addr = PLAT_CSS_MHU_BASE + 83 NRD_REMOTE_CHIP_MEM_OFFSET(1) + 84 MHU_V3_SENDER_REG_SET(0), 85 .db_preserve_mask = 0xfffffffe, 86 .db_modify_mask = 0x1, 87 .ring_doorbell = &mhu_ring_doorbell, 88 }, 89 #endif 90 #if (NRD_CHIP_COUNT > 2) 91 { 92 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE + 93 NRD_REMOTE_CHIP_MEM_OFFSET(2), 94 .db_reg_addr = PLAT_CSS_MHU_BASE + 95 NRD_REMOTE_CHIP_MEM_OFFSET(2) + 96 MHU_V3_SENDER_REG_SET(0), 97 .db_preserve_mask = 0xfffffffe, 98 .db_modify_mask = 0x1, 99 .ring_doorbell = &mhu_ring_doorbell, 100 }, 101 #endif 102 #if (NRD_CHIP_COUNT > 3) 103 { 104 .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE + 105 NRD_REMOTE_CHIP_MEM_OFFSET(3), 106 .db_reg_addr = PLAT_CSS_MHU_BASE + 107 NRD_REMOTE_CHIP_MEM_OFFSET(3) + 108 MHU_V3_SENDER_REG_SET(0), 109 .db_preserve_mask = 0xfffffffe, 110 .db_modify_mask = 0x1, 111 .ring_doorbell = &mhu_ring_doorbell, 112 }, 113 #endif 114 }; 115 116 scmi_channel_plat_info_t *plat_css_get_scmi_info(unsigned int channel_id) 117 { 118 if (nrd_plat_info.platform_id == RD_N2_SID_VER_PART_NUM || 119 nrd_plat_info.platform_id == RD_V2_SID_VER_PART_NUM || 120 nrd_plat_info.platform_id == RD_N2_CFG1_SID_VER_PART_NUM || 121 nrd_plat_info.platform_id == RD_N2_CFG3_SID_VER_PART_NUM) { 122 if (channel_id >= ARRAY_SIZE(plat_rd_scmi_info)) { 123 panic(); 124 } 125 return &plat_rd_scmi_info[channel_id]; 126 } else if (nrd_plat_info.platform_id == RD_V3_SID_VER_PART_NUM || 127 nrd_plat_info.platform_id == RD_V3_CFG1_SID_VER_PART_NUM || 128 nrd_plat_info.platform_id == RD_V3_CFG2_SID_VER_PART_NUM) { 129 if (channel_id >= ARRAY_SIZE(plat3_rd_scmi_info)) { 130 panic(); 131 } 132 return &plat3_rd_scmi_info[channel_id]; 133 } else { 134 panic(); 135 } 136 } 137 138 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, 139 u_register_t arg2, u_register_t arg3) 140 { 141 /* Initialize the console to provide early debug support */ 142 arm_console_boot_init(); 143 144 nrd_plat_info.platform_id = plat_arm_nrd_get_platform_id(); 145 nrd_plat_info.config_id = plat_arm_nrd_get_config_id(); 146 nrd_plat_info.multi_chip_mode = plat_arm_nrd_get_multi_chip_mode(); 147 148 #if RESET_TO_BL31 149 #if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER) 150 /* Set the counter frequency for the generic timer */ 151 write_cntfrq_el0(plat_get_syscnt_freq2()); 152 #endif 153 #endif /* RESET_TO_BL31 */ 154 155 /* Initialize generic timer */ 156 generic_delay_timer_init(); 157 158 #if SPMD_SPM_AT_SEL2 && !RESET_TO_BL31 159 INFO("BL31 FCONF: FW_CONFIG address = 0x%lx\n", (uintptr_t)arg1); 160 /* Initialize BL31's copy of the DTB registry because SPMD needs the 161 * TOS_FW_CONFIG's addresses to make a copy. 162 */ 163 fconf_populate("FW_CONFIG", arg1); 164 165 /* arg1 is supposed to point to SOC_FW_CONFIG */ 166 const struct dyn_cfg_dtb_info_t *soc_fw_config_info; 167 168 soc_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, SOC_FW_CONFIG_ID); 169 if (soc_fw_config_info != NULL) { 170 arg1 = soc_fw_config_info->config_addr; 171 } 172 #endif /* SPMD_SPM_AT_SEL2 && !RESET_TO_BL31 */ 173 arm_bl31_early_platform_setup(arg0, arg1, arg2, arg3); 174 } 175 176 /******************************************************************************* 177 * This function inserts platform information via device tree nodes as, 178 * system-id { 179 * platform-id = <0>; 180 * config-id = <0>; 181 * } 182 ******************************************************************************/ 183 #if RESET_TO_BL31 184 static int append_config_node(uintptr_t fdt_base_addr, uintptr_t fdt_base_size) 185 { 186 void *fdt; 187 int nodeoffset, err; 188 unsigned int platid = 0, platcfg = 0; 189 190 if (fdt_base_addr == 0) { 191 ERROR("NT_FW CONFIG base address is NULL\n"); 192 return -1; 193 } 194 195 fdt = (void *)fdt_base_addr; 196 197 /* Check the validity of the fdt */ 198 if (fdt_check_header(fdt) != 0) { 199 ERROR("Invalid NT_FW_CONFIG DTB passed\n"); 200 return -1; 201 } 202 203 nodeoffset = fdt_subnode_offset(fdt, 0, "system-id"); 204 if (nodeoffset < 0) { 205 ERROR("Failed to get system-id node offset\n"); 206 return -1; 207 } 208 209 platid = plat_arm_nrd_get_platform_id(); 210 err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid); 211 if (err < 0) { 212 ERROR("Failed to set platform-id\n"); 213 return -1; 214 } 215 216 platcfg = plat_arm_nrd_get_config_id(); 217 err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg); 218 if (err < 0) { 219 ERROR("Failed to set config-id\n"); 220 return -1; 221 } 222 223 platcfg = plat_arm_nrd_get_multi_chip_mode(); 224 err = fdt_setprop_u32(fdt, nodeoffset, "multi-chip-mode", platcfg); 225 if (err < 0) { 226 ERROR("Failed to set multi-chip-mode\n"); 227 return -1; 228 } 229 230 flush_dcache_range((uintptr_t)fdt, fdt_base_size); 231 return 0; 232 } 233 #endif 234 235 void nrd_bl31_common_platform_setup(void) 236 { 237 238 arm_bl31_platform_setup(); 239 240 /* Configure the warm reboot SGI for primary core */ 241 css_setup_cpu_pwr_down_intr(); 242 243 #if CSS_SYSTEM_GRACEFUL_RESET 244 /* Register priority level handlers for reboot */ 245 ehf_register_priority_handler(PLAT_REBOOT_PRI, 246 css_reboot_interrupt_handler); 247 #endif 248 249 #if RESET_TO_BL31 250 int ret = append_config_node(NRD_CSS_BL31_PRELOAD_DTB_BASE, 251 NRD_CSS_BL31_PRELOAD_DTB_SIZE); 252 253 if (ret != 0) { 254 panic(); 255 } 256 #endif 257 } 258 259 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) 260 { 261 return css_scmi_override_pm_ops(ops); 262 } 263