soc/intel/apollolake: Set PL1 limits for RAPL MSR registers

This patch sets the package power limit (PL1) value in RAPL MSR
and disables MMIO register. Added configurable PL1 override
parameter to leverage full TDP capacity.

BUG=chrome-os-partner:56922
TEST=webGL performance(fps) not impacted before and after S3.

Change-Id: I34208048a6d4a127e9b1267d2df043cb2c46cf77
Signed-off-by: Sumeet Pawnikar <sumeet.r.pawnikar@intel.com>
Signed-off-by: Venkateswarlu Vinjamuri <venkateswarlu.v.vinjamuri@intel.com>
Reviewed-on: https://review.coreboot.org/16884
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/src/soc/intel/apollolake/chip.c b/src/soc/intel/apollolake/chip.c
index eeac6ce..181d4d6 100644
--- a/src/soc/intel/apollolake/chip.c
+++ b/src/soc/intel/apollolake/chip.c
@@ -193,22 +193,67 @@
 	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;
+	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;
 
-	rapl_reg = (void*)(uintptr_t) (MCH_BASE_ADDR + MCHBAR_RAPL_PPL);
+	if (!dev || !dev->chip_info) {
+		printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n");
+		return;
+	}
 
-	/* 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);
+	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 @@
 	/* 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 74a6411..6c3bcd8 100644
--- a/src/soc/intel/apollolake/chip.h
+++ b/src/soc/intel/apollolake/chip.h
@@ -107,6 +107,9 @@
 	/* 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 22412af..bffe4bc 100644
--- a/src/soc/intel/apollolake/include/soc/cpu.h
+++ b/src/soc/intel/apollolake/include/soc/cpu.h
@@ -39,6 +39,20 @@
 #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