Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright 2019 Google LLC |
| 4 | * Written by Simon Glass <sjg@chromium.org> |
| 5 | */ |
| 6 | |
| 7 | #include <common.h> |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 8 | #include <binman.h> |
Simon Glass | 1ea9789 | 2020-05-10 11:40:00 -0600 | [diff] [blame] | 9 | #include <bootstage.h> |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 10 | #include <dm.h> |
Simon Glass | 9758973 | 2020-05-10 11:40:02 -0600 | [diff] [blame] | 11 | #include <init.h> |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 12 | #include <irq.h> |
Simon Glass | 0f2af88 | 2020-05-10 11:40:05 -0600 | [diff] [blame] | 13 | #include <log.h> |
Simon Glass | 9bc1564 | 2020-02-03 07:36:16 -0700 | [diff] [blame] | 14 | #include <malloc.h> |
Simon Glass | 5046109 | 2020-04-08 16:57:35 -0600 | [diff] [blame] | 15 | #include <acpi/acpi_s3.h> |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 16 | #include <asm/intel_pinctrl.h> |
| 17 | #include <asm/io.h> |
| 18 | #include <asm/intel_regs.h> |
| 19 | #include <asm/msr.h> |
| 20 | #include <asm/msr-index.h> |
| 21 | #include <asm/pci.h> |
| 22 | #include <asm/arch/cpu.h> |
| 23 | #include <asm/arch/systemagent.h> |
| 24 | #include <asm/arch/fsp/fsp_configs.h> |
| 25 | #include <asm/arch/fsp/fsp_s_upd.h> |
Simon Glass | 4dcacfc | 2020-05-10 11:40:13 -0600 | [diff] [blame] | 26 | #include <linux/bitops.h> |
Bernhard Messerklinger | d65763c | 2020-05-18 12:33:35 +0200 | [diff] [blame] | 27 | #include <asm/arch/fsp_bindings.h> |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 28 | |
| 29 | #define PCH_P2SB_E0 0xe0 |
| 30 | #define HIDE_BIT BIT(0) |
| 31 | |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 32 | int fsps_update_config(struct udevice *dev, ulong rom_offset, |
| 33 | struct fsps_upd *upd) |
| 34 | { |
| 35 | struct fsp_s_config *cfg = &upd->config; |
Bernhard Messerklinger | d65763c | 2020-05-18 12:33:35 +0200 | [diff] [blame] | 36 | ofnode node; |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 37 | |
Bernhard Messerklinger | 7f8ff51 | 2020-05-18 12:33:33 +0200 | [diff] [blame] | 38 | if (IS_ENABLED(CONFIG_HAVE_VBT)) { |
Simon Glass | 5e40c05 | 2020-07-07 21:32:25 -0600 | [diff] [blame^] | 39 | void *buf; |
Bernhard Messerklinger | 7f8ff51 | 2020-05-18 12:33:33 +0200 | [diff] [blame] | 40 | int ret; |
| 41 | |
Simon Glass | 5e40c05 | 2020-07-07 21:32:25 -0600 | [diff] [blame^] | 42 | ret = binman_entry_map(ofnode_null(), "intel-vbt", &buf, NULL); |
Bernhard Messerklinger | 7f8ff51 | 2020-05-18 12:33:33 +0200 | [diff] [blame] | 43 | if (ret) |
| 44 | return log_msg_ret("Cannot find VBT", ret); |
Simon Glass | 5e40c05 | 2020-07-07 21:32:25 -0600 | [diff] [blame^] | 45 | if (*(u32 *)buf != VBT_SIGNATURE) |
| 46 | return log_msg_ret("VBT signature", -EINVAL); |
Bernhard Messerklinger | 7f8ff51 | 2020-05-18 12:33:33 +0200 | [diff] [blame] | 47 | |
| 48 | /* |
| 49 | * Load VBT before devicetree-specific config. This only |
| 50 | * supports memory-mapped SPI at present. |
| 51 | */ |
Simon Glass | 5e40c05 | 2020-07-07 21:32:25 -0600 | [diff] [blame^] | 52 | cfg->graphics_config_ptr = (ulong)buf; |
Bernhard Messerklinger | 7f8ff51 | 2020-05-18 12:33:33 +0200 | [diff] [blame] | 53 | } |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 54 | |
Bernhard Messerklinger | d65763c | 2020-05-18 12:33:35 +0200 | [diff] [blame] | 55 | node = dev_read_subnode(dev, "fsp-s"); |
| 56 | if (!ofnode_valid(node)) |
| 57 | return log_msg_ret("fsp-s settings", -ENOENT); |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 58 | |
Bernhard Messerklinger | d65763c | 2020-05-18 12:33:35 +0200 | [diff] [blame] | 59 | return fsp_s_update_config_from_dtb(node, cfg); |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | static void p2sb_set_hide_bit(pci_dev_t dev, int hide) |
| 63 | { |
| 64 | pci_x86_clrset_config(dev, PCH_P2SB_E0 + 1, HIDE_BIT, |
| 65 | hide ? HIDE_BIT : 0, PCI_SIZE_8); |
| 66 | } |
| 67 | |
| 68 | /* Configure package power limits */ |
| 69 | static int set_power_limits(struct udevice *dev) |
| 70 | { |
| 71 | msr_t rapl_msr_reg, limit; |
| 72 | u32 power_unit; |
| 73 | u32 tdp, min_power, max_power; |
| 74 | u32 pl2_val; |
| 75 | u32 override_tdp[2]; |
| 76 | int ret; |
| 77 | |
| 78 | /* Get units */ |
| 79 | rapl_msr_reg = msr_read(MSR_PKG_POWER_SKU_UNIT); |
| 80 | power_unit = 1 << (rapl_msr_reg.lo & 0xf); |
| 81 | |
| 82 | /* Get power defaults for this SKU */ |
| 83 | rapl_msr_reg = msr_read(MSR_PKG_POWER_SKU); |
| 84 | tdp = rapl_msr_reg.lo & PKG_POWER_LIMIT_MASK; |
| 85 | pl2_val = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK; |
| 86 | min_power = (rapl_msr_reg.lo >> 16) & PKG_POWER_LIMIT_MASK; |
| 87 | max_power = rapl_msr_reg.hi & PKG_POWER_LIMIT_MASK; |
| 88 | |
| 89 | if (min_power > 0 && tdp < min_power) |
| 90 | tdp = min_power; |
| 91 | |
| 92 | if (max_power > 0 && tdp > max_power) |
| 93 | tdp = max_power; |
| 94 | |
| 95 | ret = dev_read_u32_array(dev, "tdp-pl-override-mw", override_tdp, |
| 96 | ARRAY_SIZE(override_tdp)); |
| 97 | if (ret) |
| 98 | return log_msg_ret("tdp-pl-override-mw", ret); |
| 99 | |
| 100 | /* Set PL1 override value */ |
| 101 | if (override_tdp[0]) |
| 102 | tdp = override_tdp[0] * power_unit / 1000; |
| 103 | |
| 104 | /* Set PL2 override value */ |
| 105 | if (override_tdp[1]) |
| 106 | pl2_val = override_tdp[1] * power_unit / 1000; |
| 107 | |
| 108 | /* Set long term power limit to TDP */ |
| 109 | limit.lo = tdp & PKG_POWER_LIMIT_MASK; |
| 110 | /* Set PL1 Pkg Power clamp bit */ |
| 111 | limit.lo |= PKG_POWER_LIMIT_CLAMP; |
| 112 | |
| 113 | limit.lo |= PKG_POWER_LIMIT_EN; |
| 114 | limit.lo |= (MB_POWER_LIMIT1_TIME_DEFAULT & |
| 115 | PKG_POWER_LIMIT_TIME_MASK) << PKG_POWER_LIMIT_TIME_SHIFT; |
| 116 | |
| 117 | /* Set short term power limit PL2 */ |
| 118 | limit.hi = pl2_val & PKG_POWER_LIMIT_MASK; |
| 119 | limit.hi |= PKG_POWER_LIMIT_EN; |
| 120 | |
| 121 | /* Program package power limits in RAPL MSR */ |
| 122 | msr_write(MSR_PKG_POWER_LIMIT, limit); |
| 123 | log_info("RAPL PL1 %d.%dW\n", tdp / power_unit, |
| 124 | 100 * (tdp % power_unit) / power_unit); |
| 125 | log_info("RAPL PL2 %d.%dW\n", pl2_val / power_unit, |
| 126 | 100 * (pl2_val % power_unit) / power_unit); |
| 127 | |
| 128 | /* |
| 129 | * Sett RAPL MMIO register for Power limits. RAPL driver is using MSR |
| 130 | * instead of MMIO, so disable LIMIT_EN bit for MMIO |
| 131 | */ |
| 132 | writel(limit.lo & ~PKG_POWER_LIMIT_EN, MCHBAR_REG(MCHBAR_RAPL_PPL)); |
| 133 | writel(limit.hi & ~PKG_POWER_LIMIT_EN, MCHBAR_REG(MCHBAR_RAPL_PPL + 4)); |
| 134 | |
| 135 | return 0; |
| 136 | } |
| 137 | |
| 138 | int p2sb_unhide(void) |
| 139 | { |
| 140 | pci_dev_t dev = PCI_BDF(0, 0xd, 0); |
| 141 | ulong val; |
| 142 | |
| 143 | p2sb_set_hide_bit(dev, 0); |
| 144 | |
| 145 | pci_x86_read_config(dev, PCI_VENDOR_ID, &val, PCI_SIZE_16); |
| 146 | |
| 147 | if (val != PCI_VENDOR_ID_INTEL) |
| 148 | return log_msg_ret("p2sb unhide", -EIO); |
| 149 | |
| 150 | return 0; |
| 151 | } |
| 152 | |
| 153 | /* Overwrites the SCI IRQ if another IRQ number is given by device tree */ |
| 154 | static void set_sci_irq(void) |
| 155 | { |
| 156 | /* Skip this for now */ |
| 157 | } |
| 158 | |
| 159 | int arch_fsps_preinit(void) |
| 160 | { |
| 161 | struct udevice *itss; |
| 162 | int ret; |
| 163 | |
Simon Glass | 21bb12a | 2020-02-06 09:54:58 -0700 | [diff] [blame] | 164 | ret = irq_first_device_type(X86_IRQT_ITSS, &itss); |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 165 | if (ret) |
| 166 | return log_msg_ret("no itss", ret); |
| 167 | /* |
| 168 | * Snapshot the current GPIO IRQ polarities. FSP is setting a default |
| 169 | * policy that doesn't honour boards' requirements |
| 170 | */ |
| 171 | irq_snapshot_polarities(itss); |
| 172 | |
| 173 | /* |
| 174 | * Clear the GPI interrupt status and enable registers. These |
| 175 | * registers do not get reset to default state when booting from S5. |
| 176 | */ |
| 177 | ret = pinctrl_gpi_clear_int_cfg(); |
| 178 | if (ret) |
| 179 | return log_msg_ret("gpi_clear", ret); |
| 180 | |
| 181 | return 0; |
| 182 | } |
| 183 | |
| 184 | int arch_fsp_init_r(void) |
| 185 | { |
Simon Glass | e6ad202 | 2020-07-09 18:43:16 -0600 | [diff] [blame] | 186 | bool s3wake; |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 187 | struct udevice *dev, *itss; |
| 188 | int ret; |
| 189 | |
Simon Glass | 8eac3f3 | 2020-04-26 09:12:54 -0600 | [diff] [blame] | 190 | if (!ll_boot_init()) |
| 191 | return 0; |
Simon Glass | e6ad202 | 2020-07-09 18:43:16 -0600 | [diff] [blame] | 192 | |
| 193 | s3wake = IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && |
| 194 | gd->arch.prev_sleep_state == ACPI_S3; |
| 195 | |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 196 | /* |
| 197 | * This must be called before any devices are probed. Put any probing |
| 198 | * into arch_fsps_preinit() above. |
| 199 | * |
| 200 | * We don't use CONFIG_APL_BOOT_FROM_FAST_SPI_FLASH here since it will |
| 201 | * force PCI to be probed. |
| 202 | */ |
| 203 | ret = fsp_silicon_init(s3wake, false); |
| 204 | if (ret) |
| 205 | return ret; |
| 206 | |
Simon Glass | 21bb12a | 2020-02-06 09:54:58 -0700 | [diff] [blame] | 207 | ret = irq_first_device_type(X86_IRQT_ITSS, &itss); |
Simon Glass | 42bf7db | 2019-12-08 17:40:19 -0700 | [diff] [blame] | 208 | if (ret) |
| 209 | return log_msg_ret("no itss", ret); |
| 210 | /* Restore GPIO IRQ polarities back to previous settings */ |
| 211 | irq_restore_polarities(itss); |
| 212 | |
| 213 | /* soc_init() */ |
| 214 | ret = p2sb_unhide(); |
| 215 | if (ret) |
| 216 | return log_msg_ret("unhide p2sb", ret); |
| 217 | |
| 218 | /* Set RAPL MSR for Package power limits*/ |
| 219 | ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); |
| 220 | if (ret) |
| 221 | return log_msg_ret("Cannot get northbridge", ret); |
| 222 | set_power_limits(dev); |
| 223 | |
| 224 | /* |
| 225 | * FSP-S routes SCI to IRQ 9. With the help of this function you can |
| 226 | * select another IRQ for SCI. |
| 227 | */ |
| 228 | set_sci_irq(); |
| 229 | |
| 230 | return 0; |
| 231 | } |