[PATCH v4 00/59] dm: Add programatic generation of ACPI tables (part D)

classic Classic list List threaded Threaded
62 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

[PATCH v4 20/59] x86: Add some definitions for SMM

Simon Glass-3
U-Boot does not support SMM (System Management Mode) at present, but needs
a few definitions to correctly set up the ACPI table. Add these.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 arch/x86/include/asm/smm.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 arch/x86/include/asm/smm.h

diff --git a/arch/x86/include/asm/smm.h b/arch/x86/include/asm/smm.h
new file mode 100644
index 00000000000..1e539fda067
--- /dev/null
+++ b/arch/x86/include/asm/smm.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SMM definitions (U-Boot does not support SMM itself)
+ *
+ * Copyright (C) 2008-2009 coresystems GmbH
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot smm.h
+ */
+
+#ifndef _ASM_SMM_H
+#define _ASM_SMM_H
+
+#define APM_CNT 0xb2
+#define APM_CNT_CST_CONTROL 0x85
+#define APM_CNT_PST_CONTROL 0x80
+#define APM_CNT_ACPI_DISABLE 0x1e
+#define APM_CNT_ACPI_ENABLE 0xe1
+#define APM_CNT_MBI_UPDATE 0xeb
+#define APM_CNT_GNVS_UPDATE 0xea
+#define APM_CNT_FINALIZE 0xcb
+#define APM_CNT_LEGACY 0xcc
+#define APM_CNT_SMMSTORE 0xed
+#define APM_CNT_ELOG_GSMI 0xef
+#define APM_STS 0xb3
+
+#endif /* _ASM_SMM_H */
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 21/59] x86: apl: Add power-management definitions

Simon Glass-3
In reply to this post by Simon Glass-3
Add SCI and power-state definitions required by ACPI tables. Fix the
license to match the original source file.

Als update the guard on acpi_pmc.h to avoid an error when buiding ASL.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Use SHIFT and MASK for defines

 arch/x86/include/asm/arch-apollolake/pm.h | 40 ++++++++++++++++++++++-
 include/power/acpi_pmc.h                  |  4 +--
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/arch-apollolake/pm.h b/arch/x86/include/asm/arch-apollolake/pm.h
index 6718290c4fe..9a8d971e910 100644
--- a/arch/x86/include/asm/arch-apollolake/pm.h
+++ b/arch/x86/include/asm/arch-apollolake/pm.h
@@ -1,12 +1,15 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2015-2016 Intel Corp.
  * (Written by Lance Zhao <[hidden email]> for Intel Corp.)
+ * Copyright 2019 Google LLC
  */
 
 #ifndef _ASM_ARCH_PM_H
 #define _ASM_ARCH_PM_H
 
+#include <power/acpi_pmc.h>
+
 #define PMC_GPE_SW_31_0 0
 #define PMC_GPE_SW_63_32 1
 #define PMC_GPE_NW_31_0 3
@@ -16,4 +19,39 @@
 #define PMC_GPE_N_63_32 7
 #define PMC_GPE_W_31_0 9
 
+#define IRQ_REG 0x106c
+#define SCI_IRQ_SHIFT 24
+#define SCI_IRQ_MASK (0xff << SCI_IRQ_SHIFT)
+#define SCIS_IRQ9 9
+#define SCIS_IRQ10 10
+#define SCIS_IRQ11 11
+#define SCIS_IRQ20 20
+#define SCIS_IRQ21 21
+#define SCIS_IRQ22 22
+#define SCIS_IRQ23 23
+
+/* P-state configuration */
+#define PSS_MAX_ENTRIES 8
+#define PSS_RATIO_STEP 2
+#define PSS_LATENCY_TRANSITION 10
+#define PSS_LATENCY_BUSMASTER 10
+
+#ifndef __ASSEMBLY__
+/* Track power state from reset to log events */
+struct __packed chipset_power_state {
+ u16 pm1_sts;
+ u16 pm1_en;
+ u32 pm1_cnt;
+ u32 gpe0_sts[GPE0_REG_MAX];
+ u32 gpe0_en[GPE0_REG_MAX];
+ u16 tco1_sts;
+ u16 tco2_sts;
+ u32 prsts;
+ u32 gen_pmcon1;
+ u32 gen_pmcon2;
+ u32 gen_pmcon3;
+ u32 prev_sleep_state;
+};
+#endif /* !__ASSEMBLY__ */
+
 #endif
diff --git a/include/power/acpi_pmc.h b/include/power/acpi_pmc.h
index 5fbf7451369..222288b71a4 100644
--- a/include/power/acpi_pmc.h
+++ b/include/power/acpi_pmc.h
@@ -6,7 +6,7 @@
 #ifndef __ACPI_PMC_H
 #define __ACPI_PMC_H
 
-#ifndef __ACPI__
+#ifndef __ASSEMBLY__
 
 enum {
  GPE0_REG_MAX = 4,
@@ -194,6 +194,6 @@ void pmc_dump_info(struct udevice *dev);
  */
 int pmc_gpe_init(struct udevice *dev);
 
-#endif /* !__ACPI__ */
+#endif /* !__ASSEMBLY__ */
 
 #endif
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 22/59] x86: apl: Update iomap for ACPI

Simon Glass-3
In reply to this post by Simon Glass-3
Add some more definitions to the iomap. These will be used by
ACPI-generation code as well as the device tree.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 arch/x86/include/asm/arch-apollolake/iomap.h | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/x86/include/asm/arch-apollolake/iomap.h b/arch/x86/include/asm/arch-apollolake/iomap.h
index 4ce10170558..21c5f33021a 100644
--- a/arch/x86/include/asm/arch-apollolake/iomap.h
+++ b/arch/x86/include/asm/arch-apollolake/iomap.h
@@ -11,11 +11,27 @@
 
 /* Put p2sb at 0xd0000000 in TPL */
 #define IOMAP_P2SB_BAR 0xd0000000
+#define IOMAP_P2SB_SIZE 0x10000000
 
 #define IOMAP_SPI_BASE 0xfe010000
 
 #define IOMAP_ACPI_BASE 0x400
 #define IOMAP_ACPI_SIZE 0x100
+#define ACPI_BASE_ADDRESS IOMAP_ACPI_BASE
+
+#define PMC_BAR0 0xfe042000
+
+#define MCH_BASE_ADDRESS 0xfed10000
+#define MCH_SIZE 0x8000
+
+#ifdef __ACPI__
+#define HPET_BASE_ADDRESS 0xfed00000
+
+#define SRAM_BASE_0 0xfe900000
+#define SRAM_SIZE_0 (8 * KiB)
+#define SRAM_BASE_2 0xfe902000
+#define SRAM_SIZE_2 (4 * KiB)
+#endif
 
 /*
  * Use UART2. To use UART1 you need to set '2' to '1', change device tree serial
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 23/59] x86: Add a few common Intel CPU functions

Simon Glass-3
In reply to this post by Simon Glass-3
Add functions to query CPU information, needed for ACPI.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Add more comments and rename cpu_get_bus_clock to cpu_get_bus_clock_khz()

 arch/x86/cpu/intel_common/cpu.c   | 64 +++++++++++++++++++++++++++++++
 arch/x86/include/asm/cpu_common.h | 49 +++++++++++++++++++++++
 include/acpi/acpigen.h            | 12 ++++++
 3 files changed, 125 insertions(+)

diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c
index 509730aea96..cb4ef84013a 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>
@@ -227,3 +228,66 @@ 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;
+}
diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h
index cdd99a90b76..a7b7112d417 100644
--- a/arch/x86/include/asm/cpu_common.h
+++ b/arch/x86/include/asm/cpu_common.h
@@ -128,4 +128,53 @@ void cpu_set_eist(bool eist_status);
  */
 void cpu_set_p_state_to_turbo_ratio(void);
 
+/**
+ * cpu_get_coord_type() - Get the type of coordination for P-State transition
+ *
+ * See ACPI spec v6.3 section 8.4.6.5 _PSD (P-State Dependency)
+ *
+ * @return HW_ALL (always)
+ */
+int cpu_get_coord_type(void);
+
+/**
+ * cpu_get_min_ratio() - get minimum support frequency ratio for CPU
+ *
+ * @return minimum ratio
+ */
+int cpu_get_min_ratio(void);
+
+/**
+ * cpu_get_max_ratio() - get nominal TDP ration or max non-turbo ratio
+ *
+ * If a nominal TDP ratio is available, it is returned. Otherwise this returns
+ * the  maximum non-turbo frequency ratio for this processor
+ *
+ * @return max ratio
+ */
+int cpu_get_max_ratio(void);
+
+/**
+ * cpu_get_bus_clock_khz() - Get the bus clock frequency in KHz
+ *
+ * This is the value the clock ratio is multiplied with
+ *
+ * @return bus-block frequency in KHz
+ */
+int cpu_get_bus_clock_khz(void);
+
+/**
+ * cpu_get_power_max() - Get maximum CPU TDP
+ *
+ * @return maximum CPU TDP (Thermal-design power) in mW
+ */
+int cpu_get_power_max(void);
+
+/**
+ * cpu_get_max_turbo_ratio() - Get maximum turbo ratio
+ *
+ * @return maximum ratio
+ */
+int cpu_get_max_turbo_ratio(void);
+
 #endif
diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 34b3115bc9c..c412898169e 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -73,6 +73,18 @@ enum {
  RETURN_OP = 0xa4,
 };
 
+/**
+ * enum psd_coord - Coordination types for P-states
+ *
+ * The type of coordination that exists (hardware) or is required (software) as
+ * a result of the underlying hardware dependency
+ */
+enum psd_coord {
+ SW_ALL = 0xfc,
+ SW_ANY = 0xfd,
+ HW_ALL = 0xfe
+};
+
 /**
  * acpigen_get_current() - Get the current ACPI code output pointer
  *
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 24/59] x86: acpi: Support generation of the HPET table

Simon Glass-3
In reply to this post by Simon Glass-3
Add an implementation of the HPET (High Precision Event Timer) ACPI
table. Since this is x86-specific, put it in an x86-specific file

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Put this code in an x86-specific place and update commit message

 arch/x86/include/asm/acpi_table.h | 10 ++++++
 arch/x86/lib/acpi_table.c         | 59 +++++++++++++++++++++++++++++++
 include/acpi/acpi_table.h         | 31 +++++++++++-----
 3 files changed, 91 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 733085c1785..7047ee6c772 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -36,6 +36,16 @@ int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base,
 u32 acpi_fill_mcfg(u32 current);
 u32 acpi_fill_csrt(u32 current);
 
+/**
+ * acpi_write_hpet() - Write out a HPET table
+ *
+ * Write out the table for High-Precision Event Timers
+ *
+ * @ctx: Current ACPI context
+ * @return 0 if OK, -ve on error
+ */
+int acpi_write_hpet(struct acpi_ctx *ctx);
+
 /**
  * acpi_create_gnvs() - Create a GNVS (Global Non Volatile Storage) table
  *
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 36ef3e5f0b7..0080c96cfe7 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -529,3 +529,62 @@ ulong acpi_get_rsdp_addr(void)
 {
  return acpi_rsdp_addr;
 }
+
+/**
+ * acpi_write_hpet() - Write out a HPET table
+ *
+ * Write out the table for High-Precision Event Timers
+ *
+ * @hpet: Place to put HPET table
+ */
+static int acpi_create_hpet(struct acpi_hpet *hpet)
+{
+ struct acpi_table_header *header = &hpet->header;
+ struct acpi_gen_regaddr *addr = &hpet->addr;
+
+ /*
+ * See IA-PC HPET (High Precision Event Timers) Specification v1.0a
+ * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
+ */
+ memset((void *)hpet, '\0', sizeof(struct acpi_hpet));
+
+ /* Fill out header fields. */
+ acpi_fill_header(header, "HPET");
+
+ header->aslc_revision = ASL_REVISION;
+ header->length = sizeof(struct acpi_hpet);
+ header->revision = acpi_get_table_revision(ACPITAB_HPET);
+
+ /* Fill out HPET address */
+ addr->space_id = 0;  /* Memory */
+ addr->bit_width = 64;
+ addr->bit_offset = 0;
+ addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
+ addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
+
+ hpet->id = *(u32 *)CONFIG_HPET_ADDRESS;
+ hpet->number = 0;
+ hpet->min_tick = 0; /* HPET_MIN_TICKS */
+
+ header->checksum = table_compute_checksum(hpet,
+  sizeof(struct acpi_hpet));
+
+ return 0;
+}
+
+int acpi_write_hpet(struct acpi_ctx *ctx)
+{
+ struct acpi_hpet *hpet;
+ int ret;
+
+ log_debug("ACPI:    * HPET\n");
+
+ hpet = ctx->current;
+ acpi_inc_align(ctx, sizeof(struct acpi_hpet));
+ acpi_create_hpet(hpet);
+ ret = acpi_add_table(ctx, hpet);
+ if (ret)
+ return log_msg_ret("add", ret);
+
+ return 0;
+}
diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h
index fe9b29f3f82..f8140446a59 100644
--- a/include/acpi/acpi_table.h
+++ b/include/acpi/acpi_table.h
@@ -20,6 +20,9 @@
 #define OEM_TABLE_ID "U-BOOTBL" /* U-Boot Table */
 #define ASLC_ID "INTL" /* Intel ASL Compiler */
 
+/* TODO([hidden email]): Figure out how to get compiler revision */
+#define ASL_REVISION 0
+
 #define ACPI_RSDP_REV_ACPI_1_0 0
 #define ACPI_RSDP_REV_ACPI_2_0 2
 
@@ -56,6 +59,15 @@ struct __packed acpi_table_header {
  u32 aslc_revision; /* ASL compiler revision number */
 };
 
+struct acpi_gen_regaddr {
+ u8 space_id; /* Address space ID */
+ u8 bit_width; /* Register size in bits */
+ u8 bit_offset; /* Register bit offset */
+ u8 access_size; /* Access size */
+ u32 addrl; /* Register address, low 32 bits */
+ u32 addrh; /* Register address, high 32 bits */
+};
+
 /* A maximum number of 32 ACPI tables ought to be enough for now */
 #define MAX_ACPI_TABLES 32
 
@@ -71,6 +83,16 @@ struct acpi_xsdt {
  u64 entry[MAX_ACPI_TABLES];
 };
 
+/* HPET timers */
+struct __packed acpi_hpet {
+ struct acpi_table_header header;
+ u32 id;
+ struct acpi_gen_regaddr addr;
+ u8 number;
+ u16 min_tick;
+ u8 attributes;
+};
+
 /* FADT Preferred Power Management Profile */
 enum acpi_pm_profile {
  ACPI_PM_UNSPECIFIED = 0,
@@ -138,15 +160,6 @@ enum acpi_address_space_size {
  ACPI_ACCESS_SIZE_QWORD_ACCESS
 };
 
-struct acpi_gen_regaddr {
- u8 space_id; /* Address space ID */
- u8 bit_width; /* Register size in bits */
- u8 bit_offset; /* Register bit offset */
- u8 access_size; /* Access size */
- u32 addrl; /* Register address, low 32 bits */
- u32 addrh; /* Register address, high 32 bits */
-};
-
 /* FADT (Fixed ACPI Description Table) */
 struct __packed acpi_fadt {
  struct acpi_table_header header;
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 25/59] x86: acpi: Support generation of the DBG2 table

Simon Glass-3
In reply to this post by Simon Glass-3
Add an implementation of the DBG2 (Debug Port Table 2) ACPI table.
Adjust one of the header includes to be in the correct order, before
adding more.

Note that the DBG2 table is generic but the PCI UART is x86-specific at
present since it assumes an ns16550 UART. It can be generalised later
if necessary.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Move ASL_REVISION define into this patch
- Move acpi_create_dbg2() into generic code
- Update commit message

 arch/x86/include/asm/acpi_table.h | 11 ++++++
 arch/x86/lib/acpi_table.c         | 41 ++++++++++++++++++++
 include/acpi/acpi_table.h         | 40 +++++++++++++++++++
 lib/acpi/acpi_table.c             | 64 +++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+)

diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 7047ee6c772..1b7ff509516 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -46,6 +46,17 @@ u32 acpi_fill_csrt(u32 current);
  */
 int acpi_write_hpet(struct acpi_ctx *ctx);
 
+/**
+ * acpi_write_dbg2_pci_uart() - Write out a DBG2 table
+ *
+ * @ctx: Current ACPI context
+ * @dev: Debug UART device to describe
+ * @access_size: Access size for UART (e.g. ACPI_ACCESS_SIZE_DWORD_ACCESS)
+ * @return 0 if OK, -ve on error
+ */
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+     uint access_size);
+
 /**
  * acpi_create_gnvs() - Create a GNVS (Global Non Volatile Storage) table
  *
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index 0080c96cfe7..e257c789838 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -15,6 +15,7 @@
 #include <serial.h>
 #include <version.h>
 #include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
 #include <acpi/acpi_table.h>
 #include <asm/acpi/global_nvs.h>
 #include <asm/ioapic.h>
@@ -588,3 +589,43 @@ int acpi_write_hpet(struct acpi_ctx *ctx)
 
  return 0;
 }
+
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+     uint access_size)
+{
+ struct acpi_dbg2_header *dbg2 = ctx->current;
+ char path[ACPI_PATH_MAX];
+ struct acpi_gen_regaddr address;
+ phys_addr_t addr;
+ int ret;
+
+ if (!device_active(dev)) {
+ log_info("Device not enabled\n");
+ return -EACCES;
+ }
+ /*
+ * PCI devices don't remember their resource allocation information in
+ * U-Boot at present. We assume that MMIO is used for the UART and that
+ * the address space is 32 bytes: ns16550 uses 8 registers of up to
+ * 32-bits each. This is only for debugging so it is not a big deal.
+ */
+ addr = dm_pci_read_bar32(dev, 0);
+ printf("UART addr %lx\n", (ulong)addr);
+
+ memset(&address, '\0', sizeof(address));
+ address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ address.addrl = (uint32_t)addr;
+ address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
+ address.access_size = access_size;
+
+ ret = acpi_device_path(dev, path, sizeof(path));
+ if (ret)
+ return log_msg_ret("path", ret);
+ acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
+ ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
+
+ acpi_inc_align(ctx, dbg2->header.length);
+ acpi_add_table(ctx, dbg2);
+
+ return 0;
+}
diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h
index f8140446a59..c826a797f5b 100644
--- a/include/acpi/acpi_table.h
+++ b/include/acpi/acpi_table.h
@@ -448,6 +448,29 @@ struct __packed acpi_dmar {
 
 #define ACPI_DBG2_UNKNOWN 0x00FF
 
+/* DBG2: Microsoft Debug Port Table 2 header */
+struct __packed acpi_dbg2_header {
+ struct acpi_table_header header;
+ u32 devices_offset;
+ u32 devices_count;
+};
+
+/* DBG2: Microsoft Debug Port Table 2 device entry */
+struct __packed acpi_dbg2_device {
+ u8  revision;
+ u16 length;
+ u8 address_count;
+ u16 namespace_string_length;
+ u16 namespace_string_offset;
+ u16 oem_data_length;
+ u16 oem_data_offset;
+ u16 port_type;
+ u16 port_subtype;
+ u8  reserved[2];
+ u16 base_address_offset;
+ u16 address_size_offset;
+};
+
 /* SPCR (Serial Port Console Redirection table) */
 struct __packed acpi_spcr {
  struct acpi_table_header header;
@@ -522,6 +545,23 @@ int acpi_get_table_revision(enum acpi_tables table);
  */
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
 
+/**
+ * acpi_create_dbg2() - Create a DBG2 table
+ *
+ * This table describes how to access the debug UART
+ *
+ * @dbg2: Place to put information
+ * @port_type: Serial port type (see ACPI_DBG2_...)
+ * @port_subtype: Serial port sub-type (see ACPI_DBG2_...)
+ * @address: ACPI address of port
+ * @address_size: Size of address space
+ * @device_path: Path of device (created using acpi_device_path())
+ */
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+      int port_type, int port_subtype,
+      struct acpi_gen_regaddr *address, uint32_t address_size,
+      const char *device_path);
+
 /**
  * acpi_fill_header() - Set up a new table header
  *
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index acc55e7fad6..908d8903893 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -264,3 +264,67 @@ void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
  */
  acpi_align64(ctx);
 }
+
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+      int port_type, int port_subtype,
+      struct acpi_gen_regaddr *address, u32 address_size,
+      const char *device_path)
+{
+ uintptr_t current;
+ struct acpi_dbg2_device *device;
+ u32 *dbg2_addr_size;
+ struct acpi_table_header *header;
+ size_t path_len;
+ const char *path;
+ char *namespace;
+
+ /* Fill out header fields. */
+ current = (uintptr_t)dbg2;
+ memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
+ header = &dbg2->header;
+
+ header->revision = acpi_get_table_revision(ACPITAB_DBG2);
+ acpi_fill_header(header, "DBG2");
+ header->aslc_revision = ASL_REVISION;
+
+ /* One debug device defined */
+ dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
+ dbg2->devices_count = 1;
+ current += sizeof(struct acpi_dbg2_header);
+
+ /* Device comes after the header */
+ device = (struct acpi_dbg2_device *)current;
+ memset(device, 0, sizeof(struct acpi_dbg2_device));
+ current += sizeof(struct acpi_dbg2_device);
+
+ device->revision = 0;
+ device->address_count = 1;
+ device->port_type = port_type;
+ device->port_subtype = port_subtype;
+
+ /* Base Address comes after device structure */
+ memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
+ device->base_address_offset = current - (uintptr_t)device;
+ current += sizeof(struct acpi_gen_regaddr);
+
+ /* Address Size comes after address structure */
+ dbg2_addr_size = (uint32_t *)current;
+ device->address_size_offset = current - (uintptr_t)device;
+ *dbg2_addr_size = address_size;
+ current += sizeof(uint32_t);
+
+ /* Namespace string comes last, use '.' if not provided */
+ path = device_path ? : ".";
+ /* Namespace string length includes NULL terminator */
+ path_len = strlen(path) + 1;
+ namespace = (char *)current;
+ device->namespace_string_length = path_len;
+ device->namespace_string_offset = current - (uintptr_t)device;
+ strncpy(namespace, path, path_len);
+ current += path_len;
+
+ /* Update structure lengths and checksum */
+ device->length = current - (uintptr_t)device;
+ header->length = current - (uintptr_t)dbg2;
+ header->checksum = table_compute_checksum(dbg2, header->length);
+}
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 26/59] acpi: Add support for generating processor tables

Simon Glass-3
In reply to this post by Simon Glass-3
ACPI has a number of CPU-related tables. Add utility functions to write
out the basic packages.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 include/acpi/acpigen.h |  39 +++++++++++++++
 lib/acpi/acpigen.c     |  55 +++++++++++++++++++++
 test/dm/acpigen.c      | 106 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 200 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index c412898169e..3a2c6339d5e 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -64,7 +64,9 @@ enum {
  OR_OP = 0x7d,
  NOT_OP = 0x80,
  DEVICE_OP = 0x82,
+ PROCESSOR_OP = 0x83,
  POWER_RES_OP = 0x84,
+ NOTIFY_OP = 0x86,
  LEQUAL_OP = 0x93,
  TO_BUFFER_OP = 0x96,
  TO_INTEGER_OP = 0x99,
@@ -777,4 +779,41 @@ void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx);
  */
 void acpigen_write_dsm_end(struct acpi_ctx *ctx);
 
+/**
+ * acpigen_write_processor() - Write a Processor package
+ *
+ * This emits a Processor package header with the required information. The
+ * caller must complete the information and call acpigen_pop_len() at the end
+ *
+ * @ctx: ACPI context pointer
+ * @cpuindex: CPU number
+ * @pblock_addr: PBlk system IO address
+ * @pblock_len: PBlk length
+ */
+void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex,
+     u32 pblock_addr, uint pblock_len);
+
+/**
+ * acpigen_write_processor_package() - Write a package containing the processors
+ *
+ * The package containins the name of each processor in the SoC
+ *
+ * @ctx: ACPI context pointer
+ * @name: Package name (.e.g "PPKG")
+ * @first_core: Number of the first core (e.g. 0)
+ * @core_count: Number of cores (e.g. 4)
+ */
+void acpigen_write_processor_package(struct acpi_ctx *ctx, const char *name,
+     uint first_core, uint core_count);
+
+/**
+ * acpigen_write_processor_cnot() - Write a processor notification method
+ *
+ * This writes a method that notifies all CPU cores
+ *
+ * @ctx: ACPI context pointer
+ * @num_cores: Number of CPU cores
+ */
+void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index d859f378413..b9985075cde 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -17,6 +17,9 @@
 #include <acpi/acpi_table.h>
 #include <dm/acpi.h>
 
+/* CPU path format */
+#define ACPI_CPU_STRING "\\_PR.CP%02d"
+
 u8 *acpigen_get_current(struct acpi_ctx *ctx)
 {
  return ctx->current;
@@ -340,6 +343,58 @@ void acpigen_write_method_serialized(struct acpi_ctx *ctx, const char *name,
       ACPI_METHOD_SERIALIZED_MASK);
 }
 
+void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex,
+     u32 pblock_addr, uint pblock_len)
+{
+ /*
+ * Processor (\_PR.CPnn, cpuindex, pblock_addr, pblock_len)
+ * {
+ */
+ char pscope[16];
+
+ acpigen_emit_ext_op(ctx, PROCESSOR_OP);
+ acpigen_write_len_f(ctx);
+
+ snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, cpuindex);
+ acpigen_emit_namestring(ctx, pscope);
+ acpigen_emit_byte(ctx, cpuindex);
+ acpigen_emit_dword(ctx, pblock_addr);
+ acpigen_emit_byte(ctx, pblock_len);
+}
+
+void acpigen_write_processor_package(struct acpi_ctx *ctx,
+     const char *const name,
+     const uint first_core,
+     const uint core_count)
+{
+ uint i;
+ char pscope[16];
+
+ acpigen_write_name(ctx, name);
+ acpigen_write_package(ctx, core_count);
+ for (i = first_core; i < first_core + core_count; ++i) {
+ snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, i);
+ acpigen_emit_namestring(ctx, pscope);
+ }
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores)
+{
+ int core_id;
+
+ acpigen_write_method(ctx, "\\_PR.CNOT", 1);
+ for (core_id = 0; core_id < num_cores; core_id++) {
+ char buffer[30];
+
+ snprintf(buffer, sizeof(buffer), ACPI_CPU_STRING, core_id);
+ acpigen_emit_byte(ctx, NOTIFY_OP);
+ acpigen_emit_namestring(ctx, buffer);
+ acpigen_emit_byte(ctx, ARG0_OP);
+ }
+ acpigen_pop_len(ctx);
+}
+
 void acpigen_write_device(struct acpi_ctx *ctx, const char *name)
 {
  acpigen_emit_ext_op(ctx, DEVICE_OP);
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 381fcb97022..74b7e23aab3 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -1344,3 +1344,109 @@ static int dm_test_acpi_write_i2c_dsm(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_acpi_write_i2c_dsm, 0);
 
+/* Test emitting a processor */
+static int dm_test_acpi_write_processor(struct unit_test_state *uts)
+{
+ const int cpuindex = 6;
+ const u32 pblock_addr = 0x12345600;
+ const u32 pblock_len = 0x60;
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_processor(ctx, cpuindex, pblock_addr, pblock_len);
+ acpigen_pop_len(ctx);
+
+ ut_asserteq(EXT_OP_PREFIX, *ptr++);
+ ut_asserteq(PROCESSOR_OP, *ptr++);
+ ut_asserteq(0x13, acpi_test_get_length(ptr));
+ ptr += 3;
+ ut_asserteq_strn("\\._PR_CP06", (char *)ptr);
+ ptr += 10;
+ ut_asserteq(cpuindex, *ptr++);
+ ut_asserteq(pblock_addr, get_unaligned((u32 *)ptr));
+ ptr += 4;
+ ut_asserteq(pblock_len, *ptr++);
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_processor, 0);
+
+/* Test emitting a processor package */
+static int dm_test_acpi_write_processor_package(struct unit_test_state *uts)
+{
+ const int core_count = 3;
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_processor_package(ctx, "XCPU", 0, core_count);
+
+ ut_asserteq(NAME_OP, *ptr++);
+ ut_asserteq_strn("XCPU", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(core_count, *ptr++);
+
+ ut_asserteq_strn("\\._PR_CP00", (char *)ptr);
+ ptr += 10;
+ ut_asserteq_strn("\\._PR_CP01", (char *)ptr);
+ ptr += 10;
+ ut_asserteq_strn("\\._PR_CP02", (char *)ptr);
+ ptr += 10;
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_processor_package, 0);
+
+/* Test emitting a processor notification package */
+static int dm_test_acpi_write_processor_cnot(struct unit_test_state *uts)
+{
+ const int core_count = 3;
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_processor_cnot(ctx, core_count);
+
+ ut_asserteq(METHOD_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq_strn("\\._PR_CNOT", (char *)ptr);
+ ptr += 10;
+ ut_asserteq(1, *ptr++);
+
+ ut_asserteq(NOTIFY_OP, *ptr++);
+ ut_asserteq_strn("\\._PR_CP00", (char *)ptr);
+ ptr += 10;
+ ut_asserteq(ARG0_OP, *ptr++);
+ ut_asserteq(NOTIFY_OP, *ptr++);
+ ut_asserteq_strn("\\._PR_CP01", (char *)ptr);
+ ptr += 10;
+ ut_asserteq(ARG0_OP, *ptr++);
+ ut_asserteq(NOTIFY_OP, *ptr++);
+ ut_asserteq_strn("\\._PR_CP02", (char *)ptr);
+ ptr += 10;
+ ut_asserteq(ARG0_OP, *ptr++);
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_processor_cnot, 0);
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 27/59] x86: acpi: Add PCT and PTC tables

Simon Glass-3
In reply to this post by Simon Glass-3
These are needed for the CPU tables. Add them into an x86-specific file
since we do not support them on sandbox, or include tests.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Split PCT and PTC tables into a separate patch

 arch/x86/include/asm/acpigen.h | 35 +++++++++++++
 arch/x86/lib/Makefile          |  2 +-
 arch/x86/lib/acpigen.c         | 96 ++++++++++++++++++++++++++++++++++
 3 files changed, 132 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/include/asm/acpigen.h
 create mode 100644 arch/x86/lib/acpigen.c

diff --git a/arch/x86/include/asm/acpigen.h b/arch/x86/include/asm/acpigen.h
new file mode 100644
index 00000000000..c531dd61d53
--- /dev/null
+++ b/arch/x86/include/asm/acpigen.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Generation of x86-specific ACPI tables
+ *
+ * Copyright 2020 Google LLC
+ */
+
+#ifndef __ASM_ACPIGEN_H__
+#define __ASM_ACPIGEN_H__
+
+struct acpi_ctx;
+
+/**
+ * acpigen_write_empty_pct() - Write an empty PCT
+ *
+ * See ACPI v6.3 section 8.4.6.1: _PCT (Performance Control)
+ *
+ * This writes an empty table so that CPU performance works as expected
+ *
+ * @ctx: ACPI context pointer
+ */
+void acpigen_write_empty_pct(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_write_empty_ptc() - Write an empty PTC
+ *
+ * See ACPI v6.3 section 8.4.5.1: _PTC (Processor Throttling Control)
+ *
+ * This writes an empty table so that CPU performance works as expected
+ *
+ * @ctx: ACPI context pointer
+ */
+void acpigen_write_empty_ptc(struct acpi_ctx *ctx);
+
+#endif /* __ASM_ACPI_H__ */
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 1185a88c27c..f04d275dd9a 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -38,7 +38,7 @@ obj-y += sfi.o
 obj-y += acpi.o
 obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o
 ifndef CONFIG_QEMU
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o acpigen.o
 endif
 obj-y += tables.o
 ifndef CONFIG_SPL_BUILD
diff --git a/arch/x86/lib/acpigen.c b/arch/x86/lib/acpigen.c
new file mode 100644
index 00000000000..ea2ec2a9083
--- /dev/null
+++ b/arch/x86/lib/acpigen.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Google LLC
+ */
+
+#include <common.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpigen.h>
+
+void acpigen_write_empty_pct(struct acpi_ctx *ctx)
+{
+ /*
+ * Name (_PCT, Package (0x02)
+ * {
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00,               // Bit Width
+ * 0x00,               // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * },
+ *
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00,               // Bit Width
+ * 0x00,               // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * }
+ * })
+ */
+ static char stream[] = {
+ /* 00000030    "0._PCT.," */
+ 0x08, 0x5f, 0x50, 0x43, 0x54, 0x12, 0x2c,
+ /* 00000038    "........" */
+ 0x02, 0x11, 0x14, 0x0a, 0x11, 0x82, 0x0c, 0x00,
+ /* 00000040    "........" */
+ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000048    "....y..." */
+ 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x11, 0x14,
+ /* 00000050    "........" */
+ 0x0a, 0x11, 0x82, 0x0c, 0x00, 0x7f, 0x00, 0x00,
+ /* 00000058    "........" */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x79, 0x00
+ };
+ acpigen_emit_stream(ctx, stream, ARRAY_SIZE(stream));
+}
+
+void acpigen_write_empty_ptc(struct acpi_ctx *ctx)
+{
+ /*
+ * Name (_PTC, Package (0x02)
+ * {
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00,               // Bit Width
+ * 0x00,               // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * },
+ *
+ * ResourceTemplate ()
+ * {
+ * Register (FFixedHW,
+ * 0x00,               // Bit Width
+ * 0x00,               // Bit Offset
+ * 0x0000000000000000, // Address
+ * ,)
+ * }
+ * })
+ */
+ struct acpi_gen_regaddr addr = {
+ .space_id    = ACPI_ADDRESS_SPACE_FIXED,
+ .bit_width   = 0,
+ .bit_offset  = 0,
+ .access_size = 0,
+ .addrl       = 0,
+ .addrh       = 0,
+ };
+
+ acpigen_write_name(ctx, "_PTC");
+ acpigen_write_package(ctx, 2);
+
+ /* ControlRegister */
+ acpigen_write_register_resource(ctx, &addr);
+
+ /* StatusRegister */
+ acpigen_write_register_resource(ctx, &addr);
+
+ acpigen_pop_len(ctx);
+}
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 28/59] acpi: Add more support for generating processor tables

Simon Glass-3
In reply to this post by Simon Glass-3
This adds tables relating to P-States and C-States.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 include/acpi/acpigen.h | 162 +++++++++++++++++++++++
 lib/acpi/acpigen.c     | 167 +++++++++++++++++++++++
 test/dm/acpigen.c      | 294 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 623 insertions(+)

diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h
index 3a2c6339d5e..976f4dbb9af 100644
--- a/include/acpi/acpigen.h
+++ b/include/acpi/acpigen.h
@@ -10,8 +10,10 @@
 #ifndef __ACPI_ACPIGEN_H
 #define __ACPI_ACPIGEN_H
 
+#include <acpi/acpi_table.h>
 #include <linux/types.h>
 
+struct acpi_cstate;
 struct acpi_ctx;
 struct acpi_gen_regaddr;
 struct acpi_gpio;
@@ -87,6 +89,53 @@ enum psd_coord {
  HW_ALL = 0xfe
 };
 
+/**
+ * enum csd_coord -  Coordination types for C-states
+ *
+ * The type of coordination that exists (hardware) or is required (software) as
+ * a result of the underlying hardware dependency
+ */
+enum csd_coord {
+ CSD_HW_ALL = 0xfe,
+};
+
+/**
+ * struct acpi_cstate - Information about a C-State
+ *
+ * @ctype: C State type (1=C1, 2=C2, 3=C3)
+ * @latency: Worst-case latency to enter and exit the C State (in uS)
+ * @power: Average power consumption of the processor when in this C-State (mW)
+ * @resource: Register to read to place the processor in this state
+ */
+struct acpi_cstate {
+ uint ctype;
+ uint latency;
+ uint power;
+ struct acpi_gen_regaddr resource;
+};
+
+/**
+ * struct acpi_tstate - Information about a Throttling Supported State
+ *
+ * See ACPI v6.3 section 8.4.5.2: _TSS (Throttling Supported States)
+ *
+ * @percent: Percent of the core CPU operating frequency that will be
+ * available when this throttling state is invoked
+ * @power: Throttling state’s maximum power dissipation (mw)
+ * @latency: Worst-case latency (uS) that the CPU is unavailable during a
+ * transition from any throttling state to this throttling state
+ * @control: Value to be written to the Processor Control Register
+ * (THROTTLE_CTRL) to initiate a transition to this throttling state
+ * @status: Value in THROTTLE_STATUS when in this state
+ */
+struct acpi_tstate {
+ uint percent;
+ uint power;
+ uint latency;
+ uint control;
+ uint status;
+};
+
 /**
  * acpigen_get_current() - Get the current ACPI code output pointer
  *
@@ -816,4 +865,117 @@ void acpigen_write_processor_package(struct acpi_ctx *ctx, const char *name,
  */
 void acpigen_write_processor_cnot(struct acpi_ctx *ctx, const uint num_cores);
 
+/**
+ * acpigen_write_ppc() - generates a function returning max P-states
+ *
+ * @ctx: ACPI context pointer
+ * @num_pstates: Number of pstates to return
+ */
+void acpigen_write_ppc(struct acpi_ctx *ctx, uint num_pstates);
+
+/**
+ * acpigen_write_ppc() - generates a function returning PPCM
+ *
+ * This returns the maximum number of supported P-states, as saved in the
+ * variable PPCM
+ *
+ * @ctx: ACPI context pointer
+ */
+void acpigen_write_ppc_nvs(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_write_tpc() - Write a _TPC method that returns the TPC limit
+ *
+ * @ctx: ACPI context pointer
+ * @gnvs_tpc_limit: Variable that holds the TPC limit
+ */
+void acpigen_write_tpc(struct acpi_ctx *ctx, const char *gnvs_tpc_limit);
+
+/**
+ * acpigen_write_pss_package() - Write a PSS package
+ *
+ * See ACPI v6.3 section 8.4.6: Processor Performance Control
+ *
+ * @ctx: ACPI context pointer
+ * @corefreq: CPU core frequency in MHz
+ * @translat: worst-case latency in uS that the CPU is unavailable during a
+ * transition from any performance state to this performance state
+ * @busmlat: worst-case latency in microseconds that Bus Masters are prevented
+ * from accessing memory during a transition from any performance state to
+ * this performance state
+ * @control: Value to write to PERF_CTRL to move to this performance state
+ * @status: Expected PERF_STATUS value when in this state
+ */
+void acpigen_write_pss_package(struct acpi_ctx *ctx, uint corefreq, uint power,
+       uint translat, uint busmlat, uint control,
+       uint status);
+
+/**
+ * acpigen_write_psd_package() - Write a PSD package
+ *
+ * Writes a P-State dependency package
+ *
+ * See ACPI v6.3 section 8.4.6.5: _PSD (P-State Dependency)
+ *
+ * @ctx: ACPI context pointer
+ * @domain: Dependency domain number to which this P state entry belongs
+ * @numprocs: Number of processors belonging to the domain for this logical
+ * processor’s P-states
+ * @coordtype: Coordination type
+ */
+void acpigen_write_psd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+       enum psd_coord coordtype);
+
+/**
+ * acpigen_write_cst_package() - Write a _CST package
+ *
+ * See ACPI v6.3 section 8.4.2.1: _CST (C States)
+ *
+ * @ctx: ACPI context pointer
+ * @entry: Array of entries
+ * @nentries; Number of entries
+ */
+void acpigen_write_cst_package(struct acpi_ctx *ctx,
+       const struct acpi_cstate *entry, int nentries);
+
+/**
+ * acpigen_write_csd_package() - Write a _CSD Package
+ *
+ * See ACPI v6.3 section 8.4.2.2: _CSD (C-State Dependency)
+ *
+ * @ctx: ACPI context pointer
+ * @domain: dependency domain number to which this C state entry belongs
+ * @numprocs: number of processors belonging to the domain for the particular
+ * C-state
+ * @coordtype: Co-ordination type
+ * @index: Index of the C-State entry in the _CST object for which the
+ * dependency applies
+ */
+void acpigen_write_csd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+       enum csd_coord coordtype, uint index);
+
+/**
+ * acpigen_write_tss_package() - Write a _TSS package
+ *
+ * @ctx: ACPI context pointer
+ * @entry: Entries to write
+ * @nentries: Number of entries to write
+ */
+void acpigen_write_tss_package(struct acpi_ctx *ctx,
+       struct acpi_tstate *entry, int nentries);
+
+/**
+ * acpigen_write_tsd_package() - Write a _TSD package
+ *
+ * See ACPI v6.3 section 8.4.5.4: _TSD (T-State Dependency)
+ *
+ * @ctx: ACPI context pointer
+ * @domain: dependency domain number to which this T state entry belongs
+ * @numprocs: Number of processors belonging to the domain for this logical
+ * processor’s T-states
+ * @coordtype: Coordination type
+ */
+void acpigen_write_tsd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+       enum psd_coord coordtype);
+
 #endif
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index b9985075cde..e395226e3de 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -481,6 +481,53 @@ void acpigen_write_register_resource(struct acpi_ctx *ctx,
  acpigen_write_resourcetemplate_footer(ctx);
 }
 
+void acpigen_write_ppc(struct acpi_ctx *ctx, uint num_pstates)
+{
+ /*
+ * Method (_PPC, 0, NotSerialized)
+ * {
+ * Return (num_pstates)
+ * }
+ */
+ acpigen_write_method(ctx, "_PPC", 0);
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_write_byte(ctx, num_pstates);
+ acpigen_pop_len(ctx);
+}
+
+/*
+ * Generates a func with max supported P-states saved
+ * in the variable PPCM.
+ */
+void acpigen_write_ppc_nvs(struct acpi_ctx *ctx)
+{
+ /*
+ * Method (_PPC, 0, NotSerialized)
+ * {
+ * Return (PPCM)
+ * }
+ */
+ acpigen_write_method(ctx, "_PPC", 0);
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_emit_namestring(ctx, "PPCM");
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tpc(struct acpi_ctx *ctx, const char *gnvs_tpc_limit)
+{
+ /*
+ * // Sample _TPC method
+ * Method (_TPC, 0, NotSerialized)
+ * {
+ * Return (\TLVL)
+ * }
+ */
+ acpigen_write_method(ctx, "_TPC", 0);
+ acpigen_emit_byte(ctx, RETURN_OP);
+ acpigen_emit_namestring(ctx, gnvs_tpc_limit);
+ acpigen_pop_len(ctx);
+}
+
 void acpigen_write_prw(struct acpi_ctx *ctx, uint wake, uint level)
 {
  /* Name (_PRW, Package () { wake, level } */
@@ -491,6 +538,126 @@ void acpigen_write_prw(struct acpi_ctx *ctx, uint wake, uint level)
  acpigen_pop_len(ctx);
 }
 
+void acpigen_write_pss_package(struct acpi_ctx *ctx, u32 core_freq, u32 power,
+       u32 trans_lat, u32 busm_lat, u32 control,
+       u32 status)
+{
+ acpigen_write_package(ctx, 6);
+ acpigen_write_dword(ctx, core_freq);
+ acpigen_write_dword(ctx, power);
+ acpigen_write_dword(ctx, trans_lat);
+ acpigen_write_dword(ctx, busm_lat);
+ acpigen_write_dword(ctx, control);
+ acpigen_write_dword(ctx, status);
+ acpigen_pop_len(ctx);
+
+ log_debug("PSS: %uMHz power %u control 0x%x status 0x%x\n",
+  core_freq, power, control, status);
+}
+
+void acpigen_write_psd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+       enum psd_coord coordtype)
+{
+ acpigen_write_name(ctx, "_PSD");
+ acpigen_write_package(ctx, 1);
+ acpigen_write_package(ctx, 5);
+ acpigen_write_byte(ctx, 5); // 5 values
+ acpigen_write_byte(ctx, 0); // revision 0
+ acpigen_write_dword(ctx, domain);
+ acpigen_write_dword(ctx, coordtype);
+ acpigen_write_dword(ctx, numprocs);
+ acpigen_pop_len(ctx);
+ acpigen_pop_len(ctx);
+}
+
+static void acpigen_write_cst_package_entry(struct acpi_ctx *ctx,
+    const struct acpi_cstate *cstate)
+{
+ acpigen_write_package(ctx, 4);
+ acpigen_write_register_resource(ctx, &cstate->resource);
+ acpigen_write_dword(ctx, cstate->ctype);
+ acpigen_write_dword(ctx, cstate->latency);
+ acpigen_write_dword(ctx, cstate->power);
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_cst_package(struct acpi_ctx *ctx,
+       const struct acpi_cstate *cstate, int nentries)
+{
+ int i;
+
+ acpigen_write_name(ctx, "_CST");
+ acpigen_write_package(ctx, nentries + 1);
+ acpigen_write_dword(ctx, nentries);
+
+ for (i = 0; i < nentries; i++)
+ acpigen_write_cst_package_entry(ctx, cstate + i);
+
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_csd_package(struct acpi_ctx *ctx, uint domain, uint numprocs,
+       enum csd_coord coordtype, uint index)
+{
+ acpigen_write_name(ctx, "_CSD");
+ acpigen_write_package(ctx, 1);
+ acpigen_write_package(ctx, 6);
+ acpigen_write_byte(ctx, 6); // 6 values
+ acpigen_write_byte(ctx, 0); // revision 0
+ acpigen_write_dword(ctx, domain);
+ acpigen_write_dword(ctx, coordtype);
+ acpigen_write_dword(ctx, numprocs);
+ acpigen_write_dword(ctx, index);
+ acpigen_pop_len(ctx);
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tss_package(struct acpi_ctx *ctx,
+       struct acpi_tstate *entry, int nentries)
+{
+ /*
+ * Sample _TSS package with 100% and 50% duty cycles
+ * Name (_TSS, Package (0x02)
+ * {
+ * Package(){100, 1000, 0, 0x00, 0)
+ * Package(){50, 520, 0, 0x18, 0)
+ * })
+ */
+ struct acpi_tstate *tstate = entry;
+ int i;
+
+ acpigen_write_name(ctx, "_TSS");
+ acpigen_write_package(ctx, nentries);
+
+ for (i = 0; i < nentries; i++) {
+ acpigen_write_package(ctx, 5);
+ acpigen_write_dword(ctx, tstate->percent);
+ acpigen_write_dword(ctx, tstate->power);
+ acpigen_write_dword(ctx, tstate->latency);
+ acpigen_write_dword(ctx, tstate->control);
+ acpigen_write_dword(ctx, tstate->status);
+ acpigen_pop_len(ctx);
+ tstate++;
+ }
+
+ acpigen_pop_len(ctx);
+}
+
+void acpigen_write_tsd_package(struct acpi_ctx *ctx, u32 domain, u32 numprocs,
+       enum psd_coord coordtype)
+{
+ acpigen_write_name(ctx, "_TSD");
+ acpigen_write_package(ctx, 1);
+ acpigen_write_package(ctx, 5);
+ acpigen_write_byte(ctx, 5); // 5 values
+ acpigen_write_byte(ctx, 0); // revision 0
+ acpigen_write_dword(ctx, domain);
+ acpigen_write_dword(ctx, coordtype);
+ acpigen_write_dword(ctx, numprocs);
+ acpigen_pop_len(ctx);
+ acpigen_pop_len(ctx);
+}
+
 /*
  * ToUUID(uuid)
  *
diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c
index 74b7e23aab3..3ec2743af9f 100644
--- a/test/dm/acpigen.c
+++ b/test/dm/acpigen.c
@@ -1450,3 +1450,297 @@ static int dm_test_acpi_write_processor_cnot(struct unit_test_state *uts)
  return 0;
 }
 DM_TEST(dm_test_acpi_write_processor_cnot, 0);
+
+/* Test acpigen_write_tpc */
+static int dm_test_acpi_write_tpc(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_tpc(ctx, "\\TLVL");
+
+ ut_asserteq(METHOD_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq_strn("_TPC", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(0, *ptr++);
+ ut_asserteq(RETURN_OP, *ptr++);
+ ut_asserteq_strn("\\TLVL", (char *)ptr);
+ ptr += 5;
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_tpc, 0);
+
+/* Test acpigen_write_pss_package(), etc. */
+static int dm_test_acpi_write_pss_psd(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_pss_package(ctx, 1, 2, 3, 4, 5, 6);
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(6, *ptr++);
+
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(1, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(2, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(3, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(4, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(5, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(6, get_unaligned((u32 *)ptr));
+ ptr += 4;
+
+ acpigen_write_psd_package(ctx, 6, 7, HW_ALL);
+ ut_asserteq(NAME_OP, *ptr++);
+ ut_asserteq_strn("_PSD", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(1, *ptr++);
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(5, *ptr++);
+
+ ut_asserteq(BYTE_PREFIX, *ptr++);
+ ut_asserteq(5, *ptr++);
+ ut_asserteq(BYTE_PREFIX, *ptr++);
+ ut_asserteq(0, *ptr++);
+
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(6, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(HW_ALL, get_unaligned((u32 *)ptr));
+ ptr += 5;
+
+ ut_asserteq(7, get_unaligned((u32 *)ptr));
+ ptr += 4;
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_pss_psd, 0);
+
+/* Test acpi_write_cst_package() */
+static int dm_test_acpi_write_cst(struct unit_test_state *uts)
+{
+ 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,
+ },
+ },
+ };
+ int nentries = ARRAY_SIZE(cstate_map);
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+ int i;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_cst_package(ctx, cstate_map, nentries);
+
+ ut_asserteq(NAME_OP, *ptr++);
+ ut_asserteq_strn("_CST", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(nentries + 1, *ptr++);
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(nentries, get_unaligned((u32 *)ptr));
+ ptr += 4;
+
+ for (i = 0; i < nentries; i++) {
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(4, *ptr++);
+ ut_asserteq(BUFFER_OP, *ptr++);
+ ptr += 0x17;
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(cstate_map[i].ctype, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(cstate_map[i].latency, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(cstate_map[i].power, get_unaligned((u32 *)ptr));
+ ptr += 4;
+ }
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_cst, 0);
+
+/* Test acpi_write_cst_package() */
+static int dm_test_acpi_write_csd(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_csd_package(ctx, 12, 34, CSD_HW_ALL, 56);
+
+ ut_asserteq(NAME_OP, *ptr++);
+ ut_asserteq_strn("_CSD", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(1, *ptr++);
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(6, *ptr++);
+
+ ut_asserteq(BYTE_PREFIX, *ptr++);
+ ut_asserteq(6, *ptr++);
+ ut_asserteq(BYTE_PREFIX, *ptr++);
+ ut_asserteq(0, *ptr++);
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(12, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(CSD_HW_ALL, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(34, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(56, get_unaligned((u32 *)ptr));
+ ptr += 4;
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_csd, 0);
+
+/* Test acpigen_write_tss_package() */
+static int dm_test_acpi_write_tss(struct unit_test_state *uts)
+{
+ static struct acpi_tstate tstate_list[] = {
+ { 1, 2, 3, 4, 5, },
+ { 6, 7, 8, 9, 10, },
+ };
+ int nentries = ARRAY_SIZE(tstate_list);
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+ int i;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_tss_package(ctx, tstate_list, nentries);
+
+ ut_asserteq(NAME_OP, *ptr++);
+ ut_asserteq_strn("_TSS", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(nentries, *ptr++);
+
+ for (i = 0; i < nentries; i++) {
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(5, *ptr++);
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(tstate_list[i].percent, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(tstate_list[i].power, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(tstate_list[i].latency, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(tstate_list[i].control, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(tstate_list[i].status, get_unaligned((u32 *)ptr));
+ ptr += 4;
+ }
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_tss, 0);
+
+/* Test acpigen_write_tsd_package() */
+static int dm_test_acpi_write_tsd_package(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_write_tsd_package(ctx, 12, 34, HW_ALL);
+
+ ut_asserteq(NAME_OP, *ptr++);
+ ut_asserteq_strn("_TSD", (char *)ptr);
+ ptr += 4;
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(1, *ptr++);
+ ut_asserteq(PACKAGE_OP, *ptr++);
+ ptr += 3;  /* skip length */
+ ut_asserteq(5, *ptr++);
+
+ ut_asserteq(BYTE_PREFIX, *ptr++);
+ ut_asserteq(5, *ptr++);
+ ut_asserteq(BYTE_PREFIX, *ptr++);
+ ut_asserteq(0, *ptr++);
+ ut_asserteq(DWORD_PREFIX, *ptr++);
+ ut_asserteq(12, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(CSD_HW_ALL, get_unaligned((u32 *)ptr));
+ ptr += 5;
+ ut_asserteq(34, get_unaligned((u32 *)ptr));
+ ptr += 4;
+
+ ut_asserteq_ptr(ptr, ctx->current);
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_write_tsd_package, 0);
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 29/59] x86: acpi: Add common Intel ACPI tables

Simon Glass-3
In reply to this post by Simon Glass-3
Add various tables that are common to Intel CPUs. These functions can be
used by arch-specific CPU code.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 arch/x86/cpu/intel_common/Makefile |   2 +
 arch/x86/cpu/intel_common/acpi.c   | 377 +++++++++++++++++++++++++++++
 arch/x86/cpu/intel_common/cpu.c    |  14 ++
 arch/x86/include/asm/acpi_table.h  |  22 ++
 arch/x86/include/asm/cpu_common.h  |   7 +
 arch/x86/include/asm/intel_acpi.h  |  52 ++++
 drivers/core/Kconfig               |   9 +
 7 files changed, 483 insertions(+)
 create mode 100644 arch/x86/cpu/intel_common/acpi.c
 create mode 100644 arch/x86/include/asm/intel_acpi.h

diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
index f1d1513a981..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
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([hidden email]): 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 cb4ef84013a..d8a3d60ae72 100644
--- a/arch/x86/cpu/intel_common/cpu.c
+++ b/arch/x86/cpu/intel_common/cpu.c
@@ -291,3 +291,17 @@ int cpu_get_max_turbo_ratio(void)
 
  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/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 1b7ff509516..3245e447813 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -76,4 +76,26 @@ ulong write_acpi_tables(ulong start);
  */
 ulong acpi_get_rsdp_addr(void);
 
+/**
+ * arch_read_sci_irq_select() - Read the system-control interrupt number
+ *
+ * @returns value of IRQ register in the PMC
+ */
+int arch_read_sci_irq_select(void);
+
+/**
+ * arch_write_sci_irq_select() - Set the system-control interrupt number
+ *
+ * @scis: New value for IRQ register in the PMC
+ */
+int arch_write_sci_irq_select(uint scis);
+
+/**
+ * arch_madt_sci_irq_polarity() - Return the priority to use for the MADT
+ *
+ * @sci: System-control interrupt number
+ * @return priority to use (MP_IRQ_POLARITY_...)
+ */
+int arch_madt_sci_irq_polarity(int sci);
+
 #endif /* __ASM_ACPI_TABLE_H__ */
diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h
index a7b7112d417..48f56c2aad9 100644
--- a/arch/x86/include/asm/cpu_common.h
+++ b/arch/x86/include/asm/cpu_common.h
@@ -177,4 +177,11 @@ int cpu_get_power_max(void);
  */
 int cpu_get_max_turbo_ratio(void);
 
+/**
+ * cpu_get_cores_per_package() - Get the number of CPU cores in each package
+ *
+ * @return number of cores
+ */
+int cpu_get_cores_per_package(void);
+
 #endif
diff --git a/arch/x86/include/asm/intel_acpi.h b/arch/x86/include/asm/intel_acpi.h
new file mode 100644
index 00000000000..a5781f1af45
--- /dev/null
+++ b/arch/x86/include/asm/intel_acpi.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018, Bin Meng <[hidden email]>
+ */
+
+#ifndef __ASM_INTEL_ACPI_H__
+#define __ASM_INTEL_ACPI_H__
+
+struct acpi_cstate;
+struct acpi_ctx;
+struct acpi_tstate;
+struct udevice;
+
+/**
+ * acpi_generate_cpu_header() - Start generating an ACPI CPU entry
+ *
+ * Generates the ACPI information for a CPU. After this, the caller should
+ * generate_p_state_entries(), generate_t_state_entries and then
+ * acpigen_pop_len() to close off this package.
+ *
+ * @ctx: ACPI context pointer
+ * @core_id: CPU core number, as numbered by the SoC
+ * @c_state_map: Information about each C state
+ * @num_cstates: Number of entries in @c_state_map
+ * @return 0 if OK, -ve on error
+ */
+int acpi_generate_cpu_header(struct acpi_ctx *ctx, int core_id,
+     const struct acpi_cstate *c_state_map,
+     int num_cstates);
+
+/**
+ * acpi_generate_cpu_package_final() - Write out the CPU PPKG entry
+ *
+ * This writes information about the CPUs in the package
+ *
+ * @ctx: ACPI context pointer
+ * @cores_per_package: Number of CPU cores in each package in the SoC
+ */
+int acpi_generate_cpu_package_final(struct acpi_ctx *ctx,
+    int cores_per_package);
+
+void generate_p_state_entries(struct acpi_ctx *ctx, int core,
+      int cores_per_package);
+void generate_t_state_entries(struct acpi_ctx *ctx, int core,
+      int cores_per_package, struct acpi_tstate *entry,
+      int nentries);
+int southbridge_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx);
+
+int intel_southbridge_write_acpi_tables(const struct udevice *dev,
+ struct acpi_ctx *ctx);
+
+#endif /* __ASM_INTEL_ACPI_H__ */
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 00d1d80dc38..1ca5d66141b 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -277,4 +277,13 @@ config ACPIGEN
   things like generating device-specific tables and returning the ACPI
   name of a device.
 
+config INTEL_ACPIGEN
+ bool "Support ACPI table generation for Intel SoCs"
+ depends on ACPIGEN
+ help
+  This option adds some functions used for programatic generation of
+  ACPI tables on Intel SoCs. This provides features for writing CPU
+  information such as P states and T stages. Also included is a way
+  to create a GNVS table and set it up.
+
 endmenu
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 30/59] x86: Support Atom SoCs using SWSMISCI rather than the SWSCI

Simon Glass-3
In reply to this post by Simon Glass-3
Some Atom SoCs use SWSMISCI for SMI control. Add a Kconfig to select this.
It is used on Apollo Lake.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 arch/x86/Kconfig                | 6 ++++++
 arch/x86/cpu/apollolake/Kconfig | 1 +
 2 files changed, 7 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 495629d32ed..eddf2a774ef 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1017,4 +1017,10 @@ config INTEL_GENERIC_WIFI
   network functionality. It is only here to generate the ACPI tables
   required by Linux.
 
+config INTEL_GMA_SWSMISCI
+ bool
+ help
+  Select this option for Atom-based platforms which use the SWSMISCI
+  register (0xe0) rather than the SWSCI register (0xe8).
+
 endmenu
diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig
index 319f12684b7..35a425cd1bc 100644
--- a/arch/x86/cpu/apollolake/Kconfig
+++ b/arch/x86/cpu/apollolake/Kconfig
@@ -17,6 +17,7 @@ config INTEL_APOLLOLAKE
  select PCH_SUPPORT
  select P2SB
  select SMP_AP_WORK
+ select INTEL_GMA_SWSMISCI
  select ACPI_GNVS_EXTERNAL
  imply ENABLE_MRC_CACHE
  imply AHCI_PCI
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 31/59] x86: acpi: Add support for additional Intel tables

Simon Glass-3
In reply to this post by Simon Glass-3
Apollo Lake needs to generate a few more table types used on Intel SoCs.
Add support for these into the x86 ACPI code.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Move this code into an x86-specific file
- Update commit message
- Use OEM_TABLE_ID instead of ACPI_TABLE_CREATOR

 arch/x86/include/asm/acpi_table.h | 115 ++++++++++++++++++++++++++++++
 arch/x86/lib/acpi_table.c         | 111 ++++++++++++++++++++++++++++
 include/acpi/acpi_table.h         |  43 +++++++++++
 3 files changed, 269 insertions(+)

diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 3245e447813..faf31730730 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -98,4 +98,119 @@ int arch_write_sci_irq_select(uint scis);
  */
 int arch_madt_sci_irq_polarity(int sci);
 
+/**
+ * acpi_create_dmar_drhd() - Create a table for DMA remapping with the IOMMU
+ *
+ * See here for the specification
+ * https://software.intel.com/sites/default/files/managed/c5/15/vt-directed-io-spec.pdf
+ *
+ * @ctx: ACPI context pointer
+ * @flags: (DRHD_INCLUDE_...)
+ * @segment: PCI segment asscociated with this unit
+ * @bar: Base address of remapping hardware register-set for this unit
+ */
+void acpi_create_dmar_drhd(struct acpi_ctx *ctx, uint flags, uint segment,
+   u64 bar);
+
+/**
+ * acpi_create_dmar_rmrr() - Set up an RMRR
+ *
+ * This sets up a Reserved-Memory Region Reporting structure, used to allow
+ * DMA to regions used by devices that the BIOS controls.
+ *
+ * @ctx: ACPI context pointer
+ * @segment: PCI segment asscociated with this unit
+ * @bar: Base address of mapping
+ * @limit: End address of mapping
+ */
+void acpi_create_dmar_rmrr(struct acpi_ctx *ctx, uint segment, u64 bar,
+   u64 limit);
+
+/**
+ * acpi_dmar_drhd_fixup() - Set the length of an DRHD
+ *
+ * This sets the DRHD length field based on the current ctx->current
+ *
+ * @ctx: ACPI context pointer
+ * @base: Address of the start of the DRHD
+ */
+void acpi_dmar_drhd_fixup(struct acpi_ctx *ctx, void *base);
+
+/**
+ * acpi_dmar_rmrr_fixup() - Set the length of an RMRR
+ *
+ * This sets the RMRR length field based on the current ctx->current
+ *
+ * @ctx: ACPI context pointer
+ * @base: Address of the start of the RMRR
+ */
+void acpi_dmar_rmrr_fixup(struct acpi_ctx *ctx, void *base);
+
+/**
+ * acpi_create_dmar_ds_pci() - Set up a DMAR scope for a PCI device
+ *
+ * @ctx: ACPI context pointer
+ * @bdf: PCI device to add
+ * @return length of mapping in bytes
+ */
+int acpi_create_dmar_ds_pci(struct acpi_ctx *ctx, pci_dev_t bdf);
+
+/**
+ * acpi_create_dmar_ds_pci_br() - Set up a DMAR scope for a PCI bridge
+ *
+ * This is used to provide a mapping for a PCI bridge
+ *
+ * @ctx: ACPI context pointer
+ * @bdf: PCI device to add
+ * @return length of mapping in bytes
+ */
+int acpi_create_dmar_ds_pci_br(struct acpi_ctx *ctx, pci_dev_t bdf);
+
+/**
+ * acpi_create_dmar_ds_ioapic() - Set up a DMAR scope for an IOAPIC device
+ *
+ * @ctx: ACPI context pointer
+ * @enumeration_id: Enumeration ID (typically 2)
+ * @bdf: PCI device to add
+ * @return length of mapping in bytes
+ */
+int acpi_create_dmar_ds_ioapic(struct acpi_ctx *ctx, uint enumeration_id,
+       pci_dev_t bdf);
+
+/**
+ * acpi_create_dmar_ds_msi_hpet() - Set up a DMAR scope for an HPET
+ *
+ * Sets up a scope for a High-Precision Event Timer that supports
+ * Message-Signalled Interrupts
+ *
+ * @ctx: ACPI context pointer
+ * @enumeration_id: Enumeration ID (typically 0)
+ * @bdf: PCI device to add
+ * @return length of mapping in bytes
+ */
+int acpi_create_dmar_ds_msi_hpet(struct acpi_ctx *ctx, uint enumeration_id,
+ pci_dev_t bdf);
+
+/**
+ * acpi_fadt_common() - Handle common parts of filling out an FADT
+ *
+ * This sets up the Fixed ACPI Description Table
+ *
+ * @fadt: Pointer to place to put FADT
+ * @facs: Pointer to the FACS
+ * @dsdt: Pointer to the DSDT
+ */
+void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs,
+      void *dsdt);
+
+/**
+ * intel_acpi_fill_fadt() - Set up the contents of the FADT
+ *
+ * This sets up parts of the Fixed ACPI Description Table that are common to
+ * Intel chips
+ *
+ * @fadt: Pointer to place to put FADT
+ */
+void intel_acpi_fill_fadt(struct acpi_fadt *fadt);
+
 #endif /* __ASM_ACPI_TABLE_H__ */
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index e257c789838..86a9a35cb25 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -629,3 +629,114 @@ int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
 
  return 0;
 }
+
+void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs,
+      void *dsdt)
+{
+ struct acpi_table_header *header = &fadt->header;
+
+ memset((void *)fadt, '\0', sizeof(struct acpi_fadt));
+
+ acpi_fill_header(header, "FACP");
+ header->length = sizeof(struct acpi_fadt);
+ header->revision = 4;
+ memcpy(header->oem_id, OEM_ID, 6);
+ memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
+ memcpy(header->aslc_id, ASLC_ID, 4);
+ header->aslc_revision = 1;
+
+ fadt->firmware_ctrl = (unsigned long)facs;
+ fadt->dsdt = (unsigned long)dsdt;
+
+ fadt->x_firmware_ctl_l = (unsigned long)facs;
+ fadt->x_firmware_ctl_h = 0;
+ fadt->x_dsdt_l = (unsigned long)dsdt;
+ fadt->x_dsdt_h = 0;
+
+ fadt->preferred_pm_profile = ACPI_PM_MOBILE;
+
+ /* Use ACPI 3.0 revision */
+ fadt->header.revision = 4;
+}
+
+void acpi_create_dmar_drhd(struct acpi_ctx *ctx, uint flags, uint segment,
+   u64 bar)
+{
+ struct dmar_entry *drhd = ctx->current;
+
+ memset(drhd, '\0', sizeof(*drhd));
+ drhd->type = DMAR_DRHD;
+ drhd->length = sizeof(*drhd); /* will be fixed up later */
+ drhd->flags = flags;
+ drhd->segment = segment;
+ drhd->bar = bar;
+ acpi_inc(ctx, drhd->length);
+}
+
+void acpi_create_dmar_rmrr(struct acpi_ctx *ctx, uint segment, u64 bar,
+   u64 limit)
+{
+ struct dmar_rmrr_entry *rmrr = ctx->current;
+
+ memset(rmrr, '\0', sizeof(*rmrr));
+ rmrr->type = DMAR_RMRR;
+ rmrr->length = sizeof(*rmrr); /* will be fixed up later */
+ rmrr->segment = segment;
+ rmrr->bar = bar;
+ rmrr->limit = limit;
+ acpi_inc(ctx, rmrr->length);
+}
+
+void acpi_dmar_drhd_fixup(struct acpi_ctx *ctx, void *base)
+{
+ struct dmar_entry *drhd = base;
+
+ drhd->length = ctx->current - base;
+}
+
+void acpi_dmar_rmrr_fixup(struct acpi_ctx *ctx, void *base)
+{
+ struct dmar_rmrr_entry *rmrr = base;
+
+ rmrr->length = ctx->current - base;
+}
+
+static int acpi_create_dmar_ds(struct acpi_ctx *ctx, enum dev_scope_type type,
+       uint enumeration_id, pci_dev_t bdf)
+{
+ /* we don't support longer paths yet */
+ const size_t dev_scope_length = sizeof(struct dev_scope) + 2;
+ struct dev_scope *ds = ctx->current;
+
+ memset(ds, '\0', dev_scope_length);
+ ds->type = type;
+ ds->length = dev_scope_length;
+ ds->enumeration = enumeration_id;
+ ds->start_bus = PCI_BUS(bdf);
+ ds->path[0].dev = PCI_DEV(bdf);
+ ds->path[0].fn = PCI_FUNC(bdf);
+
+ return ds->length;
+}
+
+int acpi_create_dmar_ds_pci_br(struct acpi_ctx *ctx, pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_PCI_SUB, 0, bdf);
+}
+
+int acpi_create_dmar_ds_pci(struct acpi_ctx *ctx, pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_PCI_ENDPOINT, 0, bdf);
+}
+
+int acpi_create_dmar_ds_ioapic(struct acpi_ctx *ctx, uint enumeration_id,
+       pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_IOAPIC, enumeration_id, bdf);
+}
+
+int acpi_create_dmar_ds_msi_hpet(struct acpi_ctx *ctx, uint enumeration_id,
+ pci_dev_t bdf)
+{
+ return acpi_create_dmar_ds(ctx, SCOPE_MSI_HPET, enumeration_id, bdf);
+}
diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h
index c826a797f5b..a2e510cf56e 100644
--- a/include/acpi/acpi_table.h
+++ b/include/acpi/acpi_table.h
@@ -377,6 +377,49 @@ struct acpi_csrt_shared_info {
  u32 max_block_size;
 };
 
+/* Port types for ACPI _UPC object */
+enum acpi_upc_type {
+ UPC_TYPE_A,
+ UPC_TYPE_MINI_AB,
+ UPC_TYPE_EXPRESSCARD,
+ UPC_TYPE_USB3_A,
+ UPC_TYPE_USB3_B,
+ UPC_TYPE_USB3_MICRO_B,
+ UPC_TYPE_USB3_MICRO_AB,
+ UPC_TYPE_USB3_POWER_B,
+ UPC_TYPE_C_USB2_ONLY,
+ UPC_TYPE_C_USB2_SS_SWITCH,
+ UPC_TYPE_C_USB2_SS,
+ UPC_TYPE_PROPRIETARY = 0xff,
+ /*
+ * The following types are not directly defined in the ACPI
+ * spec but are used by coreboot to identify a USB device type.
+ */
+ UPC_TYPE_INTERNAL = 0xff,
+ UPC_TYPE_UNUSED,
+ UPC_TYPE_HUB
+};
+
+enum dev_scope_type {
+ SCOPE_PCI_ENDPOINT = 1,
+ SCOPE_PCI_SUB = 2,
+ SCOPE_IOAPIC = 3,
+ SCOPE_MSI_HPET = 4,
+ SCOPE_ACPI_NAMESPACE_DEVICE = 5
+};
+
+struct __packed dev_scope {
+ u8 type;
+ u8 length;
+ u8 reserved[2];
+ u8 enumeration;
+ u8 start_bus;
+ struct {
+ u8 dev;
+ u8 fn;
+ } __packed path[0];
+};
+
 enum dmar_type {
  DMAR_DRHD = 0,
  DMAR_RMRR = 1,
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 32/59] x86: apl: Allow reading hostbridge base addresses

Simon Glass-3
In reply to this post by Simon Glass-3
Add a few functions to permit reading of various useful base addresses
provided by the hostbridge.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Add comments

 arch/x86/cpu/apollolake/hostbridge.c          | 27 ++++++++++++++++
 .../include/asm/arch-apollolake/systemagent.h | 31 +++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/arch/x86/cpu/apollolake/hostbridge.c b/arch/x86/cpu/apollolake/hostbridge.c
index cb46ec6c0bb..056f7e57a9a 100644
--- a/arch/x86/cpu/apollolake/hostbridge.c
+++ b/arch/x86/cpu/apollolake/hostbridge.c
@@ -40,7 +40,9 @@ enum {
 
  PCIEXBAR_PCIEXBAREN = 1 << 0,
 
+ BGSM = 0xb4,  /* Base GTT Stolen Memory */
  TSEG = 0xb8,  /* TSEG base */
+ TOLUD = 0xbc,
 };
 
 static int apl_hostbridge_early_init_pinctrl(struct udevice *dev)
@@ -165,6 +167,31 @@ static int apl_hostbridge_probe(struct udevice *dev)
  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);
+}
+
 static const struct udevice_id apl_hostbridge_ids[] = {
  { .compatible = "intel,apl-hostbridge" },
  { }
diff --git a/arch/x86/include/asm/arch-apollolake/systemagent.h b/arch/x86/include/asm/arch-apollolake/systemagent.h
index 9e7bd62751a..788a63d7999 100644
--- a/arch/x86/include/asm/arch-apollolake/systemagent.h
+++ b/arch/x86/include/asm/arch-apollolake/systemagent.h
@@ -35,4 +35,35 @@
  */
 void enable_bios_reset_cpl(void);
 
+/**
+ * sa_get_tolud_base() - Get the TOLUD base address
+ *
+ * This returns the Top Of Low Useable DRAM, marking the top of usable DRAM
+ * below 4GB
+ *
+ * @dev: hostbridge device
+ * @return TOLUD address
+ */
+ulong sa_get_tolud_base(struct udevice *dev);
+
+/**
+ * sa_get_gsm_base() - Get the GSM base address
+ *
+ * This returns the base of GTT Stolen Memory, marking the start of memory used
+ * for Graphics Translation Tables.
+ *
+ * @dev: hostbridge device
+ * @return GSM address
+ */
+ulong sa_get_gsm_base(struct udevice *dev);
+
+/**
+ * sa_get_tseg_base() - Get the TSEG base address
+ *
+ * This returns the top address of DRAM available below 4GB
+ *
+ * @return TSEG base
+ */
+ulong sa_get_tseg_base(struct udevice *dev);
+
 #endif
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 33/59] p2sb: Add some definitions used for ACPI

Simon Glass-3
In reply to this post by Simon Glass-3
Allow this header to be included in ASL files by adding a header guard and
a few definitions that are needed.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 include/p2sb.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/p2sb.h b/include/p2sb.h
index 93e1155dca6..a25170e3d11 100644
--- a/include/p2sb.h
+++ b/include/p2sb.h
@@ -10,6 +10,12 @@
 /* Port Id lives in bits 23:16 and register offset lives in 15:0 of address */
 #define PCR_PORTID_SHIFT 16
 
+#if !defined(__ACPI__)
+
+/* These registers contain IOAPIC and HPET devfn */
+#define PCH_P2SB_IBDF 0x6c
+#define PCH_P2SB_HBDF 0x70
+
 /**
  * struct p2sb_child_platdata - Information about each child of a p2sb device
  *
@@ -164,4 +170,6 @@ int p2sb_get_port_id(struct udevice *dev);
  */
 void *pcr_reg_address(struct udevice *dev, uint offset);
 
+#endif /* !__ACPI__ */
+
 #endif
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 34/59] x86: apl: Generate required ACPI tables

Simon Glass-3
In reply to this post by Simon Glass-3
Add support for generating various ACPI tables for Apollo Lake. Add a few
S3 definitions that are needed.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Drop unnecessary callbacks

 arch/x86/cpu/apollolake/Makefile            |   1 +
 arch/x86/cpu/apollolake/acpi.c              | 211 ++++++++++++++++++++
 arch/x86/include/asm/arch-apollolake/acpi.h |  18 ++
 include/acpi/acpi_s3.h                      |   4 +
 4 files changed, 234 insertions(+)
 create mode 100644 arch/x86/cpu/apollolake/acpi.c
 create mode 100644 arch/x86/include/asm/arch-apollolake/acpi.h

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 <[hidden email]> 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([hidden email]): 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([hidden email]): 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([hidden email]): 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/include/asm/arch-apollolake/acpi.h b/arch/x86/include/asm/arch-apollolake/acpi.h
new file mode 100644
index 00000000000..ed852feee03
--- /dev/null
+++ b/arch/x86/include/asm/arch-apollolake/acpi.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef _ASM_ARCH_ACPI_H
+#define _ASM_ARCH_ACPI_H
+
+struct acpi_ctx;
+
+/**
+ * apl_acpi_fill_dmar() - Set up the DMAR for APL
+ *
+ * @ctx: ACPI context pointer
+ */
+int apl_acpi_fill_dmar(struct acpi_ctx *ctx);
+
+#endif /* _ASM_ARCH_CPU_H */
diff --git a/include/acpi/acpi_s3.h b/include/acpi/acpi_s3.h
index baa848dcd15..847139baa0c 100644
--- a/include/acpi/acpi_s3.h
+++ b/include/acpi/acpi_s3.h
@@ -28,6 +28,10 @@
 #define SLP_TYP_S4 6
 #define SLP_TYP_S5 7
 
+/* PM1_STS register */
+#define RTC_EN BIT(10)
+#define PWRBTN_EN BIT(8)
+
 /* Memory size reserved for S3 resume */
 #define S3_RESERVE_SIZE 0x1000
 
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 35/59] x86: apl: Add support for hostbridge ACPI generation

Simon Glass-3
In reply to this post by Simon Glass-3
Support generating a DMAR table and add a few helper routines as well.
Also set up NHLT so that audio works.

Signed-off-by: Simon Glass <[hidden email]>
---

Changes in v4:
Drop extra acpi_align() in apl_acpi_hb_write_tables()

Changes in v1:
- Add support for NHLT table
- Capitalise ACPI_OPS_PTR
- Move the acpi.h header file to this commit
- Update commit message

 arch/x86/cpu/apollolake/hostbridge.c | 220 +++++++++++++++++++++++++--
 1 file changed, 211 insertions(+), 9 deletions(-)

diff --git a/arch/x86/cpu/apollolake/hostbridge.c b/arch/x86/cpu/apollolake/hostbridge.c
index 056f7e57a9a..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 <[hidden email]> for Intel Corp.)
+ * (Written by Andrey Petrov <[hidden email]> 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,17 +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,
+};
 
- BGSM = 0xb4,  /* Base GTT Stolen Memory */
- TSEG = 0xb8,  /* TSEG base */
- TOLUD = 0xbc,
+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)
@@ -167,6 +278,86 @@ 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([hidden email]): Consider adding code from coreboot's
+ * platform_fsp_notify_status()
+ */
+
+ return 0;
+}
+
 static ulong sa_read_reg(struct udevice *dev, int reg)
 {
  u32 val;
@@ -192,6 +383,14 @@ 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" },
  { }
@@ -203,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,
 };
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 36/59] x86: apl: Generate CPU tables

Simon Glass-3
In reply to this post by Simon Glass-3
Add ACPI generation to the APL CPU driver.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Capitalise ACPI_OPS_PTR
- Handle table generation without callbacks

 arch/x86/cpu/apollolake/cpu.c      | 77 ++++++++++++++++++++++++++++++
 arch/x86/lib/Makefile              |  3 +-
 configs/chromebook_coral_defconfig |  1 +
 3 files changed, 80 insertions(+), 1 deletion(-)

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/lib/Makefile b/arch/x86/lib/Makefile
index f04d275dd9a..1bcbb49a61f 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -38,7 +38,8 @@ obj-y += sfi.o
 obj-y += acpi.o
 obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o
 ifndef CONFIG_QEMU
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o acpigen.o
+obj-y += acpigen.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o
 endif
 obj-y += tables.o
 ifndef CONFIG_SPL_BUILD
diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig
index c9006e2f934..ef4dabbe26e 100644
--- a/configs/chromebook_coral_defconfig
+++ b/configs/chromebook_coral_defconfig
@@ -72,6 +72,7 @@ CONFIG_ENV_OVERWRITE=y
 CONFIG_REGMAP=y
 CONFIG_SYSCON=y
 CONFIG_SPL_OF_TRANSLATE=y
+CONFIG_INTEL_ACPIGEN=y
 CONFIG_CPU=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_DW=y
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 37/59] x86: apl: Generate ACPI table for LPC

Simon Glass-3
In reply to this post by Simon Glass-3
Add an ACPI table for the LPC on Apollo Lake.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Capitalise ACPI_OPS_PTR

 arch/x86/cpu/apollolake/lpc.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

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)
 };
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 38/59] x86: apl: Drop unnecessary code in PMC driver

Simon Glass-3
In reply to this post by Simon Glass-3
We don't have CONFIG_PCI in TPL but it is present in SPL, etc. So this
code is not needed. Drop it, and fix a code-style nit just above.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

 arch/x86/cpu/apollolake/pmc.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

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)
--
2.28.0.681.g6f77f65b4e-goog

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 39/59] tpm: cr50: Add ACPI support

Simon Glass-3
In reply to this post by Simon Glass-3
Generate ACPI information for this device so that Linux can use it
correctly.

Signed-off-by: Simon Glass <[hidden email]>
---

(no changes since v1)

Changes in v1:
- Capitalise ACPI_OPS_PTR
- Update for acpi_device_write_i2c_dev() return-value change
- Use acpi,ddn instead of acpi,desc

 drivers/tpm/cr50_i2c.c | 55 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index 1942c07c605..64831a42232 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -14,11 +14,14 @@
 #include <log.h>
 #include <spl.h>
 #include <tpm-v2.h>
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch/iomap.h>
 #include <asm/arch/pm.h>
 #include <linux/delay.h>
+#include <dm/acpi.h>
 
 enum {
  TIMEOUT_INIT_MS = 30000, /* Very long timeout for TPM init */
@@ -581,6 +584,53 @@ static int cr50_i2c_cleanup(struct udevice *dev)
  return 0;
 }
 
+static int cr50_acpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ char scope[ACPI_PATH_MAX];
+ char name[ACPI_NAME_MAX];
+ const char *hid;
+ int ret;
+
+ ret = acpi_device_scope(dev, scope, sizeof(scope));
+ if (ret)
+ return log_msg_ret("scope", ret);
+ ret = acpi_get_name(dev, name);
+ if (ret)
+ return log_msg_ret("name", ret);
+
+ hid = dev_read_string(dev, "acpi,hid");
+ if (!hid)
+ return log_msg_ret("hid", ret);
+
+ /* Device */
+ acpigen_write_scope(ctx, scope);
+ acpigen_write_device(ctx, name);
+ acpigen_write_name_string(ctx, "_HID", hid);
+ acpigen_write_name_integer(ctx, "_UID",
+   dev_read_u32_default(dev, "acpi,uid", 0));
+ acpigen_write_name_string(ctx, "_DDN",
+  dev_read_string(dev, "acpi,ddn"));
+ acpigen_write_sta(ctx, acpi_device_status(dev));
+
+ /* Resources */
+ acpigen_write_name(ctx, "_CRS");
+ acpigen_write_resourcetemplate_header(ctx);
+ ret = acpi_device_write_i2c_dev(ctx, dev);
+ if (ret < 0)
+ return log_msg_ret("i2c", ret);
+ ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev,
+  "ready-gpios");
+ if (ret < 0)
+ return log_msg_ret("irq_gpio", ret);
+
+ acpigen_write_resourcetemplate_footer(ctx);
+
+ acpigen_pop_len(ctx); /* Device */
+ acpigen_pop_len(ctx); /* Scope */
+
+ return 0;
+}
+
 enum {
  TPM_TIMEOUT_MS = 5,
  SHORT_TIMEOUT_MS = 750,
@@ -653,6 +703,10 @@ static int cr50_i2c_probe(struct udevice *dev)
  return 0;
 }
 
+struct acpi_ops cr50_acpi_ops = {
+ .fill_ssdt = cr50_acpi_fill_ssdt,
+};
+
 static const struct tpm_ops cr50_i2c_ops = {
  .open = cr50_i2c_open,
  .get_desc = cr50_i2c_get_desc,
@@ -675,5 +729,6 @@ U_BOOT_DRIVER(cr50_i2c) = {
  .probe = cr50_i2c_probe,
  .remove = cr50_i2c_cleanup,
  .priv_auto_alloc_size = sizeof(struct cr50_priv),
+ ACPI_OPS_PTR(&cr50_acpi_ops)
  .flags = DM_FLAG_OS_PREPARE,
 };
--
2.28.0.681.g6f77f65b4e-goog

1234