coreboot-kgpe-d16/src/soc/amd/picasso/acpi.c
Felix Held cf2eeff3cf soc/amd/picasso/acpi: generate PPKG object in generate_cpu_entries call
Generate the PPKG object in the generate_cpu_entries function instead of
generating the PCNT object that is the used in the PPKG method in
cpu.asl to provide the PPKG object. This both simplifies the code and
aligns Picasso with Cezanne and Sabrina. This will also make the code
behave correctly in a case where the number of CPU cores/threads isn't a
power of two.

TEST=Mandolin still boots successfully to Linux desktop and dmesg
doesn't show any any possibly related problems.

Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Change-Id: Ifb84435345c6d8c5d11a8b42e5538cfb86432780
Reviewed-on: https://review.coreboot.org/c/coreboot/+/62517
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Raul Rangel <rrangel@chromium.org>
2022-03-03 18:33:43 +00:00

359 lines
10 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ACPI - create the Fixed ACPI Description Tables (FADT)
*/
#include <console/console.h>
#include <acpi/acpi.h>
#include <acpi/acpigen.h>
#include <device/pci_ops.h>
#include <arch/ioapic.h>
#include <arch/smp/mpspec.h>
#include <cpu/amd/cpuid.h>
#include <cpu/amd/msr.h>
#include <cpu/x86/smm.h>
#include <device/device.h>
#include <device/pci.h>
#include <amdblocks/acpimmio.h>
#include <amdblocks/acpi.h>
#include <amdblocks/chip.h>
#include <amdblocks/cpu.h>
#include <amdblocks/ioapic.h>
#include <soc/acpi.h>
#include <soc/pci_devs.h>
#include <soc/msr.h>
#include <soc/southbridge.h>
#include <soc/gpio.h>
#include <version.h>
#include "chip.h"
unsigned long acpi_fill_madt(unsigned long current)
{
/* create all subtables for processors */
current = acpi_create_madt_lapics(current);
current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current,
FCH_IOAPIC_ID, IO_APIC_ADDR, 0);
current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current,
GNB_IOAPIC_ID, GNB_IO_APIC_ADDR, IO_APIC_INTERRUPTS);
/* PIT is connected to legacy IRQ 0, but IOAPIC GSI 2 */
current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)current,
MP_BUS_ISA, 0, 2,
MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT);
/* SCI IRQ type override */
current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)current,
MP_BUS_ISA, 9, 9,
MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW);
current = acpi_fill_madt_irqoverride(current);
/* create all subtables for processors */
current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS,
MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
1 /* 1: LINT1 connect to NMI */);
return current;
}
/*
* Reference section 5.2.9 Fixed ACPI Description Table (FADT)
* in the ACPI 3.0b specification.
*/
void acpi_fill_fadt(acpi_fadt_t *fadt)
{
const struct soc_amd_common_config *cfg = soc_get_common_config();
printk(BIOS_DEBUG, "pm_base: 0x%04x\n", ACPI_IO_BASE);
fadt->sci_int = 9; /* IRQ 09 - ACPI SCI */
if (permanent_smi_handler()) {
fadt->smi_cmd = APM_CNT;
fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
}
fadt->pm1a_evt_blk = ACPI_PM_EVT_BLK;
fadt->pm1a_cnt_blk = ACPI_PM1_CNT_BLK;
fadt->pm_tmr_blk = ACPI_PM_TMR_BLK;
fadt->gpe0_blk = ACPI_GPE0_BLK;
fadt->pm1_evt_len = 4; /* 32 bits */
fadt->pm1_cnt_len = 2; /* 16 bits */
fadt->pm_tmr_len = 4; /* 32 bits */
fadt->gpe0_blk_len = 8; /* 64 bits */
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
fadt->duty_offset = 1; /* CLK_VAL bits 3:1 */
fadt->duty_width = 3; /* CLK_VAL bits 3:1 */
fadt->day_alrm = RTC_DATE_ALARM;
fadt->mon_alrm = 0;
fadt->iapc_boot_arch = cfg->fadt_boot_arch; /* legacy free default */
fadt->res2 = 0; /* reserved, MUST be 0 ACPI 3.0 */
fadt->flags |= ACPI_FADT_WBINVD | /* See table 5-34 ACPI 6.3 spec */
ACPI_FADT_C1_SUPPORTED |
ACPI_FADT_S4_RTC_WAKE |
ACPI_FADT_32BIT_TIMER |
ACPI_FADT_PCI_EXPRESS_WAKE |
ACPI_FADT_PLATFORM_CLOCK |
ACPI_FADT_S4_RTC_VALID |
ACPI_FADT_REMOTE_POWER_ON;
fadt->flags |= cfg->fadt_flags; /* additional board-specific flags */
fadt->ARM_boot_arch = 0; /* Must be zero if ACPI Revision <= 5.0 */
fadt->x_firmware_ctl_l = 0; /* set to 0 if firmware_ctrl is used */
fadt->x_firmware_ctl_h = 0;
fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_pm1a_evt_blk.bit_width = 32;
fadt->x_pm1a_evt_blk.bit_offset = 0;
fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
fadt->x_pm1a_evt_blk.addrl = ACPI_PM_EVT_BLK;
fadt->x_pm1a_evt_blk.addrh = 0x0;
fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_pm1a_cnt_blk.bit_width = 16;
fadt->x_pm1a_cnt_blk.bit_offset = 0;
fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
fadt->x_pm1a_cnt_blk.addrl = ACPI_PM1_CNT_BLK;
fadt->x_pm1a_cnt_blk.addrh = 0x0;
fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_pm_tmr_blk.bit_width = 32;
fadt->x_pm_tmr_blk.bit_offset = 0;
fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
fadt->x_pm_tmr_blk.addrl = ACPI_PM_TMR_BLK;
fadt->x_pm_tmr_blk.addrh = 0x0;
fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_gpe0_blk.bit_width = 64; /* EventStatus + Event Enable */
fadt->x_gpe0_blk.bit_offset = 0;
fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
fadt->x_gpe0_blk.addrl = ACPI_GPE0_BLK;
fadt->x_gpe0_blk.addrh = 0x0;
}
static uint32_t get_pstate_core_freq(msr_t pstate_def)
{
uint32_t core_freq, core_freq_mul, core_freq_div;
bool valid_freq_divisor;
/* Core frequency multiplier */
core_freq_mul = pstate_def.lo & PSTATE_DEF_LO_FREQ_MUL_MASK;
/* Core frequency divisor ID */
core_freq_div =
(pstate_def.lo & PSTATE_DEF_LO_FREQ_DIV_MASK) >> PSTATE_DEF_LO_FREQ_DIV_SHIFT;
if (core_freq_div == 0) {
return 0;
} else if ((core_freq_div >= PSTATE_DEF_LO_FREQ_DIV_MIN)
&& (core_freq_div <= PSTATE_DEF_LO_EIGHTH_STEP_MAX)) {
/* Allow 1/8 integer steps for this range */
valid_freq_divisor = 1;
} else if ((core_freq_div > PSTATE_DEF_LO_EIGHTH_STEP_MAX)
&& (core_freq_div <= PSTATE_DEF_LO_FREQ_DIV_MAX) && !(core_freq_div & 0x1)) {
/* Only allow 1/4 integer steps for this range */
valid_freq_divisor = 1;
} else {
valid_freq_divisor = 0;
}
if (valid_freq_divisor) {
/* 25 * core_freq_mul / (core_freq_div / 8) */
core_freq =
((PSTATE_DEF_LO_CORE_FREQ_BASE * core_freq_mul * 8) / (core_freq_div));
} else {
printk(BIOS_WARNING, "Undefined core_freq_div %x used. Force to 1.\n",
core_freq_div);
core_freq = (PSTATE_DEF_LO_CORE_FREQ_BASE * core_freq_mul);
}
return core_freq;
}
static uint32_t get_pstate_core_power(msr_t pstate_def)
{
uint32_t voltage_in_uvolts, core_vid, current_value_amps, current_divisor, power_in_mw;
/* Core voltage ID */
core_vid =
(pstate_def.lo & PSTATE_DEF_LO_CORE_VID_MASK) >> PSTATE_DEF_LO_CORE_VID_SHIFT;
/* Current value in amps */
current_value_amps =
(pstate_def.lo & PSTATE_DEF_LO_CUR_VAL_MASK) >> PSTATE_DEF_LO_CUR_VAL_SHIFT;
/* Current divisor */
current_divisor =
(pstate_def.lo & PSTATE_DEF_LO_CUR_DIV_MASK) >> PSTATE_DEF_LO_CUR_DIV_SHIFT;
/* Voltage */
if ((core_vid >= 0xF8) && (core_vid <= 0xFF)) {
/* Voltage off for VID codes 0xF8 to 0xFF */
voltage_in_uvolts = 0;
} else {
voltage_in_uvolts =
SERIAL_VID_MAX_MICROVOLTS - (SERIAL_VID_DECODE_MICROVOLTS * core_vid);
}
/* Power in mW */
power_in_mw = (voltage_in_uvolts) / 1000 * current_value_amps;
switch (current_divisor) {
case 0:
break;
case 1:
power_in_mw = power_in_mw / 10L;
break;
case 2:
power_in_mw = power_in_mw / 100L;
break;
case 3:
/* current_divisor is set to an undefined value.*/
printk(BIOS_WARNING, "Undefined current_divisor set for enabled P-state .\n");
power_in_mw = 0;
break;
}
return power_in_mw;
}
/*
* Populate structure describing enabled p-states and return count of enabled p-states.
*/
static size_t get_pstate_info(struct acpi_sw_pstate *pstate_values,
struct acpi_xpss_sw_pstate *pstate_xpss_values)
{
msr_t pstate_def;
size_t pstate_count, pstate;
uint32_t pstate_enable, max_pstate;
pstate_count = 0;
max_pstate = (rdmsr(PS_LIM_REG).lo & PS_LIM_MAX_VAL_MASK) >> PS_MAX_VAL_SHFT;
for (pstate = 0; pstate <= max_pstate; pstate++) {
pstate_def = rdmsr(PSTATE_0_MSR + pstate);
pstate_enable = (pstate_def.hi & PSTATE_DEF_HI_ENABLE_MASK)
>> PSTATE_DEF_HI_ENABLE_SHIFT;
if (!pstate_enable)
continue;
pstate_values[pstate_count].core_freq = get_pstate_core_freq(pstate_def);
pstate_values[pstate_count].power = get_pstate_core_power(pstate_def);
pstate_values[pstate_count].transition_latency = 0;
pstate_values[pstate_count].bus_master_latency = 0;
pstate_values[pstate_count].control_value = pstate;
pstate_values[pstate_count].status_value = pstate;
pstate_xpss_values[pstate_count].core_freq =
(uint64_t)pstate_values[pstate_count].core_freq;
pstate_xpss_values[pstate_count].power =
(uint64_t)pstate_values[pstate_count].power;
pstate_xpss_values[pstate_count].transition_latency = 0;
pstate_xpss_values[pstate_count].bus_master_latency = 0;
pstate_xpss_values[pstate_count].control_value = (uint64_t)pstate;
pstate_xpss_values[pstate_count].status_value = (uint64_t)pstate;
pstate_count++;
}
return pstate_count;
}
void generate_cpu_entries(const struct device *device)
{
int logical_cores;
size_t pstate_count, cpu, proc_blk_len;
struct acpi_sw_pstate pstate_values[MAX_PSTATES] = { {0} };
struct acpi_xpss_sw_pstate pstate_xpss_values[MAX_PSTATES] = { {0} };
uint32_t threads_per_core, proc_blk_addr;
uint32_t cstate_base_address =
rdmsr(MSR_CSTATE_ADDRESS).lo & MSR_CSTATE_ADDRESS_MASK;
const acpi_addr_t perf_ctrl = {
.space_id = ACPI_ADDRESS_SPACE_FIXED,
.bit_width = 64,
.addrl = PS_CTL_REG,
};
const acpi_addr_t perf_sts = {
.space_id = ACPI_ADDRESS_SPACE_FIXED,
.bit_width = 64,
.addrl = PS_STS_REG,
};
const acpi_cstate_t cstate_info[] = {
[0] = {
.ctype = 1,
.latency = 1,
.power = 0,
.resource = {
.space_id = ACPI_ADDRESS_SPACE_FIXED,
.bit_width = 2,
.bit_offset = 2,
.addrl = 0,
.addrh = 0,
},
},
[1] = {
.ctype = 2,
.latency = 400,
.power = 0,
.resource = {
.space_id = ACPI_ADDRESS_SPACE_IO,
.bit_width = 8,
.bit_offset = 0,
.addrl = cstate_base_address + 1,
.addrh = 0,
.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS,
},
},
};
threads_per_core = get_threads_per_core();
pstate_count = get_pstate_info(pstate_values, pstate_xpss_values);
logical_cores = get_cpu_count();
for (cpu = 0; cpu < logical_cores; cpu++) {
if (cpu == 0) {
/* BSP values for \_SB.Pxxx */
proc_blk_len = 6;
proc_blk_addr = ACPI_GPE0_BLK;
} else {
/* AP values for \_SB.Pxxx */
proc_blk_addr = 0;
proc_blk_len = 0;
}
acpigen_write_processor(cpu, proc_blk_addr, proc_blk_len);
acpigen_write_pct_package(&perf_ctrl, &perf_sts);
acpigen_write_pss_object(pstate_values, pstate_count);
acpigen_write_xpss_object(pstate_xpss_values, pstate_count);
if (CONFIG(ACPI_SSDT_PSD_INDEPENDENT))
acpigen_write_PSD_package(cpu / threads_per_core, threads_per_core,
HW_ALL);
else
acpigen_write_PSD_package(0, logical_cores, SW_ALL);
acpigen_write_PPC(0);
acpigen_write_CST_package(cstate_info, ARRAY_SIZE(cstate_info));
acpigen_write_CSD_package(cpu / threads_per_core, threads_per_core,
CSD_HW_ALL, 0);
acpigen_pop_len();
}
acpigen_write_processor_package("PPKG", 0, logical_cores);
}