soc/intel/common/block: Common ACPI
This patch adds the common acpi code.ACPI code is very similar accross different intel chipsets.This patch is an effort to move those code in common place so that it can be shared accross different intel platforms instead of duplicating for each platform. We are removing the common acpi files in src/soc/intel/common. This removes the acpi.c file which was previously in src/soc/common/acpi. The config for common acpi is SOC_INTEL_COMMON_BLOCK_ACPI which can be defined in SOC's Kconfig file in order to use the common ACPI code. This patch also includes the changes in APL platform to use the common ACPI block. TEST= Tested the patch as below: 1.Builds and system boots up with the patch. 2.Check all the ACPI tables are present in /sys/firmware/acpi/tables 3.Check SCI's are properly working as we are modifying the function to override madt. 4.Extract acpi tables like DSDT,APIC, FACP, FACS and decompile the by iasl and compare with good known tables. 5.Execute the extracted tables in aciexec to check acpi methods are working properly. Change-Id: Ib6eb6fd5366e6e28fd81bc22d050b0efa05a2e5d Signed-off-by: Shaunak Saha <shaunak.saha@intel.com> Reviewed-on: https://review.coreboot.org/20630 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Sumeet R Pawnikar <sumeet.r.pawnikar@intel.com>
This commit is contained in:
parent
af896d071b
commit
bd427803ab
|
@ -1,8 +1,7 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corp.
|
||||
* (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
|
||||
* Copyright (C) 2017 Intel Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -15,14 +14,13 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _SOC_APOLLOLAKE_ACPI_H_
|
||||
#define _SOC_APOLLOLAKE_ACPI_H_
|
||||
#ifndef CPU_INTEL_RESET_H
|
||||
#define CPU_INTEL_RESET_H
|
||||
|
||||
#include <arch/acpi.h>
|
||||
/* Reset control port */
|
||||
#define RST_CNT 0xcf9
|
||||
#define FULL_RST (1 << 3)
|
||||
#define RST_CPU (1 << 2)
|
||||
#define SYS_RST (1 << 1)
|
||||
|
||||
unsigned long southbridge_write_acpi_tables(device_t device,
|
||||
unsigned long current, struct acpi_rsdp *rsdp);
|
||||
|
||||
void southbridge_inject_dsdt(device_t device);
|
||||
|
||||
#endif /* _SOC_APOLLOLAKE_ACPI_H_ */
|
||||
#endif /* CPU_INTEL_RESET_H */
|
|
@ -59,9 +59,9 @@ config CPU_SPECIFIC_OPTIONS
|
|||
select SMM_TSEG
|
||||
select SA_ENABLE_IMR
|
||||
select SOC_INTEL_COMMON
|
||||
select SOC_INTEL_COMMON_ACPI
|
||||
select SOC_INTEL_COMMON_ACPI_WAKE_SOURCE
|
||||
select SOC_INTEL_COMMON_BLOCK
|
||||
select SOC_INTEL_COMMON_BLOCK_ACPI
|
||||
select SOC_INTEL_COMMON_BLOCK_CPU
|
||||
select SOC_INTEL_COMMON_BLOCK_FAST_SPI
|
||||
select SOC_INTEL_COMMON_BLOCK_GPIO
|
||||
|
|
|
@ -17,20 +17,20 @@
|
|||
|
||||
#include <arch/acpi.h>
|
||||
#include <arch/acpigen.h>
|
||||
#include <arch/io.h>
|
||||
#include <arch/ioapic.h>
|
||||
#include <arch/smp/mpspec.h>
|
||||
#include <cbmem.h>
|
||||
#include <cpu/x86/smm.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <soc/acpi.h>
|
||||
#include <soc/intel/common/acpi.h>
|
||||
#include <gpio.h>
|
||||
#include <intelblocks/acpi.h>
|
||||
#include <intelblocks/pmclib.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <soc/pm.h>
|
||||
#include <soc/nvs.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <string.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <gpio.h>
|
||||
#include "chip.h"
|
||||
|
||||
#define CSTATE_RES(address_space, width, offset, address) \
|
||||
|
@ -41,116 +41,41 @@
|
|||
.addrl = address, \
|
||||
}
|
||||
|
||||
unsigned long acpi_fill_mcfg(unsigned long current)
|
||||
static acpi_cstate_t cstate_map[] = {
|
||||
{
|
||||
/* C1 */
|
||||
.ctype = 1, /* ACPI C1 */
|
||||
.latency = 1,
|
||||
.power = 1000,
|
||||
.resource = CSTATE_RES(ACPI_ADDRESS_SPACE_FIXED, 0, 0, 0),
|
||||
},
|
||||
{
|
||||
.ctype = 2, /* ACPI C2 */
|
||||
.latency = 50,
|
||||
.power = 10,
|
||||
.resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0, 0x415),
|
||||
},
|
||||
{
|
||||
.ctype = 3, /* ACPI C3 */
|
||||
.latency = 150,
|
||||
.power = 10,
|
||||
.resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0, 0x419),
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t soc_read_sci_irq_select(void)
|
||||
{
|
||||
/* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */
|
||||
current += acpi_create_mcfg_mmconfig((void *) current,
|
||||
CONFIG_MMCONF_BASE_ADDRESS, 0, 0,
|
||||
255);
|
||||
return current;
|
||||
uintptr_t pmc_bar = soc_read_pmc_base();
|
||||
return read32((void *)pmc_bar + IRQ_REG);
|
||||
}
|
||||
|
||||
static int acpi_sci_irq(void)
|
||||
acpi_cstate_t *soc_get_cstate_map(size_t *entries)
|
||||
{
|
||||
int sci_irq = 9;
|
||||
return sci_irq;
|
||||
*entries = ARRAY_SIZE(cstate_map);
|
||||
return cstate_map;
|
||||
}
|
||||
|
||||
static unsigned long acpi_madt_irq_overrides(unsigned long current)
|
||||
{
|
||||
int sci = acpi_sci_irq();
|
||||
uint16_t flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW;
|
||||
|
||||
/* INT_SRC_OVR */
|
||||
current += acpi_create_madt_irqoverride((void *)current, 0, 0, 2, 0);
|
||||
|
||||
/* SCI */
|
||||
current += acpi_create_madt_irqoverride((void *)current, 0, sci, sci,
|
||||
flags);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
unsigned long acpi_fill_madt(unsigned long current)
|
||||
{
|
||||
/* Local APICs */
|
||||
current = acpi_create_madt_lapics(current);
|
||||
|
||||
/* IOAPIC */
|
||||
current += acpi_create_madt_ioapic((void *) current,
|
||||
2, IO_APIC_ADDR, 0);
|
||||
|
||||
return acpi_madt_irq_overrides(current);
|
||||
}
|
||||
|
||||
void acpi_fill_fadt(acpi_fadt_t *fadt)
|
||||
{
|
||||
const uint16_t pmbase = ACPI_BASE_ADDRESS;
|
||||
|
||||
/* Use ACPI 3.0 revision. */
|
||||
fadt->header.revision = ACPI_FADT_REV_ACPI_3_0;
|
||||
|
||||
fadt->sci_int = acpi_sci_irq();
|
||||
fadt->smi_cmd = APM_CNT;
|
||||
fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
|
||||
fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
|
||||
|
||||
fadt->pm1a_evt_blk = pmbase + PM1_STS;
|
||||
fadt->pm1a_cnt_blk = pmbase + PM1_CNT;
|
||||
fadt->pm_tmr_blk = pmbase + PM1_TMR;
|
||||
fadt->gpe0_blk = pmbase + GPE0_STS(0);
|
||||
|
||||
fadt->pm1_evt_len = 4;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
fadt->pm_tmr_len = 4;
|
||||
/* There are 4 GPE0 STS/EN pairs each 32 bits wide. */
|
||||
fadt->gpe0_blk_len = 2 * GPE0_REG_MAX * sizeof(uint32_t);
|
||||
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
|
||||
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
|
||||
fadt->flush_size = 0x400; /* twice of cache size*/
|
||||
fadt->flush_stride = 0x10; /* Cache line width */
|
||||
fadt->duty_offset = 1;
|
||||
fadt->duty_width = 3;
|
||||
fadt->day_alrm = 0xd;
|
||||
fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
|
||||
|
||||
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
|
||||
ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON |
|
||||
ACPI_FADT_RESET_REGISTER | ACPI_FADT_SEALED_CASE |
|
||||
ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK;
|
||||
|
||||
fadt->reset_reg.space_id = 1;
|
||||
fadt->reset_reg.bit_width = 8;
|
||||
fadt->reset_reg.addrl = 0xcf9;
|
||||
fadt->reset_value = 6;
|
||||
|
||||
fadt->x_pm1a_evt_blk.space_id = 1;
|
||||
fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;
|
||||
fadt->x_pm1a_evt_blk.addrl = pmbase + PM1_STS;
|
||||
|
||||
fadt->x_pm1b_evt_blk.space_id = 1;
|
||||
|
||||
fadt->x_pm1a_cnt_blk.space_id = 1;
|
||||
fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8;
|
||||
fadt->x_pm1a_cnt_blk.addrl = pmbase + PM1_CNT;
|
||||
|
||||
fadt->x_pm1b_cnt_blk.space_id = 1;
|
||||
|
||||
fadt->x_pm_tmr_blk.space_id = 1;
|
||||
fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8;
|
||||
fadt->x_pm_tmr_blk.addrl = pmbase + PM1_TMR;
|
||||
|
||||
fadt->x_gpe1_blk.space_id = 1;
|
||||
}
|
||||
|
||||
unsigned long southbridge_write_acpi_tables(device_t device,
|
||||
unsigned long current,
|
||||
struct acpi_rsdp *rsdp)
|
||||
{
|
||||
return acpi_write_hpet(device, current, rsdp);
|
||||
}
|
||||
|
||||
static void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
||||
void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
||||
{
|
||||
struct soc_intel_apollolake_config *cfg;
|
||||
struct device *dev = SA_DEV_ROOT;
|
||||
|
@ -159,7 +84,7 @@ static void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
|||
memset(gnvs, 0, sizeof(*gnvs));
|
||||
|
||||
if (IS_ENABLED(CONFIG_CONSOLE_CBMEM))
|
||||
gnvs->cbmc = (uintptr_t)cbmem_find(CBMEM_ID_CONSOLE);
|
||||
gnvs->cbmc = (uintptr_t) cbmem_find(CBMEM_ID_CONSOLE);
|
||||
|
||||
if (IS_ENABLED(CONFIG_CHROMEOS)) {
|
||||
/* Initialize Verified Boot data */
|
||||
|
@ -184,7 +109,7 @@ static void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
|||
|
||||
/* Assign address of PERST_0 if GPIO is defined in devicetree */
|
||||
if (cfg->prt0_gpio != GPIO_PRT0_UDEF)
|
||||
gnvs->prt0 = (uintptr_t)gpio_dwx_address(cfg->prt0_gpio);
|
||||
gnvs->prt0 = (uintptr_t) gpio_dwx_address(cfg->prt0_gpio);
|
||||
|
||||
/* Get sdcard cd GPIO portid if GPIO is defined in devicetree.
|
||||
* Get offset of sdcard cd pin.
|
||||
|
@ -195,87 +120,50 @@ static void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
|||
}
|
||||
}
|
||||
|
||||
/* Save wake source information for calculating ACPI _SWS values */
|
||||
int soc_fill_acpi_wake(uint32_t *pm1, uint32_t **gpe0)
|
||||
uint32_t acpi_fill_soc_wake(uint32_t generic_pm1_en,
|
||||
const struct chipset_power_state *ps)
|
||||
{
|
||||
struct chipset_power_state *ps;
|
||||
static uint32_t gpe0_sts[GPE0_REG_MAX];
|
||||
uint32_t pm1_en;
|
||||
int i;
|
||||
|
||||
ps = cbmem_find(CBMEM_ID_POWER_STATE);
|
||||
if (ps == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* PM1_EN to check the basic wake events which can happen through
|
||||
* powerbtn or any other wake source like lidopen, key board press etc.
|
||||
* WAK_STS bit is set when the system is in one of the sleep states
|
||||
* (via the SLP_EN bit) and an enabled wake event occurs. Upon setting
|
||||
* this bit, the PMC will transition the system to the ON state and
|
||||
* can only be set by hardware and can only be cleared by writing a one
|
||||
* to this bit position.
|
||||
*/
|
||||
pm1_en = ps->pm1_en | WAK_STS | RTC_EN | PWRBTN_EN;
|
||||
*pm1 = ps->pm1_sts & pm1_en;
|
||||
|
||||
/* Mask off GPE0 status bits that are not enabled */
|
||||
*gpe0 = &gpe0_sts[0];
|
||||
for (i = 0; i < GPE0_REG_MAX; i++)
|
||||
gpe0_sts[i] = ps->gpe0_sts[i] & ps->gpe0_en[i];
|
||||
|
||||
return GPE0_REG_MAX;
|
||||
generic_pm1_en |= WAK_STS | RTC_EN | PWRBTN_EN;
|
||||
return generic_pm1_en;
|
||||
}
|
||||
|
||||
void southbridge_inject_dsdt(device_t device)
|
||||
int soc_madt_sci_irq_polarity(int sci)
|
||||
{
|
||||
struct global_nvs_t *gnvs;
|
||||
|
||||
gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
|
||||
|
||||
if (gnvs) {
|
||||
acpi_create_gnvs(gnvs);
|
||||
acpi_save_gnvs((uintptr_t)gnvs);
|
||||
/* And tell SMI about it */
|
||||
smm_setup_structures(gnvs, NULL, NULL);
|
||||
|
||||
/* Add it to DSDT. */
|
||||
acpigen_write_scope("\\");
|
||||
acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
|
||||
acpigen_pop_len();
|
||||
}
|
||||
}
|
||||
static acpi_cstate_t cstate_map[] = {
|
||||
{
|
||||
/* C1 */
|
||||
.ctype = 1, /* ACPI C1 */
|
||||
.latency = 1,
|
||||
.power = 1000,
|
||||
.resource = CSTATE_RES(ACPI_ADDRESS_SPACE_FIXED, 0, 0, 0),
|
||||
},
|
||||
{
|
||||
.ctype = 2, /* ACPI C2 */
|
||||
.latency = 50,
|
||||
.power = 10,
|
||||
.resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0, 0x415),
|
||||
},
|
||||
{
|
||||
.ctype = 3, /* ACPI C3 */
|
||||
.latency = 150,
|
||||
.power = 10,
|
||||
.resource = CSTATE_RES(ACPI_ADDRESS_SPACE_IO, 8, 0, 0x419),
|
||||
}
|
||||
};
|
||||
|
||||
acpi_cstate_t *soc_get_cstate_map(int *entries)
|
||||
{
|
||||
*entries = ARRAY_SIZE(cstate_map);
|
||||
return cstate_map;
|
||||
return MP_IRQ_POLARITY_LOW;
|
||||
}
|
||||
|
||||
uint16_t soc_get_acpi_base_address(void)
|
||||
void soc_fill_fadt(acpi_fadt_t *fadt)
|
||||
{
|
||||
return ACPI_BASE_ADDRESS;
|
||||
fadt->pm_tmr_blk = ACPI_BASE_ADDRESS + PM1_TMR;
|
||||
|
||||
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
|
||||
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
|
||||
|
||||
fadt->pm_tmr_len = 4;
|
||||
fadt->duty_width = 3;
|
||||
|
||||
fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
|
||||
|
||||
fadt->x_pm_tmr_blk.space_id = 1;
|
||||
fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8;
|
||||
fadt->x_pm_tmr_blk.addrl = ACPI_BASE_ADDRESS + PM1_TMR;
|
||||
}
|
||||
|
||||
void soc_power_states_generation(int core_id, int cores_per_package)
|
||||
{
|
||||
/* Generate P-state tables */
|
||||
generate_p_state_entries(core_id, cores_per_package);
|
||||
|
||||
/* Generate T-state tables */
|
||||
generate_t_state_entries(core_id, cores_per_package);
|
||||
}
|
||||
|
||||
static void acpigen_soc_get_dw0_in_local5(uintptr_t addr)
|
||||
|
@ -294,7 +182,7 @@ static void acpigen_soc_get_dw0_in_local5(uintptr_t addr)
|
|||
static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask)
|
||||
{
|
||||
assert(gpio_num < TOTAL_PADS);
|
||||
uintptr_t addr = (uintptr_t)gpio_dwx_address(gpio_num);
|
||||
uintptr_t addr = (uintptr_t) gpio_dwx_address(gpio_num);
|
||||
|
||||
acpigen_soc_get_dw0_in_local5(addr);
|
||||
|
||||
|
@ -320,7 +208,7 @@ static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask)
|
|||
static int acpigen_soc_set_gpio_val(unsigned int gpio_num, uint32_t val)
|
||||
{
|
||||
assert(gpio_num < TOTAL_PADS);
|
||||
uintptr_t addr = (uintptr_t)gpio_dwx_address(gpio_num);
|
||||
uintptr_t addr = (uintptr_t) gpio_dwx_address(gpio_num);
|
||||
|
||||
acpigen_soc_get_dw0_in_local5(addr);
|
||||
|
||||
|
|
|
@ -202,6 +202,23 @@
|
|||
#define PMC_GPE_W_31_0 9
|
||||
#endif
|
||||
|
||||
#define IRQ_REG 0x106C
|
||||
#define SCI_IRQ_ADJUST 24
|
||||
#define SCI_IRQ_SEL (255 << SCI_IRQ_ADJUST)
|
||||
#define SCIS_IRQ9 9
|
||||
#define SCIS_IRQ10 10
|
||||
#define SCIS_IRQ11 11
|
||||
#define SCIS_IRQ20 20
|
||||
#define SCIS_IRQ21 21
|
||||
#define SCIS_IRQ22 22
|
||||
#define SCIS_IRQ23 23
|
||||
|
||||
/* P-state configuration */
|
||||
#define PSS_MAX_ENTRIES 8
|
||||
#define PSS_RATIO_STEP 2
|
||||
#define PSS_LATENCY_TRANSITION 10
|
||||
#define PSS_LATENCY_BUSMASTER 10
|
||||
|
||||
/* Track power state from reset to log events. */
|
||||
struct chipset_power_state {
|
||||
uint16_t pm1_sts;
|
||||
|
|
|
@ -28,7 +28,6 @@ ramstage-$(CONFIG_MMA) += mma.c
|
|||
ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI_WAKE_SOURCE) += acpi_wake_source.c
|
||||
ramstage-y += vbt.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_GFX_OPREGION) += opregion.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI) += ./acpi/acpi.c
|
||||
ramstage-$(CONFIG_SOC_INTEL_COMMON_NHLT) += nhlt.c
|
||||
|
||||
bootblock-$(CONFIG_MAINBOARD_HAS_TPM_CR50) += tpm_tis.c
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2015 Google Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
|
@ -29,24 +25,4 @@
|
|||
*/
|
||||
int soc_fill_acpi_wake(uint32_t *pm1, uint32_t **gpe0);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SOC_INTEL_COMMON_ACPI)
|
||||
|
||||
/*
|
||||
* get_cstate_map returns a table of processor specific acpi_cstate_t entries
|
||||
* and number of entries in the table
|
||||
*/
|
||||
acpi_cstate_t *soc_get_cstate_map(int *num_entries);
|
||||
|
||||
/*
|
||||
* get_soc_tss_table returns a table of processor specific acpi_tstate_t entries
|
||||
* and number of entries in the table
|
||||
*/
|
||||
acpi_tstate_t *soc_get_tss_table(int *num_entries);
|
||||
|
||||
/*
|
||||
* soc_get_acpi_base_address returns the ACPI base address for the SOC
|
||||
*/
|
||||
uint16_t soc_get_acpi_base_address(void);
|
||||
|
||||
#endif /* CONFIG_SOC_INTEL_COMMON_ACPI */
|
||||
#endif
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <arch/acpi.h>
|
||||
#include <arch/acpigen.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <cpu/intel/turbo.h>
|
||||
#include <cpu/x86/msr.h>
|
||||
#include <intelblocks/cpulib.h>
|
||||
#include <soc/intel/common/acpi.h>
|
||||
#include <soc/pm.h>
|
||||
|
||||
#define MSR_PLATFORM_INFO 0xce
|
||||
#define MSR_TURBO_RATIO_LIMIT 0x1ad
|
||||
#define MSR_CONFIG_TDP_NOMINAL 0x648
|
||||
#define MSR_RAPL_POWER_UNIT 0x606
|
||||
#define MSR_PKG_POWER_INFO 0x614
|
||||
|
||||
/* P-state configuration */
|
||||
#define PSS_MAX_ENTRIES 8
|
||||
#define PSS_RATIO_STEP 2
|
||||
#define PSS_LATENCY_TRANSITION 10
|
||||
#define PSS_LATENCY_BUSMASTER 10
|
||||
|
||||
|
||||
__attribute__((weak)) acpi_cstate_t *soc_get_cstate_map(int *entries)
|
||||
{
|
||||
*entries = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) acpi_tstate_t *soc_get_tss_table(int *entries)
|
||||
{
|
||||
*entries = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint16_t soc_get_acpi_base_address(void)
|
||||
{
|
||||
#define ACPI_BASE_ADDR 0x400
|
||||
return ACPI_BASE_ADDR;
|
||||
}
|
||||
|
||||
static int calculate_power(int tdp, int p1_ratio, int ratio)
|
||||
{
|
||||
u32 m;
|
||||
u32 power;
|
||||
|
||||
/*
|
||||
* M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
|
||||
*
|
||||
* Power = (ratio / p1_ratio) * m * tdp
|
||||
*/
|
||||
|
||||
m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
|
||||
m = (m * m) / 1000;
|
||||
|
||||
power = ((ratio * 100000 / p1_ratio) / 100);
|
||||
power *= (m / 100) * (tdp / 1000);
|
||||
power /= 1000;
|
||||
return power;
|
||||
}
|
||||
|
||||
static int get_cores_per_package(void)
|
||||
{
|
||||
struct cpuinfo_x86 c;
|
||||
struct cpuid_result result;
|
||||
int cores = 1;
|
||||
|
||||
get_fms(&c, cpuid_eax(1));
|
||||
if (c.x86 != 6)
|
||||
return 1;
|
||||
|
||||
result = cpuid_ext(0xb, 1);
|
||||
cores = result.ebx & 0xff;
|
||||
|
||||
return cores;
|
||||
}
|
||||
|
||||
static void generate_p_state_entries(int core, int cores_per_package)
|
||||
{
|
||||
int ratio_min, ratio_max, ratio_turbo, ratio_step;
|
||||
int coord_type, power_max, num_entries;
|
||||
int ratio, power, clock, clock_max;
|
||||
|
||||
coord_type = cpu_get_coord_type();
|
||||
ratio_min = cpu_get_min_ratio();
|
||||
ratio_max = cpu_get_max_ratio();
|
||||
clock_max = (ratio_max * cpu_get_bus_clock()) / KHz;
|
||||
|
||||
/* Calculate CPU TDP in mW */
|
||||
power_max = cpu_get_power_max();
|
||||
|
||||
/* Write _PCT indicating use of FFixedHW */
|
||||
acpigen_write_empty_PCT();
|
||||
|
||||
/* Write _PPC with no limit on supported P-state */
|
||||
acpigen_write_PPC_NVS();
|
||||
/* Write PSD indicating configured coordination type */
|
||||
acpigen_write_PSD_package(core, 1, coord_type);
|
||||
|
||||
/* Add P-state entries in _PSS table */
|
||||
acpigen_write_name("_PSS");
|
||||
|
||||
/* Determine ratio points */
|
||||
ratio_step = PSS_RATIO_STEP;
|
||||
num_entries = ((ratio_max - ratio_min) / ratio_step) + 1;
|
||||
if (num_entries > PSS_MAX_ENTRIES) {
|
||||
ratio_step += 1;
|
||||
num_entries = ((ratio_max - ratio_min) / ratio_step) + 1;
|
||||
}
|
||||
|
||||
/* P[T] is Turbo state if enabled */
|
||||
if (get_turbo_state() == TURBO_ENABLED) {
|
||||
/* _PSS package count including Turbo */
|
||||
acpigen_write_package(num_entries + 2);
|
||||
ratio_turbo = cpu_get_max_turbo_ratio();
|
||||
|
||||
/* Add entry for Turbo ratio */
|
||||
acpigen_write_PSS_package(
|
||||
clock_max + 1, /* MHz */
|
||||
power_max, /* mW */
|
||||
PSS_LATENCY_TRANSITION, /* lat1 */
|
||||
PSS_LATENCY_BUSMASTER, /* lat2 */
|
||||
ratio_turbo << 8, /* control */
|
||||
ratio_turbo << 8); /* status */
|
||||
} else {
|
||||
/* _PSS package count without Turbo */
|
||||
acpigen_write_package(num_entries + 1);
|
||||
}
|
||||
|
||||
/* First regular entry is max non-turbo ratio */
|
||||
acpigen_write_PSS_package(
|
||||
clock_max, /* MHz */
|
||||
power_max, /* mW */
|
||||
PSS_LATENCY_TRANSITION, /* lat1 */
|
||||
PSS_LATENCY_BUSMASTER, /* lat2 */
|
||||
ratio_max << 8, /* control */
|
||||
ratio_max << 8); /* status */
|
||||
|
||||
/* Generate the remaining entries */
|
||||
for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
|
||||
ratio >= ratio_min; ratio -= ratio_step) {
|
||||
|
||||
/* Calculate power at this ratio */
|
||||
power = calculate_power(power_max, ratio_max, ratio);
|
||||
clock = (ratio * cpu_get_bus_clock()) / KHz;
|
||||
|
||||
acpigen_write_PSS_package(
|
||||
clock, /* MHz */
|
||||
power, /* mW */
|
||||
PSS_LATENCY_TRANSITION, /* lat1 */
|
||||
PSS_LATENCY_BUSMASTER, /* lat2 */
|
||||
ratio << 8, /* control */
|
||||
ratio << 8); /* status */
|
||||
}
|
||||
/* Fix package length */
|
||||
acpigen_pop_len();
|
||||
}
|
||||
|
||||
static void generate_c_state_entries(void)
|
||||
{
|
||||
acpi_cstate_t *c_state_map;
|
||||
int entries;
|
||||
|
||||
c_state_map = soc_get_cstate_map(&entries);
|
||||
|
||||
/* Generate C-state tables */
|
||||
acpigen_write_CST_package(c_state_map, entries);
|
||||
}
|
||||
|
||||
static void generate_t_state_entries(int core, int cores_per_package)
|
||||
{
|
||||
acpi_tstate_t *soc_tss_table;
|
||||
int entries;
|
||||
|
||||
soc_tss_table = soc_get_tss_table(&entries);
|
||||
if (entries == 0)
|
||||
return;
|
||||
|
||||
/* Indicate SW_ALL coordination for T-states */
|
||||
acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
|
||||
|
||||
/* Indicate FFixedHW so OS will use MSR */
|
||||
acpigen_write_empty_PTC();
|
||||
|
||||
/* Set NVS controlled T-state limit */
|
||||
acpigen_write_TPC("\\TLVL");
|
||||
|
||||
/* Write TSS table for MSR access */
|
||||
acpigen_write_TSS_package(entries, soc_tss_table);
|
||||
}
|
||||
|
||||
void generate_cpu_entries(device_t device)
|
||||
{
|
||||
int core_id, cpu_id, pcontrol_blk = soc_get_acpi_base_address();
|
||||
int plen = 6;
|
||||
int totalcores = dev_count_cpu();
|
||||
int cores_per_package = get_cores_per_package();
|
||||
int numcpus = totalcores / cores_per_package;
|
||||
|
||||
printk(BIOS_DEBUG, "Found %d CPU(s) with %d core(s) each.\n",
|
||||
numcpus, cores_per_package);
|
||||
|
||||
for (cpu_id = 0; cpu_id < numcpus; cpu_id++) {
|
||||
for (core_id = 0; core_id < cores_per_package; core_id++) {
|
||||
if (core_id > 0) {
|
||||
pcontrol_blk = 0;
|
||||
plen = 0;
|
||||
}
|
||||
|
||||
/* Generate processor \_PR.CPUx */
|
||||
acpigen_write_processor(
|
||||
(cpu_id)*cores_per_package + core_id,
|
||||
pcontrol_blk, plen);
|
||||
|
||||
/* Generate P-state tables */
|
||||
generate_p_state_entries(
|
||||
core_id, cores_per_package);
|
||||
|
||||
/* Generate C-state tables */
|
||||
generate_c_state_entries();
|
||||
|
||||
/* Generate T-state tables */
|
||||
generate_t_state_entries(
|
||||
core_id, cores_per_package);
|
||||
|
||||
acpigen_pop_len();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
config SOC_INTEL_COMMON_BLOCK_ACPI
|
||||
depends on SOC_INTEL_COMMON_BLOCK_CPU
|
||||
depends on SOC_INTEL_COMMON_BLOCK_PMC
|
||||
bool
|
||||
help
|
||||
Intel Processor common code for ACPI
|
|
@ -0,0 +1 @@
|
|||
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI) += acpi.c
|
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <arch/acpigen.h>
|
||||
#include <arch/ioapic.h>
|
||||
#include <arch/smp/mpspec.h>
|
||||
#include <bootstate.h>
|
||||
#include <cbmem.h>
|
||||
#include <cpu/intel/reset.h>
|
||||
#include <cpu/intel/turbo.h>
|
||||
#include <cpu/x86/msr.h>
|
||||
#include <cpu/x86/smm.h>
|
||||
#include <intelblocks/acpi.h>
|
||||
#include <intelblocks/msr.h>
|
||||
#include <intelblocks/pmclib.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <soc/nvs.h>
|
||||
#include <soc/pm.h>
|
||||
|
||||
unsigned long acpi_fill_mcfg(unsigned long current)
|
||||
{
|
||||
/* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */
|
||||
current += acpi_create_mcfg_mmconfig((void *)current,
|
||||
CONFIG_MMCONF_BASE_ADDRESS, 0, 0,
|
||||
255);
|
||||
return current;
|
||||
}
|
||||
|
||||
static int acpi_sci_irq(void)
|
||||
{
|
||||
int sci_irq = 9;
|
||||
uint32_t scis;
|
||||
|
||||
scis = soc_read_sci_irq_select();
|
||||
scis &= SCI_IRQ_SEL;
|
||||
scis >>= SCI_IRQ_ADJUST;
|
||||
|
||||
/* Determine how SCI is routed. */
|
||||
switch (scis) {
|
||||
case SCIS_IRQ9:
|
||||
case SCIS_IRQ10:
|
||||
case SCIS_IRQ11:
|
||||
sci_irq = scis - SCIS_IRQ9 + 9;
|
||||
break;
|
||||
case SCIS_IRQ20:
|
||||
case SCIS_IRQ21:
|
||||
case SCIS_IRQ22:
|
||||
case SCIS_IRQ23:
|
||||
sci_irq = scis - SCIS_IRQ20 + 20;
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "Invalid SCI route! Defaulting to IRQ9.\n");
|
||||
sci_irq = 9;
|
||||
break;
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "SCI is IRQ%d\n", sci_irq);
|
||||
return sci_irq;
|
||||
}
|
||||
|
||||
static unsigned long acpi_madt_irq_overrides(unsigned long current)
|
||||
{
|
||||
int sci = acpi_sci_irq();
|
||||
uint16_t flags = MP_IRQ_TRIGGER_LEVEL;
|
||||
|
||||
/* INT_SRC_OVR */
|
||||
current += acpi_create_madt_irqoverride((void *)current, 0, 0, 2, 0);
|
||||
|
||||
flags |= soc_madt_sci_irq_polarity(sci);
|
||||
|
||||
/* SCI */
|
||||
current +=
|
||||
acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
unsigned long acpi_fill_madt(unsigned long current)
|
||||
{
|
||||
/* Local APICs */
|
||||
current = acpi_create_madt_lapics(current);
|
||||
|
||||
/* IOAPIC */
|
||||
current += acpi_create_madt_ioapic((void *)current, 2, IO_APIC_ADDR, 0);
|
||||
|
||||
return acpi_madt_irq_overrides(current);
|
||||
}
|
||||
|
||||
__attribute__ ((weak)) void soc_fill_fadt(acpi_fadt_t *fadt)
|
||||
{
|
||||
}
|
||||
|
||||
void acpi_fill_fadt(acpi_fadt_t *fadt)
|
||||
{
|
||||
const uint16_t pmbase = ACPI_BASE_ADDRESS;
|
||||
|
||||
/* Use ACPI 3.0 revision. */
|
||||
fadt->header.revision = ACPI_FADT_REV_ACPI_3_0;
|
||||
|
||||
fadt->sci_int = acpi_sci_irq();
|
||||
fadt->smi_cmd = APM_CNT;
|
||||
fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
|
||||
fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
|
||||
fadt->s4bios_req = 0x0;
|
||||
fadt->pstate_cnt = 0;
|
||||
|
||||
fadt->pm1a_evt_blk = pmbase + PM1_STS;
|
||||
fadt->pm1b_evt_blk = 0x0;
|
||||
fadt->pm1a_cnt_blk = pmbase + PM1_CNT;
|
||||
fadt->pm1b_cnt_blk = 0x0;
|
||||
|
||||
fadt->gpe0_blk = pmbase + GPE0_STS(0);
|
||||
|
||||
fadt->pm1_evt_len = 4;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
|
||||
/* GPE0 STS/EN pairs each 32 bits wide. */
|
||||
fadt->gpe0_blk_len = 2 * GPE0_REG_MAX * sizeof(uint32_t);
|
||||
|
||||
fadt->flush_size = 0x400; /* twice of cache size */
|
||||
fadt->flush_stride = 0x10; /* Cache line width */
|
||||
fadt->duty_offset = 1;
|
||||
fadt->day_alrm = 0xd;
|
||||
|
||||
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
|
||||
ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON |
|
||||
ACPI_FADT_RESET_REGISTER | ACPI_FADT_SEALED_CASE |
|
||||
ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK;
|
||||
|
||||
fadt->reset_reg.space_id = 1;
|
||||
fadt->reset_reg.bit_width = 8;
|
||||
fadt->reset_reg.addrl = RST_CNT;
|
||||
fadt->reset_value = RST_CPU | SYS_RST;
|
||||
|
||||
fadt->x_pm1a_evt_blk.space_id = 1;
|
||||
fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;
|
||||
fadt->x_pm1a_evt_blk.addrl = pmbase + PM1_STS;
|
||||
|
||||
fadt->x_pm1b_evt_blk.space_id = 1;
|
||||
|
||||
fadt->x_pm1a_cnt_blk.space_id = 1;
|
||||
fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8;
|
||||
fadt->x_pm1a_cnt_blk.addrl = pmbase + PM1_CNT;
|
||||
|
||||
fadt->x_pm1b_cnt_blk.space_id = 1;
|
||||
|
||||
fadt->x_gpe1_blk.space_id = 1;
|
||||
|
||||
soc_fill_fadt(fadt);
|
||||
}
|
||||
|
||||
unsigned long southbridge_write_acpi_tables(device_t device,
|
||||
unsigned long current,
|
||||
struct acpi_rsdp *rsdp)
|
||||
{
|
||||
return acpi_write_hpet(device, current, rsdp);
|
||||
}
|
||||
|
||||
__attribute__ ((weak))
|
||||
uint32_t acpi_fill_soc_wake(uint32_t generic_pm1_en,
|
||||
const struct chipset_power_state *ps)
|
||||
{
|
||||
return generic_pm1_en;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save wake source information for calculating ACPI _SWS values
|
||||
*
|
||||
* @pm1: PM1_STS register with only enabled events set
|
||||
* @gpe0: GPE0_STS registers with only enabled events set
|
||||
*
|
||||
* return the number of registers in the gpe0 array or -1 if nothing
|
||||
* is provided by this function.
|
||||
*/
|
||||
|
||||
static int acpi_fill_wake(uint32_t *pm1, uint32_t **gpe0)
|
||||
{
|
||||
struct chipset_power_state *ps;
|
||||
static uint32_t gpe0_sts[GPE0_REG_MAX];
|
||||
uint32_t pm1_en;
|
||||
int i;
|
||||
|
||||
ps = cbmem_find(CBMEM_ID_POWER_STATE);
|
||||
if (ps == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* PM1_EN to check the basic wake events which can happen through
|
||||
* powerbtn or any other wake source like lidopen, key board press etc.
|
||||
*/
|
||||
pm1_en = ps->pm1_en;
|
||||
|
||||
pm1_en = acpi_fill_soc_wake(pm1_en, ps);
|
||||
|
||||
*pm1 = ps->pm1_sts & pm1_en;
|
||||
|
||||
/* Mask off GPE0 status bits that are not enabled */
|
||||
*gpe0 = &gpe0_sts[0];
|
||||
for (i = 0; i < GPE0_REG_MAX; i++)
|
||||
gpe0_sts[i] = ps->gpe0_sts[i] & ps->gpe0_en[i];
|
||||
|
||||
return GPE0_REG_MAX;
|
||||
}
|
||||
|
||||
__attribute__ ((weak)) void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
||||
{
|
||||
}
|
||||
|
||||
void southbridge_inject_dsdt(device_t device)
|
||||
{
|
||||
struct global_nvs_t *gnvs;
|
||||
|
||||
gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
|
||||
if (!gnvs) {
|
||||
gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
|
||||
if (gnvs)
|
||||
memset(gnvs, 0, sizeof(*gnvs));
|
||||
}
|
||||
|
||||
if (gnvs) {
|
||||
acpi_create_gnvs(gnvs);
|
||||
acpi_save_gnvs((uintptr_t) gnvs);
|
||||
/* And tell SMI about it */
|
||||
smm_setup_structures(gnvs, NULL, NULL);
|
||||
|
||||
/* Add it to DSDT. */
|
||||
acpigen_write_scope("\\");
|
||||
acpigen_write_name_dword("NVSA", (uintptr_t) gnvs);
|
||||
acpigen_pop_len();
|
||||
}
|
||||
}
|
||||
|
||||
static int calculate_power(int tdp, int p1_ratio, int ratio)
|
||||
{
|
||||
u32 m;
|
||||
u32 power;
|
||||
|
||||
/*
|
||||
* M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
|
||||
*
|
||||
* Power = (ratio / p1_ratio) * m * tdp
|
||||
*/
|
||||
|
||||
m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
|
||||
m = (m * m) / 1000;
|
||||
|
||||
power = ((ratio * 100000 / p1_ratio) / 100);
|
||||
power *= (m / 100) * (tdp / 1000);
|
||||
power /= 1000;
|
||||
|
||||
return power;
|
||||
}
|
||||
|
||||
static int get_cores_per_package(void)
|
||||
{
|
||||
struct cpuinfo_x86 c;
|
||||
struct cpuid_result result;
|
||||
int cores = 1;
|
||||
|
||||
get_fms(&c, cpuid_eax(1));
|
||||
if (c.x86 != 6)
|
||||
return 1;
|
||||
|
||||
result = cpuid_ext(0xb, 1);
|
||||
cores = result.ebx & 0xff;
|
||||
|
||||
return cores;
|
||||
}
|
||||
|
||||
static void generate_c_state_entries(void)
|
||||
{
|
||||
acpi_cstate_t *c_state_map;
|
||||
size_t entries;
|
||||
|
||||
c_state_map = soc_get_cstate_map(&entries);
|
||||
|
||||
/* Generate C-state tables */
|
||||
acpigen_write_CST_package(c_state_map, entries);
|
||||
}
|
||||
|
||||
void generate_p_state_entries(int core, int cores_per_package)
|
||||
{
|
||||
int ratio_min, ratio_max, ratio_turbo, ratio_step;
|
||||
int coord_type, power_max, num_entries;
|
||||
int ratio, power, clock, clock_max;
|
||||
|
||||
coord_type = cpu_get_coord_type();
|
||||
ratio_min = cpu_get_min_ratio();
|
||||
ratio_max = cpu_get_max_ratio();
|
||||
clock_max = (ratio_max * cpu_get_bus_clock()) / KHz;
|
||||
|
||||
/* Calculate CPU TDP in mW */
|
||||
power_max = cpu_get_power_max();
|
||||
|
||||
/* Write _PCT indicating use of FFixedHW */
|
||||
acpigen_write_empty_PCT();
|
||||
|
||||
/* Write _PPC with no limit on supported P-state */
|
||||
acpigen_write_PPC_NVS();
|
||||
/* Write PSD indicating configured coordination type */
|
||||
acpigen_write_PSD_package(core, 1, coord_type);
|
||||
|
||||
/* Add P-state entries in _PSS table */
|
||||
acpigen_write_name("_PSS");
|
||||
|
||||
/* Determine ratio points */
|
||||
ratio_step = PSS_RATIO_STEP;
|
||||
num_entries = ((ratio_max - ratio_min) / ratio_step) + 1;
|
||||
if (num_entries > PSS_MAX_ENTRIES) {
|
||||
ratio_step += 1;
|
||||
num_entries = ((ratio_max - ratio_min) / ratio_step) + 1;
|
||||
}
|
||||
|
||||
/* P[T] is Turbo state if enabled */
|
||||
if (get_turbo_state() == TURBO_ENABLED) {
|
||||
/* _PSS package count including Turbo */
|
||||
acpigen_write_package(num_entries + 2);
|
||||
ratio_turbo = cpu_get_max_turbo_ratio();
|
||||
|
||||
/* Add entry for Turbo ratio */
|
||||
acpigen_write_PSS_package(clock_max + 1, /* MHz */
|
||||
power_max, /* mW */
|
||||
PSS_LATENCY_TRANSITION,/* lat1 */
|
||||
PSS_LATENCY_BUSMASTER,/* lat2 */
|
||||
ratio_turbo << 8, /* control */
|
||||
ratio_turbo << 8); /* status */
|
||||
} else {
|
||||
/* _PSS package count without Turbo */
|
||||
acpigen_write_package(num_entries + 1);
|
||||
}
|
||||
|
||||
/* First regular entry is max non-turbo ratio */
|
||||
acpigen_write_PSS_package(clock_max, /* MHz */
|
||||
power_max, /* mW */
|
||||
PSS_LATENCY_TRANSITION,/* lat1 */
|
||||
PSS_LATENCY_BUSMASTER,/* lat2 */
|
||||
ratio_max << 8, /* control */
|
||||
ratio_max << 8); /* status */
|
||||
|
||||
/* Generate the remaining entries */
|
||||
for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
|
||||
ratio >= ratio_min; ratio -= ratio_step) {
|
||||
|
||||
/* Calculate power at this ratio */
|
||||
power = calculate_power(power_max, ratio_max, ratio);
|
||||
clock = (ratio * cpu_get_bus_clock()) / KHz;
|
||||
|
||||
acpigen_write_PSS_package(clock, /* MHz */
|
||||
power, /* mW */
|
||||
PSS_LATENCY_TRANSITION,/* lat1 */
|
||||
PSS_LATENCY_BUSMASTER,/* lat2 */
|
||||
ratio << 8, /* control */
|
||||
ratio << 8); /* status */
|
||||
}
|
||||
/* Fix package length */
|
||||
acpigen_pop_len();
|
||||
}
|
||||
|
||||
static acpi_tstate_t *soc_get_tss_table(int *entries)
|
||||
{
|
||||
*entries = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void generate_t_state_entries(int core, int cores_per_package)
|
||||
{
|
||||
acpi_tstate_t *soc_tss_table;
|
||||
int entries;
|
||||
|
||||
soc_tss_table = soc_get_tss_table(&entries);
|
||||
if (entries == 0)
|
||||
return;
|
||||
|
||||
/* Indicate SW_ALL coordination for T-states */
|
||||
acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
|
||||
|
||||
/* Indicate FixedHW so OS will use MSR */
|
||||
acpigen_write_empty_PTC();
|
||||
|
||||
/* Set NVS controlled T-state limit */
|
||||
acpigen_write_TPC("\\TLVL");
|
||||
|
||||
/* Write TSS table for MSR access */
|
||||
acpigen_write_TSS_package(entries, soc_tss_table);
|
||||
}
|
||||
|
||||
__attribute__ ((weak)) void soc_power_states_generation(int core_id,
|
||||
int cores_per_package)
|
||||
{
|
||||
}
|
||||
|
||||
void generate_cpu_entries(device_t device)
|
||||
{
|
||||
int core_id, cpu_id, pcontrol_blk = ACPI_BASE_ADDRESS;
|
||||
int plen = 6;
|
||||
int totalcores = dev_count_cpu();
|
||||
int cores_per_package = get_cores_per_package();
|
||||
int numcpus = totalcores / cores_per_package;
|
||||
|
||||
printk(BIOS_DEBUG, "Found %d CPU(s) with %d core(s) each.\n",
|
||||
numcpus, cores_per_package);
|
||||
|
||||
for (cpu_id = 0; cpu_id < numcpus; cpu_id++) {
|
||||
for (core_id = 0; core_id < cores_per_package; core_id++) {
|
||||
if (core_id > 0) {
|
||||
pcontrol_blk = 0;
|
||||
plen = 0;
|
||||
}
|
||||
|
||||
/* Generate processor \_PR.CPUx */
|
||||
acpigen_write_processor((cpu_id) * cores_per_package +
|
||||
core_id, pcontrol_blk, plen);
|
||||
|
||||
/* Generate C-state tables */
|
||||
generate_c_state_entries();
|
||||
|
||||
/* Soc specific power states generation */
|
||||
soc_power_states_generation(core_id, cores_per_package);
|
||||
|
||||
acpigen_pop_len();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SOC_INTEL_COMMON_ACPI_WAKE_SOURCE)
|
||||
/* Save wake source data for ACPI _SWS methods in NVS */
|
||||
static void acpi_save_wake_source(void *unused)
|
||||
{
|
||||
global_nvs_t *gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
|
||||
uint32_t pm1, *gpe0;
|
||||
int gpe_reg, gpe_reg_count;
|
||||
int reg_size = sizeof(uint32_t) * 8;
|
||||
|
||||
if (!gnvs)
|
||||
return;
|
||||
|
||||
gnvs->pm1i = -1;
|
||||
gnvs->gpei = -1;
|
||||
|
||||
gpe_reg_count = acpi_fill_wake(&pm1, &gpe0);
|
||||
if (gpe_reg_count < 0)
|
||||
return;
|
||||
|
||||
/* Scan for first set bit in PM1 */
|
||||
for (gnvs->pm1i = 0; gnvs->pm1i < reg_size; gnvs->pm1i++) {
|
||||
if (pm1 & 1)
|
||||
break;
|
||||
pm1 >>= 1;
|
||||
}
|
||||
|
||||
/* If unable to determine then return -1 */
|
||||
if (gnvs->pm1i >= 16)
|
||||
gnvs->pm1i = -1;
|
||||
|
||||
/* Scan for first set bit in GPE registers */
|
||||
for (gpe_reg = 0; gpe_reg < gpe_reg_count; gpe_reg++) {
|
||||
uint32_t gpe = gpe0[gpe_reg];
|
||||
int start = gpe_reg * reg_size;
|
||||
int end = start + reg_size;
|
||||
|
||||
if (gpe == 0) {
|
||||
if (!gnvs->gpei)
|
||||
gnvs->gpei = end;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (gnvs->gpei = start; gnvs->gpei < end; gnvs->gpei++) {
|
||||
if (gpe & 1)
|
||||
break;
|
||||
gpe >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If unable to determine then return -1 */
|
||||
if (gnvs->gpei >= gpe_reg_count * reg_size)
|
||||
gnvs->gpei = -1;
|
||||
|
||||
printk(BIOS_DEBUG, "ACPI _SWS is PM1 Index %lld GPE Index %lld\n",
|
||||
(long long)gnvs->pm1i, (long long)gnvs->gpei);
|
||||
}
|
||||
|
||||
BOOT_STATE_INIT_ENTRY(BS_OS_RESUME, BS_ON_ENTRY, acpi_save_wake_source, NULL);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef SOC_INTEL_COMMON_BLOCK_ACPI_H
|
||||
#define SOC_INTEL_COMMON_BLOCK_ACPI_H
|
||||
|
||||
#include <arch/acpi.h>
|
||||
#include <device/device.h>
|
||||
#include <intelblocks/cpulib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Forward declare the power state struct here */
|
||||
struct chipset_power_state;
|
||||
|
||||
/* Forward declare the global nvs structure here */
|
||||
struct global_nvs_t;
|
||||
|
||||
/* Read the scis from soc specific register. Returns int scis value */
|
||||
uint32_t soc_read_sci_irq_select(void);
|
||||
|
||||
/*
|
||||
* Calls acpi_write_hpet which creates and fills HPET table and
|
||||
* adds it to the RSDT (and XSDT) structure.
|
||||
*/
|
||||
unsigned long southbridge_write_acpi_tables(device_t device,
|
||||
unsigned long current,
|
||||
struct acpi_rsdp *rsdp);
|
||||
|
||||
/*
|
||||
* Craetes acpi gnvs and adds it to the DSDT table.
|
||||
* GNVS creation is chipset specific and is done in soc specific acpi.c file.
|
||||
*/
|
||||
void southbridge_inject_dsdt(device_t device);
|
||||
|
||||
/*
|
||||
* This function populates the gnvs structure in acpi table.
|
||||
* Defined as weak in common acpi as gnvs structure definition is
|
||||
* chipset specific.
|
||||
*/
|
||||
void acpi_create_gnvs(struct global_nvs_t *gnvs);
|
||||
|
||||
/*
|
||||
* get_cstate_map returns a table of processor specific acpi_cstate_t entries
|
||||
* and number of entries in the table
|
||||
*/
|
||||
acpi_cstate_t *soc_get_cstate_map(size_t *num_entries);
|
||||
|
||||
/*
|
||||
* Chipset specific quirks for the wake enable bits.
|
||||
* Returns wake events for the soc.
|
||||
*/
|
||||
uint32_t acpi_fill_soc_wake(uint32_t generic_pm1_en,
|
||||
const struct chipset_power_state *ps);
|
||||
|
||||
/* Chipset specific settings for filling up fadt table */
|
||||
void soc_fill_fadt(acpi_fadt_t *fadt);
|
||||
|
||||
/* Return the polarity flag for SCI IRQ */
|
||||
int soc_madt_sci_irq_polarity(int sci);
|
||||
|
||||
/* Generate P-state tables */
|
||||
void generate_p_state_entries(int core, int cores_per_package);
|
||||
|
||||
/* Generate T-state tables */
|
||||
void generate_t_state_entries(int core, int cores_per_package);
|
||||
|
||||
/*
|
||||
* soc specific power states generation. We need this to be defined by soc
|
||||
* as the state generations varies in chipsets e.g. APL generates T and P
|
||||
* states while SKL generates * P state only depening on a devicetree config
|
||||
*/
|
||||
void soc_power_states_generation(int core_id, int cores_per_package);
|
||||
|
||||
#endif /* _SOC_INTEL_COMMON_BLOCK_ACPI_H_ */
|
|
@ -17,8 +17,8 @@
|
|||
#include <device/device.h>
|
||||
#include <device/pci.h>
|
||||
#include <device/pci_ids.h>
|
||||
#include <intelblocks/acpi.h>
|
||||
#include <intelblocks/lpc_lib.h>
|
||||
#include <soc/acpi.h>
|
||||
#include <soc/pm.h>
|
||||
|
||||
/* Common weak definition, needs to be implemented in each soc LPC driver. */
|
||||
|
|
|
@ -17,14 +17,9 @@
|
|||
|
||||
#include <arch/hlt.h>
|
||||
#include <arch/io.h>
|
||||
#include <cpu/intel/reset.h>
|
||||
#include <reset.h>
|
||||
|
||||
/* Reset control port */
|
||||
#define RST_CNT 0xcf9
|
||||
#define FULL_RST (1 << 3)
|
||||
#define RST_CPU (1 << 2)
|
||||
#define SYS_RST (1 << 1)
|
||||
|
||||
#if IS_ENABLED(CONFIG_HAVE_HARD_RESET)
|
||||
void do_hard_reset(void)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue