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.
*
* 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
* 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
* Foundation, Inc.
*/
#include <boot_device.h>
#include <cbfs.h>
#include <console/console.h>
#include <string.h>
#ifdef LIBPAYLOAD
# define printk(x...)
# define init_default_cbfs_media libpayload_init_default_cbfs_media
extern int libpayload_init_default_cbfs_media(struct cbfs_media *media);
#else
# include <console/console.h>
#endif
/* This assumes that the CBFS resides at 0x0, which is true for the default
* configuration. */
static const struct mem_region_device gboot_dev =
MEM_REGION_DEV_INIT(NULL, CONFIG_ROM_SIZE);
// 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) {
return 0;
}
static void *rom_media_map(struct cbfs_media *media, size_t offset, size_t count) {
const struct region_device *boot_dev;
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;
}
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;
}
static size_t rom_media_read(struct cbfs_media *media, void *dest, size_t offset,
size_t count) {
void *ptr = rom_media_map(media, offset, count);
memcpy(dest, ptr, count);
rom_media_unmap(media, ptr);
const struct region_device *boot_dev;
boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
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) {
/* this assumes that the CBFS resides at 0x0,
* which is true for the default configuration
*/
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
}
boot_device_init();
media->context = (void *)boot_device_ro();
media->open = rom_media_open;
media->close = rom_media_close;
media->map = rom_media_map;

View File

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

View File

@ -1,7 +1,7 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -17,13 +17,15 @@
* Foundation, Inc.
*/
#include <boot_device.h>
#include <cbfs.h> /* This driver serves as a CBFS media source. */
#include <soc/spi.h>
#include <symbols.h>
/* The ROM is memory mapped just below 4GiB. Form a pointer for the base. */
#define rom_base ((void *)(uintptr_t)(-(int32_t)CONFIG_ROM_SIZE))
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,
_cbfs_cache, _cbfs_cache_size);
return &boot_dev.rdev;
}

View File

@ -17,6 +17,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc.
*/
#include <boot_device.h>
#include <cbfs.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) {
void *ptr;
// Some address (ex, pointer to master header) may be given in memory
// mapped location. To workaround that, we handle >0xf0000000 as real
// memory pointer.
const struct region_device *boot_dev;
boot_dev = media->context;
/* Extremely large offsets are considered relative to end of region. */
if ((uint32_t)offset > (uint32_t)0xf0000000)
ptr = (void*)offset;
else
ptr = (void*)(0 - (uint32_t)media->context + offset);
offset += region_device_sz(boot_dev);
ptr = rdev_mmap(boot_dev, offset, count);
if (ptr == NULL)
return (void *)-1;
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,
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);
x86_rom_unmap(media, ptr);
return count;
@ -63,30 +76,14 @@ static int x86_rom_close(struct cbfs_media *media) {
return 0;
}
int init_x86rom_cbfs_media(struct cbfs_media *media);
int init_x86rom_cbfs_media(struct cbfs_media *media) {
// On X86, we always keep a reference of pointer to CBFS header in
// 0xfffffffc, and the pointer is still a memory-mapped address.
// Since the CBFS core always use ROM offset, we need to figure out
// header->romsize even before media is initialized.
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
static int init_x86rom_cbfs_media(struct cbfs_media *media) {
boot_device_init();
media->context = (void *)boot_device_ro();
if (media->context == NULL)
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->close = x86_rom_close;
media->map = x86_rom_map;

View File

@ -4,11 +4,17 @@
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Subject to the GNU GPL v2, or (at your option) any later version.
*/
#include <boot_device.h>
#include <cbfs.h>
#include <console/console.h>
const struct region_device *boot_device_ro(void)
{
return NULL;
}
int init_default_cbfs_media(struct cbfs_media *media)
{
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.
*/
#include <boot_device.h>
#include <cbfs.h>
#include <console/console.h>
#include <string.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)
{
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,
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)
{
const struct region_device *boot_dev;
boot_dev = media->context;
rdev_munmap(boot_dev, (void *)address);
return NULL;
}
static size_t on_chip_memory_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
{
void *ptr = media->map(media, offset, count);
memcpy(dest, ptr, count);
media->unmap(media, ptr);
const struct region_device *boot_dev;
boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count;
}
int init_default_cbfs_media(struct cbfs_media *media)
{
struct cbfs_header *header =
(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;
}
boot_device_init();
media->context = (void *)boot_device_ro();
media->open = dummy_open;
media->close = dummy_close;
media->map = on_chip_memory_map;

View File

@ -17,10 +17,16 @@
* Foundation, Inc.
*/
#include <boot_device.h>
#include <cbfs.h>
const struct region_device *boot_device_ro(void)
{
return NULL;
}
int init_default_cbfs_media(struct cbfs_media *media)
{
/* FIXME: add support for reading coreboot from NAND */
return 0;
/* FIXME: add support for reading coreboot from NAND */
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 += mem_pool.c
bootblock-y += region.c
bootblock-y += boot_device.c
verstage-y += prog_ops.c
verstage-y += delay.c
@ -40,6 +41,7 @@ verstage-y += halt.c
verstage-y += memcmp.c
verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
verstage-y += region.c
verstage-y += boot_device.c
verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c
verstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
@ -141,7 +143,11 @@ ramstage-y += mem_pool.c
romstage-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-$(CONFIG_COMPILER_GCC) += gcc.c

View File

@ -1,7 +1,7 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -17,12 +17,22 @@
* Foundation, Inc.
*/
#include <cbfs.h> /* This driver serves as a CBFS media source. */
#include <soc/spi.h>
#include <symbols.h>
#include <boot_device.h>
int init_default_cbfs_media(struct cbfs_media *media)
void __attribute__((weak)) boot_device_init(void)
{
return initialize_tegra_spi_cbfs_media(media,
_cbfs_cache, _cbfs_cache_size);
/* Provide weak do-nothing init. */
}
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.
*/
#include <boot_device.h>
#include <cbfs.h>
#include <region.h>
#include <spi_flash.h>
#include <symbols.h>
/* SPI flash as CBFS media. */
struct cbfs_spi_context {
struct spi_flash *spi_flash_info;
struct cbfs_simple_buffer buffer;
static struct spi_flash *spi_flash_info;
static ssize_t spi_readat(const struct region_device *rd, void *b,
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)
{
@ -49,52 +84,58 @@ static size_t cbfs_media_read(struct cbfs_media *media,
void *dest, size_t offset,
size_t count)
{
struct cbfs_spi_context *context = media->context;
const struct region_device *boot_dev;
return context->spi_flash_info->read
(context->spi_flash_info, offset, count, dest) ? 0 : count;
boot_dev = media->context;
if (rdev_readat(boot_dev, dest, offset, count) < 0)
return 0;
return count;
}
static void *cbfs_media_map(struct cbfs_media *media,
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,
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)
{
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->close = cbfs_media_close;
media->read = cbfs_media_read;
media->map = cbfs_media_map;
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
* GNU General Public License for more details.
*/
#include <boot_device.h>
#include <cbfs.h>
#include <string.h>
#include <symbols.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)
{
@ -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)
{
if (offset + count > CONFIG_ROM_SIZE)
return (void *)-1;
return (void*)(offset + 0x10000);
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 *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;
}
static size_t emu_rom_read(struct cbfs_media *media, void *dest, size_t offset,
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;
memcpy(dest, ptr, count);
emu_rom_unmap(media, ptr);
return count;
}
@ -54,10 +76,11 @@ static int emu_rom_close(struct cbfs_media *media)
return 0;
}
int init_emu_rom_cbfs_media(struct cbfs_media *media);
int init_emu_rom_cbfs_media(struct cbfs_media *media)
static 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->close = emu_rom_close;
media->map = emu_rom_map;

View File

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

View File

@ -61,11 +61,6 @@ struct tegra_spi_channel {
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);
#endif /* __NVIDIA_TEGRA124_SPI_H__ */

View File

@ -21,6 +21,7 @@
#include <arch/cache.h>
#include <arch/io.h>
#include <assert.h>
#include <boot_device.h>
#include <console/console.h>
#include <cbfs.h>
#include <delay.h>
@ -33,6 +34,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <symbols.h>
#include <timer.h>
@ -800,12 +802,6 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
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)
{
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_OUTSIZE 0x05
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
static struct spi_slave *boot_slave;
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];
unsigned int read_cmd_bytes;
int ret = count;
struct tegra_spi_channel *channel;
channel = to_tegra_spi(spi->slave->bus);
channel = to_tegra_spi(boot_slave->bus);
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[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) {
ret = -1;
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) {
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;
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
__func__, count);
@ -876,56 +873,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
tegra_spi_cbfs_read_exit:
/* de-assert /CS */
spi_release_bus(spi->slave);
return (ret < 0) ? 0 : ret;
spi_release_bus(boot_slave);
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,
size_t count)
{
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
const struct region_device *boot_dev;
void *map;
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;
}
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
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");
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,
void *buffer_address,
size_t buffer_size)
int init_default_cbfs_media(struct cbfs_media *media)
{
// 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");
context.slave = &channel->slave;
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address;
context.buffer.size = buffer_size;
media->context = (void*)&context;
boot_device_init();
media->context = (void *)boot_device_ro();
media->open = tegra_spi_cbfs_open;
media->close = tegra_spi_cbfs_close;
media->read = tegra_spi_cbfs_read;
media->map = tegra_spi_cbfs_map;
media->unmap = tegra_spi_cbfs_unmap;
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
channel->dual_mode = 1;
#endif
return 0;
}
@ -937,3 +948,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
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_asm.S
bootblock-y += cbfs.c
bootblock-y += clock.c
bootblock-y += spi.c
bootblock-y += i2c.c
@ -23,7 +22,6 @@ bootblock-$(CONFIG_DRIVERS_UART) += uart.c
endif
verstage-y += verstage.c
verstage-y += cbfs.c
verstage-y += dma.c
verstage-y += monotonic_timer.c
verstage-y += spi.c
@ -39,7 +37,6 @@ verstage-y += i2c.c
romstage-y += 32bit_reset.S
romstage-y += romstage_asm.S
romstage-y += addressmap.c
romstage-y += cbfs.c
romstage-y += cbmem.c
romstage-y += ccplex.c
romstage-y += clock.c
@ -63,7 +60,6 @@ romstage-$(CONFIG_DRIVERS_UART) += uart.c
ramstage-y += 32bit_reset.S
ramstage-y += addressmap.c
ramstage-y += cbfs.c
ramstage-y += cbmem.c
ramstage-y += cpu.c
ramstage-y += cpu_lib.S

View File

@ -62,11 +62,6 @@ struct tegra_spi_channel {
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);
#endif /* __NVIDIA_TEGRA132_SPI_H__ */

View File

@ -21,6 +21,7 @@
#include <arch/cache.h>
#include <arch/io.h>
#include <assert.h>
#include <boot_device.h>
#include <cbfs.h>
#include <console/console.h>
#include <delay.h>
@ -33,6 +34,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <symbols.h>
#include <timer.h>
@ -815,12 +817,6 @@ int spi_xfer(struct spi_slave *slave, const void *dout,
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)
{
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_OUTSIZE 0x05
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
size_t offset, size_t count)
static struct spi_slave *boot_slave;
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];
unsigned int read_cmd_bytes;
int ret = count;
struct tegra_spi_channel *channel;
channel = to_tegra_spi(spi->slave->bus);
channel = to_tegra_spi(boot_slave->bus);
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[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) {
ret = -1;
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) {
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;
printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
__func__, count);
@ -891,56 +888,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
tegra_spi_cbfs_read_exit:
/* de-assert /CS */
spi_release_bus(spi->slave);
return (ret < 0) ? 0 : ret;
spi_release_bus(boot_slave);
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,
size_t count)
{
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
const struct region_device *boot_dev;
void *map;
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;
}
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
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");
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,
void *buffer_address,
size_t buffer_size)
int init_default_cbfs_media(struct cbfs_media *media)
{
// 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");
context.slave = &channel->slave;
context.buffer.allocated = context.buffer.last_allocate = 0;
context.buffer.buffer = buffer_address;
context.buffer.size = buffer_size;
media->context = (void*)&context;
boot_device_init();
media->context = (void *)boot_device_ro();
media->open = tegra_spi_cbfs_open;
media->close = tegra_spi_cbfs_close;
media->read = tegra_spi_cbfs_read;
media->map = tegra_spi_cbfs_map;
media->unmap = tegra_spi_cbfs_unmap;
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
channel->dual_mode = 1;
#endif
return 0;
}
@ -952,3 +963,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
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 <boot_device.h>
#include <cbfs.h> /* This driver serves as a CBFS media source. */
#include <console/console.h>
#include <soc/alternate_cbfs.h>
@ -45,7 +46,7 @@
* rest of the firmware's lifetime and all subsequent stages (which will not
* 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__
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
* down to payloads.
*/
static int sdmmc_cbfs_open(struct cbfs_media *media)
static int sdmmc_cbfs_open(void)
{
#ifdef __PRE_RAM__
/*
@ -111,66 +112,109 @@ static int sdmmc_cbfs_open(struct cbfs_media *media)
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;
}
static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count)
{
ASSERT(offset + count < _cbfs_cache_size);
return _cbfs_cache + offset;
static void *exynos_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) {
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 *alternate_cbfs_unmap(struct cbfs_media *media,
const void *buffer) { return 0; }
static void *exynos_cbfs_unmap(struct cbfs_media *media,
const void *address) {
const struct region_device *boot_dev;
static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media)
{
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
boot_dev = media->context;
media->open = sdmmc_cbfs_open;
media->close = alternate_cbfs_close;
media->read = alternate_cbfs_read;
media->map = alternate_cbfs_map;
media->unmap = alternate_cbfs_unmap;
rdev_munmap(boot_dev, (void *)address);
return 0;
}
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;
return NULL;
}
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)
return initialize_exynos_usb_cbfs_media(media);
return &alternate_rdev.rdev;
switch (exynos_power->om_stat & OM_STAT_MASK) {
case OM_STAT_SDMMC:
return initialize_exynos_sdmmc_cbfs_media(media);
return &alternate_rdev.rdev;
case OM_STAT_SPI:
return initialize_exynos_spi_cbfs_media(media,
_cbfs_cache, _cbfs_cache_size);
return exynos_spi_boot_device();
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:
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
exynos_power->om_stat);
return 1;
}
}

View File

@ -20,8 +20,7 @@
#ifndef CPU_SAMSUNG_EXYNOS5250_SPI_H
#define CPU_SAMSUNG_EXYNOS5250_SPI_H
/* This driver serves as a CBFS media source. */
#include <cbfs.h>
#include <boot_device.h>
/* SPI peripheral register map; padded to 64KB */
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_close(struct exynos_spi *regs);
/* Serve as CBFS media source */
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
void *buffer_address,
size_t buffer_size);
void exynos_init_spi_boot_device(void);
const struct region_device *exynos_spi_boot_device(void);
#endif

View File

@ -20,11 +20,13 @@
#include <arch/io.h>
#include <assert.h>
#include <boot_device.h>
#include <console/console.h>
#include <soc/clk.h>
#include <soc/gpio.h>
#include <soc/spi.h>
#include <stdlib.h>
#include <symbols.h>
#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
@ -144,70 +146,47 @@ int exynos_spi_close(struct exynos_spi *regs)
return 0;
}
// SPI as CBFS media.
struct exynos_spi_media {
struct exynos_spi *regs;
struct cbfs_simple_buffer buffer;
};
static struct exynos_spi *boot_slave_regs;
static int exynos_spi_cbfs_open(struct cbfs_media *media) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
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;
static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest,
size_t offset, size_t count)
{
int bytes;
DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
bytes = exynos_spi_read(spi->regs, dest, count, offset);
// Flush and re-open the device.
exynos_spi_close(spi->regs);
exynos_spi_open(spi->regs);
exynos_spi_open(boot_slave_regs);
bytes = exynos_spi_read(boot_slave_regs, dest, count, offset);
exynos_spi_close(boot_slave_regs);
return bytes;
}
static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
static void *exynos_spi_map(const struct region_device *rdev,
size_t offset, size_t count)
{
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)
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,
const void *address) {
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_unmap\n");
return cbfs_simple_buffer_unmap(&spi->buffer, address);
static const struct region_device_ops exynos_spi_ops = {
.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)
{
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,
void *buffer_address,
size_t buffer_size) {
// 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;
const struct region_device *exynos_spi_boot_device(void)
{
return &mdev.rdev;
}

View File

@ -20,6 +20,7 @@
#include <arch/cache.h>
#include <assert.h>
#include <boot_device.h>
#include <cbfs.h> /* This driver serves as a CBFS media source. */
#include <console/console.h>
#include <soc/alternate_cbfs.h>
@ -46,7 +47,7 @@
* rest of the firmware's lifetime and all subsequent stages (which will not
* 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__
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
* down to payloads.
*/
static int sdmmc_cbfs_open(struct cbfs_media *media)
static int sdmmc_cbfs_open(void)
{
#ifdef __PRE_RAM__
/*
@ -118,66 +119,109 @@ static int sdmmc_cbfs_open(struct cbfs_media *media)
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;
}
static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count)
{
ASSERT(offset + count < _cbfs_cache_size);
return _cbfs_cache + offset;
static void *exynos_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count) {
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 *alternate_cbfs_unmap(struct cbfs_media *media,
const void *buffer) { return 0; }
static void *exynos_cbfs_unmap(struct cbfs_media *media,
const void *address) {
const struct region_device *boot_dev;
static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media)
{
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
boot_dev = media->context;
media->open = sdmmc_cbfs_open;
media->close = alternate_cbfs_close;
media->read = alternate_cbfs_read;
media->map = alternate_cbfs_map;
media->unmap = alternate_cbfs_unmap;
rdev_munmap(boot_dev, (void *)address);
return 0;
}
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;
return NULL;
}
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)
return initialize_exynos_usb_cbfs_media(media);
return &alternate_rdev.rdev;
switch (exynos_power->om_stat & OM_STAT_MASK) {
case OM_STAT_SDMMC:
return initialize_exynos_sdmmc_cbfs_media(media);
return &alternate_rdev.rdev;
case OM_STAT_SPI:
return initialize_exynos_spi_cbfs_media(media,
_cbfs_cache, _cbfs_cache_size);
return exynos_spi_boot_device();
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:
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
exynos_power->om_stat);
return 1;
}
}

View File

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

View File

@ -26,6 +26,7 @@
#include <spi_flash.h>
#include <stdlib.h>
#include <string.h>
#include <symbols.h>
#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;
}
// SPI as CBFS media.
struct exynos_spi_media {
struct spi_slave *slave;
struct cbfs_simple_buffer buffer;
};
static struct exynos_spi_slave *boot_slave;
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);
bytes = exynos_spi_read(spi->slave, dest, count, offset);
return bytes;
return exynos_spi_read(&boot_slave->slave, dest, count, offset);
}
static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset,
size_t count)
static void *exynos_spi_map(const struct region_device *rdev,
size_t offset, size_t count)
{
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
DEBUG_SPI("exynos_spi_cbfs_map\n");
// exynos: spi_rx_tx may work in 4 byte-width-transmission mode and
// requires buffer memory address to be aligned.
if (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,
const void *address)
static const struct region_device_ops exynos_spi_ops = {
.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;
DEBUG_SPI("exynos_spi_cbfs_unmap\n");
return cbfs_simple_buffer_unmap(&spi->buffer, address);
boot_slave = &exynos_spi_slaves[1];
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
}
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
void *buffer_address,
size_t buffer_size)
const struct region_device *exynos_spi_boot_device(void)
{
// TODO Replace static variable to support multiple streams.
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;
return &mdev.rdev;
}