u-boot/arch/x86/lib/sfi.c
Tom Rini d678a59d2d Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay
Ethernet"' I failed to notice that b4 noticed it was based on next and
so took that as the base commit and merged that part of next to master.

This reverts commit c8ffd1356d, reversing
changes made to 2ee6f3a5f7.

Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
2024-05-19 08:16:36 -06:00

154 lines
3.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*/
/*
* Intel Simple Firmware Interface (SFI)
*
* Yet another way to pass information to the Linux kernel.
*
* See https://simplefirmware.org/ for details
*/
#include <common.h>
#include <cpu.h>
#include <dm.h>
#include <asm/cpu.h>
#include <asm/ioapic.h>
#include <asm/sfi.h>
#include <asm/tables.h>
#include <dm/uclass-internal.h>
struct table_info {
u32 base;
int ptr;
u32 entry_start;
u64 table[SFI_TABLE_MAX_ENTRIES];
int count;
};
static void *get_entry_start(struct table_info *tab)
{
if (tab->count == SFI_TABLE_MAX_ENTRIES)
return NULL;
tab->entry_start = tab->base + tab->ptr;
tab->table[tab->count] = tab->entry_start;
tab->entry_start += sizeof(struct sfi_table_header);
return (void *)(uintptr_t)tab->entry_start;
}
static void finish_table(struct table_info *tab, const char *sig, void *entry)
{
struct sfi_table_header *hdr;
hdr = (struct sfi_table_header *)(uintptr_t)(tab->base + tab->ptr);
strcpy(hdr->sig, sig);
hdr->len = sizeof(*hdr) + ((ulong)entry - tab->entry_start);
hdr->rev = 1;
strncpy(hdr->oem_id, "U-Boot", SFI_OEM_ID_SIZE);
strncpy(hdr->oem_table_id, "Table v1", SFI_OEM_TABLE_ID_SIZE);
hdr->csum = 0;
hdr->csum = table_compute_checksum(hdr, hdr->len);
tab->ptr += hdr->len;
tab->ptr = ALIGN(tab->ptr, 16);
tab->count++;
}
static int sfi_write_system_header(struct table_info *tab)
{
u64 *entry = get_entry_start(tab);
int i;
if (!entry)
return -ENOSPC;
for (i = 0; i < tab->count; i++)
*entry++ = tab->table[i];
finish_table(tab, SFI_SIG_SYST, entry);
return 0;
}
static int sfi_write_cpus(struct table_info *tab)
{
struct sfi_cpu_table_entry *entry = get_entry_start(tab);
struct udevice *dev;
int count = 0;
if (!entry)
return -ENOSPC;
for (uclass_find_first_device(UCLASS_CPU, &dev);
dev;
uclass_find_next_device(&dev)) {
struct cpu_plat *plat = dev_get_parent_plat(dev);
if (!device_active(dev))
continue;
entry->apic_id = plat->cpu_id;
entry++;
count++;
}
/* Omit the table if there is only one CPU */
if (count > 1)
finish_table(tab, SFI_SIG_CPUS, entry);
return 0;
}
static int sfi_write_apic(struct table_info *tab)
{
struct sfi_apic_table_entry *entry = get_entry_start(tab);
if (!entry)
return -ENOSPC;
entry->phys_addr = IO_APIC_ADDR;
entry++;
finish_table(tab, SFI_SIG_APIC, entry);
return 0;
}
static int sfi_write_xsdt(struct table_info *tab)
{
struct sfi_xsdt_header *entry = get_entry_start(tab);
if (!entry)
return -ENOSPC;
entry->oem_revision = 1;
entry->creator_id = 1;
entry->creator_revision = 1;
entry++;
finish_table(tab, SFI_SIG_XSDT, entry);
return 0;
}
ulong write_sfi_table(ulong base)
{
struct table_info table;
table.base = base;
table.ptr = 0;
table.count = 0;
sfi_write_cpus(&table);
sfi_write_apic(&table);
/*
* The SFI specification marks the XSDT table as option, but Linux 4.0
* crashes on start-up when it is not provided.
*/
sfi_write_xsdt(&table);
/* Finally, write out the system header which points to the others */
sfi_write_system_header(&table);
return base + table.ptr;
}