Message ID | 20240727071742.1735703-13-patrick.rudolph@9elements.com |
---|---|
State | Changes Requested |
Delegated to: | Simon Glass |
Headers | show |
Series | Implement ACPI on aarch64 | expand |
Hi Patrick, On Sat, 27 Jul 2024 at 01:20, Patrick Rudolph <patrick.rudolph@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@9elements.com> > Cc: Simon Glass <sjg@chromium.org> > Cc: Matthias Brugger <mbrugger@suse.com> > Cc: Peter Robinson <pbrobinson@gmail.com> > Cc: Tom Rini <trini@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 = >dt->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
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 = >dt->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 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); + + /* 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
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@9elements.com> Cc: Simon Glass <sjg@chromium.org> Cc: Matthias Brugger <mbrugger@suse.com> Cc: Peter Robinson <pbrobinson@gmail.com> Cc: Tom Rini <trini@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