xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/acpi/cpu_hybrid.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 #include <acpi/acpi.h>
3 #include <acpi/acpigen.h>
4 #include <bootstate.h>
5 #include <commonlib/sort.h>
6 #include <cpu/x86/lapic.h>
7 #include <cpu/x86/mp.h>
8 #include <cpu/cpu.h>
9 #include <device/path.h>
10 #include <intelblocks/acpi.h>
11 #include <soc/cpu.h>
12 #include <stdio.h>
13 #include <types.h>
14 
15 #define CPPC_NOM_FREQ_IDX	22
16 #define CPPC_NOM_PERF_IDX	3
17 
18 enum cpu_perf_eff_type {
19 	CPU_TYPE_EFF,
20 	CPU_TYPE_PERF,
21 };
22 
23 struct cpu_apic_info_type {
24 	/*
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.
28 	 */
29 	int32_t apic_ids[CONFIG_MAX_CPUS];
30 
31 	/* Total CPU count */
32 	uint16_t total_cpu_cnt;
33 
34 	/*
35 	 * Total Performance core count. This will be used
36 	 * to identify the start of Efficient Cores's
37 	 * APIC ID list
38 	 */
39 	uint16_t perf_cpu_cnt;
40 };
41 
42 static struct cpu_apic_info_type cpu_apic_info;
43 
44 /*
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.
49  */
acpi_set_hybrid_cpu_apicid_order(void * unused)50 static void acpi_set_hybrid_cpu_apicid_order(void *unused)
51 {
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[];
55 	uint32_t i, j = 0;
56 
57 	for (i = 0; i < ARRAY_SIZE(cpu_apic_info.apic_ids); i++) {
58 		if (!cpu_infos[i].cpu)
59 			continue;
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;
63 		else
64 			eff_apic_ids[eff_core_cnt++] =
65 				cpu_infos[i].cpu->path.apic.apic_id;
66 	}
67 
68 	if (perf_core_cnt > 1)
69 		bubblesort(cpu_apic_info.apic_ids, perf_core_cnt, NUM_ASCENDING);
70 
71 	for (i = perf_core_cnt; j < eff_core_cnt; i++, j++)
72 		cpu_apic_info.apic_ids[i] = eff_apic_ids[j];
73 
74 	if (eff_core_cnt > 1)
75 		bubblesort(&cpu_apic_info.apic_ids[perf_core_cnt], eff_core_cnt, NUM_ASCENDING);
76 
77 	/* Populate total core count */
78 	cpu_apic_info.total_cpu_cnt = perf_core_cnt + eff_core_cnt;
79 
80 	cpu_apic_info.perf_cpu_cnt = perf_core_cnt;
81 }
82 
acpi_create_madt_lapics_hybrid(unsigned long current)83 static unsigned long acpi_create_madt_lapics_hybrid(unsigned long current)
84 {
85 	size_t index;
86 
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]);
90 
91 	return current;
92 }
93 
acpi_create_madt_lapics_with_nmis_hybrid(unsigned long current)94 unsigned long acpi_create_madt_lapics_with_nmis_hybrid(unsigned long current)
95 {
96 	current = acpi_create_madt_lapics_hybrid(current);
97 	current = acpi_create_madt_lapic_nmis(current);
98 	return current;
99 }
100 
get_core_type(void)101 static enum cpu_perf_eff_type get_core_type(void)
102 {
103 	return (get_soc_cpu_type() == CPUID_CORE_TYPE_INTEL_CORE) ?
104 		CPU_TYPE_PERF : CPU_TYPE_EFF;
105 }
106 
set_dev_core_type(void)107 void set_dev_core_type(void)
108 {
109 	struct cpu_info *info = cpu_info();
110 	info->cpu->path.apic.core_type = get_core_type();
111 }
112 
acpi_get_cpu_nomi_perf(u16 * eff_core_nom_perf,u16 * perf_core_nom_perf)113 static void acpi_get_cpu_nomi_perf(u16 *eff_core_nom_perf, u16 *perf_core_nom_perf)
114 {
115 	u8 max_non_turbo_ratio = cpu_get_max_non_turbo_ratio();
116 
117 	_Static_assert(CONFIG_SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR != 0,
118 		       "CONFIG_SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR must not be zero");
119 
120 	_Static_assert(CONFIG_SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR != 0,
121 		       "CONFIG_SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR must not be zero");
122 
123 	*perf_core_nom_perf = (u16)((max_non_turbo_ratio *
124 				CONFIG_SOC_INTEL_PERFORMANCE_CORE_SCALE_FACTOR) / 100);
125 
126 	*eff_core_nom_perf = (u16)((max_non_turbo_ratio *
127 				CONFIG_SOC_INTEL_EFFICIENT_CORE_SCALE_FACTOR) / 100);
128 }
129 
acpi_get_cpu_nominal_freq(void)130 static u16 acpi_get_cpu_nominal_freq(void)
131 {
132 	return cpu_get_max_non_turbo_ratio() * cpu_get_bus_frequency();
133 }
134 
135 /* Updates Nominal Frequency and Nominal Performance */
acpigen_cppc_update_nominal_freq_perf(const char * pkg_path,s32 core_id)136 static void acpigen_cppc_update_nominal_freq_perf(const char *pkg_path, s32 core_id)
137 {
138 	u16 eff_core_nom_perf, perf_core_nom_perf;
139 
140 	if (!soc_is_nominal_freq_supported())
141 		return;
142 
143 	acpi_get_cpu_nomi_perf(&eff_core_nom_perf, &perf_core_nom_perf);
144 
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);
147 	else
148 		acpigen_set_package_element_int(pkg_path, CPPC_NOM_PERF_IDX,
149 						eff_core_nom_perf);
150 
151 	/* Update CPU's nominal frequency */
152 	acpigen_set_package_element_int(pkg_path, CPPC_NOM_FREQ_IDX,
153 					acpi_get_cpu_nominal_freq());
154 }
155 
acpigen_write_CPPC_hybrid_method(s32 core_id)156 void acpigen_write_CPPC_hybrid_method(s32 core_id)
157 {
158 	char pkg_path[16];
159 
160 	if (core_id == 0)
161 		snprintf(pkg_path, sizeof(pkg_path), CPPC_PACKAGE_NAME, 0);
162 	else
163 		snprintf(pkg_path, sizeof(pkg_path),
164 			 "\\_SB." CONFIG_ACPI_CPU_STRING "." CPPC_PACKAGE_NAME, 0);
165 
166 	acpigen_write_method("_CPC", 0);
167 
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);
172 	acpigen_pop_len();
173 }
174 
175 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_EXIT, acpi_set_hybrid_cpu_apicid_order, NULL);
176