diff options
author | Duncan Laurie <dlaurie@chromium.org> | 2013-11-05 13:02:30 -0800 |
---|---|---|
committer | Aaron Durbin <adurbin@google.com> | 2014-05-06 18:39:04 +0200 |
commit | 8923be58b87cbf55f5765eca6ce29d7b6827be97 (patch) | |
tree | cdccd705ca0ab88a93a69b6dfa49845e008c0deb /src/soc/intel | |
parent | 6aa9f1f0eb97e315ab4db8e6da1d13db7ee7858f (diff) | |
download | coreboot-8923be58b87cbf55f5765eca6ce29d7b6827be97.tar.xz |
baytrail: Add ACPI CPU entries
- C-state table based on static config
MWAIT values are from ref code for non-S0ix config
C6 substate 8 is ignored by the kernel as it violates the CPUID
but it is left in as the other substate may not work.
- P-state table generated with proper ratio and VID values
relies on having the package power msr set to magic value
as the power-on default is wrong
- T-state table uses static table
BUG=chrome-os-partner:23505
BRANCH=rambi
TEST=build and boot on rambi
Change-Id: I7c997e58cb3a71d0ec413b17f0c5467bef4bf62c
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/175742
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Commit-Queue: Aaron Durbin <adurbin@chromium.org>
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/4954
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Diffstat (limited to 'src/soc/intel')
-rw-r--r-- | src/soc/intel/baytrail/acpi.c | 245 | ||||
-rw-r--r-- | src/soc/intel/baytrail/acpi/globalnvs.asl | 1 | ||||
-rw-r--r-- | src/soc/intel/baytrail/baytrail/nvs.h | 3 | ||||
-rw-r--r-- | src/soc/intel/baytrail/placeholders.c | 2 |
4 files changed, 248 insertions, 3 deletions
diff --git a/src/soc/intel/baytrail/acpi.c b/src/soc/intel/baytrail/acpi.c index ce7f5e45e6..1f358f4579 100644 --- a/src/soc/intel/baytrail/acpi.c +++ b/src/soc/intel/baytrail/acpi.c @@ -24,14 +24,56 @@ #include <arch/smp/mpspec.h> #include <console/console.h> #include <cpu/x86/smm.h> +#include <console/console.h> #include <types.h> #include <string.h> +#include <arch/cpu.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/tsc.h> +#include <cpu/intel/turbo.h> #include <baytrail/acpi.h> #include <baytrail/iomap.h> #include <baytrail/irq.h> +#include <baytrail/msr.h> +#include <baytrail/pattrs.h> #include <baytrail/pmc.h> +#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, \ + } + +/* C-state map without S0ix */ +static acpi_cstate_t cstate_map[] = { + { + /* C1 */ + .ctype = 1, /* ACPI C1 */ + .latency = 1, + .power = 1000, + .resource = MWAIT_RES(0, 0), + }, + { + /* C6NS with no L2 shrink */ + /* NOTE: this substate is above CPUID limit */ + .ctype = 2, /* ACPI C2 */ + .latency = 500, + .power = 10, + .resource = MWAIT_RES(5, 8), + }, + { + /* C6FS with full L2 shrink */ + .ctype = 3, /* ACPI C3 */ + .latency = 1500, /* 1.5ms worst case */ + .power = 10, + .resource = MWAIT_RES(5, 2), + } +}; + static int acpi_sci_irq(void) { const unsigned long actl = ILB_BASE_ADDRESS + ACTL; @@ -210,7 +252,210 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt) fadt->x_gpe1_blk.resv = 0; fadt->x_gpe1_blk.addrl = 0x0; fadt->x_gpe1_blk.addrh = 0x0; +} + +static acpi_tstate_t baytrail_tss_table[] = { + { 100, 1000, 0, 0x00, 0 }, + { 88, 875, 0, 0x1e, 0 }, + { 75, 750, 0, 0x1c, 0 }, + { 63, 625, 0, 0x1a, 0 }, + { 50, 500, 0, 0x18, 0 }, + { 38, 375, 0, 0x16, 0 }, + { 25, 250, 0, 0x14, 0 }, + { 13, 125, 0, 0x12, 0 }, +}; + +static int generate_T_state_entries(int core, int cores_per_package) +{ + int len; + + /* Indicate SW_ALL coordination for T-states */ + len = acpigen_write_TSD_package(core, cores_per_package, SW_ALL); + + /* Indicate FFixedHW so OS will use MSR */ + len += acpigen_write_empty_PTC(); + + /* Set NVS controlled T-state limit */ + len += acpigen_write_TPC("\\TLVL"); + + /* Write TSS table for MSR access */ + len += acpigen_write_TSS_package( + ARRAY_SIZE(baytrail_tss_table), baytrail_tss_table); + + return 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 (int)power; +} + +static int generate_P_state_entries(int core, int cores_per_package) +{ + int len, len_pss; + int ratio_min, ratio_max, ratio_turbo, ratio_step, ratio_range_2; + int coord_type, power_max, power_unit, num_entries; + int ratio, power, clock, clock_max; + int vid, vid_turbo, vid_min, vid_max, vid_range_2; + u32 control_status; + const struct pattrs *pattrs = pattrs_get(); + msr_t msr; + + /* Inputs from CPU attributes */ + ratio_max = pattrs->iacore_ratios[IACORE_MAX]; + ratio_min = pattrs->iacore_ratios[IACORE_LFM]; + vid_max = pattrs->iacore_vids[IACORE_MAX]; + vid_min = pattrs->iacore_vids[IACORE_LFM]; + + /* Hardware coordination of P-states */ + coord_type = HW_ALL; + + /* Max Non-Turbo Frequency */ + clock_max = (ratio_max * pattrs->bclk_khz) / 1000; + + /* Calculate CPU TDP in mW */ + msr = rdmsr(MSR_PKG_POWER_SKU_UNIT); + power_unit = 1 << (msr.lo & 0xf); + msr = rdmsr(MSR_PKG_POWER_LIMIT); + power_max = ((msr.lo & 0x7fff) / power_unit) * 1000; + + /* Write _PCT indicating use of FFixedHW */ + len = acpigen_write_empty_PCT(); + + /* Write _PPC with no limit on supported P-state */ + len += acpigen_write_PPC(0); + + /* Write PSD indicating configured coordination type */ + len += acpigen_write_PSD_package(core, 1, coord_type); + + /* Add P-state entries in _PSS table */ + len += acpigen_write_name("_PSS"); + + /* Determine ratio points */ + ratio_step = 1; + num_entries = (ratio_max - ratio_min) / ratio_step; + while (num_entries > 15) { /* ACPI max is 15 ratios */ + ratio_step <<= 1; + num_entries >>= 1; + } + + /* P[T] is Turbo state if enabled */ + if (get_turbo_state() == TURBO_ENABLED) { + /* _PSS package count including Turbo */ + len_pss = acpigen_write_package(num_entries + 2); + + ratio_turbo = pattrs->iacore_ratios[IACORE_TURBO]; + vid_turbo = pattrs->iacore_vids[IACORE_TURBO]; + control_status = (ratio_turbo << 8) | vid_turbo; + + /* Add entry for Turbo ratio */ + len_pss += acpigen_write_PSS_package( + clock_max + 1, /*MHz*/ + power_max, /*mW*/ + 10, /*lat1*/ + 10, /*lat2*/ + control_status, /*control*/ + control_status); /*status*/ + } else { + /* _PSS package count without Turbo */ + len_pss = acpigen_write_package(num_entries + 1); + ratio_turbo = ratio_max; + vid_turbo = vid_max; + } + + /* First regular entry is max non-turbo ratio */ + control_status = (ratio_max << 8) | vid_max; + len_pss += acpigen_write_PSS_package( + clock_max, /*MHz*/ + power_max, /*mW*/ + 10, /*lat1*/ + 10, /*lat2*/ + control_status, /*control */ + control_status); /*status*/ + + /* Set up ratio and vid ranges for VID calculation */ + ratio_range_2 = (ratio_turbo - ratio_min) * 2; + vid_range_2 = (vid_turbo - vid_min) * 2; + + /* Generate the remaining entries */ + for (ratio = ratio_min + ((num_entries - 1) * ratio_step); + ratio >= ratio_min; ratio -= ratio_step) { + + /* Calculate VID for this ratio */ + vid = ((ratio - ratio_min) * vid_range_2) / + ratio_range_2 + vid_min; + /* Round up if remainder */ + if (((ratio - ratio_min) * vid_range_2) % ratio_range_2) + vid++; + + /* Calculate power at this ratio */ + power = calculate_power(power_max, ratio_max, ratio); + clock = (ratio * pattrs->bclk_khz) / 1000; + control_status = (ratio << 8) | (vid & 0xff); + + len_pss += acpigen_write_PSS_package( + clock, /*MHz*/ + power, /*mW*/ + 10, /*lat1*/ + 10, /*lat2*/ + control_status, /*control*/ + control_status); /*status*/ + } + + /* Fix package length */ + len_pss--; + acpigen_patch_len(len_pss); + + return len + len_pss; +} + +void generate_cpu_entries(void) +{ + int len_pr, core; + int pcontrol_blk = get_pmbase(), plen = 6; + const struct pattrs *pattrs = pattrs_get(); + + for (core=0; core<pattrs->num_cpus; core++) { + if (core > 0) { + pcontrol_blk = 0; + plen = 0; + } + + /* Generate processor \_PR.CPUx */ + len_pr = acpigen_write_processor( + core, pcontrol_blk, plen); + + /* Generate P-state tables */ + len_pr += generate_P_state_entries( + core, pattrs->num_cpus); + + /* Generate C-state tables */ + len_pr += acpigen_write_CST_package( + cstate_map, ARRAY_SIZE(cstate_map)); + + /* Generate T-state tables */ + len_pr += generate_T_state_entries( + core, pattrs->num_cpus); + + len_pr--; + acpigen_patch_len(len_pr); + } } unsigned long acpi_madt_irq_overrides(unsigned long current) diff --git a/src/soc/intel/baytrail/acpi/globalnvs.asl b/src/soc/intel/baytrail/acpi/globalnvs.asl index 37a234c485..2f614a9806 100644 --- a/src/soc/intel/baytrail/acpi/globalnvs.asl +++ b/src/soc/intel/baytrail/acpi/globalnvs.asl @@ -50,6 +50,7 @@ Field (GNVS, ByteAcc, NoLock, Preserve) PWRS, 8, // 0x10 - Power State (AC = 1) PCNT, 8, // 0x11 - Processor count TPMP, 8, // 0x12 - TPM Present and Enabled + TLVL, 8, // 0x13 - Throttle Level /* Device Config */ Offset (0x20), diff --git a/src/soc/intel/baytrail/baytrail/nvs.h b/src/soc/intel/baytrail/baytrail/nvs.h index e261e7cefc..aed0974541 100644 --- a/src/soc/intel/baytrail/baytrail/nvs.h +++ b/src/soc/intel/baytrail/baytrail/nvs.h @@ -36,7 +36,8 @@ typedef struct { u8 pwrs; /* 0x10 - Power state (AC = 1) */ u8 pcnt; /* 0x11 - Processor Count */ u8 tpmp; /* 0x12 - TPM Present and Enabled */ - u8 rsvd1[13]; + u8 tlvl; /* 0x13 - Throttle Level */ + u8 rsvd1[12]; /* Device Config */ u8 s5u0; /* 0x20 - Enable USB0 in S5 */ diff --git a/src/soc/intel/baytrail/placeholders.c b/src/soc/intel/baytrail/placeholders.c index b10b7e69f8..9e1413da94 100644 --- a/src/soc/intel/baytrail/placeholders.c +++ b/src/soc/intel/baytrail/placeholders.c @@ -5,8 +5,6 @@ #include <baytrail/acpi.h> -void generate_cpu_entries(void) {} - void smm_init(void) {} /* Rmodules don't like weak symbols. */ |