[PATCH 40/40] RFC: rpi: Enable booting with ACPI tables
Simon Glass
sjg at chromium.org
Wed Dec 1 17:03:14 CET 2021
This is only partially implemented and includes RFC patches.
So far it boots into grub but is unable to read the OS from the USB stick,
presumably because the XHCI SSDT is missing.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
arch/arm/include/asm/acpi_table.h | 15 +
board/raspberrypi/rpi/Makefile | 2 +
board/raspberrypi/rpi/rpi.c | 460 +++++++++++++++++++++++++++++-
configs/rpi_4_defconfig | 2 +
4 files changed, 478 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/acpi_table.h b/arch/arm/include/asm/acpi_table.h
index e69de29bb2d..930e857edeb 100644
--- a/arch/arm/include/asm/acpi_table.h
+++ b/arch/arm/include/asm/acpi_table.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 Google LLC
+ */
+
+#ifndef __ASM_ACPI_TABLE_H__
+#define __ASM_ACPI_TABLE_H__
+
+#ifndef __ACPI__
+
+ulong write_acpi_tables(ulong start);
+
+#endif
+
+#endif /* __ASM_ACPI_TABLE_H__ */
diff --git a/board/raspberrypi/rpi/Makefile b/board/raspberrypi/rpi/Makefile
index b1186cdf100..67f6b05e654 100644
--- a/board/raspberrypi/rpi/Makefile
+++ b/board/raspberrypi/rpi/Makefile
@@ -4,3 +4,5 @@
obj-y := rpi.o
obj-y += lowlevel_init.o
+
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 55afaa54d9f..3fe69c66da2 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -3,6 +3,8 @@
* (C) Copyright 2012-2016 Stephen Warren
*/
+#define LOG_CATEGORY LOGC_BOARD
+
#include <common.h>
#include <config.h>
#include <dm.h>
@@ -12,19 +14,29 @@
#include <fdt_simplefb.h>
#include <init.h>
#include <lcd.h>
+#include <log.h>
#include <memalign.h>
#include <mmc.h>
+#include <signatures.h>
+#include <tables_csum.h>
+#include <acpi/acpi_table.h>
+#include <asm/acpi_table.h>
+#include <asm/global_data.h>
#include <asm/gpio.h>
#include <asm/arch/mbox.h>
#include <asm/arch/msg.h>
#include <asm/arch/sdhci.h>
-#include <asm/global_data.h>
+#include <asm/arch/acpi/bcm2836.h>
+#include <dm/acpi.h>
#include <dm/platform_data/serial_bcm283x_mu.h>
#ifdef CONFIG_ARM64
#include <asm/armv8/mmu.h>
#endif
#include <watchdog.h>
#include <dm/pinctrl.h>
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+#include "acpitables.h"
+#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -515,3 +527,449 @@ int ft_board_setup(void *blob, struct bd_info *bd)
return 0;
}
+
+#ifdef CONFIG_GENERATE_ACPI_TABLE
+int last_stage_init(void)
+{
+ int ret;
+
+ ret = write_acpi_tables(0x10000);
+ if (ret < 0) {
+ log_err("Failed to write tables\n");
+ return log_msg_ret("table", ret);
+ }
+
+ return 0;
+}
+
+static int rpi_write_facp(struct acpi_ctx *ctx, const struct acpi_writer *entry)
+{
+ struct acpi_table_header *header;
+ struct acpi_fadt *fadt;
+
+ fadt = ctx->current;
+ header = &fadt->header;
+
+ memset(fadt, '\0', sizeof(struct acpi_fadt));
+
+ acpi_fill_header(header, "FACP");
+ header->length = sizeof(struct acpi_fadt);
+ header->revision = ACPI_FADT_REV_ACPI_6_0;
+
+ fadt->firmware_ctrl = (ulong)ctx->facs;
+ fadt->dsdt = (ulong)ctx->dsdt;
+ fadt->preferred_pm_profile = ACPI_PM_APPLIANCE_PC;
+
+ fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_SLEEP_BUTTON |
+ ACPI_FADT_HW_REDUCED_ACPI;
+ fadt->arm_boot_arch = ACPI_ARM_PSCI_COMPLIANT;
+ fadt->minor_revision = 3;
+
+ fadt->x_firmware_ctl_l = (ulong)ctx->facs;
+ fadt->x_firmware_ctl_h = (ulong)ctx->facs >> 32;
+ fadt->x_dsdt_l = (ulong)ctx->dsdt;
+ fadt->x_dsdt_h = (ulong)ctx->dsdt >> 32;
+
+ header->checksum = table_compute_checksum(fadt, header->length);
+
+ acpi_add_table(ctx, fadt);
+
+ acpi_inc(ctx, sizeof(struct acpi_fadt));
+
+ return 0;
+}
+ACPI_WRITER(5facp, "FACP", rpi_write_facp, 0);
+
+#define GTDT_FLAG_INT_ACTIVE_LOW BIT(1)
+#define RPI_GTDT_GTIMER_FLAGS GTDT_FLAG_INT_ACTIVE_LOW
+
+/* ARM Architectural Timer Interrupt(GIC PPI) numbers */
+#define PcdArmArchTimerSecIntrNum 29
+#define PcdArmArchTimerIntrNum 30
+#define PcdArmArchTimerHypIntrNum 26
+#define PcdArmArchTimerVirtIntrNum 27
+
+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 = 3;
+
+ gtdt->cnt_ctrl_base = RPI_SYSTEM_TIMER_BASE_ADDRESS;
+ gtdt->sec_el1_gsiv = PcdArmArchTimerSecIntrNum;
+ gtdt->sec_el1_flags = RPI_GTDT_GTIMER_FLAGS;
+ gtdt->el1_gsiv = PcdArmArchTimerIntrNum;
+ gtdt->el1_flags = RPI_GTDT_GTIMER_FLAGS;
+ gtdt->virt_el1_gsiv = PcdArmArchTimerVirtIntrNum;
+ gtdt->virt_el1_flags = RPI_GTDT_GTIMER_FLAGS;
+ gtdt->el2_gsiv = PcdArmArchTimerHypIntrNum;
+ gtdt->el2_flags = RPI_GTDT_GTIMER_FLAGS;
+ gtdt->cnt_read_base = 0xffffffffffffffff;
+ acpi_add_table(ctx, gtdt);
+
+ acpi_inc(ctx, sizeof(struct acpi_gtdt));
+
+ return 0;
+};
+ACPI_WRITER(5gtdt, "GTDT", rpi_write_gtdt, 0);
+
+static int rpi_write_dbg2(struct acpi_ctx *ctx, const struct acpi_writer *entry)
+{
+ struct acpi_table_header *header;
+ struct acpi_dbg2_header *dbg2;
+ struct acpi_dbg2_device *ddev;
+ struct acpi_gen_regaddr *addr;
+ u32 *addr_size;
+ char *name;
+ void *end;
+
+ dbg2 = ctx->current;
+ header = &dbg2->header;
+
+ /* Note this doesn't zero everything */
+ memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
+
+ acpi_fill_header(header, "DBG2");
+ header->revision = 0;
+
+ dbg2->devices_offset = sizeof(*dbg2);
+ dbg2->devices_count = 1;
+
+ ddev = (void *)(dbg2 + 1);
+ ddev->revision = 0;
+ ddev->length = 0x35;
+ ddev->address_count = 1;
+ ddev->namespace_string_length = 0xf;
+ ddev->namespace_string_offset = 0x26;
+ ddev->oem_data_length = 0;
+ ddev->oem_data_offset = 0;
+ ddev->port_type = ACPI_DBG2_SERIAL_PORT;
+ ddev->port_subtype = ACPI_DBG2_ARM_PL011;
+
+ addr = (void *)(ddev + 1);
+ ddev->base_address_offset = sizeof(*ddev);
+ ddev->address_size_offset = sizeof(*ddev) + sizeof(*addr);
+
+ addr->space_id = ACPI_ADDRESS_SPACE_MEMORY;
+ addr->bit_width = 32;
+ addr->bit_offset = 0;
+ addr->access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ addr->addrl = 0xfe201000;
+ addr->addrh = 0;
+
+ addr_size = (u32 *)(addr + 1);
+ *addr_size = 0x1000;
+
+ name = (char *)(addr_size + 1);
+ strcpy(name, "\\_SB.GDV0.URT0");
+ end = name + strlen(name) + 1;
+ header->length = end - ctx->current;
+ acpi_add_table(ctx, dbg2);
+
+ acpi_inc(ctx, header->length);
+
+ return 0;
+};
+ACPI_WRITER(5dbg2, "DBG2", rpi_write_dbg2, 0);
+
+#if 0
+/* Need to add a logo first */
+static int rpi_write_bgrt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
+{
+ struct acpi_table_header *header;
+ struct acpi_bgrt_header *bgrt;
+
+ bgrt = ctx->current;
+ header = &dbg2->header;
+
+ memset(bgrt, '\0', sizeof(struct acpi_bgrt));
+
+ acpi_fill_header(header, "BGRT");
+ header->revision = 0;
+
+ acpi_inc(ctx, header->length);
+
+ return 0;
+};
+ACPI_WRITER(5bgrt, "BGRT", rpi_write_bgrt, 0);
+#endif
+
+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 rpi_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 = 0;
+ 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", rpi_write_pptt, 0);
+
+static void acpi_write_madt_gicc(struct acpi_ctx *ctx, uint cpu_num,
+ uint perf_gsiv, ulong phys_base, ulong gicv,
+ ulong gich, uint vgic_maint_irq, ulong mpidr,
+ uint efficiency)
+{
+ struct acpi_madr_gicc *gicc = ctx->current;
+
+ memset(gicc, '\0', sizeof(struct acpi_madr_gicc));
+ gicc->type = ACPI_APIC_GICC;
+ gicc->length = sizeof(struct acpi_madr_gicc);
+ gicc->cpu_if_num = cpu_num;
+ gicc->processor_id = cpu_num;
+ gicc->flags = ACPI_MADRF_ENABLED;
+ gicc->perf_gsiv = perf_gsiv;
+ gicc->phys_base = phys_base;
+ gicc->gicv = gicv;
+ gicc->gich = gich;
+ gicc->vgic_maint_irq = vgic_maint_irq;
+ gicc->mpidr = mpidr;
+ gicc->efficiency = efficiency;
+ acpi_inc(ctx, gicc->length);
+}
+
+static void acpi_write_madt_gicd(struct acpi_ctx *ctx, uint gic_id,
+ ulong phys_base, uint gic_version)
+{
+ struct acpi_madr_gicd *gicd = ctx->current;
+
+ memset(gicd, '\0', sizeof(struct acpi_madr_gicd));
+ gicd->type = ACPI_APIC_GICD;
+ gicd->length = sizeof(struct acpi_madr_gicd);
+ gicd->gic_id = gic_id;
+ gicd->phys_base = phys_base;
+ gicd->gic_version = gic_version;
+
+ acpi_inc(ctx, gicd->length);
+}
+
+static int rpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
+{
+ struct acpi_table_header *header;
+ struct acpi_madt *madt;
+ int i;
+
+ ctx->tab_start = ctx->current;
+ madt = ctx->current;
+
+ memset(madt, '\0', sizeof(struct acpi_madt));
+ header = &madt->header;
+
+ /* Fill out header fields */
+ acpi_fill_header(header, "APIC");
+ header->length = sizeof(struct acpi_madt);
+ header->revision = ACPI_MADT_REV_ACPI_6_0;
+
+ madt->lapic_addr = 0;
+ madt->flags = 0;
+ acpi_inc(ctx, sizeof(*madt));
+
+ for (i = 0; i < 4; i++) {
+ acpi_write_madt_gicc(ctx, i, 0x30 + i, 0xff842000, 0xff846000,
+ 0xff844000, 0x19, i, 1);
+ }
+ acpi_write_madt_gicd(ctx, 0, 0xff841000, 2);
+
+ /* (Re)calculate length and checksum */
+ header->length = (u32)(ctx->current - ctx->tab_start);
+
+ header->checksum = table_compute_checksum((void *)madt, header->length);
+ acpi_add_table(ctx, madt);
+ acpi_inc(ctx, madt->header.length);
+
+ return 0;
+}
+ACPI_WRITER(5madt, "APIC", rpi_write_madt, 0);
+
+/* DMA Controller Vendor Data */
+struct __packed dma_ctlr_vendor_data {
+ u32 length;
+ u32 type;
+ u64 chan_base;
+ u32 chan_size;
+ u64 ctlr_base;
+ u32 ctlr_size;
+ u32 chan_count;
+ u32 ctlr_irq;
+ u32 min_req_line;
+ u32 max_req_line;
+ u8 cache_coherent;
+};
+
+/* DMA Controller */
+struct __packed rd_dma_ctlr {
+ struct acpi_csrt_descriptor hdr;
+ struct dma_ctlr_vendor_data data;
+};
+
+/* dma chan vendor data */
+struct __packed dma_chan_vendor_data {
+ u32 chan;
+ u32 chan_irq;
+ u16 is_reserved;
+ u16 addr_incr;
+};
+
+/* dma chan */
+struct __packed rd_dma_chan {
+ struct acpi_csrt_descriptor hdr;
+ struct dma_chan_vendor_data data;
+};
+
+/* dma resource group */
+struct __packed rg_dma {
+ struct acpi_csrt_group hdr;
+ struct rd_dma_ctlr ctlr;
+ struct rd_dma_chan chan[];
+};
+
+#define RPI_DMA_MAX_REQ_LINES 32
+
+static void add_cmd_chan(struct rd_dma_chan *dmac, uint uid, uint chan,
+ uint chan_irq, bool is_reserved, int addr_incr)
+{
+ memset(dmac, '\0', sizeof(*dmac));
+ dmac->hdr.length = sizeof(struct rd_dma_chan);
+ dmac->hdr.type = EFI_ACPI_CSRT_RESOURCE_TYPE_DMA;
+ dmac->hdr.subtype = EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CHANNEL;
+ dmac->hdr.uid = uid;
+
+ dmac->data.chan = chan;
+ dmac->data.chan_irq = chan_irq;
+ dmac->data.is_reserved = is_reserved;
+ dmac->data.addr_incr = addr_incr;
+}
+
+int acpi_fill_csrt(struct acpi_ctx *ctx)
+{
+ struct dma_ctlr_vendor_data *data;
+ struct acpi_csrt_group *hdr;
+ struct rg_dma *dma;
+ int i;
+
+ dma = ctx->current;
+ hdr = &dma->hdr;
+ memset(hdr, '\0', sizeof(*hdr));
+ hdr->length = 0;
+ hdr->vendor_id = SIGNATURE_32('R', 'P', 'I', 'F');
+ hdr->device_id = EFI_ACPI_CSRT_DEVICE_ID_DMA;
+
+ dma->ctlr.hdr.length = sizeof(struct rd_dma_ctlr);
+ dma->ctlr.hdr.type = EFI_ACPI_CSRT_RESOURCE_TYPE_DMA;
+ dma->ctlr.hdr.subtype = EFI_ACPI_CSRT_RESOURCE_SUBTYPE_DMA_CONTROLLER;
+ dma->ctlr.hdr.uid = EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP;
+
+ data = &dma->ctlr.data;
+ data->length = sizeof(struct dma_ctlr_vendor_data);
+ data->type = 1;
+ data->chan_base = BCM2836_DMA0_BASE_ADDRESS;
+ data->chan_size = RPI_DMA_CHANNEL_COUNT * BCM2836_DMA_CHANNEL_LENGTH;
+ data->ctlr_base = BCM2836_DMA_CTRL_BASE_ADDRESS;
+ data->ctlr_size = 8;
+ data->chan_count = RPI_DMA_USED_CHANNEL_COUNT;
+ data->max_req_line = RPI_DMA_MAX_REQ_LINES - 1;
+
+ acpi_inc(ctx, sizeof(struct rg_dma));
+
+ for (i = 0; i < 10; i++) {
+ add_cmd_chan(&dma->chan[i],
+ EFI_ACPI_CSRT_RESOURCE_ID_IN_DMA_GRP + 1 + i, i,
+ 0x30 + i,
+ i == 1 || i == 2 || i == 3 || i == 6 || i == 7,
+ i == 4);
+ acpi_inc(ctx, sizeof(struct rd_dma_chan));
+ }
+
+ hdr->length = (u32)(ctx->current - (void *)dma);
+
+ return 0;
+}
+#endif
diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig
index 0720505c6a5..4a81f3e1f38 100644
--- a/configs/rpi_4_defconfig
+++ b/configs/rpi_4_defconfig
@@ -11,6 +11,7 @@ CONFIG_USE_PREBOOT=y
CONFIG_PREBOOT="pci enum; usb start;"
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_LAST_STAGE_INIT=y
CONFIG_MISC_INIT_R=y
CONFIG_SYS_PROMPT="U-Boot> "
CONFIG_CMD_DFU=y
@@ -60,4 +61,5 @@ CONFIG_DM_VIDEO=y
CONFIG_SYS_WHITE_ON_BLACK=y
CONFIG_CONSOLE_SCROLL_LINES=10
CONFIG_PHYS_TO_BUS=y
+CONFIG_GENERATE_ACPI_TABLE=y
CONFIG_OF_LIBFDT_OVERLAY=y
--
2.34.0.rc2.393.gf8c9666880-goog
More information about the U-Boot
mailing list