Sumeet R Pawnikar (sumeet.r.pawnikar@intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16884
-gerrit
commit 9793ad37963a23fb013bca4841a2c6b5b5bb7914 Author: Sumeet Pawnikar sumeet.r.pawnikar@intel.com Date: Tue Sep 27 23:18:35 2016 +0530
soc/intel/apollolake: Set package power limits for RAPL registers
This patch sets the package power limit values in RAPL MSR and MMIO registers after boot and suspend-resume cycle.
BUG=chrome-os-partner:56922 TEST=Built, booted and tested these package power limits before and after boot and suspend-resume cycle.
Change-Id: I34208048a6d4a127e9b1267d2df043cb2c46cf77 Signed-off-by: Sumeet Pawnikar sumeet.r.pawnikar@intel.com --- src/soc/intel/apollolake/chip.c | 130 +++++++++++++++++++++++++++++ src/soc/intel/apollolake/include/soc/cpu.h | 9 ++ 2 files changed, 139 insertions(+)
diff --git a/src/soc/intel/apollolake/chip.c b/src/soc/intel/apollolake/chip.c index eeac6ce..1928433 100644 --- a/src/soc/intel/apollolake/chip.c +++ b/src/soc/intel/apollolake/chip.c @@ -38,6 +38,39 @@
#include "chip.h"
+#define MAX_NUM_ENTRY (sizeof lookup_table / sizeof lookup_table[0]) + +static const struct { + uint8_t time; + uint8_t msr_val; +} lookup_table[] = { + {0, 0}, + {1, 0x0a}, + {2, 0x0b}, + {3, 0x4b}, + {4, 0x0c}, + {5, 0x2c}, + {6, 0x4c}, + {7, 0x6c}, + {8, 0x0d}, + {10, 0x2d}, + {12, 0x4d}, + {14, 0x6d}, + {16, 0x0e}, + {20, 0x2e}, + {24, 0x4e}, + {28, 0x6e}, + {32, 0x0f}, + {40, 0x2f}, + {48, 0x4f}, + {56, 0x6f}, + {64, 0x10}, + {80, 0x30}, + {96, 0x50}, + {112, 0x70}, + {128, 0x11} +}; + static void *vbt; static struct region_device vbt_rdev;
@@ -193,6 +226,100 @@ static void pcie_override_devicetree_after_silicon_init(void) pcie_update_device_tree(PCIEB0_DEVFN, 2); }
+static uint8_t find_lookup_time(u8 in_msr) +{ + uint8_t index = 0; + + while (in_msr != lookup_table[index].msr_val && index < MAX_NUM_ENTRY) + index++; + + /* + * If some value is not part of this lookup table, + * assinging the default time value for PL1. + */ + if (index >= MAX_NUM_ENTRY) + return MB_POWER_LIMIT1_TIME_DEFAULT; + + return lookup_table[index].time; +} + +static uint8_t find_lookup_msr(u8 in_time) +{ + uint8_t index = 0; + + while (in_time != lookup_table[index].time && index < MAX_NUM_ENTRY) + index++; + + /* + * If some value is not part of this lookup table, + * assinging the default time value for PL1. + */ + if (index >= MAX_NUM_ENTRY) + return find_lookup_msr(MB_POWER_LIMIT1_TIME_DEFAULT); + + return lookup_table[index].msr_val; +} + +/* Configure package power limits */ +static void set_power_limits(u8 power_limit_1_time) +{ + uint32_t *rapl_mmio_reg; + msr_t rapl_msr_reg, limit; + unsigned power_unit; + unsigned tdp, min_power, max_power, max_time; + uint8_t power_limit_1_val; + + rapl_mmio_reg = (void*)(uintptr_t) (MCH_BASE_ADDR + MCHBAR_RAPL_PPL); + + if (power_limit_1_time > MAX_NUM_ENTRY) + power_limit_1_time = MB_POWER_LIMIT1_TIME_DEFAULT; + + /* Get units */ + rapl_msr_reg = rdmsr(MSR_PKG_POWER_SKU_UNIT); + power_unit = 1 << (rapl_msr_reg.lo & 0xf); + + /* Get power defaults for this SKU */ + rapl_msr_reg = rdmsr(MSR_PKG_POWER_SKU); + tdp = rapl_msr_reg.lo & PKG_POWER_LIMIT_MASK; + min_power = (rapl_msr_reg.lo >> 16) & PKG_POWER_LIMIT_MASK; + max_power = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK; + max_time = (rapl_msr_reg.hi >> 16) & 0x7f; + + printk(BIOS_DEBUG, "CPU TDP: %u Watts\n", tdp / power_unit); + + if (find_lookup_time(max_time) > power_limit_1_time) + power_limit_1_time = find_lookup_time(max_time); + + if (min_power > 0 && tdp < min_power) + tdp = min_power; + + if (max_power > 0 && tdp > max_power) + tdp = max_power; + + power_limit_1_val = find_lookup_msr(power_limit_1_time); + + /* Set long term power limit to TDP */ + limit.lo = tdp & PKG_POWER_LIMIT_MASK; + + /* Set PL1 Pkg Power clamp bit */ + limit.lo |= PKG_POWER_LIMIT_CLAMP; + + limit.lo |= PKG_POWER_LIMIT_EN; + limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << + PKG_POWER_LIMIT_TIME_SHIFT; + + /* Set short term power limit PL2 to 15W */ + limit.hi = 0xf00 & PKG_POWER_LIMIT_MASK; + limit.hi |= PKG_POWER_LIMIT_EN; + + /* Program package power limits in RAPL MSR */ + wrmsr(MSR_PKG_POWER_LIMIT, limit); + + /* Setting RAPL MMIO register for Power limits */ + write32(rapl_mmio_reg, limit.lo & ~(PKG_POWER_LIMIT_EN)); + write32(rapl_mmio_reg + 1, limit.hi); +} + static void rapl_update(void) { uint32_t *rapl_reg; @@ -241,6 +368,9 @@ static void soc_init(void *data) /* Allocate ACPI NVS in CBMEM */ gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
+ /* Set RAPL MSR for Package power limits*/ + set_power_limits(MB_POWER_LIMIT1_TIME_DEFAULT); + /* Update RAPL package power limit */ rapl_update(); } diff --git a/src/soc/intel/apollolake/include/soc/cpu.h b/src/soc/intel/apollolake/include/soc/cpu.h index 22412af..0195249 100644 --- a/src/soc/intel/apollolake/include/soc/cpu.h +++ b/src/soc/intel/apollolake/include/soc/cpu.h @@ -39,6 +39,15 @@ void apollolake_init_cpus(struct device *dev); #define PREFETCH_L2_DISABLE (1 << 2)
#define MSR_PKG_POWER_SKU_UNIT 0x606 +#define MSR_PKG_POWER_SKU 0x614 +#define MSR_PKG_POWER_LIMIT 0x610 +#define PKG_POWER_LIMIT_MASK (0x7fff) +#define PKG_POWER_LIMIT_EN (1 << 15) +#define PKG_POWER_LIMIT_CLAMP (1 << 16) +#define PKG_POWER_LIMIT_TIME_SHIFT 17 +#define PKG_POWER_LIMIT_TIME_MASK (0x7f) +/* For Mobile, default PL1 time window value is 28 seconds */ +#define MB_POWER_LIMIT1_TIME_DEFAULT 28
#define MSR_L2_QOS_MASK(reg) (0xd10 + reg) #define MSR_IA32_PQR_ASSOC 0xc8f