diff options
Diffstat (limited to 'roms/u-boot/arch/x86/cpu/coreboot')
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/Makefile | 22 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/car.S | 13 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/coreboot.c | 134 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/ipchecksum.c | 54 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/pci.c | 49 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/sdram.c | 123 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/tables.c | 235 | ||||
| -rw-r--r-- | roms/u-boot/arch/x86/cpu/coreboot/timestamp.c | 101 | 
8 files changed, 731 insertions, 0 deletions
diff --git a/roms/u-boot/arch/x86/cpu/coreboot/Makefile b/roms/u-boot/arch/x86/cpu/coreboot/Makefile new file mode 100644 index 00000000..cd0bf4ed --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/Makefile @@ -0,0 +1,22 @@ +# +# Copyright (c) 2011 The Chromium OS Authors. +# +# (C) Copyright 2008 +# Graeme Russ, graeme.russ@gmail.com. +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2002 +# Daniel Engström, Omicron Ceti AB, daniel@omicron.se. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +obj-$(CONFIG_SYS_COREBOOT) += car.o +obj-$(CONFIG_SYS_COREBOOT) += coreboot.o +obj-$(CONFIG_SYS_COREBOOT) += tables.o +obj-$(CONFIG_SYS_COREBOOT) += ipchecksum.o +obj-$(CONFIG_SYS_COREBOOT) += sdram.o +obj-$(CONFIG_SYS_COREBOOT) += timestamp.o +obj-$(CONFIG_PCI) += pci.o diff --git a/roms/u-boot/arch/x86/cpu/coreboot/car.S b/roms/u-boot/arch/x86/cpu/coreboot/car.S new file mode 100644 index 00000000..6982106c --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/car.S @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +.section .text + +.globl car_init +car_init: +	jmp	car_init_ret diff --git a/roms/u-boot/arch/x86/cpu/coreboot/coreboot.c b/roms/u-boot/arch/x86/cpu/coreboot/coreboot.c new file mode 100644 index 00000000..e24f13af --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/coreboot.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2008 + * Graeme Russ, graeme.russ@gmail.com. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/u-boot-x86.h> +#include <flash.h> +#include <netdev.h> +#include <ns16550.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/timestamp.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Miscellaneous platform dependent initializations + */ +int cpu_init_f(void) +{ +	int ret = get_coreboot_info(&lib_sysinfo); +	if (ret != 0) +		printf("Failed to parse coreboot tables.\n"); + +	timestamp_init(); + +	return ret; +} + +int board_early_init_f(void) +{ +	return 0; +} + +int board_early_init_r(void) +{ +	/* CPU Speed to 100MHz */ +	gd->cpu_clk = 100000000; + +	/* Crystal is 33.000MHz */ +	gd->bus_clk = 33000000; + +	return 0; +} + +void show_boot_progress(int val) +{ +#if MIN_PORT80_KCLOCKS_DELAY +	/* +	 * 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 (!gd->arch.tsc_prev) { +		gd->arch.tsc_base_kclocks = rdtsc() / 1000; +		gd->arch.tsc_prev = 0; +	} else { +		uint32_t now; + +		do { +			now = rdtsc() / 1000 - gd->arch.tsc_base_kclocks; +		} while (now < (gd->arch.tsc_prev + MIN_PORT80_KCLOCKS_DELAY)); +		gd->arch.tsc_prev = now; +	} +#endif +	outb(val, 0x80); +} + +int last_stage_init(void) +{ +	if (gd->flags & GD_FLG_COLD_BOOT) +		timestamp_add_to_bootstage(); + +	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); +} + +#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 = (native_read_msr(MTRRcap_MSR) & 0xff) - 1; +	u8 top_type = native_read_msr(MTRRphysBase_MSR(top_mtrr)) & 0xff; + +	/* Make sure this MTRR is the correct Write-Protected type */ +	if (top_type == MTRR_TYPE_WP) { +		disable_caches(); +		wrmsrl(MTRRphysBase_MSR(top_mtrr), 0); +		wrmsrl(MTRRphysMask_MSR(top_mtrr), 0); +		enable_caches(); +	} + +	/* Issue SMI to Coreboot to lock down ME and registers */ +	printf("Finalizing Coreboot\n"); +	outb(0xcb, 0xb2); + +	return 0; +} + +void panic_puts(const char *str) +{ +	NS16550_t port = (NS16550_t)0x3f8; + +	NS16550_init(port, 1); +	while (*str) +		NS16550_putc(port, *str++); +} diff --git a/roms/u-boot/arch/x86/cpu/coreboot/ipchecksum.c b/roms/u-boot/arch/x86/cpu/coreboot/ipchecksum.c new file mode 100644 index 00000000..57733d8f --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/ipchecksum.c @@ -0,0 +1,54 @@ +/* + * This file is part of the libpayload project. + * + * It has originally been taken from the FreeBSD project. + * + * Copyright (c) 2001 Charles Mott <cm@linktel.net> + * Copyright (c) 2008 coresystems GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <compiler.h> +#include <asm/arch-coreboot/ipchecksum.h> + +unsigned short ipchksum(const void *vptr, unsigned long nbytes) +{ +	int sum, oddbyte; +	const unsigned short *ptr = vptr; + +	sum = 0; +	while (nbytes > 1) { +		sum += *ptr++; +		nbytes -= 2; +	} +	if (nbytes == 1) { +		oddbyte = 0; +		((u8 *)&oddbyte)[0] = *(u8 *) ptr; +		((u8 *)&oddbyte)[1] = 0; +		sum += oddbyte; +	} +	sum = (sum >> 16) + (sum & 0xffff); +	sum += (sum >> 16); +	return ~sum; +} diff --git a/roms/u-boot/arch/x86/cpu/coreboot/pci.c b/roms/u-boot/arch/x86/cpu/coreboot/pci.c new file mode 100644 index 00000000..33f16a30 --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/pci.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2008,2009 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <pci.h> +#include <asm/pci.h> + +static struct pci_controller coreboot_hose; + +static void config_pci_bridge(struct pci_controller *hose, pci_dev_t dev, +			      struct pci_config_table *table) +{ +	u8 secondary; +	hose->read_byte(hose, dev, PCI_SECONDARY_BUS, &secondary); +	hose->last_busno = max(hose->last_busno, secondary); +	pci_hose_scan_bus(hose, secondary); +} + +static struct pci_config_table pci_coreboot_config_table[] = { +	/* vendor, device, class, bus, dev, func */ +	{ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, +		PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, &config_pci_bridge }, +	{} +}; + +void pci_init_board(void) +{ +	coreboot_hose.config_table = pci_coreboot_config_table; +	coreboot_hose.first_busno = 0; +	coreboot_hose.last_busno = 0; + +	pci_set_region(coreboot_hose.regions + 0, 0x0, 0x0, 0xffffffff, +		PCI_REGION_MEM); +	coreboot_hose.region_count = 1; + +	pci_setup_type1(&coreboot_hose); + +	pci_register_hose(&coreboot_hose); + +	pci_hose_scan(&coreboot_hose); +} diff --git a/roms/u-boot/arch/x86/cpu/coreboot/sdram.c b/roms/u-boot/arch/x86/cpu/coreboot/sdram.c new file mode 100644 index 00000000..959feaae --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/sdram.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <asm/e820.h> +#include <asm/u-boot-x86.h> +#include <asm/global_data.h> +#include <asm/processor.h> +#include <asm/sections.h> +#include <asm/arch/sysinfo.h> +#include <asm/arch/tables.h> + +DECLARE_GLOBAL_DATA_PTR; + +unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) +{ +	int i; + +	unsigned num_entries = min(lib_sysinfo.n_memranges, max_entries); +	if (num_entries < lib_sysinfo.n_memranges) { +		printf("Warning: Limiting e820 map to %d entries.\n", +			num_entries); +	} +	for (i = 0; i < num_entries; i++) { +		struct memrange *memrange = &lib_sysinfo.memrange[i]; + +		entries[i].addr = memrange->base; +		entries[i].size = memrange->size; +		entries[i].type = memrange->type; +	} +	return num_entries; +} + +/* + * This function looks for the highest region of memory lower than 4GB which + * has enough space for U-Boot where U-Boot is aligned on a page boundary. It + * overrides the default implementation found elsewhere which simply picks the + * end of ram, wherever that may be. The location of the stack, the relocation + * address, and how far U-Boot is moved by relocation are set in the global + * data structure. + */ +ulong board_get_usable_ram_top(ulong total_size) +{ +	uintptr_t dest_addr = 0; +	int i; + +	for (i = 0; i < lib_sysinfo.n_memranges; i++) { +		struct memrange *memrange = &lib_sysinfo.memrange[i]; +		/* Force U-Boot to relocate to a page aligned address. */ +		uint64_t start = roundup(memrange->base, 1 << 12); +		uint64_t end = memrange->base + memrange->size; + +		/* Ignore non-memory regions. */ +		if (memrange->type != CB_MEM_RAM) +			continue; + +		/* Filter memory over 4GB. */ +		if (end > 0xffffffffULL) +			end = 0x100000000ULL; +		/* Skip this region if it's too small. */ +		if (end - start < total_size) +			continue; + +		/* Use this address if it's the largest so far. */ +		if (end > dest_addr) +			dest_addr = end; +	} + +	/* If no suitable area was found, return an error. */ +	if (!dest_addr) +		panic("No available memory found for relocation"); + +	return (ulong)dest_addr; +} + +int dram_init_f(void) +{ +	int i; +	phys_size_t ram_size = 0; + +	for (i = 0; i < lib_sysinfo.n_memranges; i++) { +		struct memrange *memrange = &lib_sysinfo.memrange[i]; +		unsigned long long end = memrange->base + memrange->size; + +		if (memrange->type == CB_MEM_RAM && end > ram_size) +			ram_size = end; +	} +	gd->ram_size = ram_size; +	if (ram_size == 0) +		return -1; +	return 0; +} + +int dram_init_banksize(void) +{ +	int i, j; + +	if (CONFIG_NR_DRAM_BANKS) { +		for (i = 0, j = 0; i < lib_sysinfo.n_memranges; i++) { +			struct memrange *memrange = &lib_sysinfo.memrange[i]; + +			if (memrange->type == CB_MEM_RAM) { +				gd->bd->bi_dram[j].start = memrange->base; +				gd->bd->bi_dram[j].size = memrange->size; +				j++; +				if (j >= CONFIG_NR_DRAM_BANKS) +					break; +			} +		} +	} +	return 0; +} + +int dram_init(void) +{ +	return dram_init_banksize(); +} diff --git a/roms/u-boot/arch/x86/cpu/coreboot/tables.c b/roms/u-boot/arch/x86/cpu/coreboot/tables.c new file mode 100644 index 00000000..0d91adc5 --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/tables.c @@ -0,0 +1,235 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2008 Advanced Micro Devices, Inc. + * Copyright (C) 2009 coresystems GmbH + * + * SPDX-License-Identifier:	BSD-3-Clause + */ + +#include <common.h> +#include <asm/arch-coreboot/ipchecksum.h> +#include <asm/arch-coreboot/sysinfo.h> +#include <asm/arch-coreboot/tables.h> + +/* + * This needs to be in the .data section so that it's copied over during + * relocation. By default it's put in the .bss section which is simply filled + * with zeroes when transitioning from "ROM", which is really RAM, to other + * RAM. + */ +struct sysinfo_t lib_sysinfo __attribute__((section(".data"))); + +/* + * Some of this is x86 specific, and the rest of it is generic. Right now, + * since we only support x86, we'll avoid trying to make lots of infrastructure + * we don't need. If in the future, we want to use coreboot on some other + * architecture, then take out the generic parsing code and move it elsewhere. + */ + +/* === Parsing code === */ +/* This is the generic parsing code. */ + +static void cb_parse_memory(unsigned char *ptr, struct sysinfo_t *info) +{ +	struct cb_memory *mem = (struct cb_memory *)ptr; +	int count = MEM_RANGE_COUNT(mem); +	int i; + +	if (count > SYSINFO_MAX_MEM_RANGES) +		count = SYSINFO_MAX_MEM_RANGES; + +	info->n_memranges = 0; + +	for (i = 0; i < count; i++) { +		struct cb_memory_range *range = +		    (struct cb_memory_range *)MEM_RANGE_PTR(mem, i); + +		info->memrange[info->n_memranges].base = +		    UNPACK_CB64(range->start); + +		info->memrange[info->n_memranges].size = +		    UNPACK_CB64(range->size); + +		info->memrange[info->n_memranges].type = range->type; + +		info->n_memranges++; +	} +} + +static void cb_parse_serial(unsigned char *ptr, struct sysinfo_t *info) +{ +	struct cb_serial *ser = (struct cb_serial *)ptr; +	info->serial = ser; +} + +static void cb_parse_vbnv(unsigned char *ptr, struct sysinfo_t *info) +{ +	struct cb_vbnv *vbnv = (struct cb_vbnv *)ptr; + +	info->vbnv_start = vbnv->vbnv_start; +	info->vbnv_size = vbnv->vbnv_size; +} + +static void cb_parse_gpios(unsigned char *ptr, struct sysinfo_t *info) +{ +	int i; +	struct cb_gpios *gpios = (struct cb_gpios *)ptr; + +	info->num_gpios = (gpios->count < SYSINFO_MAX_GPIOS) ? +				(gpios->count) : SYSINFO_MAX_GPIOS; + +	for (i = 0; i < info->num_gpios; i++) +		info->gpios[i] = gpios->gpios[i]; +} + +static void cb_parse_vdat(unsigned char *ptr, struct sysinfo_t *info) +{ +	struct cb_vdat *vdat = (struct cb_vdat *) ptr; + +	info->vdat_addr = vdat->vdat_addr; +	info->vdat_size = vdat->vdat_size; +} + +static void cb_parse_tstamp(unsigned char *ptr, struct sysinfo_t *info) +{ +	info->tstamp_table = ((struct cb_cbmem_tab *)ptr)->cbmem_tab; +} + +static void cb_parse_cbmem_cons(unsigned char *ptr, struct sysinfo_t *info) +{ +	info->cbmem_cons = ((struct cb_cbmem_tab *)ptr)->cbmem_tab; +} + +static void cb_parse_framebuffer(unsigned char *ptr, struct sysinfo_t *info) +{ +	info->framebuffer = (struct cb_framebuffer *)ptr; +} + +static void cb_parse_string(unsigned char *ptr, char **info) +{ +	*info = (char *)((struct cb_string *)ptr)->string; +} + +static int cb_parse_header(void *addr, int len, struct sysinfo_t *info) +{ +	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; + +	if (!header->table_bytes) +		return 0; + +	/* Make sure the checksums match. */ +	if (ipchksum((u16 *) header, sizeof(*header)) != 0) +		return -1; + +	if (ipchksum((u16 *) (ptr + sizeof(*header)), +		     header->table_bytes) != header->table_checksum) +		return -1; + +	/* Now, walk the tables. */ +	ptr += header->header_bytes; + +	/* Inintialize some fields to sentinel values. */ +	info->vbnv_start = info->vbnv_size = (uint32_t)(-1); + +	for (i = 0; i < header->table_entries; i++) { +		struct cb_record *rec = (struct cb_record *)ptr; + +		/* We only care about a few tags here (maybe more later). */ +		switch (rec->tag) { +		case CB_TAG_FORWARD: +			return cb_parse_header( +				(void *)(unsigned long) +				((struct cb_forward *)rec)->forward, +				len, info); +			continue; +		case CB_TAG_MEMORY: +			cb_parse_memory(ptr, info); +			break; +		case CB_TAG_SERIAL: +			cb_parse_serial(ptr, info); +			break; +		case CB_TAG_VERSION: +			cb_parse_string(ptr, &info->version); +			break; +		case CB_TAG_EXTRA_VERSION: +			cb_parse_string(ptr, &info->extra_version); +			break; +		case CB_TAG_BUILD: +			cb_parse_string(ptr, &info->build); +			break; +		case CB_TAG_COMPILE_TIME: +			cb_parse_string(ptr, &info->compile_time); +			break; +		case CB_TAG_COMPILE_BY: +			cb_parse_string(ptr, &info->compile_by); +			break; +		case CB_TAG_COMPILE_HOST: +			cb_parse_string(ptr, &info->compile_host); +			break; +		case CB_TAG_COMPILE_DOMAIN: +			cb_parse_string(ptr, &info->compile_domain); +			break; +		case CB_TAG_COMPILER: +			cb_parse_string(ptr, &info->compiler); +			break; +		case CB_TAG_LINKER: +			cb_parse_string(ptr, &info->linker); +			break; +		case CB_TAG_ASSEMBLER: +			cb_parse_string(ptr, &info->assembler); +			break; +		/* +		 * FIXME we should warn on serial if coreboot set up a +		 * framebuffer buf the payload does not know about it. +		 */ +		case CB_TAG_FRAMEBUFFER: +			cb_parse_framebuffer(ptr, info); +			break; +		case CB_TAG_GPIO: +			cb_parse_gpios(ptr, info); +			break; +		case CB_TAG_VDAT: +			cb_parse_vdat(ptr, info); +			break; +		case CB_TAG_TIMESTAMPS: +			cb_parse_tstamp(ptr, info); +			break; +		case CB_TAG_CBMEM_CONSOLE: +			cb_parse_cbmem_cons(ptr, info); +			break; +		case CB_TAG_VBNV: +			cb_parse_vbnv(ptr, info); +			break; +		} + +		ptr += rec->size; +	} + +	return 1; +} + +/* == Architecture specific == */ +/* This is the x86 specific stuff. */ + +int get_coreboot_info(struct sysinfo_t *info) +{ +	int ret = cb_parse_header((void *)0x00000000, 0x1000, info); + +	if (ret != 1) +		ret = cb_parse_header((void *)0x000f0000, 0x1000, info); + +	return (ret == 1) ? 0 : -1; +} diff --git a/roms/u-boot/arch/x86/cpu/coreboot/timestamp.c b/roms/u-boot/arch/x86/cpu/coreboot/timestamp.c new file mode 100644 index 00000000..bd3558a0 --- /dev/null +++ b/roms/u-boot/arch/x86/cpu/coreboot/timestamp.c @@ -0,0 +1,101 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/timestamp.h> +#include <asm/arch/sysinfo.h> +#include <linux/compiler.h> + +struct timestamp_entry { +	uint32_t	entry_id; +	uint64_t	entry_stamp; +} __packed; + +struct timestamp_table { +	uint64_t	base_time; +	uint32_t	max_entries; +	uint32_t	num_entries; +	struct timestamp_entry entries[0]; /* Variable number of entries */ +} __packed; + +static struct timestamp_table *ts_table  __attribute__((section(".data"))); + +void timestamp_init(void) +{ +	ts_table = lib_sysinfo.tstamp_table; +#ifdef CONFIG_SYS_X86_TSC_TIMER +	timer_set_base(ts_table->base_time); +#endif +	timestamp_add_now(TS_U_BOOT_INITTED); +} + +void timestamp_add(enum timestamp_id id, uint64_t ts_time) +{ +	struct timestamp_entry *tse; + +	if (!ts_table || (ts_table->num_entries == ts_table->max_entries)) +		return; + +	tse = &ts_table->entries[ts_table->num_entries++]; +	tse->entry_id = id; +	tse->entry_stamp = ts_time - ts_table->base_time; +} + +void timestamp_add_now(enum timestamp_id id) +{ +	timestamp_add(id, rdtsc()); +} + +int timestamp_add_to_bootstage(void) +{ +	uint i; + +	if (!ts_table) +		return -1; + +	for (i = 0; i < ts_table->num_entries; i++) { +		struct timestamp_entry *tse = &ts_table->entries[i]; +		const char *name = NULL; + +		switch (tse->entry_id) { +		case TS_START_ROMSTAGE: +			name = "start-romstage"; +			break; +		case TS_BEFORE_INITRAM: +			name = "before-initram"; +			break; +		case TS_DEVICE_INITIALIZE: +			name = "device-initialize"; +			break; +		case TS_DEVICE_DONE: +			name = "device-done"; +			break; +		case TS_SELFBOOT_JUMP: +			name = "selfboot-jump"; +			break; +		} +		if (name) { +			bootstage_add_record(0, name, BOOTSTAGEF_ALLOC, +					     tse->entry_stamp / +							get_tbclk_mhz()); +		} +	} + +	return 0; +}  | 
