summaryrefslogtreecommitdiff
path: root/arch/x86/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/cpu')
-rw-r--r--arch/x86/cpu/apollolake/Kconfig4
-rw-r--r--arch/x86/cpu/apollolake/Makefile1
-rw-r--r--arch/x86/cpu/apollolake/acpi.c211
-rw-r--r--arch/x86/cpu/apollolake/cpu.c77
-rw-r--r--arch/x86/cpu/apollolake/fsp_s.c2
-rw-r--r--arch/x86/cpu/apollolake/hostbridge.c243
-rw-r--r--arch/x86/cpu/apollolake/lpc.c18
-rw-r--r--arch/x86/cpu/apollolake/pmc.c8
-rw-r--r--arch/x86/cpu/cpu.c15
-rw-r--r--arch/x86/cpu/i386/cpu.c23
-rw-r--r--arch/x86/cpu/intel_common/Makefile7
-rw-r--r--arch/x86/cpu/intel_common/acpi.c377
-rw-r--r--arch/x86/cpu/intel_common/cpu.c79
-rw-r--r--arch/x86/cpu/intel_common/generic_wifi.c120
-rw-r--r--arch/x86/cpu/intel_common/intel_opregion.c168
-rw-r--r--arch/x86/cpu/mtrr.c24
-rw-r--r--arch/x86/cpu/tangier/Kconfig1
-rw-r--r--arch/x86/cpu/x86_64/cpu.c5
18 files changed, 1365 insertions, 18 deletions
diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig
index 99d4e105c25..35a425cd1bc 100644
--- a/arch/x86/cpu/apollolake/Kconfig
+++ b/arch/x86/cpu/apollolake/Kconfig
@@ -13,9 +13,12 @@ config INTEL_APOLLOLAKE
select TPL_X86_TSC_TIMER_NATIVE
select SPL_PCH_SUPPORT
select TPL_PCH_SUPPORT
+ select PCIEX_LENGTH_256MB
select PCH_SUPPORT
select P2SB
select SMP_AP_WORK
+ select INTEL_GMA_SWSMISCI
+ select ACPI_GNVS_EXTERNAL
imply ENABLE_MRC_CACHE
imply AHCI_PCI
imply SCSI
@@ -46,6 +49,7 @@ config INTEL_APOLLOLAKE
imply CMD_CLK
imply CLK_INTEL
imply ACPI_GPE
+ imply INTEL_GMA_ACPI
if INTEL_APOLLOLAKE
diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile
index 3aa2a556765..2ddf4af62c5 100644
--- a/arch/x86/cpu/apollolake/Makefile
+++ b/arch/x86/cpu/apollolake/Makefile
@@ -16,6 +16,7 @@ obj-y += fsp_m.o
endif
endif
ifndef CONFIG_SPL_BUILD
+obj-y += acpi.o
obj-y += fsp_s.o
endif
diff --git a/arch/x86/cpu/apollolake/acpi.c b/arch/x86/cpu/apollolake/acpi.c
new file mode 100644
index 00000000000..69b544f0d98
--- /dev/null
+++ b/arch/x86/cpu/apollolake/acpi.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Intel Corp.
+ * Copyright (C) 2017-2019 Siemens AG
+ * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.)
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot apollolake/acpi.c
+ */
+
+#define LOG_CATEGORY LOGC_ACPI
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <log.h>
+#include <p2sb.h>
+#include <pci.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_s3.h>
+#include <asm/acpi_table.h>
+#include <asm/cpu_common.h>
+#include <asm/intel_acpi.h>
+#include <asm/intel_gnvs.h>
+#include <asm/intel_pinctrl.h>
+#include <asm/intel_pinctrl_defs.h>
+#include <asm/intel_regs.h>
+#include <asm/io.h>
+#include <asm/mpspec.h>
+#include <asm/tables.h>
+#include <asm/arch/iomap.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/systemagent.h>
+#include <dm/acpi.h>
+#include <dm/uclass-internal.h>
+#include <power/acpi_pmc.h>
+
+int arch_read_sci_irq_select(void)
+{
+ struct acpi_pmc_upriv *upriv;
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_ACPI_PMC, &dev);
+ if (ret)
+ return log_msg_ret("pmc", ret);
+ upriv = dev_get_uclass_priv(dev);
+
+ return readl(upriv->pmc_bar0 + IRQ_REG);
+}
+
+int arch_write_sci_irq_select(uint scis)
+{
+ struct acpi_pmc_upriv *upriv;
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_ACPI_PMC, &dev);
+ if (ret)
+ return log_msg_ret("pmc", ret);
+ upriv = dev_get_uclass_priv(dev);
+ writel(scis, upriv->pmc_bar0 + IRQ_REG);
+
+ return 0;
+}
+
+int acpi_create_gnvs(struct acpi_global_nvs *gnvs)
+{
+ struct udevice *cpu;
+ int ret;
+
+ /* Clear out GNV */
+ memset(gnvs, '\0', sizeof(*gnvs));
+
+ /* TODO(sjg@chromium.org): Add the console log to gnvs->cbmc */
+
+#ifdef CONFIG_CHROMEOS
+ /* Initialise Verified Boot data */
+ chromeos_init_acpi(&gnvs->chromeos);
+ gnvs->chromeos.vbt2 = ACTIVE_ECFW_RO;
+#endif
+ /* Set unknown wake source */
+ gnvs->pm1i = ~0ULL;
+
+ /* CPU core count */
+ gnvs->pcnt = 1;
+ ret = uclass_find_first_device(UCLASS_CPU, &cpu);
+ if (cpu) {
+ ret = cpu_get_count(cpu);
+ if (ret > 0)
+ gnvs->pcnt = ret;
+ }
+
+ return 0;
+}
+
+uint32_t acpi_fill_soc_wake(uint32_t generic_pm1_en)
+{
+ /*
+ * WAK_STS bit is set when the system is in one of the sleep states
+ * (via the SLP_EN bit) and an enabled wake event occurs. Upon setting
+ * this bit, the PMC will transition the system to the ON state and
+ * can only be set by hardware and can only be cleared by writing a one
+ * to this bit position.
+ */
+ generic_pm1_en |= WAK_STS | RTC_EN | PWRBTN_EN;
+
+ return generic_pm1_en;
+}
+
+int arch_madt_sci_irq_polarity(int sci)
+{
+ return MP_IRQ_POLARITY_LOW;
+}
+
+void fill_fadt(struct acpi_fadt *fadt)
+{
+ fadt->pm_tmr_blk = IOMAP_ACPI_BASE + PM1_TMR;
+
+ fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
+ fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
+
+ fadt->pm_tmr_len = 4;
+ fadt->duty_width = 3;
+
+ fadt->iapc_boot_arch = ACPI_FADT_LEGACY_DEVICES | ACPI_FADT_8042;
+
+ fadt->x_pm_tmr_blk.space_id = 1;
+ fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8;
+ fadt->x_pm_tmr_blk.addrl = IOMAP_ACPI_BASE + PM1_TMR;
+}
+
+void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
+ void *dsdt)
+{
+ struct acpi_table_header *header = &fadt->header;
+
+ acpi_fadt_common(fadt, facs, dsdt);
+ intel_acpi_fill_fadt(fadt);
+ fill_fadt(fadt);
+ header->checksum = table_compute_checksum(fadt, header->length);
+}
+
+int apl_acpi_fill_dmar(struct acpi_ctx *ctx)
+{
+ struct udevice *dev, *sa_dev;
+ u64 gfxvtbar = readq(MCHBAR_REG(GFXVTBAR)) & VTBAR_MASK;
+ u64 defvtbar = readq(MCHBAR_REG(DEFVTBAR)) & VTBAR_MASK;
+ bool gfxvten = readl(MCHBAR_REG(GFXVTBAR)) & VTBAR_ENABLED;
+ bool defvten = readl(MCHBAR_REG(DEFVTBAR)) & VTBAR_ENABLED;
+ void *tmp;
+ int ret;
+
+ uclass_find_first_device(UCLASS_VIDEO, &dev);
+ ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &sa_dev);
+ if (ret)
+ return log_msg_ret("no sa", ret);
+
+ /* IGD has to be enabled, GFXVTBAR set and enabled */
+ if (dev && device_active(dev) && gfxvtbar && gfxvten) {
+ tmp = ctx->current;
+
+ acpi_create_dmar_drhd(ctx, 0, 0, gfxvtbar);
+ ret = acpi_create_dmar_ds_pci(ctx, PCI_BDF(0, 2, 0));
+ if (ret)
+ return log_msg_ret("ds_pci", ret);
+ acpi_dmar_drhd_fixup(ctx, tmp);
+
+ /* Add RMRR entry */
+ tmp = ctx->current;
+ acpi_create_dmar_rmrr(ctx->current, 0, sa_get_gsm_base(sa_dev),
+ sa_get_tolud_base(sa_dev) - 1);
+ acpi_create_dmar_ds_pci(ctx->current, PCI_BDF(0, 2, 0));
+ acpi_dmar_rmrr_fixup(ctx, tmp);
+ }
+
+ /* DEFVTBAR has to be set and enabled */
+ if (defvtbar && defvten) {
+ struct udevice *p2sb_dev;
+ u16 ibdf, hbdf;
+ uint ioapic, hpet;
+ int ret;
+
+ tmp = ctx->current;
+ /*
+ * P2SB may already be hidden. There's no clear rule, when.
+ * It is needed to get bus, device and function for IOAPIC and
+ * HPET device which is stored in P2SB device. So unhide it to
+ * get the info and hide it again when done.
+ *
+ * TODO(sjg@chromium.org): p2sb_unhide() ?
+ */
+ ret = uclass_first_device_err(UCLASS_P2SB, &p2sb_dev);
+ if (ret)
+ return log_msg_ret("p2sb", ret);
+
+ dm_pci_read_config16(p2sb_dev, PCH_P2SB_IBDF, &ibdf);
+ ioapic = PCI_TO_BDF(ibdf);
+ dm_pci_read_config16(p2sb_dev, PCH_P2SB_HBDF, &hbdf);
+ hpet = PCI_TO_BDF(hbdf);
+ /* TODO(sjg@chromium.org): p2sb_hide() ? */
+
+ acpi_create_dmar_drhd(ctx, DRHD_INCLUDE_PCI_ALL, 0, defvtbar);
+ acpi_create_dmar_ds_ioapic(ctx, 2, ioapic);
+ acpi_create_dmar_ds_msi_hpet(ctx, 0, hpet);
+ acpi_dmar_drhd_fixup(tmp, ctx->current);
+ }
+
+ return 0;
+}
diff --git a/arch/x86/cpu/apollolake/cpu.c b/arch/x86/cpu/apollolake/cpu.c
index 0a6d2ad7a4a..8da2e64e226 100644
--- a/arch/x86/cpu/apollolake/cpu.c
+++ b/arch/x86/cpu/apollolake/cpu.c
@@ -6,14 +6,90 @@
#include <common.h>
#include <cpu.h>
#include <dm.h>
+#include <log.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_table.h>
#include <asm/cpu_common.h>
#include <asm/cpu_x86.h>
+#include <asm/intel_acpi.h>
+#include <asm/msr.h>
+#include <dm/acpi.h>
+
+#define CSTATE_RES(address_space, width, offset, address) \
+ { \
+ .space_id = address_space, \
+ .bit_width = width, \
+ .bit_offset = offset, \
+ .addrl = address, \
+ }
+
+static struct acpi_cstate cstate_map[] = {
+ {
+ /* C1 */
+ .ctype = 1, /* ACPI C1 */
+ .latency = 1,
+ .power = 1000,
+ .resource = {
+ .space_id = ACPI_ADDRESS_SPACE_FIXED,
+ },
+ }, {
+ .ctype = 2, /* ACPI C2 */
+ .latency = 50,
+ .power = 10,
+ .resource = {
+ .space_id = ACPI_ADDRESS_SPACE_IO,
+ .bit_width = 8,
+ .addrl = 0x415,
+ },
+ }, {
+ .ctype = 3, /* ACPI C3 */
+ .latency = 150,
+ .power = 10,
+ .resource = {
+ .space_id = ACPI_ADDRESS_SPACE_IO,
+ .bit_width = 8,
+ .addrl = 0x419,
+ },
+ },
+};
static int apl_get_info(const struct udevice *dev, struct cpu_info *info)
{
return cpu_intel_get_info(info, INTEL_BCLK_MHZ);
}
+static int acpi_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ uint core_id = dev->req_seq;
+ int cores_per_package;
+ int ret;
+
+ cores_per_package = cpu_get_cores_per_package();
+ ret = acpi_generate_cpu_header(ctx, core_id, cstate_map,
+ ARRAY_SIZE(cstate_map));
+
+ /* Generate P-state tables */
+ generate_p_state_entries(ctx, core_id, cores_per_package);
+
+ /* Generate T-state tables */
+ generate_t_state_entries(ctx, core_id, cores_per_package, NULL, 0);
+
+ acpigen_pop_len(ctx);
+
+ if (device_is_last_sibling(dev)) {
+ ret = acpi_generate_cpu_package_final(ctx, cores_per_package);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+struct acpi_ops apl_cpu_acpi_ops = {
+ .fill_ssdt = acpi_cpu_fill_ssdt,
+};
+
static const struct cpu_ops cpu_x86_apl_ops = {
.get_desc = cpu_x86_get_desc,
.get_info = apl_get_info,
@@ -32,5 +108,6 @@ U_BOOT_DRIVER(cpu_x86_apl_drv) = {
.of_match = cpu_x86_apl_ids,
.bind = cpu_x86_bind,
.ops = &cpu_x86_apl_ops,
+ ACPI_OPS_PTR(&apl_cpu_acpi_ops)
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/arch/x86/cpu/apollolake/fsp_s.c b/arch/x86/cpu/apollolake/fsp_s.c
index e54b0ac1047..715ceab6ac7 100644
--- a/arch/x86/cpu/apollolake/fsp_s.c
+++ b/arch/x86/cpu/apollolake/fsp_s.c
@@ -157,6 +157,8 @@ int arch_fsps_preinit(void)
struct udevice *itss;
int ret;
+ if (!ll_boot_init())
+ return 0;
ret = irq_first_device_type(X86_IRQT_ITSS, &itss);
if (ret)
return log_msg_ret("no itss", ret);
diff --git a/arch/x86/cpu/apollolake/hostbridge.c b/arch/x86/cpu/apollolake/hostbridge.c
index cb46ec6c0bb..7fd67dcfb6e 100644
--- a/arch/x86/cpu/apollolake/hostbridge.c
+++ b/arch/x86/cpu/apollolake/hostbridge.c
@@ -1,17 +1,45 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 Google LLC
+ * Copyright (C) 2015 - 2017 Intel Corp.
+ * Copyright (C) 2017 - 2019 Siemens AG
+ * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
+ * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
+ *
+ * Portions from coreboot soc/intel/apollolake/chip.c
*/
+#define LOG_CATEGORY UCLASS_NORTHBRIDGE
+
#include <common.h>
#include <dm.h>
#include <dt-structs.h>
#include <log.h>
#include <spl.h>
+#include <tables_csum.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpi_nhlt.h>
#include <asm/intel_pinctrl.h>
#include <asm/intel_regs.h>
+#include <asm/io.h>
#include <asm/pci.h>
+#include <asm/arch/acpi.h>
#include <asm/arch/systemagent.h>
+#include <dt-bindings/sound/nhlt.h>
+#include <dm/acpi.h>
+
+enum {
+ PCIEXBAR = 0x60,
+ PCIEXBAR_LENGTH_256MB = 0,
+ PCIEXBAR_LENGTH_128MB,
+ PCIEXBAR_LENGTH_64MB,
+
+ PCIEXBAR_PCIEXBAREN = 1 << 0,
+
+ BGSM = 0xb4, /* Base GTT Stolen Memory */
+ TSEG = 0xb8, /* TSEG base */
+ TOLUD = 0xbc,
+};
/**
* struct apl_hostbridge_platdata - platform data for hostbridge
@@ -32,15 +60,100 @@ struct apl_hostbridge_platdata {
pci_dev_t bdf;
};
-enum {
- PCIEXBAR = 0x60,
- PCIEXBAR_LENGTH_256MB = 0,
- PCIEXBAR_LENGTH_128MB,
- PCIEXBAR_LENGTH_64MB,
+static const struct nhlt_format_config dmic_1ch_formats[] = {
+ /* 48 KHz 16-bits per sample. */
+ {
+ .num_channels = 1,
+ .sample_freq_khz = 48,
+ .container_bits_per_sample = 16,
+ .valid_bits_per_sample = 16,
+ .settings_file = "dmic-1ch-48khz-16b.dat",
+ },
+};
- PCIEXBAR_PCIEXBAREN = 1 << 0,
+static const struct nhlt_dmic_array_config dmic_1ch_mic_config = {
+ .tdm_config = {
+ .config_type = NHLT_TDM_MIC_ARRAY,
+ },
+ .array_type = NHLT_MIC_ARRAY_VENDOR_DEFINED,
+};
- TSEG = 0xb8, /* TSEG base */
+static const struct nhlt_endp_descriptor dmic_1ch_descriptors[] = {
+ {
+ .link = NHLT_LINK_PDM,
+ .device = NHLT_PDM_DEV,
+ .direction = NHLT_DIR_CAPTURE,
+ .vid = NHLT_VID,
+ .did = NHLT_DID_DMIC,
+ .cfg = &dmic_1ch_mic_config,
+ .cfg_size = sizeof(dmic_1ch_mic_config),
+ .formats = dmic_1ch_formats,
+ .num_formats = ARRAY_SIZE(dmic_1ch_formats),
+ },
+};
+
+static const struct nhlt_format_config dmic_2ch_formats[] = {
+ /* 48 KHz 16-bits per sample. */
+ {
+ .num_channels = 2,
+ .sample_freq_khz = 48,
+ .container_bits_per_sample = 16,
+ .valid_bits_per_sample = 16,
+ .settings_file = "dmic-2ch-48khz-16b.dat",
+ },
+};
+
+static const struct nhlt_dmic_array_config dmic_2ch_mic_config = {
+ .tdm_config = {
+ .config_type = NHLT_TDM_MIC_ARRAY,
+ },
+ .array_type = NHLT_MIC_ARRAY_2CH_SMALL,
+};
+
+static const struct nhlt_endp_descriptor dmic_2ch_descriptors[] = {
+ {
+ .link = NHLT_LINK_PDM,
+ .device = NHLT_PDM_DEV,
+ .direction = NHLT_DIR_CAPTURE,
+ .vid = NHLT_VID,
+ .did = NHLT_DID_DMIC,
+ .cfg = &dmic_2ch_mic_config,
+ .cfg_size = sizeof(dmic_2ch_mic_config),
+ .formats = dmic_2ch_formats,
+ .num_formats = ARRAY_SIZE(dmic_2ch_formats),
+ },
+};
+
+static const struct nhlt_format_config dmic_4ch_formats[] = {
+ /* 48 KHz 16-bits per sample. */
+ {
+ .num_channels = 4,
+ .sample_freq_khz = 48,
+ .container_bits_per_sample = 16,
+ .valid_bits_per_sample = 16,
+ .settings_file = "dmic-4ch-48khz-16b.dat",
+ },
+};
+
+static const struct nhlt_dmic_array_config dmic_4ch_mic_config = {
+ .tdm_config = {
+ .config_type = NHLT_TDM_MIC_ARRAY,
+ },
+ .array_type = NHLT_MIC_ARRAY_4CH_L_SHAPED,
+};
+
+static const struct nhlt_endp_descriptor dmic_4ch_descriptors[] = {
+ {
+ .link = NHLT_LINK_PDM,
+ .device = NHLT_PDM_DEV,
+ .direction = NHLT_DIR_CAPTURE,
+ .vid = NHLT_VID,
+ .did = NHLT_DID_DMIC,
+ .cfg = &dmic_4ch_mic_config,
+ .cfg_size = sizeof(dmic_4ch_mic_config),
+ .formats = dmic_4ch_formats,
+ .num_formats = ARRAY_SIZE(dmic_4ch_formats),
+ },
};
static int apl_hostbridge_early_init_pinctrl(struct udevice *dev)
@@ -165,6 +278,119 @@ static int apl_hostbridge_probe(struct udevice *dev)
return 0;
}
+static int apl_acpi_hb_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "RHUB");
+}
+
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+static int apl_acpi_hb_write_tables(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct acpi_table_header *header;
+ struct acpi_dmar *dmar;
+ u32 val;
+
+ /*
+ * Create DMAR table only if virtualization is enabled. Due to some
+ * constraints on Apollo Lake SoC (some stepping affected), VTD could
+ * not be enabled together with IPU. Doing so will override and disable
+ * VTD while leaving CAPID0_A still reporting that VTD is available.
+ * As in this case FSP will lock VTD to disabled state, we need to make
+ * sure that DMAR table generation only happens when at least DEFVTBAR
+ * is enabled. Otherwise the DMAR header will be generated while the
+ * content of the table will be missing.
+ */
+ dm_pci_read_config32(dev, CAPID0_A, &val);
+ if ((val & VTD_DISABLE) ||
+ !(readl(MCHBAR_REG(DEFVTBAR)) & VTBAR_ENABLED))
+ return 0;
+
+ log_debug("ACPI: * DMAR\n");
+ dmar = (struct acpi_dmar *)ctx->current;
+ header = &dmar->header;
+ acpi_create_dmar(dmar, DMAR_INTR_REMAP);
+ ctx->current += sizeof(struct acpi_dmar);
+ apl_acpi_fill_dmar(ctx);
+
+ /* (Re)calculate length and checksum */
+ header->length = ctx->current - (void *)dmar;
+ header->checksum = table_compute_checksum((void *)dmar, header->length);
+
+ acpi_align(ctx);
+ acpi_add_table(ctx, dmar);
+
+ return 0;
+}
+#endif
+
+static int apl_acpi_setup_nhlt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ struct nhlt *nhlt = ctx->nhlt;
+ u32 channels;
+ ofnode node;
+
+ node = ofnode_find_subnode(dev_ofnode(dev), "nhlt");
+ if (ofnode_read_u32(node, "intel,dmic-channels", &channels))
+ return log_msg_ret("channels", -EINVAL);
+ switch (channels) {
+ case 1:
+ return nhlt_add_endpoints(nhlt, dmic_1ch_descriptors,
+ ARRAY_SIZE(dmic_1ch_descriptors));
+ case 2:
+ return nhlt_add_endpoints(nhlt, dmic_2ch_descriptors,
+ ARRAY_SIZE(dmic_2ch_descriptors));
+ case 4:
+ return nhlt_add_endpoints(nhlt, dmic_4ch_descriptors,
+ ARRAY_SIZE(dmic_4ch_descriptors));
+ }
+
+ return log_msg_ret("channels", -EINVAL);
+}
+
+static int apl_hostbridge_remove(struct udevice *dev)
+{
+ /*
+ * TODO(sjg@chromium.org): Consider adding code from coreboot's
+ * platform_fsp_notify_status()
+ */
+
+ return 0;
+}
+
+static ulong sa_read_reg(struct udevice *dev, int reg)
+{
+ u32 val;
+
+ /* All regions concerned for have 1 MiB alignment */
+ dm_pci_read_config32(dev, BGSM, &val);
+
+ return ALIGN_DOWN(val, 1 << 20);
+}
+
+ulong sa_get_tolud_base(struct udevice *dev)
+{
+ return sa_read_reg(dev, TOLUD);
+}
+
+ulong sa_get_gsm_base(struct udevice *dev)
+{
+ return sa_read_reg(dev, BGSM);
+}
+
+ulong sa_get_tseg_base(struct udevice *dev)
+{
+ return sa_read_reg(dev, TSEG);
+}
+
+struct acpi_ops apl_hostbridge_acpi_ops = {
+ .get_name = apl_acpi_hb_get_name,
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+ .write_tables = apl_acpi_hb_write_tables,
+#endif
+ .setup_nhlt = apl_acpi_setup_nhlt,
+};
+
static const struct udevice_id apl_hostbridge_ids[] = {
{ .compatible = "intel,apl-hostbridge" },
{ }
@@ -176,5 +402,8 @@ U_BOOT_DRIVER(apl_hostbridge_drv) = {
.of_match = apl_hostbridge_ids,
.ofdata_to_platdata = apl_hostbridge_ofdata_to_platdata,
.probe = apl_hostbridge_probe,
+ .remove = apl_hostbridge_remove,
.platdata_auto_alloc_size = sizeof(struct apl_hostbridge_platdata),
+ ACPI_OPS_PTR(&apl_hostbridge_acpi_ops)
+ .flags = DM_FLAG_OS_PREPARE,
};
diff --git a/arch/x86/cpu/apollolake/lpc.c b/arch/x86/cpu/apollolake/lpc.c
index b81a458f2eb..a29832c879a 100644
--- a/arch/x86/cpu/apollolake/lpc.c
+++ b/arch/x86/cpu/apollolake/lpc.c
@@ -9,10 +9,14 @@
#include <dm.h>
#include <log.h>
#include <spl.h>
+#include <acpi/acpi_table.h>
+#include <asm/cpu_common.h>
+#include <asm/intel_acpi.h>
#include <asm/lpc_common.h>
#include <asm/pci.h>
#include <asm/arch/iomap.h>
#include <asm/arch/lpc.h>
+#include <dm/acpi.h>
#include <linux/log2.h>
void lpc_enable_fixed_io_ranges(uint io_enables)
@@ -110,6 +114,19 @@ void lpc_io_setup_comm_a_b(void)
lpc_enable_fixed_io_ranges(com_enable);
}
+static int apl_acpi_lpc_get_name(const struct udevice *dev, char *out_name)
+{
+ return acpi_copy_name(out_name, "LPCB");
+}
+
+struct acpi_ops apl_lpc_acpi_ops = {
+ .get_name = apl_acpi_lpc_get_name,
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+ .write_tables = intel_southbridge_write_acpi_tables,
+#endif
+ .inject_dsdt = southbridge_inject_dsdt,
+};
+
static const struct udevice_id apl_lpc_ids[] = {
{ .compatible = "intel,apl-lpc" },
{ }
@@ -120,4 +137,5 @@ U_BOOT_DRIVER(apl_lpc_drv) = {
.name = "intel_apl_lpc",
.id = UCLASS_LPC,
.of_match = apl_lpc_ids,
+ ACPI_OPS_PTR(&apl_lpc_acpi_ops)
};
diff --git a/arch/x86/cpu/apollolake/pmc.c b/arch/x86/cpu/apollolake/pmc.c
index 192dec7109a..576d0187570 100644
--- a/arch/x86/cpu/apollolake/pmc.c
+++ b/arch/x86/cpu/apollolake/pmc.c
@@ -118,7 +118,8 @@ int apl_pmc_ofdata_to_uc_platdata(struct udevice *dev)
int size;
int ret;
- ret = dev_read_u32_array(dev, "early-regs", base, ARRAY_SIZE(base));
+ ret = dev_read_u32_array(dev, "early-regs", base,
+ ARRAY_SIZE(base));
if (ret)
return log_msg_ret("Missing/short early-regs", ret);
if (spl_phase() == PHASE_TPL) {
@@ -133,11 +134,6 @@ int apl_pmc_ofdata_to_uc_platdata(struct udevice *dev)
}
upriv->acpi_base = base[4];
- /* Since PCI is not enabled, we must get the BDF manually */
- plat->bdf = pci_get_devfn(dev);
- if (plat->bdf < 0)
- return log_msg_ret("Cannot get PMC PCI address", plat->bdf);
-
/* Get the dwX values for pmc gpe settings */
size = dev_read_size(dev, "gpe0-dw");
if (size < 0)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index 69c14189d1f..f8692753963 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -189,6 +189,14 @@ __weak void board_final_init(void)
{
}
+/*
+ * Implement a weak default function for boards that need to do some final
+ * processing before booting the OS.
+ */
+__weak void board_final_cleanup(void)
+{
+}
+
int last_stage_init(void)
{
struct acpi_fadt __maybe_unused *fadt;
@@ -218,6 +226,13 @@ int last_stage_init(void)
}
}
+ /*
+ * TODO(sjg@chromium.org): Move this to bootm_announce_and_cleanup()
+ * once APL FSP-S at 0x200000 does not overlap with the bzimage at
+ * 0x100000.
+ */
+ board_final_cleanup();
+
return 0;
}
#endif
diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c
index 8f342dd06e2..7517b756f43 100644
--- a/arch/x86/cpu/i386/cpu.c
+++ b/arch/x86/cpu/i386/cpu.c
@@ -34,6 +34,10 @@
DECLARE_GLOBAL_DATA_PTR;
+#define CPUID_FEATURE_PAE BIT(6)
+#define CPUID_FEATURE_PSE36 BIT(17)
+#define CPUID_FEAURE_HTT BIT(28)
+
/*
* Constructor for a conventional segment GDT (or LDT) entry
* This is a macro so it can be used in initialisers
@@ -388,6 +392,25 @@ static void setup_identity(void)
}
}
+static uint cpu_cpuid_extended_level(void)
+{
+ return cpuid_eax(0x80000000);
+}
+
+int cpu_phys_address_size(void)
+{
+ if (!has_cpuid())
+ return 32;
+
+ if (cpu_cpuid_extended_level() >= 0x80000008)
+ return cpuid_eax(0x80000008) & 0xff;
+
+ if (cpuid_edx(1) & (CPUID_FEATURE_PAE | CPUID_FEATURE_PSE36))
+ return 36;
+
+ return 32;
+}
+
/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */
static void setup_pci_ram_top(void)
{
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
index 374803b8760..4a5cf17e41d 100644
--- a/arch/x86/cpu/intel_common/Makefile
+++ b/arch/x86/cpu/intel_common/Makefile
@@ -2,6 +2,8 @@
#
# Copyright (c) 2016 Google, Inc
+obj-$(CONFIG_INTEL_ACPIGEN) += acpi.o
+
ifdef CONFIG_HAVE_MRC
obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += car.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += me_status.o
@@ -9,6 +11,10 @@ obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o
endif
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_INTEL_GMA_ACPI) += intel_opregion.o
+endif
+
ifdef CONFIG_INTEL_CAR_CQOS
obj-$(CONFIG_TPL_BUILD) += car2.o
ifndef CONFIG_SPL_BUILD
@@ -20,6 +26,7 @@ obj-y += cpu.o
obj-y += fast_spi.o
obj-y += lpc.o
obj-y += lpss.o
+obj-$(CONFIG_INTEL_GENERIC_WIFI) += generic_wifi.o
ifndef CONFIG_TARGET_EFI_APP
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o
ifndef CONFIG_$(SPL_)X86_64
diff --git a/arch/x86/cpu/intel_common/acpi.c b/arch/x86/cpu/intel_common/acpi.c
new file mode 100644
index 00000000000..a4d5fbd38a7
--- /dev/null
+++ b/arch/x86/cpu/intel_common/acpi.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generic Intel ACPI table generation
+ *
+ * Copyright (C) 2017 Intel Corp.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot src/soc/intel/common/block/acpi.c
+ */
+
+#include <common.h>
+#include <bloblist.h>
+#include <cpu.h>
+#include <dm.h>
+#include <acpi/acpigen.h>
+#include <asm/acpigen.h>
+#include <asm/acpi_table.h>
+#include <asm/cpu.h>
+#include <asm/cpu_common.h>
+#include <asm/intel_acpi.h>
+#include <asm/ioapic.h>
+#include <asm/mpspec.h>
+#include <asm/smm.h>
+#include <asm/turbo.h>
+#include <asm/intel_gnvs.h>
+#include <asm/arch/iomap.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/systemagent.h>
+#include <dm/acpi.h>
+#include <linux/err.h>
+#include <power/acpi_pmc.h>
+
+u32 acpi_fill_mcfg(u32 current)
+{
+ /* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */
+ current += acpi_create_mcfg_mmconfig((void *)current,
+ CONFIG_MMCONF_BASE_ADDRESS, 0, 0,
+ (CONFIG_SA_PCIEX_LENGTH >> 20)
+ - 1);
+ return current;
+}
+
+static int acpi_sci_irq(void)
+{
+ int sci_irq = 9;
+ uint scis;
+ int ret;
+
+ ret = arch_read_sci_irq_select();
+ if (IS_ERR_VALUE(ret))
+ return log_msg_ret("sci_irq", ret);
+ scis = ret;
+ scis &= SCI_IRQ_MASK;
+ scis >>= SCI_IRQ_SHIFT;
+
+ /* Determine how SCI is routed. */
+ switch (scis) {
+ case SCIS_IRQ9:
+ case SCIS_IRQ10:
+ case SCIS_IRQ11:
+ sci_irq = scis - SCIS_IRQ9 + 9;
+ break;
+ case SCIS_IRQ20:
+ case SCIS_IRQ21:
+ case SCIS_IRQ22:
+ case SCIS_IRQ23:
+ sci_irq = scis - SCIS_IRQ20 + 20;
+ break;
+ default:
+ log_warning("Invalid SCI route! Defaulting to IRQ9\n");
+ sci_irq = 9;
+ break;
+ }
+
+ log_debug("SCI is IRQ%d\n", sci_irq);
+
+ return sci_irq;
+}
+
+static unsigned long acpi_madt_irq_overrides(unsigned long current)
+{
+ int sci = acpi_sci_irq();
+ u16 flags = MP_IRQ_TRIGGER_LEVEL;
+
+ if (sci < 0)
+ return log_msg_ret("sci irq", sci);
+
+ /* INT_SRC_OVR */
+ current += acpi_create_madt_irqoverride((void *)current, 0, 0, 2, 0);
+
+ flags |= arch_madt_sci_irq_polarity(sci);
+
+ /* SCI */
+ current +=
+ acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags);
+
+ return current;
+}
+
+u32 acpi_fill_madt(u32 current)
+{
+ /* Local APICs */
+ current += acpi_create_madt_lapics(current);
+
+ /* IOAPIC */
+ current += acpi_create_madt_ioapic((void *)current, 2, IO_APIC_ADDR, 0);
+
+ return acpi_madt_irq_overrides(current);
+}
+
+void intel_acpi_fill_fadt(struct acpi_fadt *fadt)
+{
+ const u16 pmbase = IOMAP_ACPI_BASE;
+
+ /* Use ACPI 3.0 revision. */
+ fadt->header.revision = acpi_get_table_revision(ACPITAB_FADT);
+
+ fadt->sci_int = acpi_sci_irq();
+ fadt->smi_cmd = APM_CNT;
+ fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
+ fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
+ fadt->s4bios_req = 0x0;
+ fadt->pstate_cnt = 0;
+
+ fadt->pm1a_evt_blk = pmbase + PM1_STS;
+ fadt->pm1b_evt_blk = 0x0;
+ fadt->pm1a_cnt_blk = pmbase + PM1_CNT;
+ fadt->pm1b_cnt_blk = 0x0;
+
+ fadt->gpe0_blk = pmbase + GPE0_STS;
+
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+
+ /* GPE0 STS/EN pairs each 32 bits wide. */
+ fadt->gpe0_blk_len = 2 * GPE0_REG_MAX * sizeof(uint32_t);
+
+ fadt->flush_size = 0x400; /* twice of cache size */
+ fadt->flush_stride = 0x10; /* Cache line width */
+ fadt->duty_offset = 1;
+ fadt->day_alrm = 0xd;
+
+ fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
+ ACPI_FADT_C2_MP_SUPPORTED | ACPI_FADT_SLEEP_BUTTON |
+ ACPI_FADT_RESET_REGISTER | ACPI_FADT_SEALED_CASE |
+ ACPI_FADT_S4_RTC_WAKE | ACPI_FADT_PLATFORM_CLOCK;
+
+ fadt->reset_reg.space_id = 1;
+ fadt->reset_reg.bit_width = 8;
+ fadt->reset_reg.addrl = IO_PORT_RESET;
+ fadt->reset_value = RST_CPU | SYS_RST;
+
+ fadt->x_pm1a_evt_blk.space_id = 1;
+ fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;
+ fadt->x_pm1a_evt_blk.addrl = pmbase + PM1_STS;
+
+ fadt->x_pm1b_evt_blk.space_id = 1;
+
+ fadt->x_pm1a_cnt_blk.space_id = 1;
+ fadt->x_pm1a_cnt_blk.bit_width = fadt->pm1_cnt_len * 8;
+ fadt->x_pm1a_cnt_blk.addrl = pmbase + PM1_CNT;
+
+ fadt->x_pm1b_cnt_blk.space_id = 1;
+
+ fadt->x_gpe1_blk.space_id = 1;
+}
+
+int intel_southbridge_write_acpi_tables(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ int ret;
+
+ ret = acpi_write_dbg2_pci_uart(ctx, gd->cur_serial_dev,
+ ACPI_ACCESS_SIZE_DWORD_ACCESS);
+ if (ret)
+ return log_msg_ret("dbg2", ret);
+
+ ret = acpi_write_hpet(ctx);
+ if (ret)
+ return log_msg_ret("hpet", ret);
+
+ return 0;
+}
+
+__weak u32 acpi_fill_soc_wake(u32 generic_pm1_en,
+ const struct chipset_power_state *ps)
+{
+ return generic_pm1_en;
+}
+
+__weak int acpi_create_gnvs(struct acpi_global_nvs *gnvs)
+{
+ return 0;
+}
+
+int southbridge_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ struct acpi_global_nvs *gnvs;
+ int ret;
+
+ ret = bloblist_ensure_size(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs),
+ (void **)&gnvs);
+ if (ret)
+ return log_msg_ret("bloblist", ret);
+ memset(gnvs, '\0', sizeof(*gnvs));
+
+ ret = acpi_create_gnvs(gnvs);
+ if (ret)
+ return log_msg_ret("gnvs", ret);
+
+ /*
+ * TODO(sjg@chromum.org): tell SMI about it
+ * smm_setup_structures(gnvs, NULL, NULL);
+ */
+
+ /* Add it to DSDT */
+ acpigen_write_scope(ctx, "\\");
+ acpigen_write_name_dword(ctx, "NVSA", (uintptr_t)gnvs);
+ acpigen_pop_len(ctx);
+
+ return 0;
+}
+
+static int calculate_power(int tdp, int p1_ratio, int ratio)
+{
+ u32 m;
+ u32 power;
+
+ /*
+ * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
+ *
+ * Power = (ratio / p1_ratio) * m * tdp
+ */
+
+ m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
+ m = (m * m) / 1000;
+
+ power = ((ratio * 100000 / p1_ratio) / 100);
+ power *= (m / 100) * (tdp / 1000);
+ power /= 1000;
+
+ return power;
+}
+
+void generate_p_state_entries(struct acpi_ctx *ctx, int core,
+ int cores_per_package)
+{
+ int ratio_min, ratio_max, ratio_turbo, ratio_step;
+ int coord_type, power_max, num_entries;
+ int ratio, power, clock, clock_max;
+ bool turbo;
+
+ coord_type = cpu_get_coord_type();
+ ratio_min = cpu_get_min_ratio();
+ ratio_max = cpu_get_max_ratio();
+ clock_max = (ratio_max * cpu_get_bus_clock_khz()) / 1000;
+ turbo = (turbo_get_state() == TURBO_ENABLED);
+
+ /* Calculate CPU TDP in mW */
+ power_max = cpu_get_power_max();
+
+ /* Write _PCT indicating use of FFixedHW */
+ acpigen_write_empty_pct(ctx);
+
+ /* Write _PPC with no limit on supported P-state */
+ acpigen_write_ppc_nvs(ctx);
+ /* Write PSD indicating configured coordination type */
+ acpigen_write_psd_package(ctx, core, 1, coord_type);
+
+ /* Add P-state entries in _PSS table */
+ acpigen_write_name(ctx, "_PSS");
+
+ /* Determine ratio points */
+ ratio_step = PSS_RATIO_STEP;
+ do {
+ num_entries = ((ratio_max - ratio_min) / ratio_step) + 1;
+ if (((ratio_max - ratio_min) % ratio_step) > 0)
+ num_entries += 1;
+ if (turbo)
+ num_entries += 1;
+ if (num_entries > PSS_MAX_ENTRIES)
+ ratio_step += 1;
+ } while (num_entries > PSS_MAX_ENTRIES);
+
+ /* _PSS package count depends on Turbo */
+ acpigen_write_package(ctx, num_entries);
+
+ /* P[T] is Turbo state if enabled */
+ if (turbo) {
+ ratio_turbo = cpu_get_max_turbo_ratio();
+
+ /* Add entry for Turbo ratio */
+ acpigen_write_pss_package(ctx, clock_max + 1, /* MHz */
+ power_max, /* mW */
+ PSS_LATENCY_TRANSITION,/* lat1 */
+ PSS_LATENCY_BUSMASTER,/* lat2 */
+ ratio_turbo << 8, /* control */
+ ratio_turbo << 8); /* status */
+ num_entries -= 1;
+ }
+
+ /* First regular entry is max non-turbo ratio */
+ acpigen_write_pss_package(ctx, clock_max, /* MHz */
+ power_max, /* mW */
+ PSS_LATENCY_TRANSITION,/* lat1 */
+ PSS_LATENCY_BUSMASTER,/* lat2 */
+ ratio_max << 8, /* control */
+ ratio_max << 8); /* status */
+ num_entries -= 1;
+
+ /* Generate the remaining entries */
+ for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
+ ratio >= ratio_min; ratio -= ratio_step) {
+ /* Calculate power at this ratio */
+ power = calculate_power(power_max, ratio_max, ratio);
+ clock = (ratio * cpu_get_bus_clock_khz()) / 1000;
+
+ acpigen_write_pss_package(ctx, clock, /* MHz */
+ power, /* mW */
+ PSS_LATENCY_TRANSITION,/* lat1 */
+ PSS_LATENCY_BUSMASTER,/* lat2 */
+ ratio << 8, /* control */
+ ratio << 8); /* status */
+ }
+ /* Fix package length */
+ acpigen_pop_len(ctx);
+}
+
+void generate_t_state_entries(struct acpi_ctx *ctx, int core,
+ int cores_per_package, struct acpi_tstate *entry,
+ int nentries)
+{
+ if (!nentries)
+ return;
+
+ /* Indicate SW_ALL coordination for T-states */
+ acpigen_write_tsd_package(ctx, core, cores_per_package, SW_ALL);
+
+ /* Indicate FixedHW so OS will use MSR */
+ acpigen_write_empty_ptc(ctx);
+
+ /* Set NVS controlled T-state limit */
+ acpigen_write_tpc(ctx, "\\TLVL");
+
+ /* Write TSS table for MSR access */
+ acpigen_write_tss_package(ctx, entry, nentries);
+}
+
+int acpi_generate_cpu_header(struct acpi_ctx *ctx, int core_id,
+ const struct acpi_cstate *c_state_map,
+ int num_cstates)
+{
+ bool is_first = !core_id;
+
+ /* Generate processor \_PR.CPUx */
+ acpigen_write_processor(ctx, core_id, is_first ? ACPI_BASE_ADDRESS : 0,
+ is_first ? 6 : 0);
+
+ /* Generate C-state tables */
+ acpigen_write_cst_package(ctx, c_state_map, num_cstates);
+
+ return 0;
+}
+
+int acpi_generate_cpu_package_final(struct acpi_ctx *ctx, int cores_per_package)
+{
+ /*
+ * PPKG is usually used for thermal management of the first and only
+ * package
+ */
+ acpigen_write_processor_package(ctx, "PPKG", 0, cores_per_package);
+
+ /* Add a method to notify processor nodes */
+ acpigen_write_processor_cnot(ctx, cores_per_package);
+
+ return 0;
+}
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c
index 509730aea96..39aa0f63c65 100644
--- a/arch/x86/cpu/intel_common/cpu.c
+++ b/arch/x86/cpu/intel_common/cpu.c
@@ -12,6 +12,7 @@
#include <dm.h>
#include <errno.h>
#include <log.h>
+#include <acpi/acpigen.h>
#include <asm/cpu.h>
#include <asm/cpu_common.h>
#include <asm/intel_regs.h>
@@ -126,6 +127,7 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk)
info->cpu_freq = ((msr.lo >> 8) & 0xff) * bclk * 1000000;
info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU |
1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID;
+ info->address_width = cpu_phys_address_size();
return 0;
}
@@ -227,3 +229,80 @@ void cpu_set_eist(bool eist_status)
msr.lo &= ~MISC_ENABLE_ENHANCED_SPEEDSTEP;
msr_write(MSR_IA32_MISC_ENABLE, msr);
}
+
+int cpu_get_coord_type(void)
+{
+ return HW_ALL;
+}
+
+int cpu_get_min_ratio(void)
+{
+ msr_t msr;
+
+ /* Get bus ratio limits and calculate clock speeds */
+ msr = msr_read(MSR_PLATFORM_INFO);
+
+ return (msr.hi >> 8) & 0xff; /* Max Efficiency Ratio */
+}
+
+int cpu_get_max_ratio(void)
+{
+ u32 ratio_max;
+ msr_t msr;
+
+ if (cpu_config_tdp_levels()) {
+ /* Set max ratio to nominal TDP ratio */
+ msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
+ ratio_max = msr.lo & 0xff;
+ } else {
+ msr = msr_read(MSR_PLATFORM_INFO);
+ /* Max Non-Turbo Ratio */
+ ratio_max = (msr.lo >> 8) & 0xff;
+ }
+
+ return ratio_max;
+}
+
+int cpu_get_bus_clock_khz(void)
+{
+ /*
+ * CPU bus clock is set by default here to 100MHz. This function returns
+ * the bus clock in KHz.
+ */
+ return INTEL_BCLK_MHZ * 1000;
+}
+
+int cpu_get_power_max(void)
+{
+ int power_unit;
+ msr_t msr;
+
+ msr = msr_read(MSR_PKG_POWER_SKU_UNIT);
+ power_unit = 2 << ((msr.lo & 0xf) - 1);
+ msr = msr_read(MSR_PKG_POWER_SKU);
+
+ return (msr.lo & 0x7fff) * 1000 / power_unit;
+}
+
+int cpu_get_max_turbo_ratio(void)
+{
+ msr_t msr;
+
+ msr = msr_read(MSR_TURBO_RATIO_LIMIT);
+
+ return msr.lo & 0xff;
+}
+
+int cpu_get_cores_per_package(void)
+{
+ struct cpuid_result result;
+ int cores = 1;
+
+ if (gd->arch.x86_vendor != X86_VENDOR_INTEL)
+ return 1;
+
+ result = cpuid_ext(0xb, 1);
+ cores = result.ebx & 0xff;
+
+ return cores;
+}
diff --git a/arch/x86/cpu/intel_common/generic_wifi.c b/arch/x86/cpu/intel_common/generic_wifi.c
new file mode 100644
index 00000000000..61ec5391b09
--- /dev/null
+++ b/arch/x86/cpu/intel_common/generic_wifi.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generic WiFi ACPI info
+ *
+ * Copyright 2019 Google LLC
+ * Modified from coreboot src/drivers/wifi/generic.c
+ */
+
+#include <common.h>
+#include <log.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <dm.h>
+#include <dm/acpi.h>
+
+/* WRDS Spec Revision */
+#define WRDS_REVISION 0x0
+
+/* EWRD Spec Revision */
+#define EWRD_REVISION 0x0
+
+/* WRDS Domain type */
+#define WRDS_DOMAIN_TYPE_WIFI 0x7
+
+/* EWRD Domain type */
+#define EWRD_DOMAIN_TYPE_WIFI 0x7
+
+/* WGDS Domain type */
+#define WGDS_DOMAIN_TYPE_WIFI 0x7
+
+/*
+ * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
+ * The above representation returns unique and consistent name every time
+ * generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
+ * chosen since it contains the bus address of the device.
+ */
+#define WIFI_ACPI_NAME_MAX_LEN 5
+
+/**
+ * struct generic_wifi_config - Data structure to contain common wifi config
+ * @wake: Wake pin for ACPI _PRW
+ * @maxsleep: Maximum sleep state to wake from
+ */
+struct generic_wifi_config {
+ unsigned int wake;
+ unsigned int maxsleep;
+};
+
+static int generic_wifi_fill_ssdt(struct acpi_ctx *ctx,
+ const struct udevice *dev,
+ const struct generic_wifi_config *config)
+{
+ char name[ACPI_NAME_MAX];
+ char path[ACPI_PATH_MAX];
+ pci_dev_t bdf;
+ u32 address;
+ int ret;
+
+ ret = acpi_device_path(dev_get_parent(dev), path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, path);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_integer(ctx, "_UID", 0);
+ acpigen_write_name_string(ctx, "_DDN",
+ dev_read_string(dev, "acpi,ddn"));
+
+ /* Address */
+ bdf = dm_pci_get_bdf(dev);
+ address = (PCI_DEV(bdf) << 16) | PCI_FUNC(bdf);
+ acpigen_write_name_dword(ctx, "_ADR", address);
+
+ /* Wake capabilities */
+ if (config)
+ acpigen_write_prw(ctx, config->wake, config->maxsleep);
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
+static int intel_wifi_acpi_fill_ssdt(const struct udevice *dev,
+ struct acpi_ctx *ctx)
+{
+ struct generic_wifi_config config;
+ bool have_config;
+ int ret;
+
+ ret = dev_read_u32(dev, "acpi,wake", &config.wake);
+ have_config = !ret;
+ /* By default, all intel wifi chips wake from S3 */
+ config.maxsleep = 3;
+ ret = generic_wifi_fill_ssdt(ctx, dev, have_config ? &config : NULL);
+ if (ret)
+ return log_msg_ret("wifi", ret);
+
+ return 0;
+}
+
+struct acpi_ops wifi_acpi_ops = {
+ .fill_ssdt = intel_wifi_acpi_fill_ssdt,
+};
+
+static const struct udevice_id intel_wifi_ids[] = {
+ { .compatible = "intel,generic-wifi" },
+ { }
+};
+
+U_BOOT_DRIVER(intel_wifi) = {
+ .name = "intel_wifi",
+ .id = UCLASS_MISC,
+ .of_match = intel_wifi_ids,
+ ACPI_OPS_PTR(&wifi_acpi_ops)
+};
diff --git a/arch/x86/cpu/intel_common/intel_opregion.c b/arch/x86/cpu/intel_common/intel_opregion.c
new file mode 100644
index 00000000000..4e6c64d9aaa
--- /dev/null
+++ b/arch/x86/cpu/intel_common/intel_opregion.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Writing IntelGraphicsMem table for ACPI
+ *
+ * Copyright 2019 Google LLC
+ * Modified from coreboot src/soc/intel/gma/opregion.c
+ */
+
+#include <common.h>
+#include <binman.h>
+#include <bloblist.h>
+#include <dm.h>
+#include <spi_flash.h>
+#include <asm/intel_opregion.h>
+
+static char vbt_data[8 << 10];
+
+static int locate_vbt(char **vbtp, int *sizep)
+{
+ struct binman_entry vbt;
+ struct udevice *dev;
+ u32 vbtsig = 0;
+ int size;
+ int ret;
+
+ ret = binman_entry_find("intel-vbt", &vbt);
+ if (ret)
+ return log_msg_ret("find VBT", ret);
+ ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
+ if (ret)
+ return log_msg_ret("find flash", ret);
+ size = vbt.size;
+ if (size > sizeof(vbt_data))
+ return log_msg_ret("vbt", -E2BIG);
+ ret = spi_flash_read_dm(dev, vbt.image_pos, size, vbt_data);
+ if (ret)
+ return log_msg_ret("read", ret);
+
+ memcpy(&vbtsig, vbt_data, sizeof(vbtsig));
+ if (vbtsig != VBT_SIGNATURE) {
+ log_err("Missing/invalid signature in VBT data file!\n");
+ return -EINVAL;
+ }
+
+ log_info("Found a VBT of %u bytes\n", size);
+ *sizep = size;
+ *vbtp = vbt_data;
+
+ return 0;
+}
+
+/* Write ASLS PCI register and prepare SWSCI register */
+static int intel_gma_opregion_register(struct udevice *dev, ulong opregion)
+{
+ int sci_reg;
+
+ if (!device_active(dev))
+ return -ENOENT;
+
+ /*
+ * Intel BIOS Specification
+ * Chapter 5.3.7 "Initialise Hardware State"
+ */
+ dm_pci_write_config32(dev, ASLS, opregion);
+
+ /*
+ * Atom-based platforms use a combined SMI/SCI register,
+ * whereas non-Atom platforms use a separate SCI register
+ */
+ if (IS_ENABLED(CONFIG_INTEL_GMA_SWSMISCI))
+ sci_reg = SWSMISCI;
+ else
+ sci_reg = SWSCI;
+
+ /*
+ * Intel's Windows driver relies on this:
+ * Intel BIOS Specification
+ * Chapter 5.4 "ASL Software SCI Handler"
+ */
+ dm_pci_clrset_config16(dev, sci_reg, GSSCIE, SMISCISEL);
+
+ return 0;
+}
+
+int intel_gma_init_igd_opregion(struct udevice *dev,
+ struct igd_opregion *opregion)
+{
+ struct optionrom_vbt *vbt = NULL;
+ char *vbt_buf;
+ int vbt_size;
+ int ret;
+
+ ret = locate_vbt(&vbt_buf, &vbt_size);
+ if (ret) {
+ log_err("GMA: VBT couldn't be found\n");
+ return log_msg_ret("find vbt", ret);
+ }
+ vbt = (struct optionrom_vbt *)vbt_buf;
+
+ memset(opregion, '\0', sizeof(struct igd_opregion));
+
+ memcpy(&opregion->header.signature, IGD_OPREGION_SIGNATURE,
+ sizeof(opregion->header.signature));
+ memcpy(opregion->header.vbios_version, vbt->coreblock_biosbuild,
+ ARRAY_SIZE(vbt->coreblock_biosbuild));
+ /* Extended VBT support */
+ if (vbt->hdr_vbt_size > sizeof(opregion->vbt.gvd1)) {
+ struct optionrom_vbt *ext_vbt;
+
+ ret = bloblist_ensure_size(BLOBLISTT_INTEL_VBT,
+ vbt->hdr_vbt_size,
+ (void **)&ext_vbt);
+ if (ret) {
+ log_err("GMA: Unable to add Ext VBT to bloblist\n");
+ return log_msg_ret("blob", ret);
+ }
+
+ memcpy(ext_vbt, vbt, vbt->hdr_vbt_size);
+ opregion->mailbox3.rvda = (uintptr_t)ext_vbt;
+ opregion->mailbox3.rvds = vbt->hdr_vbt_size;
+ } else {
+ /* Raw VBT size which can fit in gvd1 */
+ printf("copy to %p\n", opregion->vbt.gvd1);
+ memcpy(opregion->vbt.gvd1, vbt, vbt->hdr_vbt_size);
+ }
+
+ /* 8kb */
+ opregion->header.size = sizeof(struct igd_opregion) / 1024;
+
+ /*
+ * Left-shift version field to accommodate Intel Windows driver quirk
+ * when not using a VBIOS.
+ * Required for Legacy boot + NGI, UEFI + NGI, and UEFI + GOP driver.
+ *
+ * No adverse effects when using VBIOS or booting Linux.
+ */
+ opregion->header.version = IGD_OPREGION_VERSION << 24;
+
+ /* We just assume we're mobile for now */
+ opregion->header.mailboxes = MAILBOXES_MOBILE;
+
+ /* Initialise Mailbox 1 */
+ opregion->mailbox1.clid = 1;
+
+ /* Initialise Mailbox 3 */
+ opregion->mailbox3.bclp = IGD_BACKLIGHT_BRIGHTNESS;
+ opregion->mailbox3.pfit = IGD_FIELD_VALID | IGD_PFIT_STRETCH;
+ opregion->mailbox3.pcft = 0; /* should be (IMON << 1) & 0x3e */
+ opregion->mailbox3.cblv = IGD_FIELD_VALID | IGD_INITIAL_BRIGHTNESS;
+ opregion->mailbox3.bclm[0] = IGD_WORD_FIELD_VALID + 0x0000;
+ opregion->mailbox3.bclm[1] = IGD_WORD_FIELD_VALID + 0x0a19;
+ opregion->mailbox3.bclm[2] = IGD_WORD_FIELD_VALID + 0x1433;
+ opregion->mailbox3.bclm[3] = IGD_WORD_FIELD_VALID + 0x1e4c;
+ opregion->mailbox3.bclm[4] = IGD_WORD_FIELD_VALID + 0x2866;
+ opregion->mailbox3.bclm[5] = IGD_WORD_FIELD_VALID + 0x327f;
+ opregion->mailbox3.bclm[6] = IGD_WORD_FIELD_VALID + 0x3c99;
+ opregion->mailbox3.bclm[7] = IGD_WORD_FIELD_VALID + 0x46b2;
+ opregion->mailbox3.bclm[8] = IGD_WORD_FIELD_VALID + 0x50cc;
+ opregion->mailbox3.bclm[9] = IGD_WORD_FIELD_VALID + 0x5ae5;
+ opregion->mailbox3.bclm[10] = IGD_WORD_FIELD_VALID + 0x64ff;
+
+ /* Write ASLS PCI register and prepare SWSCI register */
+ ret = intel_gma_opregion_register(dev, (ulong)opregion);
+ if (ret)
+ return log_msg_ret("write asls", ret);
+
+ return 0;
+}
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c
index 2468d88a80a..5180eb06fcd 100644
--- a/arch/x86/cpu/mtrr.c
+++ b/arch/x86/cpu/mtrr.c
@@ -19,6 +19,7 @@
#include <common.h>
#include <cpu_func.h>
#include <log.h>
+#include <sort.h>
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/mp.h>
@@ -66,9 +67,10 @@ static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size)
void mtrr_read_all(struct mtrr_info *info)
{
+ int reg_count = mtrr_get_var_count();
int i;
- for (i = 0; i < MTRR_COUNT; i++) {
+ for (i = 0; i < reg_count; i++) {
info->mtrr[i].base = native_read_msr(MTRR_PHYS_BASE_MSR(i));
info->mtrr[i].mask = native_read_msr(MTRR_PHYS_MASK_MSR(i));
}
@@ -76,10 +78,11 @@ void mtrr_read_all(struct mtrr_info *info)
void mtrr_write_all(struct mtrr_info *info)
{
+ int reg_count = mtrr_get_var_count();
struct mtrr_state state;
int i;
- for (i = 0; i < MTRR_COUNT; i++) {
+ for (i = 0; i < reg_count; i++) {
mtrr_open(&state, true);
wrmsrl(MTRR_PHYS_BASE_MSR(i), info->mtrr[i].base);
wrmsrl(MTRR_PHYS_MASK_MSR(i), info->mtrr[i].mask);
@@ -124,6 +127,16 @@ static int mtrr_copy_to_aps(void)
return 0;
}
+static int h_comp_mtrr(const void *p1, const void *p2)
+{
+ const struct mtrr_request *req1 = p1;
+ const struct mtrr_request *req2 = p2;
+
+ s64 diff = req1->start - req2->start;
+
+ return diff < 0 ? -1 : diff > 0 ? 1 : 0;
+}
+
int mtrr_commit(bool do_caches)
{
struct mtrr_request *req = gd->arch.mtrr_req;
@@ -139,12 +152,13 @@ int mtrr_commit(bool do_caches)
debug("open\n");
mtrr_open(&state, do_caches);
debug("open done\n");
+ qsort(req, gd->arch.mtrr_req_count, sizeof(*req), h_comp_mtrr);
for (i = 0; i < gd->arch.mtrr_req_count; i++, req++)
set_var_mtrr(i, req->type, req->start, req->size);
/* Clear the ones that are unused */
debug("clear\n");
- for (; i < MTRR_COUNT; i++)
+ for (; i < MTRR_MAX_COUNT; i++)
wrmsrl(MTRR_PHYS_MASK_MSR(i), 0);
debug("close\n");
mtrr_close(&state, do_caches);
@@ -184,7 +198,7 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
return 0;
}
-static int get_var_mtrr_count(void)
+int mtrr_get_var_count(void)
{
return msr_read(MSR_MTRR_CAP_MSR).lo & MSR_MTRR_CAP_VCNT;
}
@@ -195,7 +209,7 @@ static int get_free_var_mtrr(void)
int vcnt;
int i;
- vcnt = get_var_mtrr_count();
+ vcnt = mtrr_get_var_count();
/* Identify the first var mtrr which is not valid */
for (i = 0; i < vcnt; i++) {
diff --git a/arch/x86/cpu/tangier/Kconfig b/arch/x86/cpu/tangier/Kconfig
index d2b7edecd60..571470c74b2 100644
--- a/arch/x86/cpu/tangier/Kconfig
+++ b/arch/x86/cpu/tangier/Kconfig
@@ -12,6 +12,7 @@ config INTEL_TANGIER
imply MMC_SDHCI_TANGIER
imply USB
imply USB_DWC3
+ imply BINMAN
if INTEL_TANGIER
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c
index 1b4d3971b04..90a766c3c57 100644
--- a/arch/x86/cpu/x86_64/cpu.c
+++ b/arch/x86/cpu/x86_64/cpu.c
@@ -70,3 +70,8 @@ int x86_cpu_reinit_f(void)
{
return 0;
}
+
+int cpu_phys_address_size(void)
+{
+ return CONFIG_CPU_ADDR_BITS;
+}