mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-17 18:34:42 +00:00

We use 'priv' for private data but often use 'platdata' for platform data. We can't really use 'pdata' since that is ambiguous (it could mean private or platform data). Rename some of the latter variables to end with 'plat' for consistency. Signed-off-by: Simon Glass <sjg@chromium.org>
153 lines
3.1 KiB
C
153 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_platdata *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;
|
|
}
|