13fc4124cSDan Handley /*
2*6d8546f9SChris Kay * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
33fc4124cSDan Handley *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
53fc4124cSDan Handley */
63fc4124cSDan Handley
76138ffbcSMadhukar Pappireddy #include <assert.h>
809d40e0eSAntonio Nino Diaz
909d40e0eSAntonio Nino Diaz #include <arch.h>
10560293bbSAntonio Nino Diaz #include <drivers/arm/fvp/fvp_pwrc.h>
116138ffbcSMadhukar Pappireddy #include <fconf_hw_config_getter.h>
1209d40e0eSAntonio Nino Diaz #include <lib/cassert.h>
13bd9344f6SAntonio Nino Diaz #include <plat/arm/common/arm_config.h>
14bd9344f6SAntonio Nino Diaz #include <plat/arm/common/plat_arm.h>
1509d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
1609d40e0eSAntonio Nino Diaz
176138ffbcSMadhukar Pappireddy #include <platform_def.h>
186138ffbcSMadhukar Pappireddy
190108047aSSoby Mathew /* The FVP power domain tree descriptor */
201af540efSRoberto Vargas static unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 2];
210108047aSSoby Mathew
220108047aSSoby Mathew
2389509904SSathees Balya CASSERT(((FVP_CLUSTER_COUNT > 0) && (FVP_CLUSTER_COUNT <= 256)),
2489509904SSathees Balya assert_invalid_fvp_cluster_count);
250108047aSSoby Mathew
260108047aSSoby Mathew /*******************************************************************************
276138ffbcSMadhukar Pappireddy * This function dynamically constructs the topology according to cpu-map node
286138ffbcSMadhukar Pappireddy * in HW_CONFIG dtb and returns it.
290108047aSSoby Mathew ******************************************************************************/
plat_get_power_domain_tree_desc(void)300108047aSSoby Mathew const unsigned char *plat_get_power_domain_tree_desc(void)
310108047aSSoby Mathew {
326138ffbcSMadhukar Pappireddy unsigned int i;
336138ffbcSMadhukar Pappireddy uint32_t cluster_count, cpus_per_cluster;
346138ffbcSMadhukar Pappireddy
356138ffbcSMadhukar Pappireddy /*
366138ffbcSMadhukar Pappireddy * fconf APIs are not supported for RESET_TO_SP_MIN, RESET_TO_BL31 and
3742d4d3baSArvind Ram Prakash * RESET_TO_BL2 systems.
386138ffbcSMadhukar Pappireddy */
39*6d8546f9SChris Kay #if RESET_TO_SP_MIN || RESET_TO_BL31 || RESET_TO_BL2 || IMAGE_BL1
406138ffbcSMadhukar Pappireddy cluster_count = FVP_CLUSTER_COUNT;
416138ffbcSMadhukar Pappireddy cpus_per_cluster = FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU;
426138ffbcSMadhukar Pappireddy #else
436138ffbcSMadhukar Pappireddy cluster_count = FCONF_GET_PROPERTY(hw_config, topology, plat_cluster_count);
446138ffbcSMadhukar Pappireddy cpus_per_cluster = FCONF_GET_PROPERTY(hw_config, topology, cluster_cpu_count);
456138ffbcSMadhukar Pappireddy /* Several FVP Models use the same blanket dts. Ex: FVP_Base_Cortex-A65x4
466138ffbcSMadhukar Pappireddy * and FVP_Base_Cortex-A65AEx8 both use same dts but have different number of
476138ffbcSMadhukar Pappireddy * CPUs in the cluster, as reflected by build flags FVP_MAX_CPUS_PER_CLUSTER.
486138ffbcSMadhukar Pappireddy * Take the minimum of two to ensure PSCI functions do not exceed the size of
496138ffbcSMadhukar Pappireddy * the PSCI data structures allocated at build time.
506138ffbcSMadhukar Pappireddy */
516138ffbcSMadhukar Pappireddy cpus_per_cluster = MIN(cpus_per_cluster,
526138ffbcSMadhukar Pappireddy (uint32_t)(FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU));
536138ffbcSMadhukar Pappireddy
546138ffbcSMadhukar Pappireddy #endif
556138ffbcSMadhukar Pappireddy
566138ffbcSMadhukar Pappireddy assert(cluster_count > 0U);
576138ffbcSMadhukar Pappireddy assert(cpus_per_cluster > 0U);
580108047aSSoby Mathew
5938dce70fSSoby Mathew /*
60e35a3fb5SSoby Mathew * The highest level is the system level. The next level is constituted
61e35a3fb5SSoby Mathew * by clusters and then cores in clusters.
6238dce70fSSoby Mathew */
63e35a3fb5SSoby Mathew fvp_power_domain_tree_desc[0] = 1;
646138ffbcSMadhukar Pappireddy fvp_power_domain_tree_desc[1] = (unsigned char)cluster_count;
653fc4124cSDan Handley
666138ffbcSMadhukar Pappireddy for (i = 0; i < cluster_count; i++)
676138ffbcSMadhukar Pappireddy fvp_power_domain_tree_desc[i + 2] = (unsigned char)cpus_per_cluster;
680108047aSSoby Mathew
690108047aSSoby Mathew return fvp_power_domain_tree_desc;
700108047aSSoby Mathew }
710108047aSSoby Mathew
720108047aSSoby Mathew /*******************************************************************************
730108047aSSoby Mathew * This function returns the core count within the cluster corresponding to
740108047aSSoby Mathew * `mpidr`.
750108047aSSoby Mathew ******************************************************************************/
plat_arm_get_cluster_core_count(u_register_t mpidr)760108047aSSoby Mathew unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
770108047aSSoby Mathew {
780108047aSSoby Mathew return FVP_MAX_CPUS_PER_CLUSTER;
790108047aSSoby Mathew }
803fc4124cSDan Handley
813fc4124cSDan Handley /*******************************************************************************
823fc4124cSDan Handley * This function implements a part of the critical interface between the psci
8338dce70fSSoby Mathew * generic layer and the platform that allows the former to query the platform
8438dce70fSSoby Mathew * to convert an MPIDR to a unique linear index. An error code (-1) is returned
8538dce70fSSoby Mathew * in case the MPIDR is invalid.
863fc4124cSDan Handley ******************************************************************************/
plat_core_pos_by_mpidr(u_register_t mpidr)8738dce70fSSoby Mathew int plat_core_pos_by_mpidr(u_register_t mpidr)
883fc4124cSDan Handley {
89955242d8SJeenu Viswambharan unsigned int clus_id, cpu_id, thread_id;
90955242d8SJeenu Viswambharan
91955242d8SJeenu Viswambharan /* Validate affinity fields */
9289509904SSathees Balya if ((arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) != 0U) {
93955242d8SJeenu Viswambharan thread_id = MPIDR_AFFLVL0_VAL(mpidr);
94955242d8SJeenu Viswambharan cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
95955242d8SJeenu Viswambharan clus_id = MPIDR_AFFLVL2_VAL(mpidr);
96955242d8SJeenu Viswambharan } else {
97955242d8SJeenu Viswambharan thread_id = 0;
98955242d8SJeenu Viswambharan cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
99955242d8SJeenu Viswambharan clus_id = MPIDR_AFFLVL1_VAL(mpidr);
100955242d8SJeenu Viswambharan }
101955242d8SJeenu Viswambharan
102955242d8SJeenu Viswambharan if (clus_id >= FVP_CLUSTER_COUNT)
103955242d8SJeenu Viswambharan return -1;
104955242d8SJeenu Viswambharan if (cpu_id >= FVP_MAX_CPUS_PER_CLUSTER)
105955242d8SJeenu Viswambharan return -1;
106955242d8SJeenu Viswambharan if (thread_id >= FVP_MAX_PE_PER_CPU)
107955242d8SJeenu Viswambharan return -1;
108955242d8SJeenu Viswambharan
109*6d8546f9SChris Kay #if !IMAGE_BL1
11038dce70fSSoby Mathew if (fvp_pwrc_read_psysr(mpidr) == PSYSR_INVALID)
11138dce70fSSoby Mathew return -1;
112*6d8546f9SChris Kay #endif /* IMAGE_BL1 */
1133fc4124cSDan Handley
11411ad8f20SJeenu Viswambharan /*
11511ad8f20SJeenu Viswambharan * Core position calculation for FVP platform depends on the MT bit in
11611ad8f20SJeenu Viswambharan * MPIDR. This function cannot assume that the supplied MPIDR has the MT
11711ad8f20SJeenu Viswambharan * bit set even if the implementation has. For example, PSCI clients
11811ad8f20SJeenu Viswambharan * might supply MPIDR values without the MT bit set. Therefore, we
11911ad8f20SJeenu Viswambharan * inject the current PE's MT bit so as to get the calculation correct.
12011ad8f20SJeenu Viswambharan * This of course assumes that none or all CPUs on the platform has MT
12111ad8f20SJeenu Viswambharan * bit set.
12211ad8f20SJeenu Viswambharan */
12311ad8f20SJeenu Viswambharan mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
12489509904SSathees Balya return (int) plat_arm_calc_core_pos(mpidr);
1253fc4124cSDan Handley }
126