blob: 5567a34d5953513c2f7d60b52f43b89524ef42c0 [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium OS Authors.
* (C) Copyright 2008
* Graeme Russ, graeme.russ@gmail.com.
*
* 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 <common.h>
#include <config.h>
#include <asm/u-boot-x86.h>
#include <cbfs.h>
#include <flash.h>
#include <fdtdec.h>
#include <malloc.h>
#include <netdev.h>
#include <asm/msr.h>
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/arch-coreboot/tables.h>
#include <asm/arch-coreboot/sysinfo.h>
#include <asm/arch-coreboot/timestamp.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* Miscellaneous platform dependent initializations
*/
#if !defined CONFIG_CMD_CBFS || !defined CONFIG_OF_CONTROL
#error coreboot needs CONFIG_CMD_CBFS and CONFIG_OF_CONTROL enabled.
#endif
/*
* Set this to a nonzero value to make sure there is at least so many
* thousands of tsc clocks between port 80 accesses. Set it to 4000 for the
* Google EC port 80 implementation.
*/
#define MIN_PORT80_KCLOCKS_DELAY 0
static void *find_cbmem_area(void)
{
int i;
struct cbmem_entry *cbmem_toc = NULL;
for (i = 0; i < lib_sysinfo.n_memranges; i++) {
struct memrange *memrange = &lib_sysinfo.memrange[i];
/* The CBMEM TOC lives at the last memory area marked
* as "tables" in the coreboot memory map. Find it there
*/
if (memrange->type == CB_MEM_TABLE)
cbmem_toc = (struct cbmem_entry *)
(unsigned long)memrange->base;
}
if (!cbmem_toc) {
printf("Error: Could not find coreboot tables area\n");
return NULL;
}
if (cbmem_toc[0].magic != CBMEM_MAGIC) {
printf("Error: No CBMEM area found\n");
return NULL;
}
for (i = 0; i < MAX_CBMEM_ENTRIES; i++) {
if (cbmem_toc[i].magic == CBMEM_MAGIC &&
cbmem_toc[i].id == CBMEM_ID_RESUME)
printf("Found usable memory in CBMEM area at 0x%lx\n",
(unsigned long)cbmem_toc[i].base);
return (void *)(unsigned long)cbmem_toc[i].base;
}
printf("Error: No usable memory found in CBMEM area\n");
return NULL;
}
static int map_coreboot_serial_to_fdt(void)
{
void *fdt = (void *)gd->fdt_blob;
struct cb_serial *serial = lib_sysinfo.serial;
uint32_t reg[2];
int serial_offset;
int ret = 0;
unsigned long clock_frequency;
serial_offset = fdt_path_offset(fdt, "/serial");
if (serial_offset < 0) {
/* No aliases node found. Bail out. */
printf("Couldn't find fdt \"serial\" node.\n");
return 1;
}
/* If coreboot has serial data, use it, otherwise we are done */
if (!serial)
return 0;
/* If there's a serial node and device, populate the node. */
reg[0] = cpu_to_fdt32(serial->baseaddr);
reg[1] = cpu_to_fdt32(0x8);
ret |= fdt_setprop(fdt, serial_offset, "reg", reg, sizeof(reg));
ret |= fdt_setprop_cell(fdt, serial_offset, "baudrate", serial->baud);
/*
* For now, assume an OXPCIE serial adapter
* when it's memory mapped, since this is the
* only one supported by coreboot.
*/
if (serial->type == CB_SERIAL_TYPE_MEMORY_MAPPED)
clock_frequency = 4000000;
else
clock_frequency = 115200;
ret |= fdt_setprop_cell(fdt, serial_offset,
"clock-frequency", clock_frequency);
ret |= fdt_setprop_cell(fdt, serial_offset, "io-mapped",
serial->type == CB_SERIAL_TYPE_IO_MAPPED);
ret |= fdt_setprop_string(fdt, serial_offset, "status", "okay");
return !!ret;
}
int cpu_init_f(void)
{
CbfsFile file;
int ret = get_coreboot_info(&lib_sysinfo);
int size;
void *dtb;
if (ret != 0)
printf("Failed to parse coreboot tables.\n");
file_cbfs_init(0xffffffff);
if (file_cbfs_result != CBFS_SUCCESS)
goto cbfs_failed;
file = file_cbfs_find_uncached(0xffffffff, "u-boot.dtb");
if (!file)
goto cbfs_failed;
size = file->dataLength < 16384 ? file->dataLength : 16384;
dtb = find_cbmem_area();
memcpy(dtb, (const void *)(file->data), size);
gd->fdt_blob = (const void *)dtb;
if (map_coreboot_serial_to_fdt())
printf("Couldn't add serial port to FDT.\n");
timestamp_init();
cbfs_failed:
return ret;
}
int board_early_init_f(void)
{
return 0;
}
int board_early_init_r(void)
{
if (map_coreboot_serial_to_fdt())
printf("Couldn't add serial port to FDT.\n");
return 0;
}
void show_boot_progress(int val)
{
#if MIN_PORT80_KCLOCKS_DELAY
static uint32_t prev_stamp;
static uint32_t base;
/*
* Scale the time counter reading to avoid using 64 bit arithmetics.
* Can't use get_timer() here becuase it could be not yet
* initialized or even implemented.
*/
if (!prev_stamp) {
base = rdtsc() / 1000;
prev_stamp = 0;
} else {
uint32_t now;
do {
now = rdtsc() / 1000 - base;
} while (now < (prev_stamp + MIN_PORT80_KCLOCKS_DELAY));
prev_stamp = now;
}
#endif
outb(val, 0x80);
}
int last_stage_init(void)
{
return 0;
}
#ifndef CONFIG_SYS_NO_FLASH
ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info)
{
return 0;
}
#endif
int board_eth_init(bd_t *bis)
{
return pci_eth_init(bis);
}
int misc_init_r(void)
{
return 0;
}
#define MTRR_TYPE_WP 5
#define MTRRcap_MSR 0xfe
#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
int board_final_cleanup(void)
{
/* Un-cache the ROM so the kernel has one
* more MTRR available.
*
* Coreboot should have assigned this to the
* top available variable MTRR.
*/
u8 top_mtrr = (rdmsr(MTRRcap_MSR) & 0xff) - 1;
u8 top_type = rdmsr(MTRRphysBase_MSR(top_mtrr)) & 0xff;
/* Make sure this MTRR is the correct Write-Protected type */
if (top_type == MTRR_TYPE_WP) {
disable_cache();
wrmsr(MTRRphysBase_MSR(top_mtrr), 0);
wrmsr(MTRRphysMask_MSR(top_mtrr), 0);
enable_cache();
}
/* Issue SMI to Coreboot to lock down ME and registers */
printf("Finalizing Coreboot\n");
outb(0xcb, 0xb2);
return 0;
}