2020-04-05 15:47:17 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2015-05-13 03:19:47 +02:00
|
|
|
|
2020-05-02 19:24:23 +02:00
|
|
|
#include <acpi/acpi.h>
|
2020-06-17 22:37:49 +02:00
|
|
|
#include <acpi/acpi_gnvs.h>
|
2021-01-21 15:05:26 +01:00
|
|
|
#include <acpi/acpi_pm.h>
|
2020-05-02 19:24:23 +02:00
|
|
|
#include <acpi/acpigen.h>
|
2015-10-02 02:21:33 +02:00
|
|
|
#include <arch/cpu.h>
|
2015-09-04 23:19:35 +02:00
|
|
|
#include <arch/ioapic.h>
|
2015-05-13 03:19:47 +02:00
|
|
|
#include <arch/smp/mpspec.h>
|
|
|
|
#include <console/console.h>
|
2018-07-27 23:17:29 +02:00
|
|
|
#include <cpu/intel/common/common.h>
|
2020-08-03 16:53:41 +02:00
|
|
|
#include <intelblocks/acpi.h>
|
2021-01-15 04:06:35 +01:00
|
|
|
#include <intelblocks/acpi_wake_source.h>
|
2017-05-04 14:32:17 +02:00
|
|
|
#include <intelblocks/cpulib.h>
|
2020-08-03 16:53:41 +02:00
|
|
|
#include <intelblocks/pmclib.h>
|
2017-10-12 01:12:21 +02:00
|
|
|
#include <intelblocks/sgx.h>
|
2015-05-13 03:19:47 +02:00
|
|
|
#include <soc/cpu.h>
|
|
|
|
#include <soc/msr.h>
|
|
|
|
#include <soc/pm.h>
|
2016-08-30 17:17:13 +02:00
|
|
|
#include <soc/ramstage.h>
|
2017-09-18 20:03:46 +02:00
|
|
|
#include <soc/systemagent.h>
|
2015-10-02 02:21:33 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <types.h>
|
2015-05-13 03:19:47 +02:00
|
|
|
|
2019-03-21 15:38:06 +01:00
|
|
|
#include "chip.h"
|
|
|
|
|
2015-05-13 03:19:47 +02:00
|
|
|
/*
|
2021-10-01 22:53:22 +02:00
|
|
|
* List of supported C-states in this processor.
|
2015-05-13 03:19:47 +02:00
|
|
|
*/
|
|
|
|
enum {
|
2015-05-13 03:23:27 +02:00
|
|
|
C_STATE_C0, /* 0 */
|
|
|
|
C_STATE_C1, /* 1 */
|
|
|
|
C_STATE_C1E, /* 2 */
|
|
|
|
C_STATE_C3, /* 3 */
|
|
|
|
C_STATE_C6_SHORT_LAT, /* 4 */
|
|
|
|
C_STATE_C6_LONG_LAT, /* 5 */
|
|
|
|
C_STATE_C7_SHORT_LAT, /* 6 */
|
|
|
|
C_STATE_C7_LONG_LAT, /* 7 */
|
|
|
|
C_STATE_C7S_SHORT_LAT, /* 8 */
|
|
|
|
C_STATE_C7S_LONG_LAT, /* 9 */
|
|
|
|
C_STATE_C8, /* 10 */
|
|
|
|
C_STATE_C9, /* 11 */
|
|
|
|
C_STATE_C10, /* 12 */
|
2015-05-13 03:19:47 +02:00
|
|
|
NUM_C_STATES
|
|
|
|
};
|
2015-05-13 03:23:27 +02:00
|
|
|
#define MWAIT_RES(state, sub_state) \
|
|
|
|
{ \
|
|
|
|
.addrl = (((state) << 4) | (sub_state)), \
|
|
|
|
.space_id = ACPI_ADDRESS_SPACE_FIXED, \
|
|
|
|
.bit_width = ACPI_FFIXEDHW_VENDOR_INTEL, \
|
|
|
|
.bit_offset = ACPI_FFIXEDHW_CLASS_MWAIT, \
|
|
|
|
.access_size = ACPI_FFIXEDHW_FLAG_HW_COORD, \
|
2015-05-13 03:19:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static acpi_cstate_t cstate_map[NUM_C_STATES] = {
|
|
|
|
[C_STATE_C0] = { },
|
|
|
|
[C_STATE_C1] = {
|
|
|
|
.latency = 0,
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C1_POWER,
|
2015-05-13 03:23:27 +02:00
|
|
|
.resource = MWAIT_RES(0, 0),
|
2015-05-13 03:19:47 +02:00
|
|
|
},
|
|
|
|
[C_STATE_C1E] = {
|
|
|
|
.latency = 0,
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C1_POWER,
|
2015-05-13 03:23:27 +02:00
|
|
|
.resource = MWAIT_RES(0, 1),
|
2015-05-13 03:19:47 +02:00
|
|
|
},
|
|
|
|
[C_STATE_C3] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(0),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C3_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(1, 0),
|
|
|
|
},
|
|
|
|
[C_STATE_C6_SHORT_LAT] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(1),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C6_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(2, 0),
|
|
|
|
},
|
|
|
|
[C_STATE_C6_LONG_LAT] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(2),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C6_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(2, 1),
|
|
|
|
},
|
|
|
|
[C_STATE_C7_SHORT_LAT] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(1),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C7_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(3, 0),
|
|
|
|
},
|
|
|
|
[C_STATE_C7_LONG_LAT] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(2),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C7_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(3, 1),
|
|
|
|
},
|
|
|
|
[C_STATE_C7S_SHORT_LAT] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(1),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C7_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(3, 2),
|
|
|
|
},
|
|
|
|
[C_STATE_C7S_LONG_LAT] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(2),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C7_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(3, 3),
|
|
|
|
},
|
|
|
|
[C_STATE_C8] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(3),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C8_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(4, 0),
|
|
|
|
},
|
|
|
|
[C_STATE_C9] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(4),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C9_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(5, 0),
|
|
|
|
},
|
|
|
|
[C_STATE_C10] = {
|
|
|
|
.latency = C_STATE_LATENCY_FROM_LAT_REG(5),
|
2015-09-11 23:25:15 +02:00
|
|
|
.power = C10_POWER,
|
2015-05-13 03:19:47 +02:00
|
|
|
.resource = MWAIT_RES(6, 0),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2015-05-13 03:23:27 +02:00
|
|
|
static int cstate_set_s0ix[] = {
|
2015-05-13 03:19:47 +02:00
|
|
|
C_STATE_C1E,
|
|
|
|
C_STATE_C7S_LONG_LAT,
|
|
|
|
C_STATE_C10
|
|
|
|
};
|
|
|
|
|
2015-05-13 03:23:27 +02:00
|
|
|
static int cstate_set_non_s0ix[] = {
|
2015-05-13 03:19:47 +02:00
|
|
|
C_STATE_C1E,
|
|
|
|
C_STATE_C3,
|
2015-05-13 03:23:27 +02:00
|
|
|
C_STATE_C7S_LONG_LAT,
|
2015-05-13 03:19:47 +02:00
|
|
|
};
|
|
|
|
|
2021-10-19 20:59:35 +02:00
|
|
|
const acpi_cstate_t *soc_get_cstate_map(size_t *entries)
|
2015-05-13 03:19:47 +02:00
|
|
|
{
|
2020-08-03 16:53:41 +02:00
|
|
|
static acpi_cstate_t map[MAX(ARRAY_SIZE(cstate_set_s0ix),
|
|
|
|
ARRAY_SIZE(cstate_set_non_s0ix))];
|
|
|
|
int *set;
|
|
|
|
int i;
|
2015-05-13 03:19:47 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
config_t *config = config_of_soc();
|
2015-09-04 23:19:35 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
int is_s0ix_enable = config->s0ix_enable;
|
2015-09-04 23:19:35 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
if (is_s0ix_enable) {
|
|
|
|
*entries = ARRAY_SIZE(cstate_set_s0ix);
|
|
|
|
set = cstate_set_s0ix;
|
|
|
|
} else {
|
|
|
|
*entries = ARRAY_SIZE(cstate_set_non_s0ix);
|
|
|
|
set = cstate_set_non_s0ix;
|
|
|
|
}
|
2015-09-04 23:19:35 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
for (i = 0; i < *entries; i++) {
|
2015-05-13 03:19:47 +02:00
|
|
|
memcpy(&map[i], &cstate_map[set[i]], sizeof(acpi_cstate_t));
|
|
|
|
map[i].ctype = i + 1;
|
|
|
|
}
|
2020-08-03 16:53:41 +02:00
|
|
|
return map;
|
src: Remove variable length arrays
Variable length arrays were a feature added in C99 that allows the
length of an array to be determined at runtime. Eg.
int sum(size_t n) {
int arr[n];
...
}
This adds a small amount of runtime overhead, but is also very
dangerous, since it allows use of an unlimited amount of stack memory,
potentially leading to stack overflow. This is only worsened in
coreboot, which often has very little stack space to begin with. Citing
concerns like this, all instances of VLA's were recently removed from the
Linux kernel. In the immortal words of Linus Torvalds [0],
AND USING VLA'S IS ACTIVELY STUPID! It generates much more code, and
much _slower_ code (and more fragile code), than just using a fixed
key size would have done. [...] Anyway, some of these are definitely
easy to just fix, and using VLA's is actively bad not just for
security worries, but simply because VLA's are a really horribly bad
idea in general in the kernel.
This patch follows suit and zaps all VLA's in coreboot. Some of the
existing VLA's are accidental ones, and all but one can be replaced with
small fixed-size buffers. The single tricky exception is in the SPI
controller interface, which will require a rewrite of old drivers
to remove [1].
[0] https://lkml.org/lkml/2018/3/7/621
[1] https://ticket.coreboot.org/issues/217
Change-Id: I7d9d1ddadbf1cee5f695165bbe3f0effb7bd32b9
Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/33821
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2019-06-27 00:18:16 +02:00
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
void soc_power_states_generation(int core_id, int cores_per_package)
|
src: Remove variable length arrays
Variable length arrays were a feature added in C99 that allows the
length of an array to be determined at runtime. Eg.
int sum(size_t n) {
int arr[n];
...
}
This adds a small amount of runtime overhead, but is also very
dangerous, since it allows use of an unlimited amount of stack memory,
potentially leading to stack overflow. This is only worsened in
coreboot, which often has very little stack space to begin with. Citing
concerns like this, all instances of VLA's were recently removed from the
Linux kernel. In the immortal words of Linus Torvalds [0],
AND USING VLA'S IS ACTIVELY STUPID! It generates much more code, and
much _slower_ code (and more fragile code), than just using a fixed
key size would have done. [...] Anyway, some of these are definitely
easy to just fix, and using VLA's is actively bad not just for
security worries, but simply because VLA's are a really horribly bad
idea in general in the kernel.
This patch follows suit and zaps all VLA's in coreboot. Some of the
existing VLA's are accidental ones, and all but one can be replaced with
small fixed-size buffers. The single tricky exception is in the SPI
controller interface, which will require a rewrite of old drivers
to remove [1].
[0] https://lkml.org/lkml/2018/3/7/621
[1] https://ticket.coreboot.org/issues/217
Change-Id: I7d9d1ddadbf1cee5f695165bbe3f0effb7bd32b9
Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/33821
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
2019-06-27 00:18:16 +02:00
|
|
|
{
|
2020-08-03 16:53:41 +02:00
|
|
|
config_t *config = config_of_soc();
|
2015-05-13 03:19:47 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
/* Generate P-state tables */
|
|
|
|
if (config->eist_enable)
|
|
|
|
generate_p_state_entries(core_id, cores_per_package);
|
2015-05-13 03:19:47 +02:00
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
uint32_t soc_read_sci_irq_select(void)
|
2015-05-13 03:19:47 +02:00
|
|
|
{
|
2020-08-03 16:53:41 +02:00
|
|
|
return read32p(soc_read_pmc_base() + IRQ_REG);
|
2015-05-13 03:19:47 +02:00
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
void soc_fill_gnvs(struct global_nvs *gnvs)
|
2020-10-14 19:30:46 +02:00
|
|
|
{
|
2020-08-03 16:53:41 +02:00
|
|
|
const struct soc_intel_skylake_config *config = config_of_soc();
|
2020-10-14 19:30:46 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
/* Enable DPTF based on mainboard configuration */
|
|
|
|
gnvs->dpte = config->dptf_enable;
|
2020-10-14 19:30:46 +02:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
/* Set USB2/USB3 wake enable bitmaps. */
|
|
|
|
gnvs->u2we = config->usb2_wake_enable_bitmap;
|
|
|
|
gnvs->u3we = config->usb3_wake_enable_bitmap;
|
2018-11-28 12:07:19 +01:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
if (CONFIG(SOC_INTEL_COMMON_BLOCK_SGX_ENABLE))
|
|
|
|
sgx_fill_gnvs(gnvs);
|
2018-11-28 12:07:19 +01:00
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
/* Fill in Above 4GB MMIO resource */
|
|
|
|
sa_fill_gnvs(gnvs);
|
2015-05-13 03:19:47 +02:00
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
static unsigned long soc_fill_dmar(unsigned long current)
|
2017-09-18 20:03:46 +02:00
|
|
|
{
|
|
|
|
const u32 gfx_vtbar = MCHBAR32(GFXVTBAR) & ~0xfff;
|
|
|
|
const bool gfxvten = MCHBAR32(GFXVTBAR) & 1;
|
|
|
|
|
|
|
|
/* iGFX has to be enabled, GFXVTBAR set and in 32-bit space. */
|
2020-08-03 12:29:41 +02:00
|
|
|
const bool emit_igd =
|
2021-06-23 12:13:57 +02:00
|
|
|
is_devfn_enabled(SA_DEVFN_IGD) &&
|
2020-08-03 12:29:41 +02:00
|
|
|
gfx_vtbar && gfxvten &&
|
|
|
|
!MCHBAR32(GFXVTBAR + 4);
|
|
|
|
|
|
|
|
/* First, add DRHD entries */
|
|
|
|
if (emit_igd) {
|
|
|
|
const unsigned long tmp = current;
|
2017-09-18 20:03:46 +02:00
|
|
|
|
|
|
|
current += acpi_create_dmar_drhd(current, 0, 0, gfx_vtbar);
|
2018-03-29 14:59:57 +02:00
|
|
|
current += acpi_create_dmar_ds_pci(current, 0, 2, 0);
|
2017-09-18 20:03:46 +02:00
|
|
|
|
|
|
|
acpi_dmar_drhd_fixup(tmp, current);
|
|
|
|
}
|
|
|
|
|
|
|
|
const u32 vtvc0bar = MCHBAR32(VTVC0BAR) & ~0xfff;
|
|
|
|
const bool vtvc0en = MCHBAR32(VTVC0BAR) & 1;
|
|
|
|
|
|
|
|
/* General VTBAR has to be set and in 32-bit space. */
|
2019-08-30 19:42:23 +02:00
|
|
|
if (vtvc0bar && vtvc0en && !MCHBAR32(VTVC0BAR + 4)) {
|
2017-09-18 20:03:46 +02:00
|
|
|
const unsigned long tmp = current;
|
|
|
|
|
2019-08-30 19:42:23 +02:00
|
|
|
current += acpi_create_dmar_drhd(current, DRHD_INCLUDE_PCI_ALL, 0, vtvc0bar);
|
2017-09-18 20:03:46 +02:00
|
|
|
|
2019-08-30 19:42:23 +02:00
|
|
|
current += acpi_create_dmar_ds_ioapic(current, 2, V_P2SB_IBDF_BUS,
|
|
|
|
V_P2SB_IBDF_DEV, V_P2SB_IBDF_FUN);
|
2017-09-18 20:03:46 +02:00
|
|
|
|
2019-08-30 19:42:23 +02:00
|
|
|
current += acpi_create_dmar_ds_msi_hpet(current, 0, V_P2SB_HBDF_BUS,
|
|
|
|
V_P2SB_HBDF_DEV, V_P2SB_HBDF_FUN);
|
2017-09-18 20:03:46 +02:00
|
|
|
|
|
|
|
acpi_dmar_drhd_fixup(tmp, current);
|
|
|
|
}
|
|
|
|
|
2020-08-03 12:29:41 +02:00
|
|
|
/* Then, add RMRR entries after all DRHD entries */
|
|
|
|
if (emit_igd) {
|
|
|
|
const unsigned long tmp = current;
|
|
|
|
|
|
|
|
current += acpi_create_dmar_rmrr(current, 0,
|
|
|
|
sa_get_gsm_base(), sa_get_tolud_base() - 1);
|
|
|
|
current += acpi_create_dmar_ds_pci(current, 0, 2, 0);
|
|
|
|
acpi_dmar_rmrr_fixup(tmp, current);
|
|
|
|
}
|
|
|
|
|
2017-09-18 20:03:46 +02:00
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
unsigned long sa_write_acpi_tables(const struct device *const dev,
|
|
|
|
unsigned long current,
|
|
|
|
struct acpi_rsdp *const rsdp)
|
2017-09-18 20:03:46 +02:00
|
|
|
{
|
|
|
|
acpi_dmar_t *const dmar = (acpi_dmar_t *)current;
|
|
|
|
|
|
|
|
/* Create DMAR table only if we have VT-d capability. */
|
2021-07-13 08:23:22 +02:00
|
|
|
if (!soc_vtd_enabled())
|
2017-09-18 20:03:46 +02:00
|
|
|
return current;
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * DMAR\n");
|
2020-08-03 16:53:41 +02:00
|
|
|
acpi_create_dmar(dmar, DMAR_INTR_REMAP, soc_fill_dmar);
|
2017-09-18 20:03:46 +02:00
|
|
|
current += dmar->header.length;
|
|
|
|
current = acpi_align_current(current);
|
|
|
|
acpi_add_table(rsdp, dmar);
|
|
|
|
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
int soc_madt_sci_irq_polarity(int sci)
|
2015-05-13 03:19:47 +02:00
|
|
|
{
|
|
|
|
if (sci >= 20)
|
2020-08-03 16:53:41 +02:00
|
|
|
return MP_IRQ_POLARITY_LOW;
|
2015-05-13 03:19:47 +02:00
|
|
|
else
|
2020-08-03 16:53:41 +02:00
|
|
|
return MP_IRQ_POLARITY_HIGH;
|
2015-05-13 03:23:27 +02:00
|
|
|
}
|
|
|
|
|
2020-08-03 16:53:41 +02:00
|
|
|
void acpi_fill_soc_wake(uint32_t *pm1_en, uint32_t *gpe0_en,
|
|
|
|
const struct chipset_power_state *ps)
|
2015-09-09 01:12:44 +02:00
|
|
|
{
|
2019-09-27 23:20:27 +02:00
|
|
|
const struct soc_intel_skylake_config *config = config_of_soc();
|
2020-08-03 16:53:41 +02:00
|
|
|
|
|
|
|
if (ps->prev_sleep_state == ACPI_S3 && deep_s3_enabled()) {
|
2016-10-26 05:07:22 +02:00
|
|
|
if (config->deep_sx_config & DSX_EN_LAN_WAKE_PIN)
|
2020-08-03 16:53:41 +02:00
|
|
|
gpe0_en[GPE_STD] |= LAN_WAK_EN;
|
2016-10-26 05:07:22 +02:00
|
|
|
if (config->deep_sx_config & DSX_EN_WAKE_PIN)
|
2020-08-03 16:53:41 +02:00
|
|
|
*pm1_en |= PCIEXPWAK_STS;
|
2016-10-26 05:07:22 +02:00
|
|
|
}
|
2015-09-09 01:12:44 +02:00
|
|
|
}
|