1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <acpi/acpigen.h>
5 #include <commonlib/sort.h>
6 #include <cpu/x86/lapic.h>
7 #include <cpu/x86/mp.h>
9 #include <device/path.h>
10 #include <intelblocks/acpi.h>
15 #define CPPC_NOM_FREQ_IDX 22
16 #define CPPC_NOM_PERF_IDX 3
18 enum cpu_perf_eff_type
{
23 struct cpu_apic_info_type
{
25 * Ordered APIC IDs based on core type.
26 * Array begins with Performance Cores' APIC IDs,
27 * then followed by Efficeint Cores's APIC IDs.
29 int32_t apic_ids
[CONFIG_MAX_CPUS
];
32 uint16_t total_cpu_cnt
;
35 * Total Performance core count. This will be used
36 * to identify the start of Efficient Cores's
39 uint16_t perf_cpu_cnt
;
42 static struct cpu_apic_info_type cpu_apic_info
;
45 * The function orders APIC IDs such that orders first Performance cores and then
46 * Efficient cores' APIC IDs in ascending order. Also calculates total number of
47 * Performance cores and all cores count in the system and populates the information
48 * in the cpu_apic_info sturct.
50 static void acpi_set_hybrid_cpu_apicid_order(void *unused
)
52 size_t perf_core_cnt
= 0, eff_core_cnt
= 0;
53 int32_t eff_apic_ids
[CONFIG_MAX_CPUS
] = {0};
54 extern struct cpu_info cpu_infos
[];
57 for (i
= 0; i
< ARRAY_SIZE(cpu_apic_info
.apic_ids
); i
++) {
58 if (!cpu_infos
[i
].cpu
)
60 if (cpu_infos
[i
].cpu
->path
.apic
.core_type
== CPU_TYPE_PERF
)
61 cpu_apic_info
.apic_ids
[perf_core_cnt
++] =
62 cpu_infos
[i
].cpu
->path
.apic
.apic_id
;
64 eff_apic_ids
[eff_core_cnt
++] =
65 cpu_infos
[i
].cpu
->path
.apic
.apic_id
;
68 if (perf_core_cnt
> 1)
69 bubblesort(cpu_apic_info
.apic_ids
, perf_core_cnt
, NUM_ASCENDING
);
71 for (i
= perf_core_cnt
; j
< eff_core_cnt
; i
++, j
++)
72 cpu_apic_info
.apic_ids
[i
] = eff_apic_ids
[j
];
75 bubblesort(&cpu_apic_info
.apic_ids
[perf_core_cnt
], eff_core_cnt
, NUM_ASCENDING
);
77 /* Populate total core count */
78 cpu_apic_info
.total_cpu_cnt
= perf_core_cnt
+ eff_core_cnt
;
80 cpu_apic_info
.perf_cpu_cnt
= perf_core_cnt
;
83 static unsigned long acpi_create_madt_lapics_hybrid(unsigned long current
)
87 for (index
= 0; index
< cpu_apic_info
.total_cpu_cnt
; index
++)
88 current
= acpi_create_madt_one_lapic(current
, index
,
89 cpu_apic_info
.apic_ids
[index
]);
94 unsigned long acpi_create_madt_lapics_with_nmis_hybrid(unsigned long current
)
96 current
= acpi_create_madt_lapics_hybrid(current
);
97 current
= acpi_create_madt_lapic_nmis(current
);
101 static enum cpu_perf_eff_type
get_core_type(void)
103 return (get_soc_cpu_type() == CPUID_CORE_TYPE_INTEL_CORE
) ?
104 CPU_TYPE_PERF
: CPU_TYPE_EFF
;
107 void set_dev_core_type(void)
109 struct cpu_info
*info
= cpu_info();
110 info
->cpu
->path
.apic
.core_type
= get_core_type();
113 static void acpi_get_cpu_nomi_perf(u16
*eff_core_nom_perf
, u16
*perf_core_nom_perf
)
115 u8 max_non_turbo_ratio
= cpu_get_max_non_turbo_ratio();
117 _Static_assert(CONFIG_SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR
!= 0,
118 "CONFIG_SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR must not be zero");
120 _Static_assert(CONFIG_SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR
!= 0,
121 "CONFIG_SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR must not be zero");
123 *perf_core_nom_perf
= (u16
)((max_non_turbo_ratio
*
124 CONFIG_SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR
) / 100);
126 *eff_core_nom_perf
= (u16
)((max_non_turbo_ratio
*
127 CONFIG_SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR
) / 100);
130 static u16
acpi_get_cpu_nominal_freq(void)
132 return cpu_get_max_non_turbo_ratio() * cpu_get_bus_frequency();
135 /* Updates Nominal Frequency and Nominal Performance */
136 static void acpigen_cppc_update_nominal_freq_perf(const char *pkg_path
, s32 core_id
)
138 u16 eff_core_nom_perf
, perf_core_nom_perf
;
140 if (!soc_is_nominal_freq_supported())
143 acpi_get_cpu_nomi_perf(&eff_core_nom_perf
, &perf_core_nom_perf
);
145 if (core_id
< cpu_apic_info
.perf_cpu_cnt
)
146 acpigen_set_package_element_int(pkg_path
, CPPC_NOM_PERF_IDX
, perf_core_nom_perf
);
148 acpigen_set_package_element_int(pkg_path
, CPPC_NOM_PERF_IDX
,
151 /* Update CPU's nominal frequency */
152 acpigen_set_package_element_int(pkg_path
, CPPC_NOM_FREQ_IDX
,
153 acpi_get_cpu_nominal_freq());
156 void acpigen_write_CPPC_hybrid_method(s32 core_id
)
161 snprintf(pkg_path
, sizeof(pkg_path
), CPPC_PACKAGE_NAME
, 0);
163 snprintf(pkg_path
, sizeof(pkg_path
),
164 "\\_SB." CONFIG_ACPI_CPU_STRING
"." CPPC_PACKAGE_NAME
, 0);
166 acpigen_write_method("_CPC", 0);
168 /* Update nominal performance and nominal frequency */
169 acpigen_cppc_update_nominal_freq_perf(pkg_path
, core_id
);
170 acpigen_emit_byte(RETURN_OP
);
171 acpigen_emit_namestring(pkg_path
);
175 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS
, BS_ON_EXIT
, acpi_set_hybrid_cpu_apicid_order
, NULL
);