- DM ACPI support (Part A)
- Improve support for chain-loading x86 U-Boot
This commit is contained in:
Tom Rini 2020-04-30 13:00:20 -04:00
commit 9f0a6df3a5
30 changed files with 983 additions and 232 deletions

View File

@ -226,6 +226,10 @@
compatible = "denx,u-boot-acpi-test";
};
acpi-test2 {
compatible = "denx,u-boot-acpi-test";
};
clocks {
clk_fixed: clk-fixed {
compatible = "fixed-clock";

View File

@ -13,6 +13,7 @@
struct arch_global_data {
uint8_t *ram_buf; /* emulated RAM buffer */
void *text_base; /* pointer to base of text region */
ulong acpi_start; /* Start address of ACPI tables */
};
#include <asm-generic/global_data.h>

View File

@ -566,6 +566,8 @@ int arch_fsp_init_r(void)
struct udevice *dev, *itss;
int ret;
if (!ll_boot_init())
return 0;
/*
* This must be called before any devices are probed. Put any probing
* into arch_fsps_preinit() above.

View File

@ -115,20 +115,11 @@ __weak void cb_parse_unhandled(u32 tag, unsigned char *ptr)
static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
{
unsigned char *ptr = addr;
struct cb_header *header;
unsigned char *ptr = (unsigned char *)addr;
int i;
for (i = 0; i < len; i += 16, ptr += 16) {
header = (struct cb_header *)ptr;
if (!strncmp((const char *)header->signature, "LBIO", 4))
break;
}
/* We walked the entire space and didn't find anything. */
if (i >= len)
return -1;
header = (struct cb_header *)ptr;
if (!header->table_bytes)
return 0;
@ -231,10 +222,13 @@ static int cb_parse_header(void *addr, int len, struct sysinfo_t *info)
int get_coreboot_info(struct sysinfo_t *info)
{
int ret = cb_parse_header((void *)0x00000000, 0x1000, info);
long addr;
int ret;
if (ret != 1)
ret = cb_parse_header((void *)0x000f0000, 0x1000, info);
addr = locate_coreboot_table();
if (addr < 0)
return addr;
ret = cb_parse_header((void *)addr, 0x1000, info);
return (ret == 1) ? 0 : -1;
return ret == 1 ? 0 : -ENOENT;
}

View File

@ -239,8 +239,10 @@ int cpu_init_r(void)
struct udevice *dev;
int ret;
if (!ll_boot_init())
if (!ll_boot_init()) {
uclass_first_device(UCLASS_PCI, &dev);
return 0;
}
ret = x86_init_cpus();
if (ret)

View File

@ -447,10 +447,37 @@ int x86_cpu_init_f(void)
return 0;
}
long detect_coreboot_table_at(ulong start, ulong size)
{
u32 *ptr, *end;
size /= 4;
for (ptr = (void *)start, end = ptr + size; ptr < end; ptr += 4) {
if (*ptr == 0x4f49424c) /* "LBIO" */
return (long)ptr;
}
return -ENOENT;
}
long locate_coreboot_table(void)
{
long addr;
/* We look for LBIO in the first 4K of RAM and again at 960KB */
addr = detect_coreboot_table_at(0x0, 0x1000);
if (addr < 0)
addr = detect_coreboot_table_at(0xf0000, 0x1000);
return addr;
}
int x86_cpu_reinit_f(void)
{
setup_identity();
setup_pci_ram_top();
if (locate_coreboot_table() >= 0)
gd->flags |= GD_FLG_SKIP_LL_INIT;
return 0;
}

View File

@ -264,6 +264,9 @@ int interrupt_init(void)
struct udevice *dev;
int ret;
if (!ll_boot_init())
return 0;
/* Try to set up the interrupt router, but don't require one */
ret = irq_first_device_type(X86_IRQT_BASE, &dev);
if (ret && ret != -ENODEV)
@ -295,8 +298,7 @@ int interrupt_init(void)
* TODO(sjg@chromium.org): But we don't handle these correctly when
* booted from EFI.
*/
if (ll_boot_init())
enable_interrupts();
enable_interrupts();
#endif
return 0;

View File

@ -14,18 +14,30 @@
.globl _start
.type _start, @function
_start:
/* Set up memory using the existing stack */
/*
* If running from coreboot, CAR is no-longer available. Use the
* existing stack, which is large enough.
*/
call locate_coreboot_table
cmp $0, %eax
jge use_existing_stack
movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %eax
#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE
subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %eax
#endif
jmp 2f
/*
* We don't subject CONFIG_DCACHE_RAM_MRC_VAR_SIZE since memory is
* We don't subtract CONFIG_DCACHE_RAM_MRC_VAR_SIZE since memory is
* already set up. This has the happy side-effect of putting gd in a
* new place separate from SPL, so the memset() in
* board_init_f_init_reserve() does not cause any problems (otherwise
* it would zero out the gd and crash)
*/
/* Set up memory using the existing stack */
use_existing_stack:
mov %esp, %eax
2:
call board_init_f_alloc_reserve
mov %eax, %esp

View File

@ -343,4 +343,11 @@ void *high_table_malloc(size_t bytes);
*/
void write_coreboot_table(u32 addr, struct memory_area *cfg_tables);
/**
* locate_coreboot_table() - Try to find coreboot tables at standard locations
*
* @return address of table that was found, or -ve error number
*/
long locate_coreboot_table(void);
#endif

View File

@ -123,6 +123,7 @@ struct arch_global_data {
#ifdef CONFIG_FSP_VERSION2
struct fsp_header *fsp_s_hdr; /* Pointer to FSP-S header */
#endif
ulong acpi_start; /* Start address of ACPI tables */
};
#endif

View File

@ -10,6 +10,7 @@
#include <cpu.h>
#include <dm.h>
#include <dm/uclass-internal.h>
#include <mapmem.h>
#include <serial.h>
#include <version.h>
#include <acpi/acpi_table.h>
@ -19,6 +20,7 @@
#include <asm/mpspec.h>
#include <asm/tables.h>
#include <asm/arch/global_nvs.h>
#include <dm/acpi.h>
/*
* IASL compiles the dsdt entries and writes the hex values
@ -29,139 +31,6 @@ extern const unsigned char AmlCode[];
/* ACPI RSDP address to be used in boot parameters */
static ulong acpi_rsdp_addr;
static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
struct acpi_xsdt *xsdt)
{
memset(rsdp, 0, sizeof(struct acpi_rsdp));
memcpy(rsdp->signature, RSDP_SIG, 8);
memcpy(rsdp->oem_id, OEM_ID, 6);
rsdp->length = sizeof(struct acpi_rsdp);
rsdp->rsdt_address = (u32)rsdt;
/*
* Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2
*
* Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
* If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
* revision 0)
*/
if (xsdt == NULL) {
rsdp->revision = ACPI_RSDP_REV_ACPI_1_0;
} else {
rsdp->xsdt_address = (u64)(u32)xsdt;
rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
}
/* Calculate checksums */
rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
sizeof(struct acpi_rsdp));
}
void acpi_fill_header(struct acpi_table_header *header, char *signature)
{
memcpy(header->signature, signature, 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
header->oem_revision = U_BOOT_BUILD_DATE;
memcpy(header->aslc_id, ASLC_ID, 4);
}
static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
{
struct acpi_table_header *header = &(rsdt->header);
/* Fill out header fields */
acpi_fill_header(header, "RSDT");
header->length = sizeof(struct acpi_rsdt);
header->revision = 1;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum((void *)rsdt,
sizeof(struct acpi_rsdt));
}
static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
{
struct acpi_table_header *header = &(xsdt->header);
/* Fill out header fields */
acpi_fill_header(header, "XSDT");
header->length = sizeof(struct acpi_xsdt);
header->revision = 1;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum((void *)xsdt,
sizeof(struct acpi_xsdt));
}
/**
* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
* and checksum.
*/
static void acpi_add_table(struct acpi_rsdp *rsdp, void *table)
{
int i, entries_num;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
/* The RSDT is mandatory while the XSDT is not */
rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
/* This should always be MAX_ACPI_TABLES */
entries_num = ARRAY_SIZE(rsdt->entry);
for (i = 0; i < entries_num; i++) {
if (rsdt->entry[i] == 0)
break;
}
if (i >= entries_num) {
debug("ACPI: Error: too many tables\n");
return;
}
/* Add table to the RSDT */
rsdt->entry[i] = (u32)table;
/* Fix RSDT length or the kernel will assume invalid entries */
rsdt->header.length = sizeof(struct acpi_table_header) +
sizeof(u32) * (i + 1);
/* Re-calculate checksum */
rsdt->header.checksum = 0;
rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
rsdt->header.length);
/* The RSDT is mandatory while the XSDT is not */
if (!rsdp->xsdt_address)
return;
/*
* And now the same thing for the XSDT. We use the same index as for
* now we want the XSDT and RSDT to always be in sync in U-Boot
*/
xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
/* Add table to the XSDT */
xsdt->entry[i] = (u64)(u32)table;
/* Fix XSDT length */
xsdt->header.length = sizeof(struct acpi_table_header) +
sizeof(u64) * (i + 1);
/* Re-calculate checksum */
xsdt->header.checksum = 0;
xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
xsdt->header.length);
}
static void acpi_create_facs(struct acpi_facs *facs)
{
memset((void *)facs, 0, sizeof(struct acpi_facs));
@ -487,12 +356,9 @@ static void acpi_create_spcr(struct acpi_spcr *spcr)
/*
* QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
*/
ulong write_acpi_tables(ulong start)
ulong write_acpi_tables(ulong start_addr)
{
u32 current;
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
struct acpi_ctx sctx, *ctx = &sctx;
struct acpi_facs *facs;
struct acpi_table_header *dsdt;
struct acpi_fadt *fadt;
@ -500,60 +366,39 @@ ulong write_acpi_tables(ulong start)
struct acpi_madt *madt;
struct acpi_csrt *csrt;
struct acpi_spcr *spcr;
void *start;
ulong addr;
int i;
current = start;
start = map_sysmem(start_addr, 0);
/* Align ACPI tables to 16 byte */
current = ALIGN(current, 16);
debug("ACPI: Writing ACPI tables at %lx\n", start_addr);
debug("ACPI: Writing ACPI tables at %lx\n", start);
/* We need at least an RSDP and an RSDT Table */
rsdp = (struct acpi_rsdp *)current;
current += sizeof(struct acpi_rsdp);
current = ALIGN(current, 16);
rsdt = (struct acpi_rsdt *)current;
current += sizeof(struct acpi_rsdt);
current = ALIGN(current, 16);
xsdt = (struct acpi_xsdt *)current;
current += sizeof(struct acpi_xsdt);
/*
* Per ACPI spec, the FACS table address must be aligned to a 64 byte
* boundary (Windows checks this, but Linux does not).
*/
current = ALIGN(current, 64);
/* clear all table memory */
memset((void *)start, 0, current - start);
acpi_write_rsdp(rsdp, rsdt, xsdt);
acpi_write_rsdt(rsdt);
acpi_write_xsdt(xsdt);
acpi_setup_base_tables(ctx, start);
debug("ACPI: * FACS\n");
facs = (struct acpi_facs *)current;
current += sizeof(struct acpi_facs);
current = ALIGN(current, 16);
facs = ctx->current;
acpi_inc_align(ctx, sizeof(struct acpi_facs));
acpi_create_facs(facs);
debug("ACPI: * DSDT\n");
dsdt = (struct acpi_table_header *)current;
dsdt = ctx->current;
memcpy(dsdt, &AmlCode, sizeof(struct acpi_table_header));
current += sizeof(struct acpi_table_header);
memcpy((char *)current,
acpi_inc(ctx, sizeof(struct acpi_table_header));
memcpy(ctx->current,
(char *)&AmlCode + sizeof(struct acpi_table_header),
dsdt->length - sizeof(struct acpi_table_header));
current += dsdt->length - sizeof(struct acpi_table_header);
current = ALIGN(current, 16);
acpi_inc_align(ctx, dsdt->length - sizeof(struct acpi_table_header));
/* Pack GNVS into the ACPI table area */
for (i = 0; i < dsdt->length; i++) {
u32 *gnvs = (u32 *)((u32)dsdt + i);
if (*gnvs == ACPI_GNVS_ADDR) {
debug("Fix up global NVS in DSDT to 0x%08x\n", current);
*gnvs = current;
ulong addr = (ulong)map_to_sysmem(ctx->current);
debug("Fix up global NVS in DSDT to %#08lx\n", addr);
*gnvs = addr;
break;
}
}
@ -563,51 +408,48 @@ ulong write_acpi_tables(ulong start)
dsdt->checksum = table_compute_checksum((void *)dsdt, dsdt->length);
/* Fill in platform-specific global NVS variables */
acpi_create_gnvs((struct acpi_global_nvs *)current);
current += sizeof(struct acpi_global_nvs);
current = ALIGN(current, 16);
acpi_create_gnvs(ctx->current);
acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
debug("ACPI: * FADT\n");
fadt = (struct acpi_fadt *)current;
current += sizeof(struct acpi_fadt);
current = ALIGN(current, 16);
fadt = ctx->current;
acpi_inc_align(ctx, sizeof(struct acpi_fadt));
acpi_create_fadt(fadt, facs, dsdt);
acpi_add_table(rsdp, fadt);
acpi_add_table(ctx, fadt);
debug("ACPI: * MADT\n");
madt = (struct acpi_madt *)current;
madt = ctx->current;
acpi_create_madt(madt);
current += madt->header.length;
acpi_add_table(rsdp, madt);
current = ALIGN(current, 16);
acpi_inc_align(ctx, madt->header.length);
acpi_add_table(ctx, madt);
debug("ACPI: * MCFG\n");
mcfg = (struct acpi_mcfg *)current;
mcfg = ctx->current;
acpi_create_mcfg(mcfg);
current += mcfg->header.length;
acpi_add_table(rsdp, mcfg);
current = ALIGN(current, 16);
acpi_inc_align(ctx, mcfg->header.length);
acpi_add_table(ctx, mcfg);
debug("ACPI: * CSRT\n");
csrt = (struct acpi_csrt *)current;
csrt = ctx->current;
acpi_create_csrt(csrt);
current += csrt->header.length;
acpi_add_table(rsdp, csrt);
current = ALIGN(current, 16);
acpi_inc_align(ctx, csrt->header.length);
acpi_add_table(ctx, csrt);
debug("ACPI: * SPCR\n");
spcr = (struct acpi_spcr *)current;
spcr = ctx->current;
acpi_create_spcr(spcr);
current += spcr->header.length;
acpi_add_table(rsdp, spcr);
current = ALIGN(current, 16);
acpi_inc_align(ctx, spcr->header.length);
acpi_add_table(ctx, spcr);
debug("current = %x\n", current);
acpi_write_dev_tables(ctx);
acpi_rsdp_addr = (unsigned long)rsdp;
addr = map_to_sysmem(ctx->current);
debug("current = %lx\n", addr);
acpi_rsdp_addr = (unsigned long)ctx->rsdp;
debug("ACPI: done\n");
return current;
return addr;
}
ulong acpi_get_rsdp_addr(void)

View File

@ -44,6 +44,14 @@ int dram_init_banksize(void)
phys_addr_t low_end;
uint bank;
if (!ll_boot_init()) {
gd->bd->bi_dram[0].start = 0;
gd->bd->bi_dram[0].size = gd->ram_size;
mtrr_add_request(MTRR_TYPE_WRBACK, 0, gd->ram_size);
return 0;
}
low_end = 0;
for (bank = 1, hdr = gd->arch.hob_list;
bank < CONFIG_NR_DRAM_BANKS && !end_of_hob(hdr);

View File

@ -78,6 +78,9 @@ static int fsp_video_probe(struct udevice *dev)
struct vesa_mode_info *vesa = &mode_info.vesa;
int ret;
if (!ll_boot_init())
return 0;
printf("Video: ");
/* Initialize vesa_mode_info structure */

View File

@ -12,11 +12,18 @@
#include <asm/fsp/fsp_support.h>
#include <asm/fsp2/fsp_api.h>
#include <asm/fsp2/fsp_internal.h>
#include <linux/sizes.h>
int dram_init(void)
{
int ret;
if (!ll_boot_init()) {
/* Use a small and safe amount of 1GB */
gd->ram_size = SZ_1G;
return 0;
}
if (spl_phase() == PHASE_SPL) {
#ifdef CONFIG_HAVE_ACPI_RESUME
bool s3wake = gd->arch.prev_sleep_state == ACPI_S3;
@ -68,6 +75,9 @@ int dram_init(void)
ulong board_get_usable_ram_top(ulong total_size)
{
if (!ll_boot_init())
return gd->ram_size;
#if CONFIG_IS_ENABLED(HANDOFF)
struct spl_handoff *ho = gd->spl_handoff;

View File

@ -23,7 +23,7 @@ int arch_cpu_init_dm(void)
int ret;
/* Make sure pads are set up early in U-Boot */
if (spl_phase() != PHASE_BOARD_F)
if (!ll_boot_init() || spl_phase() != PHASE_BOARD_F)
return 0;
/* Probe all pinctrl devices to set up the pads */

View File

@ -30,6 +30,9 @@ int init_cache_f_r(void)
return ret;
}
if (!ll_boot_init())
return 0;
/* Initialise the CPU cache(s) */
return init_cache();
}

View File

@ -190,6 +190,20 @@ comment "Commands"
menu "Info commands"
config CMD_ACPI
bool "acpi"
default y if ACPIGEN
help
List and dump ACPI tables. ACPI (Advanced Configuration and Power
Interface) is used mostly on x86 for providing information to the
Operating System about devices in the system. The tables are set up
by the firmware, typically U-Boot but possibly an earlier firmware
module, if U-Boot is chain-loaded from something else. ACPI tables
can also include code, to perform hardware-specific tasks required
by the Operating Systems. This allows some amount of separation
between the firmware and OS, and is particularly useful when you
want to make hardware changes without the OS needing to be adjusted.
config CMD_BDI
bool "bdinfo"
default y

View File

@ -11,6 +11,7 @@ obj-y += help.o
obj-y += version.o
# command
obj-$(CONFIG_CMD_ACPI) += acpi.o
obj-$(CONFIG_CMD_AES) += aes.o
obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o
obj-$(CONFIG_CMD_ADC) += adc.o

186
cmd/acpi.c Normal file
View File

@ -0,0 +1,186 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <command.h>
#include <mapmem.h>
#include <acpi/acpi_table.h>
#include <asm/acpi_table.h>
#include <dm/acpi.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* dump_hdr() - Dump an ACPI header
*
* If the header is for FACS then it shows the revision information as well
*
* @hdr: ACPI header to dump
*/
static void dump_hdr(struct acpi_table_header *hdr)
{
bool has_hdr = memcmp(hdr->signature, "FACS", ACPI_NAME_LEN);
printf("%.*s %08lx %06x", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr), hdr->length);
if (has_hdr) {
printf(" (v%02d %.6s %.8s %u %.4s %d)\n", hdr->revision,
hdr->oem_id, hdr->oem_table_id, hdr->oem_revision,
hdr->aslc_id, hdr->aslc_revision);
} else {
printf("\n");
}
}
/**
* find_table() - Look up an ACPI table
*
* @sig: Signature of table (4 characters, upper case)
* @return pointer to table header, or NULL if not found
*/
struct acpi_table_header *find_table(const char *sig)
{
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
int len, i, count;
rsdp = map_sysmem(gd->arch.acpi_start, 0);
if (!rsdp)
return NULL;
rsdt = map_sysmem(rsdp->rsdt_address, 0);
len = rsdt->header.length - sizeof(rsdt->header);
count = len / sizeof(u32);
for (i = 0; i < count; i++) {
struct acpi_table_header *hdr;
hdr = map_sysmem(rsdt->entry[i], 0);
if (!memcmp(hdr->signature, sig, ACPI_NAME_LEN))
return hdr;
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) {
struct acpi_fadt *fadt = (struct acpi_fadt *)hdr;
if (!memcmp(sig, "DSDT", ACPI_NAME_LEN) && fadt->dsdt)
return map_sysmem(fadt->dsdt, 0);
if (!memcmp(sig, "FACS", ACPI_NAME_LEN) &&
fadt->firmware_ctrl)
return map_sysmem(fadt->firmware_ctrl, 0);
}
}
return NULL;
}
static int dump_table_name(const char *sig)
{
struct acpi_table_header *hdr;
hdr = find_table(sig);
if (!hdr)
return -ENOENT;
printf("%.*s @ %08lx\n", ACPI_NAME_LEN, hdr->signature,
(ulong)map_to_sysmem(hdr));
print_buffer(0, hdr, 1, hdr->length, 0);
return 0;
}
static void list_fadt(struct acpi_fadt *fadt)
{
if (fadt->dsdt)
dump_hdr(map_sysmem(fadt->dsdt, 0));
if (fadt->firmware_ctrl)
dump_hdr(map_sysmem(fadt->firmware_ctrl, 0));
}
static int list_rsdt(struct acpi_rsdt *rsdt, struct acpi_xsdt *xsdt)
{
int len, i, count;
dump_hdr(&rsdt->header);
if (xsdt)
dump_hdr(&xsdt->header);
len = rsdt->header.length - sizeof(rsdt->header);
count = len / sizeof(u32);
for (i = 0; i < count; i++) {
struct acpi_table_header *hdr;
if (!rsdt->entry[i])
break;
hdr = map_sysmem(rsdt->entry[i], 0);
dump_hdr(hdr);
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN))
list_fadt((struct acpi_fadt *)hdr);
if (xsdt) {
if (xsdt->entry[i] != rsdt->entry[i]) {
printf(" (xsdt mismatch %llx)\n",
xsdt->entry[i]);
}
}
}
return 0;
}
static int list_rsdp(struct acpi_rsdp *rsdp)
{
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
printf("RSDP %08lx %06x (v%02d %.6s)\n", (ulong)map_to_sysmem(rsdp),
rsdp->length, rsdp->revision, rsdp->oem_id);
rsdt = map_sysmem(rsdp->rsdt_address, 0);
xsdt = map_sysmem(rsdp->xsdt_address, 0);
list_rsdt(rsdt, xsdt);
return 0;
}
static int do_acpi_list(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
struct acpi_rsdp *rsdp;
rsdp = map_sysmem(gd->arch.acpi_start, 0);
if (!rsdp) {
printf("No ACPI tables present\n");
return 0;
}
printf("ACPI tables start at %lx\n", gd->arch.acpi_start);
list_rsdp(rsdp);
return 0;
}
static int do_acpi_dump(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
const char *name;
char sig[ACPI_NAME_LEN];
int ret;
if (argc < 2)
return CMD_RET_USAGE;
name = argv[1];
if (strlen(name) != ACPI_NAME_LEN) {
printf("Table name '%s' must be four characters\n", name);
return CMD_RET_FAILURE;
}
str_to_upper(name, sig, -1);
ret = dump_table_name(sig);
if (ret) {
printf("Table '%.*s' not found\n", ACPI_NAME_LEN, sig);
return CMD_RET_FAILURE;
}
return 0;
}
static char acpi_help_text[] =
"list - list ACPI tables\n"
"acpi dump <name> - Dump ACPI table";
U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text,
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_acpi_list),
U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump));

View File

@ -712,6 +712,34 @@ to load a 'u-boot-payload.efi', see below test logs on QEMU.
See :doc:`../uefi/u-boot_on_efi` and :doc:`../uefi/uefi` for details of
EFI support in U-Boot.
Chain-loading
-------------
U-Boot can be chain-loaded from another bootloader, such as coreboot or
Slim Bootloader. Typically this is done by building for targets 'coreboot' or
'slimbootloader'.
For example, at present we have a 'coreboot' target but this runs very
different code from the bare-metal targets, such as coral. There is very little
in common between them.
It is useful to be able to boot the same U-Boot on a device, with or without a
first-stage bootloader. For example, with chromebook_coral, it is helpful for
testing to be able to boot the same U-Boot (complete with FSP) on bare metal
and from coreboot. It allows checking of things like CPU speed, comparing
registers, ACPI tables and the like.
To do this you can use ll_boot_init() in appropriate places to skip init that
has already been done by the previous stage. This works by setting a
GD_FLG_NO_LL_INIT flag when U-Boot detects that it is running from another
bootloader.
With this feature, you can build a bare-metal target and boot it from
coreboot, for example.
Note that this is a development feature only. It is not intended for use in
production environments. Also it is not currently part of the automated tests
so may break in the future.
TODO List
---------
- Audio

View File

@ -0,0 +1,36 @@
Devices
=======
Device bindings are described by their own individual binding files.
U-Boot provides for some optional properties which are documented here. See
also hid-over-i2c.txt which describes HID devices. See also
Documentation/firmware-guide/acpi/enumeration.rst in the Linux kernel for
the acpi,compatible property.
- acpi,has-power-resource : (boolean) true if this device has a power resource.
This causes an ACPI PowerResource to be written containing the properties
provided by this binding, to describe how to handle powering the device up
and down using GPIOs
- acpi,compatible : compatible string to report
- acpi,ddn : Contains the string to use as the _DDN (DOS (Disk Operating
System) Device Name)
- acpi,hid : Contains the string to use as the HID (Hardware ID)
identifier _HID
- acpi,uid : _UID value for device
- linux,probed : Tells U-Boot to add 'linux,probed' to the ACPI tables so that
Linux will only load the driver if the device can be detected (e.g. on I2C
bus). Note that this is an out-of-tree Linux feature.
Example
-------
elan_touchscreen: elan-touchscreen@10 {
compatible = "i2c-chip";
reg = <0x10>;
acpi,hid = "ELAN0001";
acpi,ddn = "ELAN Touchscreen";
interrupts-extended = <&acpi_gpe GPIO_21_IRQ IRQ_TYPE_EDGE_FALLING>;
linux,probed;
};

View File

@ -11,8 +11,17 @@
#include <common.h>
#include <dm.h>
#include <dm/acpi.h>
#include <dm/device-internal.h>
#include <dm/root.h>
/* Type of method to call */
enum method_t {
METHOD_WRITE_TABLES,
};
/* Prototype for all methods */
typedef int (*acpi_method)(const struct udevice *dev, struct acpi_ctx *ctx);
int acpi_copy_name(char *out_name, const char *name)
{
strncpy(out_name, name, ACPI_NAME_LEN);
@ -31,3 +40,56 @@ int acpi_get_name(const struct udevice *dev, char *out_name)
return -ENOSYS;
}
acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
{
struct acpi_ops *aops;
aops = device_get_acpi_ops(dev);
if (aops) {
switch (method) {
case METHOD_WRITE_TABLES:
return aops->write_tables;
}
}
return NULL;
}
int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
enum method_t method)
{
struct udevice *dev;
acpi_method func;
int ret;
func = acpi_get_method(parent, method);
if (func) {
log_debug("\n");
log_debug("- %s %p\n", parent->name, func);
ret = device_ofdata_to_platdata(parent);
if (ret)
return log_msg_ret("ofdata", ret);
ret = func(parent, ctx);
if (ret)
return log_msg_ret("func", ret);
}
device_foreach_child(dev, parent) {
ret = acpi_recurse_method(ctx, dev, method);
if (ret)
return log_msg_ret("recurse", ret);
}
return 0;
}
int acpi_write_dev_tables(struct acpi_ctx *ctx)
{
int ret;
log_debug("Writing device tables\n");
ret = acpi_recurse_method(ctx, dm_root(), METHOD_WRITE_TABLES);
log_debug("Writing finished, err=%d\n", ret);
return ret;
}

View File

@ -1009,7 +1009,7 @@ static int pci_uclass_post_probe(struct udevice *bus)
if (ret)
return ret;
if (CONFIG_IS_ENABLED(PCI_PNP) &&
if (CONFIG_IS_ENABLED(PCI_PNP) && ll_boot_init() &&
(!hose->skip_auto_config_until_reloc ||
(gd->flags & GD_FLG_RELOC))) {
ret = pci_auto_config_devices(bus);
@ -1031,7 +1031,7 @@ static int pci_uclass_post_probe(struct udevice *bus)
* Note we only call this 1) after U-Boot is relocated, and 2)
* root bus has finished probing.
*/
if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0)) {
if ((gd->flags & GD_FLG_RELOC) && bus->seq == 0 && ll_boot_init()) {
ret = fsp_init_phase_pci();
if (ret)
return ret;

View File

@ -23,6 +23,8 @@
#if !defined(__ACPI__)
struct acpi_ctx;
/*
* RSDP (Root System Description Pointer)
* Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum
@ -505,6 +507,69 @@ int acpi_get_table_revision(enum acpi_tables table);
*/
int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
/**
* acpi_fill_header() - Set up a new table header
*
* This sets all fields except length, revision, checksum and aslc_revision
*
* @header: ACPI header to update
* @signature: Table signature to use (4 characters)
*/
void acpi_fill_header(struct acpi_table_header *header, char *signature);
/**
* acpi_align() - Align the ACPI output pointer to a 16-byte boundary
*
* @ctx: ACPI context
*/
void acpi_align(struct acpi_ctx *ctx);
/**
* acpi_align64() - Align the ACPI output pointer to a 64-byte boundary
*
* @ctx: ACPI context
*/
void acpi_align64(struct acpi_ctx *ctx);
/**
* acpi_inc() - Increment the ACPI output pointer by a bit
*
* The pointer is NOT aligned afterwards.
*
* @ctx: ACPI context
* @amount: Amount to increment by
*/
void acpi_inc(struct acpi_ctx *ctx, uint amount);
/**
* acpi_inc_align() - Increment the ACPI output pointer by a bit and align
*
* The pointer is aligned afterwards to a 16-byte boundary
*
* @ctx: ACPI context
* @amount: Amount to increment by
*/
void acpi_inc_align(struct acpi_ctx *ctx, uint amount);
/**
* acpi_add_table() - Add a new table to the RSDP and XSDT
*
* @ctx: ACPI context
* @table: Table to add
* @return 0 if OK, -E2BIG if too many tables
*/
int acpi_add_table(struct acpi_ctx *ctx, void *table);
/**
* acpi_setup_base_tables() - Set up context along with RSDP, RSDT and XSDT
*
* Set up the context with the given start position. Some basic tables are
* always needed, so set them up as well.
*
* @ctx: Context to set up
*/
void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start);
#endif /* !__ACPI__*/
#include <asm/acpi_table.h>

View File

@ -166,5 +166,6 @@ typedef struct global_data {
#define GD_FLG_SPL_EARLY_INIT 0x04000 /* Early SPL init is done */
#define GD_FLG_LOG_READY 0x08000 /* Log system is ready for use */
#define GD_FLG_WDT_READY 0x10000 /* Watchdog is ready for use */
#define GD_FLG_SKIP_LL_INIT 0x20000 /* Don't perform low-level init */
#endif /* __ASM_GENERIC_GBL_DATA_H */

View File

@ -135,7 +135,7 @@ void file_cbfs_get_next(const struct cbfs_cachenode **file);
*/
const struct cbfs_cachenode *file_cbfs_find(const char *name);
struct cbfs_priv *priv;
struct cbfs_priv;
/**
* cbfs_find_file() - Find a file in a given CBFS

View File

@ -24,6 +24,24 @@
#if !defined(__ACPI__)
/**
* struct acpi_ctx - Context used for writing ACPI tables
*
* This contains a few useful pieces of information used when writing
*
* @current: Current address for writing
* @rsdp: Pointer to the Root System Description Pointer, typically used when
* adding a new table. The RSDP holds pointers to the RSDT and XSDT.
* @rsdt: Pointer to the Root System Description Table
* @xsdt: Pointer to the Extended System Description Table
*/
struct acpi_ctx {
void *current;
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
};
/**
* struct acpi_ops - ACPI operations supported by driver model
*/
@ -38,6 +56,15 @@ struct acpi_ops {
* other error
*/
int (*get_name)(const struct udevice *dev, char *out_name);
/**
* write_tables() - Write out any tables required by this device
*
* @dev: Device to write
* @ctx: ACPI context to use
* @return 0 if OK, -ve on error
*/
int (*write_tables)(const struct udevice *dev, struct acpi_ctx *ctx);
};
#define device_get_acpi_ops(dev) ((dev)->driver->acpi_ops)
@ -72,6 +99,16 @@ int acpi_get_name(const struct udevice *dev, char *out_name);
*/
int acpi_copy_name(char *out_name, const char *name);
/**
* acpi_write_dev_tables() - Write ACPI tables required by devices
*
* This scans through all devices and tells them to write any tables they want
* to write.
*
* @return 0 if OK, -ve if any device returned an error
*/
int acpi_write_dev_tables(struct acpi_ctx *ctx);
#endif /* __ACPI__ */
#endif

View File

@ -20,7 +20,7 @@ struct global_data;
#ifdef CONFIG_EFI_STUB
#define ll_boot_init() false
#else
#define ll_boot_init() true
#define ll_boot_init() (!(gd->flags & GD_FLG_SKIP_LL_INIT))
#endif
/*

View File

@ -6,12 +6,14 @@
*/
#include <common.h>
#include <acpi/acpi_table.h>
#include <dm.h>
#include <cpu.h>
#include <mapmem.h>
#include <tables_csum.h>
#include <version.h>
#include <acpi/acpi_table.h>
#include <dm/acpi.h>
/* Temporary change to ensure bisectability */
#ifndef CONFIG_SANDBOX
int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
{
struct acpi_table_header *header = &dmar->header;
@ -37,7 +39,6 @@ int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
return 0;
}
#endif
int acpi_get_table_revision(enum acpi_tables table)
{
@ -91,3 +92,173 @@ int acpi_get_table_revision(enum acpi_tables table)
return -EINVAL;
}
}
void acpi_fill_header(struct acpi_table_header *header, char *signature)
{
memcpy(header->signature, signature, 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
header->oem_revision = U_BOOT_BUILD_DATE;
memcpy(header->aslc_id, ASLC_ID, 4);
}
void acpi_align(struct acpi_ctx *ctx)
{
ctx->current = (void *)ALIGN((ulong)ctx->current, 16);
}
void acpi_align64(struct acpi_ctx *ctx)
{
ctx->current = (void *)ALIGN((ulong)ctx->current, 64);
}
void acpi_inc(struct acpi_ctx *ctx, uint amount)
{
ctx->current += amount;
}
void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
{
ctx->current += amount;
acpi_align(ctx);
}
/**
* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
* and checksum.
*/
int acpi_add_table(struct acpi_ctx *ctx, void *table)
{
int i, entries_num;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
/* The RSDT is mandatory while the XSDT is not */
rsdt = ctx->rsdt;
/* This should always be MAX_ACPI_TABLES */
entries_num = ARRAY_SIZE(rsdt->entry);
for (i = 0; i < entries_num; i++) {
if (rsdt->entry[i] == 0)
break;
}
if (i >= entries_num) {
log_err("ACPI: Error: too many tables\n");
return -E2BIG;
}
/* Add table to the RSDT */
rsdt->entry[i] = map_to_sysmem(table);
/* Fix RSDT length or the kernel will assume invalid entries */
rsdt->header.length = sizeof(struct acpi_table_header) +
(sizeof(u32) * (i + 1));
/* Re-calculate checksum */
rsdt->header.checksum = 0;
rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
rsdt->header.length);
/*
* And now the same thing for the XSDT. We use the same index as for
* now we want the XSDT and RSDT to always be in sync in U-Boot
*/
xsdt = ctx->xsdt;
/* Add table to the XSDT */
xsdt->entry[i] = map_to_sysmem(table);
/* Fix XSDT length */
xsdt->header.length = sizeof(struct acpi_table_header) +
(sizeof(u64) * (i + 1));
/* Re-calculate checksum */
xsdt->header.checksum = 0;
xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
xsdt->header.length);
return 0;
}
static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
struct acpi_xsdt *xsdt)
{
memset(rsdp, 0, sizeof(struct acpi_rsdp));
memcpy(rsdp->signature, RSDP_SIG, 8);
memcpy(rsdp->oem_id, OEM_ID, 6);
rsdp->length = sizeof(struct acpi_rsdp);
rsdp->rsdt_address = map_to_sysmem(rsdt);
rsdp->xsdt_address = map_to_sysmem(xsdt);
rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
/* Calculate checksums */
rsdp->checksum = table_compute_checksum(rsdp, 20);
rsdp->ext_checksum = table_compute_checksum(rsdp,
sizeof(struct acpi_rsdp));
}
static void acpi_write_rsdt(struct acpi_rsdt *rsdt)
{
struct acpi_table_header *header = &rsdt->header;
/* Fill out header fields */
acpi_fill_header(header, "RSDT");
header->length = sizeof(struct acpi_rsdt);
header->revision = 1;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum(rsdt,
sizeof(struct acpi_rsdt));
}
static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
{
struct acpi_table_header *header = &xsdt->header;
/* Fill out header fields */
acpi_fill_header(header, "XSDT");
header->length = sizeof(struct acpi_xsdt);
header->revision = 1;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum(xsdt,
sizeof(struct acpi_xsdt));
}
void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
{
ctx->current = start;
/* Align ACPI tables to 16 byte */
acpi_align(ctx);
gd->arch.acpi_start = map_to_sysmem(ctx->current);
/* We need at least an RSDP and an RSDT Table */
ctx->rsdp = ctx->current;
acpi_inc_align(ctx, sizeof(struct acpi_rsdp));
ctx->rsdt = ctx->current;
acpi_inc_align(ctx, sizeof(struct acpi_rsdt));
ctx->xsdt = ctx->current;
acpi_inc_align(ctx, sizeof(struct acpi_xsdt));
/* clear all table memory */
memset((void *)start, '\0', ctx->current - start);
acpi_write_rsdp(ctx->rsdp, ctx->rsdt, ctx->xsdt);
acpi_write_rsdt(ctx->rsdt);
acpi_write_xsdt(ctx->xsdt);
/*
* Per ACPI spec, the FACS table address must be aligned to a 64 byte
* boundary (Windows checks this, but Linux does not).
*/
acpi_align64(ctx);
}

View File

@ -7,13 +7,36 @@
*/
#include <common.h>
#include <console.h>
#include <dm.h>
#include <malloc.h>
#include <mapmem.h>
#include <version.h>
#include <tables_csum.h>
#include <version.h>
#include <acpi/acpi_table.h>
#include <dm/acpi.h>
#include <dm/test.h>
#include <test/ut.h>
#define ACPI_TEST_DEV_NAME "ABCD"
#define BUF_SIZE 4096
static int testacpi_write_tables(const struct udevice *dev,
struct acpi_ctx *ctx)
{
struct acpi_dmar *dmar;
int ret;
dmar = (struct acpi_dmar *)ctx->current;
acpi_create_dmar(dmar, DMAR_INTR_REMAP);
ctx->current += sizeof(struct acpi_dmar);
ret = acpi_add_table(ctx, dmar);
if (ret)
return log_msg_ret("add", ret);
return 0;
}
static int testacpi_get_name(const struct udevice *dev, char *out_name)
{
@ -22,6 +45,7 @@ static int testacpi_get_name(const struct udevice *dev, char *out_name)
struct acpi_ops testacpi_ops = {
.get_name = testacpi_get_name,
.write_tables = testacpi_write_tables,
};
static const struct udevice_id testacpi_ids[] = {
@ -68,8 +92,6 @@ static int dm_test_acpi_get_table_revision(struct unit_test_state *uts)
DM_TEST(dm_test_acpi_get_table_revision,
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Temporary change to ensure bisectability */
#ifndef CONFIG_SANDBOX
/* Test acpi_create_dmar() */
static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
{
@ -82,4 +104,214 @@ static int dm_test_acpi_create_dmar(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_acpi_create_dmar, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
#endif
/* Test acpi_fill_header() */
static int dm_test_acpi_fill_header(struct unit_test_state *uts)
{
struct acpi_table_header hdr;
/* Make sure these 5 fields are not changed */
hdr.length = 0x11;
hdr.revision = 0x22;
hdr.checksum = 0x33;
hdr.aslc_revision = 0x44;
acpi_fill_header(&hdr, "ABCD");
ut_asserteq_mem("ABCD", hdr.signature, sizeof(hdr.signature));
ut_asserteq(0x11, hdr.length);
ut_asserteq(0x22, hdr.revision);
ut_asserteq(0x33, hdr.checksum);
ut_asserteq_mem(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id));
ut_asserteq_mem(OEM_TABLE_ID, hdr.oem_table_id,
sizeof(hdr.oem_table_id));
ut_asserteq(U_BOOT_BUILD_DATE, hdr.oem_revision);
ut_asserteq_mem(ASLC_ID, hdr.aslc_id, sizeof(hdr.aslc_id));
ut_asserteq(0x44, hdr.aslc_revision);
return 0;
}
DM_TEST(dm_test_acpi_fill_header, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test ACPI write_tables() */
static int dm_test_acpi_write_tables(struct unit_test_state *uts)
{
struct acpi_dmar *dmar;
struct acpi_ctx ctx;
void *buf;
buf = malloc(BUF_SIZE);
ut_assertnonnull(buf);
acpi_setup_base_tables(&ctx, buf);
dmar = ctx.current;
ut_assertok(acpi_write_dev_tables(&ctx));
/*
* We should have two dmar tables, one for each "denx,u-boot-acpi-test"
* device
*/
ut_asserteq_ptr(dmar + 2, ctx.current);
ut_asserteq(DMAR_INTR_REMAP, dmar->flags);
ut_asserteq(32 - 1, dmar->host_address_width);
ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags);
ut_asserteq(32 - 1, dmar[1].host_address_width);
/* Check that the pointers were added correctly */
ut_asserteq(map_to_sysmem(dmar), ctx.rsdt->entry[0]);
ut_asserteq(map_to_sysmem(dmar + 1), ctx.rsdt->entry[1]);
ut_asserteq(0, ctx.rsdt->entry[2]);
ut_asserteq(map_to_sysmem(dmar), ctx.xsdt->entry[0]);
ut_asserteq(map_to_sysmem(dmar + 1), ctx.xsdt->entry[1]);
ut_asserteq(0, ctx.xsdt->entry[2]);
return 0;
}
DM_TEST(dm_test_acpi_write_tables, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test basic ACPI functions */
static int dm_test_acpi_basic(struct unit_test_state *uts)
{
struct acpi_ctx ctx;
/* Check align works */
ctx.current = (void *)5;
acpi_align(&ctx);
ut_asserteq_ptr((void *)16, ctx.current);
/* Check that align does nothing if already aligned */
acpi_align(&ctx);
ut_asserteq_ptr((void *)16, ctx.current);
acpi_align64(&ctx);
ut_asserteq_ptr((void *)64, ctx.current);
acpi_align64(&ctx);
ut_asserteq_ptr((void *)64, ctx.current);
/* Check incrementing */
acpi_inc(&ctx, 3);
ut_asserteq_ptr((void *)67, ctx.current);
acpi_inc_align(&ctx, 3);
ut_asserteq_ptr((void *)80, ctx.current);
return 0;
}
DM_TEST(dm_test_acpi_basic, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test acpi_setup_base_tables */
static int dm_test_acpi_setup_base_tables(struct unit_test_state *uts)
{
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
struct acpi_ctx ctx;
void *buf, *end;
/*
* Use an unaligned address deliberately, by allocating an aligned
* address and then adding 4 to it
*/
buf = memalign(64, BUF_SIZE);
ut_assertnonnull(buf);
acpi_setup_base_tables(&ctx, buf + 4);
ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd->arch.acpi_start);
rsdp = buf + 16;
ut_asserteq_ptr(rsdp, ctx.rsdp);
ut_assertok(memcmp(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature)));
ut_asserteq(sizeof(*rsdp), rsdp->length);
ut_assertok(table_compute_checksum(rsdp, 20));
ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp)));
rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
ut_asserteq_ptr(rsdt, ctx.rsdt);
ut_assertok(memcmp("RSDT", rsdt->header.signature, ACPI_NAME_LEN));
ut_asserteq(sizeof(*rsdt), rsdt->header.length);
ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
ut_asserteq_ptr(xsdt, ctx.xsdt);
ut_assertok(memcmp("XSDT", xsdt->header.signature, ACPI_NAME_LEN));
ut_asserteq(sizeof(*xsdt), xsdt->header.length);
ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
ut_asserteq_ptr(end, ctx.current);
ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address);
ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address);
return 0;
}
DM_TEST(dm_test_acpi_setup_base_tables,
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test 'acpi list' command */
static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
{
struct acpi_ctx ctx;
ulong addr;
void *buf;
buf = memalign(16, BUF_SIZE);
ut_assertnonnull(buf);
acpi_setup_base_tables(&ctx, buf);
ut_assertok(acpi_write_dev_tables(&ctx));
console_record_reset();
run_command("acpi list", 0);
addr = (ulong)map_to_sysmem(buf);
ut_assert_nextline("ACPI tables start at %lx", addr);
ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
sizeof(struct acpi_rsdp));
addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_table_header) +
2 * sizeof(u32), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_table_header) +
2 * sizeof(u64), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %u INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
ut_assert_console_end();
return 0;
}
DM_TEST(dm_test_acpi_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test 'acpi dump' command */
static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
{
struct acpi_ctx ctx;
ulong addr;
void *buf;
buf = memalign(16, BUF_SIZE);
ut_assertnonnull(buf);
acpi_setup_base_tables(&ctx, buf);
ut_assertok(acpi_write_dev_tables(&ctx));
/* First search for a non-existent table */
console_record_reset();
run_command("acpi dump rdst", 0);
ut_assert_nextline("Table 'RDST' not found");
ut_assert_console_end();
/* Now a real table */
console_record_reset();
run_command("acpi dump dmar", 0);
addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64);
ut_assert_nextline("DMAR @ %08lx", addr);
ut_assert_nextlines_are_dump(0x30);
ut_assert_console_end();
return 0;
}
DM_TEST(dm_test_acpi_cmd_dump, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);