diff --git a/src/soc/intel/apollolake/include/soc/acpi.h b/src/include/cpu/intel/reset.h similarity index 59% rename from src/soc/intel/apollolake/include/soc/acpi.h rename to src/include/cpu/intel/reset.h index ba3b8fc9b5..9cf6168a7c 100644 --- a/src/soc/intel/apollolake/include/soc/acpi.h +++ b/src/include/cpu/intel/reset.h @@ -1,8 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2016 Intel Corp. - * (Written by Lance Zhao 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 +/* 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 */ diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index a3b458d489..29483f4985 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -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 diff --git a/src/soc/intel/apollolake/acpi.c b/src/soc/intel/apollolake/acpi.c index 1826b48458..e4846e4d05 100644 --- a/src/soc/intel/apollolake/acpi.c +++ b/src/soc/intel/apollolake/acpi.c @@ -17,20 +17,20 @@ #include #include +#include #include #include #include #include #include -#include -#include +#include +#include +#include #include #include #include #include #include -#include -#include #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); diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h index 3be39554ed..37e4cedc3e 100644 --- a/src/soc/intel/apollolake/include/soc/pm.h +++ b/src/soc/intel/apollolake/include/soc/pm.h @@ -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; diff --git a/src/soc/intel/common/Makefile.inc b/src/soc/intel/common/Makefile.inc index cd942580a6..450473006f 100644 --- a/src/soc/intel/common/Makefile.inc +++ b/src/soc/intel/common/Makefile.inc @@ -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 diff --git a/src/soc/intel/common/acpi.h b/src/soc/intel/common/acpi.h index 19ab92666b..4547204894 100644 --- a/src/soc/intel/common/acpi.h +++ b/src/soc/intel/common/acpi.h @@ -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 diff --git a/src/soc/intel/common/acpi/acpi.c b/src/soc/intel/common/acpi/acpi.c deleted file mode 100644 index 0934dbd2ae..0000000000 --- a/src/soc/intel/common/acpi/acpi.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include - -#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(); - } - } -} diff --git a/src/soc/intel/common/block/acpi/Kconfig b/src/soc/intel/common/block/acpi/Kconfig new file mode 100644 index 0000000000..ff59172f3b --- /dev/null +++ b/src/soc/intel/common/block/acpi/Kconfig @@ -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 diff --git a/src/soc/intel/common/block/acpi/Makefile.inc b/src/soc/intel/common/block/acpi/Makefile.inc new file mode 100644 index 0000000000..c6bdac5d3e --- /dev/null +++ b/src/soc/intel/common/block/acpi/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI) += acpi.c diff --git a/src/soc/intel/common/block/acpi/acpi.c b/src/soc/intel/common/block/acpi/acpi.c new file mode 100644 index 0000000000..e216f2e001 --- /dev/null +++ b/src/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 diff --git a/src/soc/intel/common/block/include/intelblocks/acpi.h b/src/soc/intel/common/block/include/intelblocks/acpi.h new file mode 100644 index 0000000000..010773b52a --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/acpi.h @@ -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 +#include +#include +#include + +/* 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_ */ diff --git a/src/soc/intel/common/block/lpc/lpc.c b/src/soc/intel/common/block/lpc/lpc.c index 0559d95399..1c4e2ce785 100644 --- a/src/soc/intel/common/block/lpc/lpc.c +++ b/src/soc/intel/common/block/lpc/lpc.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include /* Common weak definition, needs to be implemented in each soc LPC driver. */ diff --git a/src/soc/intel/common/reset.c b/src/soc/intel/common/reset.c index 06a534ce99..bdd7d9198e 100644 --- a/src/soc/intel/common/reset.c +++ b/src/soc/intel/common/reset.c @@ -17,14 +17,9 @@ #include #include +#include #include -/* 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) {