1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <acpi/acpigen.h>
5 #include <console/console.h>
7 #include <cpu/intel/fsb.h>
8 #include <cpu/intel/speedstep.h>
9 #include <device/device.h>
12 static void gen_pstate_entries(const sst_table_t
*const pstates
,
13 const int cpuID
, const int cores_per_package
,
14 const uint8_t coordination
)
19 acpigen_write_empty_PCT();
20 acpigen_write_PSD_package(
21 cpuID
, cores_per_package
, coordination
);
22 acpigen_write_name("_PSS");
24 int fsb3
= get_ia32_fsb_x3();
26 printk(BIOS_ERR
, "CPU or FSB not supported. Assuming 200MHz\n");
30 const int min_ratio2
= SPEEDSTEP_DOUBLE_RATIO(
31 pstates
->states
[pstates
->num_states
- 1]);
32 const int max_ratio2
= SPEEDSTEP_DOUBLE_RATIO(pstates
->states
[0]);
33 printk(BIOS_DEBUG
, "clocks between %d and %d MHz.\n",
35 / (pstates
->states
[pstates
->num_states
- 1].is_slfm
? 12 : 6),
36 (max_ratio2
* fsb3
) / 6);
39 "adding %x P-States between busratio %x and %x, incl. P0\n",
40 pstates
->num_states
, min_ratio2
/ 2, max_ratio2
/ 2);
41 acpigen_write_package(pstates
->num_states
);
42 for (i
= 0; i
< pstates
->num_states
; ++i
) {
43 const sst_state_t
*const pstate
= &pstates
->states
[i
];
44 /* Report frequency of turbo mode as that of HFM + 1. */
46 frequency
= (SPEEDSTEP_DOUBLE_RATIO(
47 pstates
->states
[i
+ 1]) * fsb3
) / 6 + 1;
48 /* Super-LFM runs at half frequency. */
49 else if (pstate
->is_slfm
)
50 frequency
= (SPEEDSTEP_DOUBLE_RATIO(*pstate
)*fsb3
)/12;
52 frequency
= (SPEEDSTEP_DOUBLE_RATIO(*pstate
)*fsb3
)/6;
53 acpigen_write_PSS_package(
54 frequency
, pstate
->power
, 0, 0,
55 SPEEDSTEP_ENCODE_STATE(*pstate
),
56 SPEEDSTEP_ENCODE_STATE(*pstate
));
63 static uint8_t get_p_state_coordination(void)
65 /* For Penryn use HW_ALL. */
66 if (((cpuid_eax(1) >> 4) & 0xffff) == 0x1067)
69 /* Use SW_ANY as that was the default. */
73 static void generate_cpu_entry(int cpu
, int core
, int cores_per_package
)
75 int pcontrol_blk
= PMB0_BASE
, plen
= 6;
81 const acpi_cstate_t
*cstates
;
87 s
.coordination
= get_p_state_coordination();
88 s
.num_cstates
= get_cst_entries(&s
.cstates
);
89 speedstep_gen_pstates(&s
.pstates
);
97 /* Generate processor \_SB.CPUx. */
98 acpigen_write_processor(cpu
* cores_per_package
+ core
, pcontrol_blk
, plen
);
100 /* Generate p-state entries. */
101 gen_pstate_entries(&s
.pstates
, cpu
, cores_per_package
, s
.coordination
);
103 /* Generate c-state entries. */
104 if (s
.num_cstates
> 0)
105 acpigen_write_CST_package(s
.cstates
, s
.num_cstates
);
111 * @brief Generate ACPI entries for Speedstep for each cpu
113 void generate_cpu_entries(const struct device
*device
)
115 int totalcores
= dev_count_cpu();
116 int cores_per_package
= (cpuid_ebx(1) >> 16) & 0xff;
118 /* This assumes that all CPUs share the same layout. */
119 int numcpus
= totalcores
/ cores_per_package
;
121 printk(BIOS_DEBUG
, "Found %d CPU(s) with %d core(s) each.\n",
122 numcpus
, cores_per_package
);
124 for (int cpu_id
= 0; cpu_id
< numcpus
; ++cpu_id
)
125 for (int core_id
= 0; core_id
< cores_per_package
; core_id
++)
126 generate_cpu_entry(cpu_id
, core_id
, cores_per_package
);
128 /* PPKG is usually used for thermal management
129 of the first and only package. */
130 acpigen_write_processor_package("PPKG", 0, cores_per_package
);
132 acpigen_write_processor_cnot(cores_per_package
);
134 acpigen_write_scope("\\");
135 acpigen_write_name_integer("MPEN", numcpus
> 1);