blob: f8bb57a35421ba0324b4216c20cbedffd7b8e64a [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <assert.h>
#include <stdint.h>
#include "base/coreboot/sysinfo.h"
#include "base/coreboot/tables.h"
#include "base/device_tree.h"
#include "base/fwdb.h"
#include "base/init_funcs.h"
#include "base/memory.h"
static int install_coreboot_data(DeviceTreeFixup *fixup, DeviceTree *tree)
{
uint32_t addr_cells = 1, size_cells = 1;
const char *firmware_path[] = { "firmware", NULL };
DeviceTreeNode *firmware_node = dt_find_node(tree->root,
firmware_path, &addr_cells, &size_cells, 1);
// Need to add 'ranges' to the intermediate node to make 'reg' work.
dt_add_bin_prop(firmware_node, "ranges", NULL, 0);
const char *coreboot_path[] = { "coreboot", NULL };
DeviceTreeNode *coreboot_node = dt_find_node(firmware_node,
coreboot_path, &addr_cells, &size_cells, 1);
dt_add_string_prop(coreboot_node, "compatible", "coreboot");
E820MemRanges *e820 = get_e820_mem_ranges();
if (!e820)
return 1;
E820MemRange *cbmem_range = NULL;
for (int i = e820->num_ranges - 1; i >= 0; i--) {
E820MemRange *range = &e820->ranges[i];
if (range->handoff_tag == CB_MEM_TABLE) {
cbmem_range = range;
break;
}
}
if (!cbmem_range)
return 1;
uint64_t reg_addrs[2];
uint64_t reg_sizes[2];
// First 'reg' address range is the coreboot table.
reg_addrs[0] = (uintptr_t)get_sysinfo()->header;
reg_sizes[0] = get_sysinfo()->header->header_bytes +
get_sysinfo()->header->table_bytes;
// Second is the CBMEM area (which usually includes the coreboot table).
reg_addrs[1] = cbmem_range->base;
reg_sizes[1] = cbmem_range->size;
dt_add_reg_prop(coreboot_node, reg_addrs, reg_sizes, 2,
addr_cells, size_cells);
// Expose board ID and RAM code exported from coreboot to userspace.
if (get_sysinfo()->board_id != ~0) {
dt_add_u32_prop(coreboot_node,
"board-id", get_sysinfo()->board_id);
}
FwdbEntry ram_code_entry;
if (fwdb_access("coreboot.ram_code", &ram_code_entry, NULL)) {
uint32_t ram_code;
assert(sizeof(ram_code) == ram_code_entry.size);
ram_code = *(typeof(ram_code) *)ram_code_entry.ptr;
dt_add_u32_prop(coreboot_node, "ram-code", ram_code);
}
return 0;
}
static DeviceTreeFixup coreboot_fixup = {
.fixup = &install_coreboot_data
};
static int coreboot_setup(void)
{
list_insert_after(&coreboot_fixup.list_node, &device_tree_fixups);
return 0;
}
INIT_FUNC(coreboot_setup);