diff options
-rw-r--r-- | src/soc/intel/apollolake/chip.c | 79 | ||||
-rw-r--r-- | src/soc/intel/apollolake/chip.h | 3 | ||||
-rw-r--r-- | src/soc/intel/apollolake/include/soc/cpu.h | 14 |
3 files changed, 79 insertions, 17 deletions
diff --git a/src/soc/intel/apollolake/chip.c b/src/soc/intel/apollolake/chip.c index eeac6cee5e..181d4d68bc 100644 --- a/src/soc/intel/apollolake/chip.c +++ b/src/soc/intel/apollolake/chip.c @@ -193,22 +193,67 @@ static void pcie_override_devicetree_after_silicon_init(void) pcie_update_device_tree(PCIEB0_DEVFN, 2); } -static void rapl_update(void) +/* Configure package power limits */ +static void set_power_limits(void) { - uint32_t *rapl_reg; - uint32_t val; - const uint32_t power_mw = 15000; - - rapl_reg = (void*)(uintptr_t) (MCH_BASE_ADDR + MCHBAR_RAPL_PPL); - - /* Due to an incorrect value set for the power limit PL1 as 6W in RAPL - * MMIO register from FSP code, the system is not able to leverage full - * TDP capacity. This RAPL MMIO register is a physically separate - * instance from RAPL MSR register. Punit algorithm controls to the - * minimum power limit PL1 mentioned in the RAPL MMIO and MSR registers. - * Here, setting RAPL PL1 in Bits[14:0] to 15W in RAPL MMIO register. */ - val = (power_mw << (rdmsr(MSR_PKG_POWER_SKU_UNIT).lo & 0xf)) / 1000; - write32(rapl_reg, (read32(rapl_reg) & ~0x7fff) | val); + static struct soc_intel_apollolake_config *cfg; + struct device *dev = NB_DEV_ROOT; + msr_t rapl_msr_reg, limit; + uint32_t power_unit; + uint32_t tdp, min_power, max_power; + uint32_t *rapl_mmio_reg; + + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + return; + } + + cfg = dev->chip_info; + + /* 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; + + if (min_power > 0 && tdp < min_power) + tdp = min_power; + + if (max_power > 0 && tdp > max_power) + tdp = max_power; + + /* Set PL1 override value */ + tdp = (cfg->tdp_pl1_override_mw == 0) ? + tdp : (cfg->tdp_pl1_override_mw * power_unit) / 1000; + + /* Set long term power limit to TDP */ + limit.lo = tdp & PKG_POWER_LIMIT_MASK; + /* PL2 is invalid for small core */ + limit.hi = 0x0; + + /* Set PL1 Pkg Power clamp bit */ + limit.lo |= PKG_POWER_LIMIT_CLAMP; + + limit.lo |= PKG_POWER_LIMIT_EN; + limit.lo |= (MB_POWER_LIMIT1_TIME_DEFAULT & + PKG_POWER_LIMIT_TIME_MASK) << PKG_POWER_LIMIT_TIME_SHIFT; + + /* Program package power limits in RAPL MSR */ + wrmsr(MSR_PKG_POWER_LIMIT, limit); + printk(BIOS_INFO, "RAPL PL1 %d.%dW\n", tdp / power_unit, + 100 * (tdp % power_unit) / power_unit); + + /* Get the MMIO address */ + rapl_mmio_reg = (void *)(uintptr_t) (MCH_BASE_ADDR + MCHBAR_RAPL_PPL); + /* + * Disable RAPL MMIO PL1 Power limits because RAPL uses MSR value. + * PL2 (limit.hi) is invalid for small cores + */ + write32(rapl_mmio_reg, limit.lo & ~(PKG_POWER_LIMIT_EN)); } static void soc_init(void *data) @@ -241,8 +286,8 @@ static void soc_init(void *data) /* Allocate ACPI NVS in CBMEM */ gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs)); - /* Update RAPL package power limit */ - rapl_update(); + /* Set RAPL MSR for Package power limits*/ + set_power_limits(); } static void soc_final(void *data) diff --git a/src/soc/intel/apollolake/chip.h b/src/soc/intel/apollolake/chip.h index 74a6411b50..6c3bcd8cad 100644 --- a/src/soc/intel/apollolake/chip.h +++ b/src/soc/intel/apollolake/chip.h @@ -107,6 +107,9 @@ struct soc_intel_apollolake_config { /* Enable DPTF support */ int dptf_enable; + /* PL1 override value in mW for APL */ + uint16_t tdp_pl1_override_mw; + /* Configure Audio clk gate and power gate * IOSF-SB port ID 92 offset 0x530 [5] and [3] */ diff --git a/src/soc/intel/apollolake/include/soc/cpu.h b/src/soc/intel/apollolake/include/soc/cpu.h index 22412aff2d..bffe4bcd8d 100644 --- a/src/soc/intel/apollolake/include/soc/cpu.h +++ b/src/soc/intel/apollolake/include/soc/cpu.h @@ -39,6 +39,20 @@ 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, RAPL default PL1 time window value set to 28 seconds. + * RAPL time window calculation defined as follows: + * Time Window = (float)((1+X/4)*(2*^Y), X Corresponds to [23:22], + * Y to [21:17] in MSR 0x610. 28 sec is equal to 0x6e. + */ +#define MB_POWER_LIMIT1_TIME_DEFAULT 0x6e #define MSR_L2_QOS_MASK(reg) (0xd10 + reg) #define MSR_IA32_PQR_ASSOC 0xc8f |