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