| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright 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. |
| * |
| * 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 <device/pci_ids.h> |
| #include <device/pci_ops.h> |
| #include <fsp/api.h> |
| #include <soc/ramstage.h> |
| #include <soc/vr_config.h> |
| #include <console/console.h> |
| #include <intelblocks/cpulib.h> |
| |
| /* Default values for domain configuration. PSI3 and PSI4 are disabled. */ |
| static const struct vr_config default_configs[NUM_VR_DOMAINS] = { |
| [VR_SYSTEM_AGENT] = { |
| .vr_config_enable = 1, |
| .psi1threshold = VR_CFG_AMP(20), |
| .psi2threshold = VR_CFG_AMP(4), |
| .psi3threshold = VR_CFG_AMP(1), |
| .psi3enable = 0, |
| .psi4enable = 0, |
| .imon_slope = 0, |
| .imon_offset = 0, |
| .icc_max = 0, |
| .voltage_limit = 1520, |
| }, |
| [VR_IA_CORE] = { |
| .vr_config_enable = 1, |
| .psi1threshold = VR_CFG_AMP(20), |
| .psi2threshold = VR_CFG_AMP(5), |
| .psi3threshold = VR_CFG_AMP(1), |
| .psi3enable = 0, |
| .psi4enable = 0, |
| .imon_slope = 0, |
| .imon_offset = 0, |
| .icc_max = 0, |
| .voltage_limit = 1520, |
| }, |
| [VR_GT_UNSLICED] = { |
| .vr_config_enable = 1, |
| .psi1threshold = VR_CFG_AMP(20), |
| .psi2threshold = VR_CFG_AMP(5), |
| .psi3threshold = VR_CFG_AMP(1), |
| .psi3enable = 0, |
| .psi4enable = 0, |
| .imon_slope = 0, |
| .imon_offset = 0, |
| .icc_max = 0, |
| .voltage_limit = 1520, |
| }, |
| [VR_GT_SLICED] = { |
| .vr_config_enable = 1, |
| .psi1threshold = VR_CFG_AMP(20), |
| .psi2threshold = VR_CFG_AMP(5), |
| .psi3threshold = VR_CFG_AMP(1), |
| .psi3enable = 0, |
| .psi4enable = 0, |
| .imon_slope = 0, |
| .imon_offset = 0, |
| .icc_max = 0, |
| .voltage_limit = 1520, |
| }, |
| }; |
| |
| static uint16_t get_sku_icc_max(int domain) |
| { |
| const uint16_t tdp = cpu_get_power_max(); |
| |
| static uint16_t mch_id = 0, igd_id = 0; |
| if (!mch_id) { |
| struct device *dev = pcidev_path_on_root(SA_DEVFN_ROOT); |
| mch_id = dev ? pci_read_config16(dev, PCI_DEVICE_ID) : 0xffff; |
| } |
| if (!igd_id) { |
| struct device *dev = pcidev_path_on_root(SA_DEVFN_IGD); |
| igd_id = dev ? pci_read_config16(dev, PCI_DEVICE_ID) : 0xffff; |
| } |
| |
| /* |
| * Iccmax table from Doc #559100 Section 7.2 DC Specifications, the |
| * Iccmax is the same among KBL-Y but KBL-U/R. |
| * Addendum for AML-Y #594883, IccMax for IA core is 28A. |
| * KBL-S #335195, KBL-H #335190, SKL-S #332687, SKL-H #332986, |
| * SKL-U/Y #332990 |
| * |
| * Platform Segment SA IA GT (GT/GTx) |
| * --------------------------------------------------------------------- |
| * KBL/SKL-S (95W) quad 11.1 100 45 |
| * SKL-S (80W) quad 11.1 82 45 |
| * KBL/SKL-S (65W) quad 11.1 79 45 |
| * SKL-S (45W) quad 11.1 70 0 |
| * KBL/SKL-S (35W) quad 11.1 66 35 |
| * SKL-S (25W) quad 11.1 55 35 |
| * |
| * KBL/SKL-S (54W) dual 11.1 58 48 |
| * KBL/SKL-S (51W) dual 11.1 45 48 |
| * KBL/SKL-S (35W) dual 11.1 40 48 |
| * |
| * SKL-H + OPC (65W) GT4 quad 8 74 105/24 |
| * SKL-H + OPC (45W) GT4 quad 8 74 94/20 |
| * SKL-H + OPC (35W) GT4 quad 8 66 94/20 |
| * |
| * SKL-H (35W) GT2 dual 11.1 60 55 |
| * |
| * KBL/SKL-H (45W) GT2 quad 11.1 68 55 |
| * KBL-H (18W) GT2 quad 6.6 60 55 |
| * |
| * SKL-U + OPC (28W) GT3 dual 5.1 32 57/19 |
| * SKL-U + OPC (15W) GT3 dual 5.1 29 57/19 |
| * SKL-U (15W) GT2 dual 4.5 29 31 |
| * |
| * KBL-U + OPC (28W) GT3 dual 5.1 32 57/19 |
| * KBL-U + OPC (15W) GT3 dual 5.1 32 57/19 |
| * KBL-U (15W) GT1/2 dual 4.5 32 31 |
| * KBL-U [*] (15W) GT1 quad 4.5 29 31 |
| * |
| * KBL-U/R (15W) GT2 quad 6 64 31 |
| * |
| * SKL/KBL-Y (6W) 4.1 24 24 |
| * SKL/KBL-Y (4.5W) 4.1 24 24 |
| * |
| * [*] Pentium/Celeron CPUs with HD Graphics 610 |
| */ |
| |
| switch (mch_id) { |
| case PCI_DEVICE_ID_INTEL_SKL_ID_S_2: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_S: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(11.1, 40, 48, 48); |
| if (tdp >= 54) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(58); |
| else if (tdp >= 51) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(45); |
| |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_S_4: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_DT_2: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_DT: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(11.1, 55, 45, 45); |
| if (tdp >= 91) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(100); |
| else if (tdp >= 80) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(82); |
| else if (tdp >= 65) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(79); |
| else if (tdp >= 45) { |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(70); |
| icc_max[VR_GT_SLICED] = 0; |
| icc_max[VR_GT_UNSLICED] = 0; |
| } else if (tdp >= 25) { |
| if (tdp >= 35) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(66); |
| |
| icc_max[VR_GT_SLICED] = VR_CFG_AMP(35); |
| icc_max[VR_GT_UNSLICED] = VR_CFG_AMP(35); |
| } |
| |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_H_4: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(11.1, 60, 94, 20); |
| if (tdp >= 45) { |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(74); |
| if (tdp >= 65) { |
| icc_max[VR_GT_SLICED] = VR_CFG_AMP(105); |
| icc_max[VR_GT_UNSLICED] = VR_CFG_AMP(24); |
| } |
| } |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_H_2: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_SKL_ID_H_EM: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_H: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(6.6, 60, 55, 55); |
| if (tdp >= 35) { |
| if (tdp >= 45) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(68); |
| |
| icc_max[VR_SYSTEM_AGENT] = VR_CFG_AMP(11.1); |
| } |
| |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_U: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(5.1, 29, 57, 19); |
| if (tdp >= 28) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(32); |
| else if (igd_id != PCI_DEVICE_ID_INTEL_SKL_GT3E_SULTM_1) { |
| const uint16_t icc_max_gt2[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_ICC(4.5, 29, 31, 31); |
| |
| return icc_max_gt2[domain]; |
| } |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_KBL_U_R: { |
| const uint16_t icc_max[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_ICC(6, 64, 31, 31); |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_Y: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_Y: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(4.1, 24, 24, 24); |
| |
| if (igd_id == PCI_DEVICE_ID_INTEL_AML_GT2_ULX) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(28); |
| |
| return icc_max[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_KBL_ID_U: { |
| uint16_t icc_max[NUM_VR_DOMAINS] = VR_CFG_ALL_DOMAINS_ICC(4.5, 32, 31, 31); |
| |
| if (igd_id == PCI_DEVICE_ID_INTEL_KBL_GT1_SULTM) |
| icc_max[VR_IA_CORE] = VR_CFG_AMP(29); |
| |
| else if ((igd_id == PCI_DEVICE_ID_INTEL_KBL_GT3E_SULTM_1) || |
| (igd_id == PCI_DEVICE_ID_INTEL_KBL_GT3E_SULTM_2)) { |
| const uint16_t icc_max_gt3[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_ICC(5.1, 32, 57, 19); |
| |
| return icc_max_gt3[domain]; |
| } |
| |
| return icc_max[domain]; |
| } |
| default: |
| printk(BIOS_ERR, "ERROR: Unknown MCH (0x%x) in VR-config\n", mch_id); |
| } |
| return 0; |
| } |
| |
| static uint16_t get_sku_ac_dc_loadline(const int domain) |
| { |
| static uint16_t mch_id = 0, igd_id = 0; |
| if (!mch_id) { |
| struct device *dev = pcidev_path_on_root(SA_DEVFN_ROOT); |
| mch_id = dev ? pci_read_config16(dev, PCI_DEVICE_ID) : 0xffff; |
| } |
| if (!igd_id) { |
| struct device *dev = pcidev_path_on_root(SA_DEVFN_IGD); |
| igd_id = dev ? pci_read_config16(dev, PCI_DEVICE_ID) : 0xffff; |
| } |
| |
| switch (mch_id) { |
| case PCI_DEVICE_ID_INTEL_SKL_ID_S_2: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_SKL_ID_S_4: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_S: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_DT: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_DT_2: { |
| /* SA Loadline is not specified */ |
| const uint16_t loadline[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_LOADLINE(0, 2.1, 3.1, 3.1); |
| return loadline[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_H_2: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_SKL_ID_H_EM: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_SKL_ID_H_4: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_H: { |
| const uint16_t loadline[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_LOADLINE(10, 1.8, 2.65, 2.65); |
| |
| if (igd_id == PCI_DEVICE_ID_INTEL_SKL_GT4_SHALM) { |
| const uint16_t loadline_gt4[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_LOADLINE(6, 1.6, 1.4, 6); |
| return loadline_gt4[domain]; |
| } |
| |
| return loadline[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_Y: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_Y: { |
| uint16_t loadline[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_LOADLINE(18, 5.9, 5.7, 5.7); |
| |
| if (igd_id == PCI_DEVICE_ID_INTEL_AML_GT2_ULX) |
| loadline[VR_IA_CORE] = VR_CFG_MOHMS(4); |
| |
| return loadline[domain]; |
| } |
| case PCI_DEVICE_ID_INTEL_SKL_ID_U: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_U_R: /* fallthrough */ |
| case PCI_DEVICE_ID_INTEL_KBL_ID_U: { |
| uint16_t loadline[NUM_VR_DOMAINS] = |
| VR_CFG_ALL_DOMAINS_LOADLINE(10.3, 2.4, 3.1, 3.1); |
| |
| if ((igd_id == PCI_DEVICE_ID_INTEL_SKL_GT3E_SULTM_1) || |
| (igd_id == PCI_DEVICE_ID_INTEL_SKL_GT3E_SULTM_2) || |
| (igd_id == PCI_DEVICE_ID_INTEL_KBL_GT3E_SULTM_1) || |
| (igd_id == PCI_DEVICE_ID_INTEL_KBL_GT3E_SULTM_2)) { |
| loadline[VR_GT_UNSLICED] = VR_CFG_MOHMS(2); |
| loadline[VR_GT_SLICED] = VR_CFG_MOHMS(6); |
| } |
| |
| return loadline[domain]; |
| } |
| default: |
| printk(BIOS_ERR, "ERROR: Unknown MCH (0x%x) in VR-config\n", mch_id); |
| } |
| return 0; |
| } |
| |
| void fill_vr_domain_config(void *params, |
| int domain, const struct vr_config *chip_cfg) |
| { |
| FSP_SIL_UPD *vr_params = (FSP_SIL_UPD *)params; |
| const struct vr_config *cfg; |
| |
| if (domain < 0 || domain >= NUM_VR_DOMAINS) |
| return; |
| |
| /* Use device tree override if requested. */ |
| if (chip_cfg->vr_config_enable) |
| cfg = chip_cfg; |
| else |
| cfg = &default_configs[domain]; |
| |
| vr_params->VrConfigEnable[domain] = cfg->vr_config_enable; |
| vr_params->Psi1Threshold[domain] = cfg->psi1threshold; |
| vr_params->Psi2Threshold[domain] = cfg->psi2threshold; |
| vr_params->Psi3Threshold[domain] = cfg->psi3threshold; |
| vr_params->Psi3Enable[domain] = cfg->psi3enable; |
| vr_params->Psi4Enable[domain] = cfg->psi4enable; |
| vr_params->ImonSlope[domain] = cfg->imon_slope; |
| vr_params->ImonOffset[domain] = cfg->imon_offset; |
| |
| /* If board provided non-zero value, use it. */ |
| if (cfg->icc_max) |
| vr_params->IccMax[domain] = cfg->icc_max; |
| else |
| vr_params->IccMax[domain] = get_sku_icc_max(domain); |
| vr_params->VrVoltageLimit[domain] = cfg->voltage_limit; |
| |
| if (cfg->ac_loadline) |
| vr_params->AcLoadline[domain] = cfg->ac_loadline; |
| else |
| vr_params->AcLoadline[domain] = get_sku_ac_dc_loadline(domain); |
| if (cfg->dc_loadline) |
| vr_params->DcLoadline[domain] = cfg->dc_loadline; |
| else |
| vr_params->DcLoadline[domain] = get_sku_ac_dc_loadline(domain); |
| } |