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