1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <acpi/acpigen.h>
5 #include <console/console.h>
7 #include <cpu/intel/speedstep.h>
8 #include <cpu/intel/turbo.h>
9 #include <cpu/x86/msr.h>
10 #include <device/device.h>
13 #include "model_206ax.h"
17 * List of supported C-states in this processor
19 * Latencies are typical worst-case package exit time in uS
20 * taken from the SandyBridge BIOS specification.
22 static const acpi_cstate_t cstate_map
[] = {
28 .addrl
= 0x00, /* MWAIT State 0 */
29 .space_id
= ACPI_ADDRESS_SPACE_FIXED
,
30 .bit_width
= ACPI_FFIXEDHW_VENDOR_INTEL
,
31 .bit_offset
= ACPI_FFIXEDHW_CLASS_MWAIT
,
32 .access_size
= ACPI_FFIXEDHW_FLAG_HW_COORD
,
39 .addrl
= 0x01, /* MWAIT State 0 Sub-state 1 */
40 .space_id
= ACPI_ADDRESS_SPACE_FIXED
,
41 .bit_width
= ACPI_FFIXEDHW_VENDOR_INTEL
,
42 .bit_offset
= ACPI_FFIXEDHW_CLASS_MWAIT
,
43 .access_size
= ACPI_FFIXEDHW_FLAG_HW_COORD
,
50 .addrl
= 0x10, /* MWAIT State 1 */
51 .space_id
= ACPI_ADDRESS_SPACE_FIXED
,
52 .bit_width
= ACPI_FFIXEDHW_VENDOR_INTEL
,
53 .bit_offset
= ACPI_FFIXEDHW_CLASS_MWAIT
,
54 .access_size
= ACPI_FFIXEDHW_FLAG_HW_COORD
,
61 .addrl
= 0x20, /* MWAIT State 2 */
62 .space_id
= ACPI_ADDRESS_SPACE_FIXED
,
63 .bit_width
= ACPI_FFIXEDHW_VENDOR_INTEL
,
64 .bit_offset
= ACPI_FFIXEDHW_CLASS_MWAIT
,
65 .access_size
= ACPI_FFIXEDHW_FLAG_HW_COORD
,
72 .addrl
= 0x30, /* MWAIT State 3 */
73 .space_id
= ACPI_ADDRESS_SPACE_FIXED
,
74 .bit_width
= ACPI_FFIXEDHW_VENDOR_INTEL
,
75 .bit_offset
= ACPI_FFIXEDHW_CLASS_MWAIT
,
76 .access_size
= ACPI_FFIXEDHW_FLAG_HW_COORD
,
83 .addrl
= 0x31, /* MWAIT State 3 Sub-state 1 */
84 .space_id
= ACPI_ADDRESS_SPACE_FIXED
,
85 .bit_width
= ACPI_FFIXEDHW_VENDOR_INTEL
,
86 .bit_offset
= ACPI_FFIXEDHW_CLASS_MWAIT
,
87 .access_size
= ACPI_FFIXEDHW_FLAG_HW_COORD
,
92 static int get_logical_cores_per_package(void)
94 msr_t msr
= rdmsr(MSR_CORE_THREAD_COUNT
);
95 return msr
.lo
& 0xffff;
98 static void generate_C_state_entries(const struct device
*dev
)
100 struct cpu_intel_model_206ax_config
*conf
= dev
->chip_info
;
102 const int acpi_cstates
[3] = { conf
->acpi_c1
, conf
->acpi_c2
, conf
->acpi_c3
};
104 acpi_cstate_t acpi_cstate_map
[ARRAY_SIZE(acpi_cstates
)] = { 0 };
106 /* Count number of active C-states */
109 for (int i
= 0; i
< ARRAY_SIZE(acpi_cstates
); i
++) {
110 if (acpi_cstates
[i
] > 0 && acpi_cstates
[i
] < ARRAY_SIZE(cstate_map
)) {
111 acpi_cstate_map
[count
] = cstate_map
[acpi_cstates
[i
]];
112 acpi_cstate_map
[count
].ctype
= i
+ 1;
116 acpigen_write_CST_package(acpi_cstate_map
, count
);
119 static acpi_tstate_t tss_table_fine
[] = {
120 { 100, 1000, 0, 0x00, 0 },
121 { 94, 940, 0, 0x1f, 0 },
122 { 88, 880, 0, 0x1e, 0 },
123 { 82, 820, 0, 0x1d, 0 },
124 { 75, 760, 0, 0x1c, 0 },
125 { 69, 700, 0, 0x1b, 0 },
126 { 63, 640, 0, 0x1a, 0 },
127 { 57, 580, 0, 0x19, 0 },
128 { 50, 520, 0, 0x18, 0 },
129 { 44, 460, 0, 0x17, 0 },
130 { 38, 400, 0, 0x16, 0 },
131 { 32, 340, 0, 0x15, 0 },
132 { 25, 280, 0, 0x14, 0 },
133 { 19, 220, 0, 0x13, 0 },
134 { 13, 160, 0, 0x12, 0 },
137 static acpi_tstate_t tss_table_coarse
[] = {
138 { 100, 1000, 0, 0x00, 0 },
139 { 88, 875, 0, 0x1f, 0 },
140 { 75, 750, 0, 0x1e, 0 },
141 { 63, 625, 0, 0x1d, 0 },
142 { 50, 500, 0, 0x1c, 0 },
143 { 38, 375, 0, 0x1b, 0 },
144 { 25, 250, 0, 0x1a, 0 },
145 { 13, 125, 0, 0x19, 0 },
148 static void generate_T_state_entries(int core
, int cores_per_package
)
150 /* Indicate SW_ALL coordination for T-states */
151 acpigen_write_TSD_package(core
, cores_per_package
, SW_ALL
);
153 /* Indicate FFixedHW so OS will use MSR */
154 acpigen_write_empty_PTC();
156 /* Set a T-state limit that can be modified in NVS */
157 acpigen_write_TPC("\\TLVL");
160 * CPUID.(EAX=6):EAX[5] indicates support
161 * for extended throttle levels.
163 if (cpuid_eax(6) & (1 << 5))
164 acpigen_write_TSS_package(
165 ARRAY_SIZE(tss_table_fine
), tss_table_fine
);
167 acpigen_write_TSS_package(
168 ARRAY_SIZE(tss_table_coarse
), tss_table_coarse
);
171 static int calculate_power(int tdp
, int p1_ratio
, int ratio
)
177 * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
179 * Power = (ratio / p1_ratio) * m * tdp
182 m
= (110000 - ((p1_ratio
- ratio
) * 625)) / 11;
185 power
= ((ratio
* 100000 / p1_ratio
) / 100);
186 power
*= (m
/ 100) * (tdp
/ 1000);
192 static void generate_P_state_entries(int core
, int cores_per_package
)
194 int ratio_min
, ratio_max
, ratio_turbo
, ratio_step
;
195 int coord_type
, power_max
, power_unit
, num_entries
;
196 int ratio
, power
, clock
, clock_max
;
199 /* Determine P-state coordination type from MISC_PWR_MGMT[0] */
200 msr
= rdmsr(MSR_MISC_PWR_MGMT
);
201 if (msr
.lo
& MISC_PWR_MGMT_EIST_HW_DIS
)
206 /* Get bus ratio limits and calculate clock speeds */
207 msr
= rdmsr(MSR_PLATFORM_INFO
);
208 ratio_min
= (msr
.hi
>> (40-32)) & 0xff; /* Max Efficiency Ratio */
210 /* Determine if this CPU has configurable TDP */
211 if (cpu_config_tdp_levels()) {
212 /* Set max ratio to nominal TDP ratio */
213 msr
= rdmsr(MSR_CONFIG_TDP_NOMINAL
);
214 ratio_max
= msr
.lo
& 0xff;
216 /* Max Non-Turbo Ratio */
217 ratio_max
= (msr
.lo
>> 8) & 0xff;
219 clock_max
= ratio_max
* SANDYBRIDGE_BCLK
;
221 /* Calculate CPU TDP in mW */
222 msr
= rdmsr(MSR_PKG_POWER_SKU_UNIT
);
223 power_unit
= 2 << ((msr
.lo
& 0xf) - 1);
224 msr
= rdmsr(MSR_PKG_POWER_SKU
);
225 power_max
= ((msr
.lo
& 0x7fff) / power_unit
) * 1000;
227 /* Write _PCT indicating use of FFixedHW */
228 acpigen_write_empty_PCT();
230 /* Write _PPC with no limit on supported P-state */
231 acpigen_write_PPC_NVS();
233 /* Write PSD indicating configured coordination type */
234 acpigen_write_PSD_package(core
, cores_per_package
, coord_type
);
236 /* Add P-state entries in _PSS table */
237 acpigen_write_name("_PSS");
239 /* Determine ratio points */
240 ratio_step
= PSS_RATIO_STEP
;
241 num_entries
= (ratio_max
- ratio_min
) / ratio_step
;
242 while (num_entries
> PSS_MAX_ENTRIES
-1) {
247 /* P[T] is Turbo state if enabled */
248 if (get_turbo_state() == TURBO_ENABLED
) {
249 /* _PSS package count including Turbo */
250 acpigen_write_package(num_entries
+ 2);
252 msr
= rdmsr(MSR_TURBO_RATIO_LIMIT
);
253 ratio_turbo
= msr
.lo
& 0xff;
255 /* Add entry for Turbo ratio */
256 acpigen_write_PSS_package(
257 clock_max
+ 1, /*MHz*/
259 PSS_LATENCY_TRANSITION
, /*lat1*/
260 PSS_LATENCY_BUSMASTER
, /*lat2*/
261 ratio_turbo
<< 8, /*control*/
262 ratio_turbo
<< 8); /*status*/
264 /* _PSS package count without Turbo */
265 acpigen_write_package(num_entries
+ 1);
268 /* First regular entry is max non-turbo ratio */
269 acpigen_write_PSS_package(
272 PSS_LATENCY_TRANSITION
, /*lat1*/
273 PSS_LATENCY_BUSMASTER
, /*lat2*/
274 ratio_max
<< 8, /*control*/
275 ratio_max
<< 8); /*status*/
277 /* Generate the remaining entries */
278 for (ratio
= ratio_min
+ ((num_entries
- 1) * ratio_step
);
279 ratio
>= ratio_min
; ratio
-= ratio_step
) {
280 /* Calculate power at this ratio */
281 power
= calculate_power(power_max
, ratio_max
, ratio
);
282 clock
= ratio
* SANDYBRIDGE_BCLK
;
284 acpigen_write_PSS_package(
287 PSS_LATENCY_TRANSITION
, /*lat1*/
288 PSS_LATENCY_BUSMASTER
, /*lat2*/
289 ratio
<< 8, /*control*/
290 ratio
<< 8); /*status*/
293 /* Fix package length */
297 void generate_cpu_entries(const struct device
*device
)
300 int totalcores
= dev_count_cpu();
301 int cores_per_package
= get_logical_cores_per_package();
302 int numcpus
= totalcores
/cores_per_package
;
304 printk(BIOS_DEBUG
, "Found %d CPU(s) with %d core(s) each.\n",
305 numcpus
, cores_per_package
);
307 for (cpuID
= 1; cpuID
<= numcpus
; cpuID
++) {
308 for (coreID
= 1; coreID
<= cores_per_package
; coreID
++) {
309 /* Generate processor \_SB.CPUx */
310 acpigen_write_processor(
311 (cpuID
-1)*cores_per_package
+coreID
-1, 0, 0);
313 /* Generate P-state tables */
314 generate_P_state_entries(
315 cpuID
-1, cores_per_package
);
317 /* Generate C-state tables */
318 generate_C_state_entries(device
);
320 /* Generate T-state tables */
321 generate_T_state_entries(
322 cpuID
-1, cores_per_package
);
328 /* PPKG is usually used for thermal management
329 of the first and only package. */
330 acpigen_write_processor_package("PPKG", 0, cores_per_package
);
332 /* Add a method to notify processor nodes */
333 acpigen_write_processor_cnot(cores_per_package
);
336 struct chip_operations cpu_intel_model_206ax_ops
= {
337 CHIP_NAME("Intel SandyBridge/IvyBridge CPU")