u-boot/arch/x86/cpu/apollolake/acpi.c
Maximilian Brune f5f7962091 acpi: x86: Write FADT in common code
Write the FADT in common code since it's used on all architectures.
Since the FADT is mandatory all SoCs or mainboards must implement the
introduced function acpi_fill_fadt() and properly update the FADT.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Bin Meng <bmeng.cn@gmail.com>
2024-10-27 17:12:44 -06:00

218 lines
5.4 KiB
C

// 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 <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;
}
/**
* chromeos_init_acpi() - Initialise basic data to boot Chrome OS
*
* This tells Chrome OS to boot in developer mode
*
* @cros: Structure to initialise
*/
static void chromeos_init_acpi(struct chromeos_acpi_gnvs *cros)
{
cros->active_main_fw = 1;
cros->active_main_fw = 1; /* A */
cros->switches = CHSW_DEVELOPER_SWITCH;
cros->main_fw_type = 2; /* Developer */
}
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 */
if (IS_ENABLED(CONFIG_CHROMEOS))
chromeos_init_acpi(&gnvs->chromeos);
/* 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;
}
gnvs->dpte = 1;
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 acpi_fill_fadt(struct acpi_fadt *fadt)
{
intel_acpi_fill_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;
fadt->preferred_pm_profile = ACPI_PM_MOBILE;
}
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;
}