coreboot: introduce boot_device

The boot_device is a region_device that represents the
device from which coreboot retrieves and boots its stages.
The existing cbfs implementations use the boot_device as
the intermediary for accessing the CBFS region. Also,
there's currently only support for a read-only view of
the boot_device. i.e. one cannot write to the boot_device
using this view. However, a writable boot_device could
be added in the future.

Change-Id: Ic0da796ab161b8025c90631be3423ba6473ad31c
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/10216
Tested-by: build bot (Jenkins)
Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
Aaron Durbin 2015-05-15 13:15:34 -05:00
parent def0fb57df
commit c6588c5af9
24 changed files with 683 additions and 430 deletions

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the coreboot project. * This file is part of the coreboot project.
* *
* Copyright (C) 2013 The Chromium OS Authors. All rights reserved. * Copyright 2015 Google Inc.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@ -17,40 +17,59 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc. * Foundation, Inc.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <console/console.h>
#include <string.h> #include <string.h>
#ifdef LIBPAYLOAD /* This assumes that the CBFS resides at 0x0, which is true for the default
# define printk(x...) * configuration. */
# define init_default_cbfs_media libpayload_init_default_cbfs_media static const struct mem_region_device gboot_dev =
extern int libpayload_init_default_cbfs_media(struct cbfs_media *media); MEM_REGION_DEV_INIT(NULL, CONFIG_ROM_SIZE);
#else
# include <console/console.h>
#endif
// Implementation of memory-mapped ROM media source on X86. const struct region_device *boot_device_ro(void)
{
return &gboot_dev.rdev;
}
static int rom_media_open(struct cbfs_media *media) { static int rom_media_open(struct cbfs_media *media) {
return 0; return 0;
} }
static void *rom_media_map(struct cbfs_media *media, size_t offset, size_t count) { static void *rom_media_map(struct cbfs_media *media, size_t offset, size_t count) {
const struct region_device *boot_dev;
void *ptr; void *ptr;
printk(BIOS_INFO, "%s: media %p, offset %lx, size %ld.\n", __func__, media, offset, count);
ptr = (void*)offset; printk(BIOS_INFO, "%s: media %p, offset %lx, size %ld.\n", __func__, media, offset, count);
boot_dev = media->context;
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr; return ptr;
} }
static void *rom_media_unmap(struct cbfs_media *media, const void *address) { static void *rom_media_unmap(struct cbfs_media *media, const void *address) {
const struct region_device *boot_dev;
boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL; return NULL;
} }
static size_t rom_media_read(struct cbfs_media *media, void *dest, size_t offset, static size_t rom_media_read(struct cbfs_media *media, void *dest, size_t offset,
size_t count) { size_t count) {
void *ptr = rom_media_map(media, offset, count); const struct region_device *boot_dev;
memcpy(dest, ptr, count);
rom_media_unmap(media, ptr); boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count; return count;
} }
@ -59,25 +78,8 @@ static int rom_media_close(struct cbfs_media *media) {
} }
static int init_rom_media_cbfs(struct cbfs_media *media) { static int init_rom_media_cbfs(struct cbfs_media *media) {
/* this assumes that the CBFS resides at 0x0, boot_device_init();
* which is true for the default configuration media->context = (void *)boot_device_ro();
*/
int32_t *cbfs_header_ptr = (int32_t*)(uintptr_t)(CONFIG_CBFS_SIZE - 4);
uint64_t cbfs_header_offset = CONFIG_CBFS_SIZE + *cbfs_header_ptr;
struct cbfs_header *header = (struct cbfs_header*) cbfs_header_offset;
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
printk(BIOS_ERR, "Expected %08lx and got %08lx\n", (unsigned long) CBFS_HEADER_MAGIC, (unsigned long) ntohl(header->magic));
return -1;
} else {
uint32_t romsize = ntohl(header->romsize);
media->context = (void*)(uintptr_t)romsize;
#if defined(CONFIG_ROM_SIZE)
if (CONFIG_ROM_SIZE != romsize)
printk(BIOS_INFO, "Warning: rom size unmatch (%d/%d)\n",
CONFIG_ROM_SIZE, romsize);
#endif
}
media->open = rom_media_open; media->open = rom_media_open;
media->close = rom_media_close; media->close = rom_media_close;
media->map = rom_media_map; media->map = rom_media_map;

View File

@ -6,6 +6,7 @@ romstage-y += memset.c
romstage-y += memcpy.c romstage-y += memcpy.c
romstage-y += memmove.c romstage-y += memmove.c
romstage-y += rom_media.c romstage-y += rom_media.c
romstage-y += mmap_boot.c
endif # CONFIG_ARCH_ROMSTAGE_X86_32 endif # CONFIG_ARCH_ROMSTAGE_X86_32
@ -22,6 +23,7 @@ ramstage-y += memcpy.c
ramstage-y += memmove.c ramstage-y += memmove.c
ramstage-y += ebda.c ramstage-y += ebda.c
ramstage-y += rom_media.c ramstage-y += rom_media.c
ramstage-y += mmap_boot.c
ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c
ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S
ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
@ -32,6 +34,7 @@ smm-y += memset.c
smm-y += memcpy.c smm-y += memcpy.c
smm-y += memmove.c smm-y += memmove.c
smm-y += rom_media.c smm-y += rom_media.c
smm-y += mmap_boot.c
rmodules_x86_32-y += memset.c rmodules_x86_32-y += memset.c
rmodules_x86_32-y += memcpy.c rmodules_x86_32-y += memcpy.c

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the coreboot project. * This file is part of the coreboot project.
* *
* Copyright 2013 Google Inc. * Copyright 2015 Google Inc.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,13 +17,15 @@
* Foundation, Inc. * Foundation, Inc.
*/ */
#include <boot_device.h>
#include <cbfs.h> /* This driver serves as a CBFS media source. */ /* The ROM is memory mapped just below 4GiB. Form a pointer for the base. */
#include <soc/spi.h> #define rom_base ((void *)(uintptr_t)(-(int32_t)CONFIG_ROM_SIZE))
#include <symbols.h>
int init_default_cbfs_media(struct cbfs_media *media) static const struct mem_region_device boot_dev =
MEM_REGION_DEV_INIT(rom_base, CONFIG_ROM_SIZE);
const struct region_device *boot_device_ro(void)
{ {
return initialize_tegra_spi_cbfs_media(media, return &boot_dev.rdev;
_cbfs_cache, _cbfs_cache_size);
} }

View File

@ -17,6 +17,8 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc. * Foundation, Inc.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <string.h> #include <string.h>
@ -36,14 +38,19 @@ static int x86_rom_open(struct cbfs_media *media) {
static void *x86_rom_map(struct cbfs_media *media, size_t offset, size_t count) { static void *x86_rom_map(struct cbfs_media *media, size_t offset, size_t count) {
void *ptr; void *ptr;
// Some address (ex, pointer to master header) may be given in memory const struct region_device *boot_dev;
// mapped location. To workaround that, we handle >0xf0000000 as real
// memory pointer.
boot_dev = media->context;
/* Extremely large offsets are considered relative to end of region. */
if ((uint32_t)offset > (uint32_t)0xf0000000) if ((uint32_t)offset > (uint32_t)0xf0000000)
ptr = (void*)offset; offset += region_device_sz(boot_dev);
else
ptr = (void*)(0 - (uint32_t)media->context + offset); ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr; return ptr;
} }
@ -53,7 +60,13 @@ static void *x86_rom_unmap(struct cbfs_media *media, const void *address) {
static size_t x86_rom_read(struct cbfs_media *media, void *dest, size_t offset, static size_t x86_rom_read(struct cbfs_media *media, void *dest, size_t offset,
size_t count) { size_t count) {
void *ptr = x86_rom_map(media, offset, count); void *ptr;
ptr = x86_rom_map(media, offset, count);
if (ptr == (void *)-1)
return 0;
memcpy(dest, ptr, count); memcpy(dest, ptr, count);
x86_rom_unmap(media, ptr); x86_rom_unmap(media, ptr);
return count; return count;
@ -63,30 +76,14 @@ static int x86_rom_close(struct cbfs_media *media) {
return 0; return 0;
} }
int init_x86rom_cbfs_media(struct cbfs_media *media); static int init_x86rom_cbfs_media(struct cbfs_media *media) {
int init_x86rom_cbfs_media(struct cbfs_media *media) { boot_device_init();
// On X86, we always keep a reference of pointer to CBFS header in
// 0xfffffffc, and the pointer is still a memory-mapped address. media->context = (void *)boot_device_ro();
// Since the CBFS core always use ROM offset, we need to figure out
// header->romsize even before media is initialized. if (media->context == NULL)
struct cbfs_header *header = (struct cbfs_header*)
*(uint32_t*)(0xfffffffc);
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
#if defined(CONFIG_ROM_SIZE)
printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
media->context = (void*)CONFIG_ROM_SIZE;
#else
return -1; return -1;
#endif
} else {
uint32_t romsize = ntohl(header->romsize);
media->context = (void*)romsize;
#if defined(CONFIG_ROM_SIZE)
if (CONFIG_ROM_SIZE != romsize)
printk(BIOS_INFO, "Warning: rom size unmatch (%d/%d)\n",
CONFIG_ROM_SIZE, romsize);
#endif
}
media->open = x86_rom_open; media->open = x86_rom_open;
media->close = x86_rom_close; media->close = x86_rom_close;
media->map = x86_rom_map; media->map = x86_rom_map;

View File

@ -4,11 +4,17 @@
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Subject to the GNU GPL v2, or (at your option) any later version. * Subject to the GNU GPL v2, or (at your option) any later version.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <console/console.h> #include <console/console.h>
const struct region_device *boot_device_ro(void)
{
return NULL;
}
int init_default_cbfs_media(struct cbfs_media *media) int init_default_cbfs_media(struct cbfs_media *media)
{ {
printk(BIOS_ERR, "Oh my! I don't know how to access CBFS yet."); printk(BIOS_ERR, "Oh my! I don't know how to access CBFS yet.");
return 0; return -1;
} }

View File

@ -17,11 +17,21 @@
* Foundation, Inc. * Foundation, Inc.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <console/console.h> #include <console/console.h>
#include <string.h> #include <string.h>
#include <symbols.h> #include <symbols.h>
/* FIXME: No idea how big the internal SRAM actually is. */
static const struct mem_region_device gboot_dev =
MEM_REGION_DEV_INIT(_dram, CONFIG_ROM_SIZE);
const struct region_device *boot_device_ro(void)
{
return &gboot_dev.rdev;
}
static int dummy_open(struct cbfs_media *media) static int dummy_open(struct cbfs_media *media)
{ {
return 0; return 0;
@ -35,33 +45,48 @@ static int dummy_close(struct cbfs_media *media)
static void * on_chip_memory_map(struct cbfs_media *media, size_t offset, static void * on_chip_memory_map(struct cbfs_media *media, size_t offset,
size_t count) size_t count)
{ {
return _dram + offset; const struct region_device *boot_dev;
void *ptr;
boot_dev = media->context;
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr;
} }
static void * dummy_unmap(struct cbfs_media *media, const void *address) static void * dummy_unmap(struct cbfs_media *media, const void *address)
{ {
const struct region_device *boot_dev;
boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL; return NULL;
} }
static size_t on_chip_memory_read(struct cbfs_media *media, void *dest, static size_t on_chip_memory_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count) size_t offset, size_t count)
{ {
void *ptr = media->map(media, offset, count); const struct region_device *boot_dev;
memcpy(dest, ptr, count);
media->unmap(media, ptr); boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count; return count;
} }
int init_default_cbfs_media(struct cbfs_media *media) int init_default_cbfs_media(struct cbfs_media *media)
{ {
struct cbfs_header *header = boot_device_init();
(struct cbfs_header *)(_dram + CONFIG_CBFS_HEADER_ROM_OFFSET);
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
return -1;
}
media->context = (void *)boot_device_ro();
media->open = dummy_open; media->open = dummy_open;
media->close = dummy_close; media->close = dummy_close;
media->map = on_chip_memory_map; media->map = on_chip_memory_map;

View File

@ -17,10 +17,16 @@
* Foundation, Inc. * Foundation, Inc.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
const struct region_device *boot_device_ro(void)
{
return NULL;
}
int init_default_cbfs_media(struct cbfs_media *media) int init_default_cbfs_media(struct cbfs_media *media)
{ {
/* FIXME: add support for reading coreboot from NAND */ /* FIXME: add support for reading coreboot from NAND */
return 0; return -1;
} }

41
src/include/boot_device.h Normal file
View File

@ -0,0 +1,41 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2015 Google Inc.
*
* 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.
*/
#ifndef _BOOT_DEVICE_H_
#define _BOOT_DEVICE_H_
#include <region.h>
/* Return the region_device for the read-only boot device. */
const struct region_device *boot_device_ro(void);
/*
* Create a sub-region of the read-only boot device.
* Returns 0 on success, < 0 on error.
*/
int boot_device_ro_subregion(const struct region *sub,
struct region_device *subrd);
/*
* Initialize the boot device. This may be called multiple times within
* a stage so boot device implementations should account for this behavior.
**/
void boot_device_init(void);
#endif /* _BOOT_DEVICE_H_ */

View File

@ -31,6 +31,7 @@ bootblock-y += memchr.c
bootblock-y += memcmp.c bootblock-y += memcmp.c
bootblock-y += mem_pool.c bootblock-y += mem_pool.c
bootblock-y += region.c bootblock-y += region.c
bootblock-y += boot_device.c
verstage-y += prog_ops.c verstage-y += prog_ops.c
verstage-y += delay.c verstage-y += delay.c
@ -40,6 +41,7 @@ verstage-y += halt.c
verstage-y += memcmp.c verstage-y += memcmp.c
verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
verstage-y += region.c verstage-y += region.c
verstage-y += boot_device.c
verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c
verstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c verstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
@ -141,7 +143,11 @@ ramstage-y += mem_pool.c
romstage-y += region.c romstage-y += region.c
ramstage-y += region.c ramstage-y += region.c
romstage-y += boot_device.c
ramstage-y += boot_device.c
smm-y += region.c
smm-y += boot_device.c
smm-y += cbfs.c cbfs_core.c memcmp.c smm-y += cbfs.c cbfs_core.c memcmp.c
smm-$(CONFIG_COMPILER_GCC) += gcc.c smm-$(CONFIG_COMPILER_GCC) += gcc.c

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the coreboot project. * This file is part of the coreboot project.
* *
* Copyright 2014 Google Inc. * Copyright 2015 Google Inc.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -17,12 +17,22 @@
* Foundation, Inc. * Foundation, Inc.
*/ */
#include <cbfs.h> /* This driver serves as a CBFS media source. */ #include <boot_device.h>
#include <soc/spi.h>
#include <symbols.h>
int init_default_cbfs_media(struct cbfs_media *media) void __attribute__((weak)) boot_device_init(void)
{ {
return initialize_tegra_spi_cbfs_media(media, /* Provide weak do-nothing init. */
_cbfs_cache, _cbfs_cache_size); }
int boot_device_ro_subregion(const struct region *sub,
struct region_device *subrd)
{
const struct region_device *boot_dev;
boot_dev = boot_device_ro();
if (boot_dev == NULL)
return -1;
return rdev_chain(subrd, boot_dev, region_offset(sub), region_sz(sub));
} }

View File

@ -23,17 +23,52 @@
* SPI. * SPI.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <region.h>
#include <spi_flash.h> #include <spi_flash.h>
#include <symbols.h> #include <symbols.h>
/* SPI flash as CBFS media. */ static struct spi_flash *spi_flash_info;
struct cbfs_spi_context {
struct spi_flash *spi_flash_info; static ssize_t spi_readat(const struct region_device *rd, void *b,
struct cbfs_simple_buffer buffer; size_t offset, size_t size)
{
if (spi_flash_info->read(spi_flash_info, offset, size, b))
return -1;
return size;
}
static const struct region_device_ops spi_ops = {
.mmap = mmap_helper_rdev_mmap,
.munmap = mmap_helper_rdev_munmap,
.readat = spi_readat,
}; };
static struct cbfs_spi_context spi_context; static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&spi_ops, 0, CONFIG_ROM_SIZE);
void boot_device_init(void)
{
int bus = CONFIG_BOOT_MEDIA_SPI_BUS;
int cs = 0;
if (spi_flash_info != NULL)
return;
spi_flash_info = spi_flash_probe(bus, cs);
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
}
/* Return the CBFS boot device. */
const struct region_device *boot_device_ro(void)
{
if (spi_flash_info == NULL)
return NULL;
return &mdev.rdev;
}
static int cbfs_media_open(struct cbfs_media *media) static int cbfs_media_open(struct cbfs_media *media)
{ {
@ -49,52 +84,58 @@ static size_t cbfs_media_read(struct cbfs_media *media,
void *dest, size_t offset, void *dest, size_t offset,
size_t count) size_t count)
{ {
struct cbfs_spi_context *context = media->context; const struct region_device *boot_dev;
return context->spi_flash_info->read boot_dev = media->context;
(context->spi_flash_info, offset, count, dest) ? 0 : count;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count;
} }
static void *cbfs_media_map(struct cbfs_media *media, static void *cbfs_media_map(struct cbfs_media *media,
size_t offset, size_t count) size_t offset, size_t count)
{ {
struct cbfs_spi_context *context = media->context; const struct region_device *boot_dev;
void *ptr;
return cbfs_simple_buffer_map(&context->buffer, media, offset, count); boot_dev = media->context;
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr;
} }
static void *cbfs_media_unmap(struct cbfs_media *media, static void *cbfs_media_unmap(struct cbfs_media *media,
const void *address) const void *address)
{ {
struct cbfs_spi_context *context = media->context; const struct region_device *boot_dev;
return cbfs_simple_buffer_unmap(&context->buffer, address); boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL;
} }
static int init_cbfs_media_context(void)
{
if (!spi_context.spi_flash_info) {
spi_context.spi_flash_info = spi_flash_probe
(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
if (!spi_context.spi_flash_info)
return -1;
spi_context.buffer.buffer = (void *)_cbfs_cache;
spi_context.buffer.size = _cbfs_cache_size;
}
return 0;
}
int init_default_cbfs_media(struct cbfs_media *media) int init_default_cbfs_media(struct cbfs_media *media)
{ {
media->context = &spi_context; boot_device_init();
media->context = (void *)boot_device_ro();
if (media->context == NULL)
return -1;
media->open = cbfs_media_open; media->open = cbfs_media_open;
media->close = cbfs_media_close; media->close = cbfs_media_close;
media->read = cbfs_media_read; media->read = cbfs_media_read;
media->map = cbfs_media_map; media->map = cbfs_media_map;
media->unmap = cbfs_media_unmap; media->unmap = cbfs_media_unmap;
return init_cbfs_media_context(); return 0;
} }

View File

@ -12,12 +12,20 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <string.h> #include <string.h>
#include <symbols.h> #include <symbols.h>
#include <console/console.h> #include <console/console.h>
/* Simple memory-mapped ROM emulation. */ /* Maps directly to qemu memory mapped space of 0x10000 up to rom size. */
static const struct mem_region_device gboot_dev =
MEM_REGION_DEV_INIT((void *)0x10000, CONFIG_ROM_SIZE);
const struct region_device *boot_device_ro(void)
{
return &gboot_dev.rdev;
}
static int emu_rom_open(struct cbfs_media *media) static int emu_rom_open(struct cbfs_media *media)
{ {
@ -26,26 +34,40 @@ static int emu_rom_open(struct cbfs_media *media)
static void *emu_rom_map(struct cbfs_media *media, size_t offset, size_t count) static void *emu_rom_map(struct cbfs_media *media, size_t offset, size_t count)
{ {
if (offset + count > CONFIG_ROM_SIZE) const struct region_device *boot_dev;
return (void *)-1; void *ptr;
return (void*)(offset + 0x10000);
boot_dev = media->context;
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr;
} }
static void *emu_rom_unmap(struct cbfs_media *media, const void *address) static void *emu_rom_unmap(struct cbfs_media *media, const void *address)
{ {
const struct region_device *boot_dev;
boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL; return NULL;
} }
static size_t emu_rom_read(struct cbfs_media *media, void *dest, size_t offset, static size_t emu_rom_read(struct cbfs_media *media, void *dest, size_t offset,
size_t count) size_t count)
{ {
void *ptr = emu_rom_map(media, offset, count); const struct region_device *boot_dev;
if (ptr == (void *)-1) boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0; return 0;
memcpy(dest, ptr, count);
emu_rom_unmap(media, ptr);
return count; return count;
} }
@ -54,10 +76,11 @@ static int emu_rom_close(struct cbfs_media *media)
return 0; return 0;
} }
int init_emu_rom_cbfs_media(struct cbfs_media *media); static int init_emu_rom_cbfs_media(struct cbfs_media *media)
int init_emu_rom_cbfs_media(struct cbfs_media *media)
{ {
boot_device_init();
media->context = (void *)boot_device_ro();
media->open = emu_rom_open; media->open = emu_rom_open;
media->close = emu_rom_close; media->close = emu_rom_close;
media->map = emu_rom_map; media->map = emu_rom_map;

View File

@ -2,7 +2,6 @@ ifeq ($(CONFIG_SOC_NVIDIA_TEGRA124),y)
bootblock-y += bootblock.c bootblock-y += bootblock.c
bootblock-y += bootblock_asm.S bootblock-y += bootblock_asm.S
bootblock-y += cbfs.c
bootblock-y += clock.c bootblock-y += clock.c
bootblock-y += dma.c bootblock-y += dma.c
bootblock-y += i2c.c bootblock-y += i2c.c
@ -22,7 +21,6 @@ bootblock-$(CONFIG_DRIVERS_UART) += uart.c
endif endif
verstage-y += verstage.c verstage-y += verstage.c
verstage-y += cbfs.c
verstage-y += dma.c verstage-y += dma.c
verstage-y += monotonic_timer.c verstage-y += monotonic_timer.c
verstage-y += spi.c verstage-y += spi.c
@ -34,7 +32,6 @@ verstage-y += clock.c
verstage-y += i2c.c verstage-y += i2c.c
verstage-y += cache.c verstage-y += cache.c
romstage-y += cbfs.c
romstage-y += cbmem.c romstage-y += cbmem.c
romstage-y += clock.c romstage-y += clock.c
romstage-y += dma.c romstage-y += dma.c
@ -51,7 +48,6 @@ romstage-y += ../tegra/pinmux.c
romstage-y += cache.c romstage-y += cache.c
romstage-$(CONFIG_DRIVERS_UART) += uart.c romstage-$(CONFIG_DRIVERS_UART) += uart.c
ramstage-y += cbfs.c
ramstage-y += cbmem.c ramstage-y += cbmem.c
ramstage-y += clock.c ramstage-y += clock.c
ramstage-y += display.c ramstage-y += display.c

View File

@ -61,11 +61,6 @@ struct tegra_spi_channel {
enum spi_xfer_mode xfer_mode; enum spi_xfer_mode xfer_mode;
}; };
struct cbfs_media;
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
void *buffer_address,
size_t buffer_size);
struct tegra_spi_channel *tegra_spi_init(unsigned int bus); struct tegra_spi_channel *tegra_spi_init(unsigned int bus);
#endif /* __NVIDIA_TEGRA124_SPI_H__ */ #endif /* __NVIDIA_TEGRA124_SPI_H__ */

View File

@ -21,6 +21,7 @@
#include <arch/cache.h> #include <arch/cache.h>
#include <arch/io.h> #include <arch/io.h>
#include <assert.h> #include <assert.h>
#include <boot_device.h>
#include <console/console.h> #include <console/console.h>
#include <cbfs.h> #include <cbfs.h>
#include <delay.h> #include <delay.h>
@ -33,6 +34,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <symbols.h>
#include <timer.h> #include <timer.h>
@ -800,12 +802,6 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
return ret; return ret;
} }
/* SPI as CBFS media. */
struct tegra_spi_media {
struct spi_slave *slave;
struct cbfs_simple_buffer buffer;
};
static int tegra_spi_cbfs_open(struct cbfs_media *media) static int tegra_spi_cbfs_open(struct cbfs_media *media)
{ {
DEBUG_SPI("tegra_spi_cbfs_open\n"); DEBUG_SPI("tegra_spi_cbfs_open\n");
@ -823,16 +819,17 @@ static int tegra_spi_cbfs_close(struct cbfs_media *media)
#define JEDEC_FAST_READ_DUAL 0x3b #define JEDEC_FAST_READ_DUAL 0x3b
#define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05 #define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, static struct spi_slave *boot_slave;
size_t offset, size_t count)
static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest,
size_t offset, size_t count)
{ {
struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context;
u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE]; u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
unsigned int read_cmd_bytes; unsigned int read_cmd_bytes;
int ret = count; int ret = count;
struct tegra_spi_channel *channel; struct tegra_spi_channel *channel;
channel = to_tegra_spi(spi->slave->bus); channel = to_tegra_spi(boot_slave->bus);
if (channel->dual_mode) { if (channel->dual_mode) {
/* /*
@ -853,9 +850,9 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
spi_read_cmd[2] = (offset >> 8) & 0xff; spi_read_cmd[2] = (offset >> 8) & 0xff;
spi_read_cmd[3] = offset & 0xff; spi_read_cmd[3] = offset & 0xff;
spi_claim_bus(spi->slave); spi_claim_bus(boot_slave);
if (spi_xfer(spi->slave, spi_read_cmd, if (spi_xfer(boot_slave, spi_read_cmd,
read_cmd_bytes, NULL, 0) < 0) { read_cmd_bytes, NULL, 0) < 0) {
ret = -1; ret = -1;
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n", printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
@ -866,7 +863,7 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
if (channel->dual_mode) { if (channel->dual_mode) {
setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT); setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
} }
if (spi_xfer(spi->slave, NULL, 0, dest, count)) { if (spi_xfer(boot_slave, NULL, 0, dest, count)) {
ret = -1; ret = -1;
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n", printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
__func__, count); __func__, count);
@ -876,56 +873,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
tegra_spi_cbfs_read_exit: tegra_spi_cbfs_read_exit:
/* de-assert /CS */ /* de-assert /CS */
spi_release_bus(spi->slave); spi_release_bus(boot_slave);
return (ret < 0) ? 0 : ret; return ret;
}
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
const struct region_device *boot_dev;
boot_dev = media->context;
printk(BIOS_ERR, "%s: reading %zx bytes from %zx\n",
__func__, count, offset);
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count;
} }
static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset, static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) size_t count)
{ {
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; const struct region_device *boot_dev;
void *map; void *map;
DEBUG_SPI("tegra_spi_cbfs_map\n"); DEBUG_SPI("tegra_spi_cbfs_map\n");
map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
boot_dev = media->context;
map = rdev_mmap(boot_dev, offset, count);
if (map == NULL)
map = (void *)-1;
return map; return map;
} }
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media, static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
const void *address) const void *address)
{ {
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; const struct region_device *boot_dev;
DEBUG_SPI("tegra_spi_cbfs_unmap\n"); DEBUG_SPI("tegra_spi_cbfs_unmap\n");
return cbfs_simple_buffer_unmap(&spi->buffer, address);
boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL;
} }
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media, int init_default_cbfs_media(struct cbfs_media *media)
void *buffer_address,
size_t buffer_size)
{ {
// TODO Replace static variable to support multiple streams.
static struct tegra_spi_media context;
static struct tegra_spi_channel *channel;
channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
DEBUG_SPI("Initializing CBFS media on SPI\n"); DEBUG_SPI("Initializing CBFS media on SPI\n");
context.slave = &channel->slave; boot_device_init();
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address; media->context = (void *)boot_device_ro();
context.buffer.size = buffer_size;
media->context = (void*)&context;
media->open = tegra_spi_cbfs_open; media->open = tegra_spi_cbfs_open;
media->close = tegra_spi_cbfs_close; media->close = tegra_spi_cbfs_close;
media->read = tegra_spi_cbfs_read; media->read = tegra_spi_cbfs_read;
media->map = tegra_spi_cbfs_map; media->map = tegra_spi_cbfs_map;
media->unmap = tegra_spi_cbfs_unmap; media->unmap = tegra_spi_cbfs_unmap;
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
channel->dual_mode = 1;
#endif
return 0; return 0;
} }
@ -937,3 +948,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
return &channel->slave; return &channel->slave;
} }
static const struct region_device_ops tegra_spi_ops = {
.mmap = mmap_helper_rdev_mmap,
.munmap = mmap_helper_rdev_munmap,
.readat = tegra_spi_readat,
};
static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE);
const struct region_device *boot_device_ro(void)
{
return &mdev.rdev;
}
void boot_device_init(void)
{
struct tegra_spi_channel *boot_chan;
boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
boot_chan->dual_mode = 1;
#endif
boot_slave = &boot_chan->slave;
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
}

View File

@ -2,7 +2,6 @@ ifeq ($(CONFIG_SOC_NVIDIA_TEGRA132),y)
bootblock-y += bootblock.c bootblock-y += bootblock.c
bootblock-y += bootblock_asm.S bootblock-y += bootblock_asm.S
bootblock-y += cbfs.c
bootblock-y += clock.c bootblock-y += clock.c
bootblock-y += spi.c bootblock-y += spi.c
bootblock-y += i2c.c bootblock-y += i2c.c
@ -23,7 +22,6 @@ bootblock-$(CONFIG_DRIVERS_UART) += uart.c
endif endif
verstage-y += verstage.c verstage-y += verstage.c
verstage-y += cbfs.c
verstage-y += dma.c verstage-y += dma.c
verstage-y += monotonic_timer.c verstage-y += monotonic_timer.c
verstage-y += spi.c verstage-y += spi.c
@ -39,7 +37,6 @@ verstage-y += i2c.c
romstage-y += 32bit_reset.S romstage-y += 32bit_reset.S
romstage-y += romstage_asm.S romstage-y += romstage_asm.S
romstage-y += addressmap.c romstage-y += addressmap.c
romstage-y += cbfs.c
romstage-y += cbmem.c romstage-y += cbmem.c
romstage-y += ccplex.c romstage-y += ccplex.c
romstage-y += clock.c romstage-y += clock.c
@ -63,7 +60,6 @@ romstage-$(CONFIG_DRIVERS_UART) += uart.c
ramstage-y += 32bit_reset.S ramstage-y += 32bit_reset.S
ramstage-y += addressmap.c ramstage-y += addressmap.c
ramstage-y += cbfs.c
ramstage-y += cbmem.c ramstage-y += cbmem.c
ramstage-y += cpu.c ramstage-y += cpu.c
ramstage-y += cpu_lib.S ramstage-y += cpu_lib.S

View File

@ -62,11 +62,6 @@ struct tegra_spi_channel {
enum spi_xfer_mode xfer_mode; enum spi_xfer_mode xfer_mode;
}; };
struct cbfs_media;
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
void *buffer_address,
size_t buffer_size);
struct tegra_spi_channel *tegra_spi_init(unsigned int bus); struct tegra_spi_channel *tegra_spi_init(unsigned int bus);
#endif /* __NVIDIA_TEGRA132_SPI_H__ */ #endif /* __NVIDIA_TEGRA132_SPI_H__ */

View File

@ -21,6 +21,7 @@
#include <arch/cache.h> #include <arch/cache.h>
#include <arch/io.h> #include <arch/io.h>
#include <assert.h> #include <assert.h>
#include <boot_device.h>
#include <cbfs.h> #include <cbfs.h>
#include <console/console.h> #include <console/console.h>
#include <delay.h> #include <delay.h>
@ -33,6 +34,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <symbols.h>
#include <timer.h> #include <timer.h>
@ -815,12 +817,6 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
return ret; return ret;
} }
/* SPI as CBFS media. */
struct tegra_spi_media {
struct spi_slave *slave;
struct cbfs_simple_buffer buffer;
};
static int tegra_spi_cbfs_open(struct cbfs_media *media) static int tegra_spi_cbfs_open(struct cbfs_media *media)
{ {
DEBUG_SPI("tegra_spi_cbfs_open\n"); DEBUG_SPI("tegra_spi_cbfs_open\n");
@ -838,16 +834,17 @@ static int tegra_spi_cbfs_close(struct cbfs_media *media)
#define JEDEC_FAST_READ_DUAL 0x3b #define JEDEC_FAST_READ_DUAL 0x3b
#define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05 #define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, static struct spi_slave *boot_slave;
size_t offset, size_t count)
static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest,
size_t offset, size_t count)
{ {
struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context;
u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE]; u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
unsigned int read_cmd_bytes; unsigned int read_cmd_bytes;
int ret = count; int ret = count;
struct tegra_spi_channel *channel; struct tegra_spi_channel *channel;
channel = to_tegra_spi(spi->slave->bus); channel = to_tegra_spi(boot_slave->bus);
if (channel->dual_mode) { if (channel->dual_mode) {
/* /*
@ -868,9 +865,9 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
spi_read_cmd[2] = (offset >> 8) & 0xff; spi_read_cmd[2] = (offset >> 8) & 0xff;
spi_read_cmd[3] = offset & 0xff; spi_read_cmd[3] = offset & 0xff;
spi_claim_bus(spi->slave); spi_claim_bus(boot_slave);
if (spi_xfer(spi->slave, spi_read_cmd, if (spi_xfer(boot_slave, spi_read_cmd,
read_cmd_bytes, NULL, 0) < 0) { read_cmd_bytes, NULL, 0) < 0) {
ret = -1; ret = -1;
printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n", printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
@ -881,7 +878,7 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
if (channel->dual_mode) { if (channel->dual_mode) {
setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT); setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
} }
if (spi_xfer(spi->slave, NULL, 0, dest, count)) { if (spi_xfer(boot_slave, NULL, 0, dest, count)) {
ret = -1; ret = -1;
printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n", printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
__func__, count); __func__, count);
@ -891,56 +888,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
tegra_spi_cbfs_read_exit: tegra_spi_cbfs_read_exit:
/* de-assert /CS */ /* de-assert /CS */
spi_release_bus(spi->slave); spi_release_bus(boot_slave);
return (ret < 0) ? 0 : ret; return ret;
}
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
const struct region_device *boot_dev;
boot_dev = media->context;
DEBUG_SPI("%s: reading %zx bytes from %zx\n", __func__, count, offset);
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count;
} }
static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset, static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) size_t count)
{ {
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; const struct region_device *boot_dev;
void *map; void *map;
DEBUG_SPI("tegra_spi_cbfs_map\n"); DEBUG_SPI("tegra_spi_cbfs_map\n");
map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
boot_dev = media->context;
map = rdev_mmap(boot_dev, offset, count);
if (map == NULL)
map = (void *)-1;
return map; return map;
} }
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media, static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
const void *address) const void *address)
{ {
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; const struct region_device *boot_dev;
DEBUG_SPI("tegra_spi_cbfs_unmap\n"); DEBUG_SPI("tegra_spi_cbfs_unmap\n");
return cbfs_simple_buffer_unmap(&spi->buffer, address);
boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL;
} }
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media, int init_default_cbfs_media(struct cbfs_media *media)
void *buffer_address,
size_t buffer_size)
{ {
// TODO Replace static variable to support multiple streams.
static struct tegra_spi_media context;
static struct tegra_spi_channel *channel;
channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
DEBUG_SPI("Initializing CBFS media on SPI\n"); DEBUG_SPI("Initializing CBFS media on SPI\n");
context.slave = &channel->slave; boot_device_init();
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address; media->context = (void *)boot_device_ro();
context.buffer.size = buffer_size;
media->context = (void*)&context;
media->open = tegra_spi_cbfs_open; media->open = tegra_spi_cbfs_open;
media->close = tegra_spi_cbfs_close; media->close = tegra_spi_cbfs_close;
media->read = tegra_spi_cbfs_read; media->read = tegra_spi_cbfs_read;
media->map = tegra_spi_cbfs_map; media->map = tegra_spi_cbfs_map;
media->unmap = tegra_spi_cbfs_unmap; media->unmap = tegra_spi_cbfs_unmap;
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
channel->dual_mode = 1;
#endif
return 0; return 0;
} }
@ -952,3 +963,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
return &channel->slave; return &channel->slave;
} }
static const struct region_device_ops tegra_spi_ops = {
.mmap = mmap_helper_rdev_mmap,
.munmap = mmap_helper_rdev_munmap,
.readat = tegra_spi_readat,
};
static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE);
const struct region_device *boot_device_ro(void)
{
return &mdev.rdev;
}
void boot_device_init(void)
{
struct tegra_spi_channel *boot_chan;
boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
boot_chan->dual_mode = 1;
#endif
boot_slave = &boot_chan->slave;
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
}

View File

@ -19,6 +19,7 @@
#include <assert.h> #include <assert.h>
#include <boot_device.h>
#include <cbfs.h> /* This driver serves as a CBFS media source. */ #include <cbfs.h> /* This driver serves as a CBFS media source. */
#include <console/console.h> #include <console/console.h>
#include <soc/alternate_cbfs.h> #include <soc/alternate_cbfs.h>
@ -45,7 +46,7 @@
* rest of the firmware's lifetime and all subsequent stages (which will not * rest of the firmware's lifetime and all subsequent stages (which will not
* have __PRE_RAM__ defined) can just directly reference it there. * have __PRE_RAM__ defined) can just directly reference it there.
*/ */
static int usb_cbfs_open(struct cbfs_media *media) static int usb_cbfs_open(void)
{ {
#ifdef __PRE_RAM__ #ifdef __PRE_RAM__
static int first_run = 1; static int first_run = 1;
@ -80,7 +81,7 @@ static int usb_cbfs_open(struct cbfs_media *media)
* this seems like a safer approach. It also makes it easy to pass our image * this seems like a safer approach. It also makes it easy to pass our image
* down to payloads. * down to payloads.
*/ */
static int sdmmc_cbfs_open(struct cbfs_media *media) static int sdmmc_cbfs_open(void)
{ {
#ifdef __PRE_RAM__ #ifdef __PRE_RAM__
/* /*
@ -111,66 +112,109 @@ static int sdmmc_cbfs_open(struct cbfs_media *media)
return 0; return 0;
} }
static int alternate_cbfs_close(struct cbfs_media *media) { return 0; } static int exynos_cbfs_open(struct cbfs_media *media) {
return 0;
}
static int exynos_cbfs_close(struct cbfs_media *media) {
return 0;
}
static size_t exynos_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count) {
const struct region_device *boot_dev;
boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
static size_t alternate_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
ASSERT(offset + count < _cbfs_cache_size);
memcpy(dest, _cbfs_cache + offset, count);
return count; return count;
} }
static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset, static void *exynos_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) size_t count) {
{ const struct region_device *boot_dev;
ASSERT(offset + count < _cbfs_cache_size); void *ptr;
return _cbfs_cache + offset;
boot_dev = media->context;
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr;
} }
static void *alternate_cbfs_unmap(struct cbfs_media *media, static void *exynos_cbfs_unmap(struct cbfs_media *media,
const void *buffer) { return 0; } const void *address) {
const struct region_device *boot_dev;
static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media) boot_dev = media->context;
{
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
media->open = sdmmc_cbfs_open; rdev_munmap(boot_dev, (void *)address);
media->close = alternate_cbfs_close;
media->read = alternate_cbfs_read;
media->map = alternate_cbfs_map;
media->unmap = alternate_cbfs_unmap;
return 0; return NULL;
}
static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
{
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
media->open = usb_cbfs_open;
media->close = alternate_cbfs_close;
media->read = alternate_cbfs_read;
media->map = alternate_cbfs_map;
media->unmap = alternate_cbfs_unmap;
return 0;
} }
int init_default_cbfs_media(struct cbfs_media *media) int init_default_cbfs_media(struct cbfs_media *media)
{
boot_device_init();
media->context = (void *)boot_device_ro();
if (media->context == NULL)
return -1;
media->open = exynos_cbfs_open;
media->close = exynos_cbfs_close;
media->read = exynos_cbfs_read;
media->map = exynos_cbfs_map;
media->unmap = exynos_cbfs_unmap;
return 0;
}
static struct mem_region_device alternate_rdev = MEM_REGION_DEV_INIT(NULL, 0);
const struct region_device *boot_device_ro(void)
{ {
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB)
return initialize_exynos_usb_cbfs_media(media); return &alternate_rdev.rdev;
switch (exynos_power->om_stat & OM_STAT_MASK) { switch (exynos_power->om_stat & OM_STAT_MASK) {
case OM_STAT_SDMMC: case OM_STAT_SDMMC:
return initialize_exynos_sdmmc_cbfs_media(media); return &alternate_rdev.rdev;
case OM_STAT_SPI: case OM_STAT_SPI:
return initialize_exynos_spi_cbfs_media(media, return exynos_spi_boot_device();
_cbfs_cache, _cbfs_cache_size); default:
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
exynos_power->om_stat);
return NULL;
}
}
void boot_device_init(void)
{
mem_region_device_init(&alternate_rdev, _cbfs_cache, _cbfs_cache_size);
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) {
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
usb_cbfs_open();
return;
}
switch (exynos_power->om_stat & OM_STAT_MASK) {
case OM_STAT_SDMMC:
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
sdmmc_cbfs_open();
break;
case OM_STAT_SPI:
exynos_init_spi_boot_device();
break;
default: default:
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n", printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
exynos_power->om_stat); exynos_power->om_stat);
return 1;
} }
} }

View File

@ -20,8 +20,7 @@
#ifndef CPU_SAMSUNG_EXYNOS5250_SPI_H #ifndef CPU_SAMSUNG_EXYNOS5250_SPI_H
#define CPU_SAMSUNG_EXYNOS5250_SPI_H #define CPU_SAMSUNG_EXYNOS5250_SPI_H
/* This driver serves as a CBFS media source. */ #include <boot_device.h>
#include <cbfs.h>
/* SPI peripheral register map; padded to 64KB */ /* SPI peripheral register map; padded to 64KB */
struct exynos_spi { struct exynos_spi {
@ -92,8 +91,6 @@ int exynos_spi_open(struct exynos_spi *regs);
int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off); int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off);
int exynos_spi_close(struct exynos_spi *regs); int exynos_spi_close(struct exynos_spi *regs);
/* Serve as CBFS media source */ void exynos_init_spi_boot_device(void);
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, const struct region_device *exynos_spi_boot_device(void);
void *buffer_address,
size_t buffer_size);
#endif #endif

View File

@ -20,11 +20,13 @@
#include <arch/io.h> #include <arch/io.h>
#include <assert.h> #include <assert.h>
#include <boot_device.h>
#include <console/console.h> #include <console/console.h>
#include <soc/clk.h> #include <soc/clk.h>
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/spi.h> #include <soc/spi.h>
#include <stdlib.h> #include <stdlib.h>
#include <symbols.h>
#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI #if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x) # define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
@ -144,70 +146,47 @@ int exynos_spi_close(struct exynos_spi *regs)
return 0; return 0;
} }
// SPI as CBFS media. static struct exynos_spi *boot_slave_regs;
struct exynos_spi_media {
struct exynos_spi *regs;
struct cbfs_simple_buffer buffer;
};
static int exynos_spi_cbfs_open(struct cbfs_media *media) { static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest,
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; size_t offset, size_t count)
DEBUG_SPI("exynos_spi_cbfs_open\n"); {
return exynos_spi_open(spi->regs);
}
static int exynos_spi_cbfs_close(struct cbfs_media *media) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_close\n");
return exynos_spi_close(spi->regs);
}
static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
int bytes; int bytes;
DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count); DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
bytes = exynos_spi_read(spi->regs, dest, count, offset); exynos_spi_open(boot_slave_regs);
// Flush and re-open the device. bytes = exynos_spi_read(boot_slave_regs, dest, count, offset);
exynos_spi_close(spi->regs); exynos_spi_close(boot_slave_regs);
exynos_spi_open(spi->regs);
return bytes; return bytes;
} }
static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset, static void *exynos_spi_map(const struct region_device *rdev,
size_t count) { size_t offset, size_t count)
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; {
DEBUG_SPI("exynos_spi_cbfs_map\n"); DEBUG_SPI("exynos_spi_cbfs_map\n");
// See exynos_spi_rx_tx for I/O alignment limitation. // exynos: spi_rx_tx may work in 4 byte-width-transmission mode and
// requires buffer memory address to be aligned.
if (count % 4) if (count % 4)
count += 4 - (count % 4); count += 4 - (count % 4);
return cbfs_simple_buffer_map(&spi->buffer, media, offset, count); return mmap_helper_rdev_mmap(rdev, offset, count);
} }
static void *exynos_spi_cbfs_unmap(struct cbfs_media *media, static const struct region_device_ops exynos_spi_ops = {
const void *address) { .mmap = exynos_spi_map,
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; .munmap = mmap_helper_rdev_munmap,
DEBUG_SPI("exynos_spi_cbfs_unmap\n"); .readat = exynos_spi_readat,
return cbfs_simple_buffer_unmap(&spi->buffer, address); };
static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE);
void exynos_init_spi_boot_device(void)
{
boot_slave_regs = (void *)EXYNOS5_SPI1_BASE;
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
} }
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, const struct region_device *exynos_spi_boot_device(void)
void *buffer_address, {
size_t buffer_size) { return &mdev.rdev;
// TODO Replace static variable to support multiple streams.
static struct exynos_spi_media context;
DEBUG_SPI("initialize_exynos_spi_cbfs_media\n");
context.regs = (void*)EXYNOS5_SPI1_BASE;
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address;
context.buffer.size = buffer_size;
media->context = (void*)&context;
media->open = exynos_spi_cbfs_open;
media->close = exynos_spi_cbfs_close;
media->read = exynos_spi_cbfs_read;
media->map = exynos_spi_cbfs_map;
media->unmap = exynos_spi_cbfs_unmap;
return 0;
} }

View File

@ -20,6 +20,7 @@
#include <arch/cache.h> #include <arch/cache.h>
#include <assert.h> #include <assert.h>
#include <boot_device.h>
#include <cbfs.h> /* This driver serves as a CBFS media source. */ #include <cbfs.h> /* This driver serves as a CBFS media source. */
#include <console/console.h> #include <console/console.h>
#include <soc/alternate_cbfs.h> #include <soc/alternate_cbfs.h>
@ -46,7 +47,7 @@
* rest of the firmware's lifetime and all subsequent stages (which will not * rest of the firmware's lifetime and all subsequent stages (which will not
* have __PRE_RAM__ defined) can just directly reference it there. * have __PRE_RAM__ defined) can just directly reference it there.
*/ */
static int usb_cbfs_open(struct cbfs_media *media) static int usb_cbfs_open(void)
{ {
#ifdef __PRE_RAM__ #ifdef __PRE_RAM__
static int first_run = 1; static int first_run = 1;
@ -84,7 +85,7 @@ static int usb_cbfs_open(struct cbfs_media *media)
* this seems like a safer approach. It also makes it easy to pass our image * this seems like a safer approach. It also makes it easy to pass our image
* down to payloads. * down to payloads.
*/ */
static int sdmmc_cbfs_open(struct cbfs_media *media) static int sdmmc_cbfs_open(void)
{ {
#ifdef __PRE_RAM__ #ifdef __PRE_RAM__
/* /*
@ -118,66 +119,109 @@ static int sdmmc_cbfs_open(struct cbfs_media *media)
return 0; return 0;
} }
static int alternate_cbfs_close(struct cbfs_media *media) { return 0; } static int exynos_cbfs_open(struct cbfs_media *media) {
return 0;
}
static int exynos_cbfs_close(struct cbfs_media *media) {
return 0;
}
static size_t exynos_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count) {
const struct region_device *boot_dev;
boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
static size_t alternate_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
ASSERT(offset + count < _cbfs_cache_size);
memcpy(dest, _cbfs_cache + offset, count);
return count; return count;
} }
static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset, static void *exynos_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) size_t count) {
{ const struct region_device *boot_dev;
ASSERT(offset + count < _cbfs_cache_size); void *ptr;
return _cbfs_cache + offset;
boot_dev = media->context;
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
return ptr;
} }
static void *alternate_cbfs_unmap(struct cbfs_media *media, static void *exynos_cbfs_unmap(struct cbfs_media *media,
const void *buffer) { return 0; } const void *address) {
const struct region_device *boot_dev;
static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media) boot_dev = media->context;
{
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
media->open = sdmmc_cbfs_open; rdev_munmap(boot_dev, (void *)address);
media->close = alternate_cbfs_close;
media->read = alternate_cbfs_read;
media->map = alternate_cbfs_map;
media->unmap = alternate_cbfs_unmap;
return 0; return NULL;
}
static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
{
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
media->open = usb_cbfs_open;
media->close = alternate_cbfs_close;
media->read = alternate_cbfs_read;
media->map = alternate_cbfs_map;
media->unmap = alternate_cbfs_unmap;
return 0;
} }
int init_default_cbfs_media(struct cbfs_media *media) int init_default_cbfs_media(struct cbfs_media *media)
{
boot_device_init();
media->context = (void *)boot_device_ro();
if (media->context == NULL)
return -1;
media->open = exynos_cbfs_open;
media->close = exynos_cbfs_close;
media->read = exynos_cbfs_read;
media->map = exynos_cbfs_map;
media->unmap = exynos_cbfs_unmap;
return 0;
}
static struct mem_region_device alternate_rdev = MEM_REGION_DEV_INIT(NULL, 0);
const struct region_device *boot_device_ro(void)
{ {
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB)
return initialize_exynos_usb_cbfs_media(media); return &alternate_rdev.rdev;
switch (exynos_power->om_stat & OM_STAT_MASK) { switch (exynos_power->om_stat & OM_STAT_MASK) {
case OM_STAT_SDMMC: case OM_STAT_SDMMC:
return initialize_exynos_sdmmc_cbfs_media(media); return &alternate_rdev.rdev;
case OM_STAT_SPI: case OM_STAT_SPI:
return initialize_exynos_spi_cbfs_media(media, return exynos_spi_boot_device();
_cbfs_cache, _cbfs_cache_size); default:
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
exynos_power->om_stat);
return NULL;
}
}
void boot_device_init(void)
{
mem_region_device_init(&alternate_rdev, _cbfs_cache, _cbfs_cache_size);
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) {
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
usb_cbfs_open();
return;
}
switch (exynos_power->om_stat & OM_STAT_MASK) {
case OM_STAT_SDMMC:
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
sdmmc_cbfs_open();
break;
case OM_STAT_SPI:
exynos_init_spi_boot_device();
break;
default: default:
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n", printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
exynos_power->om_stat); exynos_power->om_stat);
return 1;
} }
} }

View File

@ -20,8 +20,7 @@
#ifndef CPU_SAMSUNG_EXYNOS5420_SPI_H #ifndef CPU_SAMSUNG_EXYNOS5420_SPI_H
#define CPU_SAMSUNG_EXYNOS5420_SPI_H #define CPU_SAMSUNG_EXYNOS5420_SPI_H
/* This driver serves as a CBFS media source. */ #include <boot_device.h>
#include <cbfs.h>
/* SPI peripheral register map; padded to 64KB */ /* SPI peripheral register map; padded to 64KB */
struct exynos_spi { struct exynos_spi {
@ -91,8 +90,6 @@ check_member(exynos_spi, fb_clk, 0x2c);
#define SPI_RX_BYTE_SWAP (1 << 6) #define SPI_RX_BYTE_SWAP (1 << 6)
#define SPI_RX_HWORD_SWAP (1 << 7) #define SPI_RX_HWORD_SWAP (1 << 7)
/* Serve as CBFS media source */ void exynos_init_spi_boot_device(void);
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, const struct region_device *exynos_spi_boot_device(void);
void *buffer_address,
size_t buffer_size);
#endif #endif

View File

@ -26,6 +26,7 @@
#include <spi_flash.h> #include <spi_flash.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <symbols.h>
#define EXYNOS_SPI_MAX_TRANSFER_BYTES (65535) #define EXYNOS_SPI_MAX_TRANSFER_BYTES (65535)
@ -242,76 +243,43 @@ static int exynos_spi_read(struct spi_slave *slave, void *dest, uint32_t len,
return len; return len;
} }
// SPI as CBFS media. static struct exynos_spi_slave *boot_slave;
struct exynos_spi_media {
struct spi_slave *slave;
struct cbfs_simple_buffer buffer;
};
static int exynos_spi_cbfs_open(struct cbfs_media *media) static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest,
size_t offset, size_t count)
{ {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_open\n");
return spi_claim_bus(spi->slave);
}
static int exynos_spi_cbfs_close(struct cbfs_media *media)
{
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_close\n");
spi_release_bus(spi->slave);
return 0;
}
static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
int bytes;
DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count); DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
bytes = exynos_spi_read(spi->slave, dest, count, offset); return exynos_spi_read(&boot_slave->slave, dest, count, offset);
return bytes;
} }
static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset, static void *exynos_spi_map(const struct region_device *rdev,
size_t count) size_t offset, size_t count)
{ {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_map\n"); DEBUG_SPI("exynos_spi_cbfs_map\n");
// exynos: spi_rx_tx may work in 4 byte-width-transmission mode and // exynos: spi_rx_tx may work in 4 byte-width-transmission mode and
// requires buffer memory address to be aligned. // requires buffer memory address to be aligned.
if (count % 4) if (count % 4)
count += 4 - (count % 4); count += 4 - (count % 4);
return cbfs_simple_buffer_map(&spi->buffer, media, offset, count); return mmap_helper_rdev_mmap(rdev, offset, count);
} }
static void *exynos_spi_cbfs_unmap(struct cbfs_media *media, static const struct region_device_ops exynos_spi_ops = {
const void *address) .mmap = exynos_spi_map,
.munmap = mmap_helper_rdev_munmap,
.readat = exynos_spi_readat,
};
static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE);
void exynos_init_spi_boot_device(void)
{ {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; boot_slave = &exynos_spi_slaves[1];
DEBUG_SPI("exynos_spi_cbfs_unmap\n");
return cbfs_simple_buffer_unmap(&spi->buffer, address); mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
} }
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, const struct region_device *exynos_spi_boot_device(void)
void *buffer_address,
size_t buffer_size)
{ {
// TODO Replace static variable to support multiple streams. return &mdev.rdev;
static struct exynos_spi_media context;
static struct exynos_spi_slave *eslave = &exynos_spi_slaves[1];
DEBUG_SPI("initialize_exynos_spi_cbfs_media\n");
context.slave = &eslave->slave;
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address;
context.buffer.size = buffer_size;
media->context = (void*)&context;
media->open = exynos_spi_cbfs_open;
media->close = exynos_spi_cbfs_close;
media->read = exynos_spi_cbfs_read;
media->map = exynos_spi_cbfs_map;
media->unmap = exynos_spi_cbfs_unmap;
return 0;
} }