[PATCH 12/17] arm: bcm283x: Write ACPI tables

Simon Glass sjg at chromium.org
Mon Jul 29 17:28:40 CEST 2024


Hi Patrick,

On Sat, 27 Jul 2024 at 01:20, Patrick Rudolph
<patrick.rudolph at 9elements.com> wrote:
>
> Allocate a 64KiB buffer for ACPI tables and provide SoC specific tables
> for BCM2711:
> - MADT
> - FADT
> - PPTT
> - GTDT
> - SPCR
>
> Board specific tables like DSDT and SSDT are added in a separate patch.
>
> When ACPI is enabled for a different SoC compliation will fail by
> design, indicating the required functions that needs to be implemented.
> When ACPI is not enabled the added code does nothing, keeping existing
> behaviour.
>
> TEST: Booted on RPi4 with only ACPI enabled, providing no FDT to the OS.
>
> Signed-off-by: Patrick Rudolph <patrick.rudolph at 9elements.com>
> Cc: Simon Glass <sjg at chromium.org>
> Cc: Matthias Brugger <mbrugger at suse.com>
> Cc: Peter Robinson <pbrobinson at gmail.com>
> Cc: Tom Rini <trini at konsulko.com>
> ---
>  arch/arm/mach-bcm283x/Makefile       |   4 +
>  arch/arm/mach-bcm283x/bcm2711_acpi.c | 172 +++++++++++++++++++++++++++
>  arch/arm/mach-bcm283x/init.c         |  30 +++++
>  3 files changed, 206 insertions(+)
>  create mode 100644 arch/arm/mach-bcm283x/bcm2711_acpi.c
>
> diff --git a/arch/arm/mach-bcm283x/Makefile b/arch/arm/mach-bcm283x/Makefile
> index 7cd068832f..38e320307d 100644
> --- a/arch/arm/mach-bcm283x/Makefile
> +++ b/arch/arm/mach-bcm283x/Makefile
> @@ -4,3 +4,7 @@
>
>  obj-$(CONFIG_BCM2835) += lowlevel_init.o
>  obj-y  += init.o reset.o mbox.o msg.o phys2bus.o
> +
> +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),y)
> +obj-$(CONFIG_BCM2711) += bcm2711_acpi.o
> +endif
> \ No newline at end of file
> diff --git a/arch/arm/mach-bcm283x/bcm2711_acpi.c b/arch/arm/mach-bcm283x/bcm2711_acpi.c
> new file mode 100644
> index 0000000000..ab0f77c245
> --- /dev/null
> +++ b/arch/arm/mach-bcm283x/bcm2711_acpi.c
> @@ -0,0 +1,172 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) Copyright 2024 9elements GmbH
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + */
> +
> +#include <acpi/acpi_table.h>
> +#include <asm/acpi_table.h>
> +#include <asm/armv8/sec_firmware.h>
> +#include <asm/arch/acpi/bcm2711.h>
> +#include <tables_csum.h>
> +#include <string.h>
> +
> +void acpi_fill_fadt(struct acpi_fadt *fadt)
> +{
> +       fadt->flags = ACPI_FADT_HW_REDUCED_ACPI | ACPI_FADT_LOW_PWR_IDLE_S0;
> +
> +       if (CONFIG_IS_ENABLED(SEC_FIRMWARE_ARMV8_PSCI) &&
> +           sec_firmware_support_psci_version() != PSCI_INVALID_VER)
> +               fadt->arm_boot_arch = ACPI_ARM_PSCI_COMPLIANT;
> +}
> +
> +void *acpi_fill_madt(struct acpi_madt *madt, void *current)
> +{
> +       struct acpi_madt_gicc *gicc;
> +       struct acpi_madt_gicd *gicd;
> +
> +       madt->lapic_addr = 0;
> +       madt->flags = 0;
> +
> +       gicc = current;
> +       for (int i = 0; i < 4; i++) {
> +               acpi_write_madt_gicc(gicc++, i, 0x30 + i, BCM2711_GIC400_BASE_ADDRESS + 0x2000,
> +                                    BCM2711_GIC400_BASE_ADDRESS + 0x6000,
> +                                    BCM2711_GIC400_BASE_ADDRESS + 0x4000,
> +                                    0x19, i, 1);
> +       }
> +
> +       gicd = (struct acpi_madt_gicd *)gicc;
> +       acpi_write_madt_gicd(gicd++, 0, BCM2711_GIC400_BASE_ADDRESS + 0x1000, 2);
> +       return gicd;
> +}
> +
> +static u32 *add_proc(struct acpi_ctx *ctx, int flags, int parent, int proc_id,
> +                    int num_resources)
> +{
> +       struct acpi_pptt_proc *proc = ctx->current;
> +       u32 *resource_list;
> +
> +       proc->hdr.type = ACPI_PPTT_TYPE_PROC;
> +       proc->flags = flags;
> +       proc->parent = parent;
> +       proc->proc_id = proc_id;
> +       proc->num_resources = num_resources;
> +       proc->hdr.length = sizeof(struct acpi_pptt_proc) +
> +               sizeof(u32) * num_resources;
> +       resource_list = ctx->current + sizeof(struct acpi_pptt_proc);
> +       acpi_inc(ctx, proc->hdr.length);
> +
> +       return resource_list;
> +}
> +
> +static int add_cache(struct acpi_ctx *ctx, int flags, int size, int sets,
> +                    int assoc, int attributes, int line_size)
> +{
> +       struct acpi_pptt_cache *cache = ctx->current;
> +       int ofs;
> +
> +       ofs = ctx->current - ctx->tab_start;
> +       cache->hdr.type = ACPI_PPTT_TYPE_CACHE;
> +       cache->hdr.length = sizeof(struct acpi_pptt_cache);
> +       cache->flags = flags;
> +       cache->next_cache_level = 0;
> +       cache->size = size;
> +       cache->sets = sets;
> +       cache->assoc = assoc;
> +       cache->attributes = attributes;
> +       cache->line_size = line_size;
> +       acpi_inc(ctx, cache->hdr.length);
> +
> +       return ofs;
> +}
> +
> +static int acpi_write_pptt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
> +{
> +       struct acpi_table_header *header;
> +       int proc_ofs;
> +       u32 *proc_ptr;
> +       int ofs, ofs0, ofs1, i;
> +
> +       header = ctx->current;
> +       ctx->tab_start = ctx->current;
> +
> +       memset(header, '\0', sizeof(struct acpi_table_header));
> +
> +       acpi_fill_header(header, "PPTT");
> +       header->revision = acpi_get_table_revision(ACPITAB_PPTT);
> +       acpi_inc(ctx, sizeof(*header));
> +
> +       proc_ofs = ctx->current - ctx->tab_start;
> +       proc_ptr = add_proc(ctx, ACPI_PPTT_PHYSICAL_PACKAGE |
> +                           ACPI_PPTT_CHILDREN_IDENTICAL, 0, 0, 1);
> +
> +       ofs = add_cache(ctx, ACPI_PPTT_ALL_VALID, 0x100000, 0x400, 0x10,
> +                       ACPI_PPTT_WRITE_ALLOC |
> +                       (ACPI_PPTT_CACHE_TYPE_UNIFIED <<
> +                        ACPI_PPTT_CACHE_TYPE_SHIFT), 0x40);
> +       *proc_ptr = ofs;
> +
> +       for (i = 0; i < 4; i++) {
> +               proc_ptr = add_proc(ctx, ACPI_PPTT_CHILDREN_IDENTICAL |
> +                                   ACPI_PPTT_NODE_IS_LEAF | ACPI_PPTT_PROC_ID_VALID,
> +                                   proc_ofs, i, 2);
> +
> +               ofs0 = add_cache(ctx, ACPI_PPTT_ALL_VALID, 0x8000, 0x100, 2,
> +                                ACPI_PPTT_WRITE_ALLOC, 0x40);
> +
> +               ofs1 = add_cache(ctx, ACPI_PPTT_ALL_BUT_WRITE_POL, 0xc000, 0x100, 3,
> +                                ACPI_PPTT_CACHE_TYPE_INSTR <<
> +                                ACPI_PPTT_CACHE_TYPE_SHIFT, 0x40);
> +               proc_ptr[0] = ofs0;
> +               proc_ptr[1] = ofs1;
> +       }
> +
> +       header->length = ctx->current - ctx->tab_start;
> +       header->checksum = table_compute_checksum(header, header->length);
> +
> +       acpi_inc(ctx, header->length);
> +       acpi_add_table(ctx, header);
> +
> +       return 0;
> +};
> +
> +ACPI_WRITER(5pptt, "PPTT", acpi_write_pptt, 0);
> +
> +static int rpi_write_gtdt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
> +{
> +       struct acpi_table_header *header;
> +       struct acpi_gtdt *gtdt;
> +
> +       gtdt = ctx->current;
> +       header = &gtdt->header;
> +
> +       memset(gtdt, '\0', sizeof(struct acpi_gtdt));
> +
> +       acpi_fill_header(header, "GTDT");
> +       header->length = sizeof(struct acpi_gtdt);
> +       header->revision = acpi_get_table_revision(ACPITAB_GTDT);
> +
> +       gtdt->cnt_ctrl_base = BCM2711_ARM_LOCAL_BASE_ADDRESS + 0x1c;
> +       gtdt->sec_el1_gsiv = 29;
> +       gtdt->sec_el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->el1_gsiv = 30;
> +       gtdt->el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->virt_el1_gsiv = 27;
> +       gtdt->virt_el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->el2_gsiv = 26;
> +       gtdt->el2_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->cnt_read_base = 0xffffffffffffffff;
> +
> +       header->checksum = table_compute_checksum(header, header->length);
> +
> +       acpi_add_table(ctx, gtdt);
> +
> +       acpi_inc(ctx, sizeof(struct acpi_gtdt));
> +
> +       return 0;
> +};
> +
> +ACPI_WRITER(5gtdt, "GTDT", rpi_write_gtdt, 0);
> \ No newline at end of file
> diff --git a/arch/arm/mach-bcm283x/init.c b/arch/arm/mach-bcm283x/init.c

This should be in arch/arm/lib or similar, i.e. generic code.

> index 7a1de22e0a..80a10f2212 100644
> --- a/arch/arm/mach-bcm283x/init.c
> +++ b/arch/arm/mach-bcm283x/init.c
> @@ -6,11 +6,13 @@
>   * project.
>   */
>
> +#include <acpi/acpi_table.h>
>  #include <cpu_func.h>
>  #include <init.h>
>  #include <dm/device.h>
>  #include <fdt_support.h>
>  #include <asm/global_data.h>
> +#include <malloc.h>
>
>  #define BCM2711_RPI4_PCIE_XHCI_MMIO_PHYS       0x600000000UL
>  #define BCM2711_RPI4_PCIE_XHCI_MMIO_SIZE       0x400000UL
> @@ -240,3 +242,31 @@ void enable_caches(void)
>         dcache_enable();
>  }
>  #endif
> +
> +#ifdef CONFIG_GENERATE_ACPI_TABLE
> +static int last_stage_init(void)
> +{
> +       ulong end;
> +       void *ptr;
> +
> +       /* Reserve 64K for ACPI tables, aligned to a 4K boundary */
> +       ptr = memalign(SZ_4K, SZ_64K);

We should really put tables in a bloblist on ARM. This is an option on
x86 but we should make it mandatory on ARM. We may have other tables,
such as SMBIOS.

> +
> +       /* Generate ACPI tables */
> +       end = write_acpi_tables((uintptr_t)ptr);
> +       if (end < 0) {
> +               log_err("Failed to write tables\n");
> +               return log_msg_ret("table", end);
> +       }
> +       if (end > ((ulong)ptr + SZ_64K)) {
> +               log_err("ACPI tables overflowed\n");
> +               return 0;
> +       }
> +
> +       gd->arch.table_start = (uintptr_t)ptr;
> +       gd->arch.table_end = end;
> +
> +       return 0;
> +}
> +EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, last_stage_init);
> +#endif
> \ No newline at end of file

But there should be :-)

> --
> 2.45.2
>

Regards,
Simon


More information about the U-Boot mailing list