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>
diff --git a/src/arch/riscv/rom_media.c b/src/arch/riscv/rom_media.c
index 8d3376c..f18030c 100644
--- a/src/arch/riscv/rom_media.c
+++ b/src/arch/riscv/rom_media.c
@@ -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 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;
diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc
index c7e8b62..e308be9 100644
--- a/src/arch/x86/lib/Makefile.inc
+++ b/src/arch/x86/lib/Makefile.inc
@@ -6,6 +6,7 @@
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 += 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 += 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
diff --git a/src/soc/nvidia/tegra124/cbfs.c b/src/arch/x86/lib/mmap_boot.c
similarity index 64%
rename from src/soc/nvidia/tegra124/cbfs.c
rename to src/arch/x86/lib/mmap_boot.c
index d82ca9a..eb7b23e 100644
--- a/src/soc/nvidia/tegra124/cbfs.c
+++ b/src/arch/x86/lib/mmap_boot.c
@@ -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;
}
diff --git a/src/arch/x86/lib/rom_media.c b/src/arch/x86/lib/rom_media.c
index 659e5e4..d4663c7 100644
--- a/src/arch/x86/lib/rom_media.c
+++ b/src/arch/x86/lib/rom_media.c
@@ -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 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 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 @@
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;
diff --git a/src/cpu/allwinner/a10/bootblock_media.c b/src/cpu/allwinner/a10/bootblock_media.c
index a5863b6..a585bca 100644
--- a/src/cpu/allwinner/a10/bootblock_media.c
+++ b/src/cpu/allwinner/a10/bootblock_media.c
@@ -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;
}
diff --git a/src/cpu/ti/am335x/bootblock_media.c b/src/cpu/ti/am335x/bootblock_media.c
index 9824fc3..79724ee 100644
--- a/src/cpu/ti/am335x/bootblock_media.c
+++ b/src/cpu/ti/am335x/bootblock_media.c
@@ -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 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);
+ boot_device_init();
- 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->close = dummy_close;
media->map = on_chip_memory_map;
diff --git a/src/cpu/ti/am335x/nand.c b/src/cpu/ti/am335x/nand.c
index a8c945b..dd05fb6 100644
--- a/src/cpu/ti/am335x/nand.c
+++ b/src/cpu/ti/am335x/nand.c
@@ -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;
}
diff --git a/src/include/boot_device.h b/src/include/boot_device.h
new file mode 100644
index 0000000..0848ea5
--- /dev/null
+++ b/src/include/boot_device.h
@@ -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_ */
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc
index 11562bd..adc4990 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -31,6 +31,7 @@
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 += 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 @@
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
diff --git a/src/soc/nvidia/tegra124/cbfs.c b/src/lib/boot_device.c
similarity index 61%
copy from src/soc/nvidia/tegra124/cbfs.c
copy to src/lib/boot_device.c
index d82ca9a..e0353fc 100644
--- a/src/soc/nvidia/tegra124/cbfs.c
+++ b/src/lib/boot_device.c
@@ -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,22 @@
* Foundation, Inc.
*/
+#include <boot_device.h>
-#include <cbfs.h> /* This driver serves as a CBFS media source. */
-#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,
- _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));
}
diff --git a/src/lib/cbfs_spi.c b/src/lib/cbfs_spi.c
index 6c8d78d..6758220 100644
--- a/src/lib/cbfs_spi.c
+++ b/src/lib/cbfs_spi.c
@@ -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 @@
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;
}
diff --git a/src/mainboard/emulation/qemu-armv7/media.c b/src/mainboard/emulation/qemu-armv7/media.c
index 8c71263..e0f2251 100644
--- a/src/mainboard/emulation/qemu-armv7/media.c
+++ b/src/mainboard/emulation/qemu-armv7/media.c
@@ -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 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 @@
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;
diff --git a/src/soc/nvidia/tegra124/Makefile.inc b/src/soc/nvidia/tegra124/Makefile.inc
index 78054f4..46ce59d 100644
--- a/src/soc/nvidia/tegra124/Makefile.inc
+++ b/src/soc/nvidia/tegra124/Makefile.inc
@@ -2,7 +2,6 @@
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 @@
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 += 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 += cache.c
romstage-$(CONFIG_DRIVERS_UART) += uart.c
-ramstage-y += cbfs.c
ramstage-y += cbmem.c
ramstage-y += clock.c
ramstage-y += display.c
diff --git a/src/soc/nvidia/tegra124/include/soc/spi.h b/src/soc/nvidia/tegra124/include/soc/spi.h
index ab04632..cfa3cd2 100644
--- a/src/soc/nvidia/tegra124/include/soc/spi.h
+++ b/src/soc/nvidia/tegra124/include/soc/spi.h
@@ -61,11 +61,6 @@
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__ */
diff --git a/src/soc/nvidia/tegra124/spi.c b/src/soc/nvidia/tegra124/spi.c
index 683edd1..0cf5495 100644
--- a/src/soc/nvidia/tegra124/spi.c
+++ b/src/soc/nvidia/tegra124/spi.c
@@ -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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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);
+}
diff --git a/src/soc/nvidia/tegra132/Makefile.inc b/src/soc/nvidia/tegra132/Makefile.inc
index 365dab3..c192055 100644
--- a/src/soc/nvidia/tegra132/Makefile.inc
+++ b/src/soc/nvidia/tegra132/Makefile.inc
@@ -2,7 +2,6 @@
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 @@
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 @@
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 @@
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
diff --git a/src/soc/nvidia/tegra132/cbfs.c b/src/soc/nvidia/tegra132/cbfs.c
deleted file mode 100644
index 7aeb59b..0000000
--- a/src/soc/nvidia/tegra132/cbfs.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2014 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.
- */
-
-#include <cbfs.h> /* This driver serves as a CBFS media source. */
-#include <soc/spi.h>
-#include <symbols.h>
-
-int init_default_cbfs_media(struct cbfs_media *media)
-{
- return initialize_tegra_spi_cbfs_media(media,
- _cbfs_cache, _cbfs_cache_size);
-}
diff --git a/src/soc/nvidia/tegra132/include/soc/spi.h b/src/soc/nvidia/tegra132/include/soc/spi.h
index 2fd9562..4c91c27 100644
--- a/src/soc/nvidia/tegra132/include/soc/spi.h
+++ b/src/soc/nvidia/tegra132/include/soc/spi.h
@@ -62,11 +62,6 @@
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__ */
diff --git a/src/soc/nvidia/tegra132/spi.c b/src/soc/nvidia/tegra132/spi.c
index 7ca66e1..1650057 100644
--- a/src/soc/nvidia/tegra132/spi.c
+++ b/src/soc/nvidia/tegra132/spi.c
@@ -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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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);
+}
diff --git a/src/soc/samsung/exynos5250/alternate_cbfs.c b/src/soc/samsung/exynos5250/alternate_cbfs.c
index 2e2aeec..546018a 100644
--- a/src/soc/samsung/exynos5250/alternate_cbfs.c
+++ b/src/soc/samsung/exynos5250/alternate_cbfs.c
@@ -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 @@
* 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 @@
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 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);
+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;
+
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 1;
+ 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);
}
}
diff --git a/src/soc/samsung/exynos5250/include/soc/spi.h b/src/soc/samsung/exynos5250/include/soc/spi.h
index 92236ae..298db1a 100644
--- a/src/soc/samsung/exynos5250/include/soc/spi.h
+++ b/src/soc/samsung/exynos5250/include/soc/spi.h
@@ -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_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
diff --git a/src/soc/samsung/exynos5250/spi.c b/src/soc/samsung/exynos5250/spi.c
index 4f32487..adf31e4 100644
--- a/src/soc/samsung/exynos5250/spi.c
+++ b/src/soc/samsung/exynos5250/spi.c
@@ -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 @@
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;
}
diff --git a/src/soc/samsung/exynos5420/alternate_cbfs.c b/src/soc/samsung/exynos5420/alternate_cbfs.c
index b30ed6b..9bba748 100644
--- a/src/soc/samsung/exynos5420/alternate_cbfs.c
+++ b/src/soc/samsung/exynos5420/alternate_cbfs.c
@@ -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 @@
* 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 @@
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 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);
+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;
+
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 1;
+ 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);
}
}
diff --git a/src/soc/samsung/exynos5420/include/soc/spi.h b/src/soc/samsung/exynos5420/include/soc/spi.h
index cf77800..77d5ffc 100644
--- a/src/soc/samsung/exynos5420/include/soc/spi.h
+++ b/src/soc/samsung/exynos5420/include/soc/spi.h
@@ -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 @@
#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
diff --git a/src/soc/samsung/exynos5420/spi.c b/src/soc/samsung/exynos5420/spi.c
index 5f29803..2edc337 100644
--- a/src/soc/samsung/exynos5420/spi.c
+++ b/src/soc/samsung/exynos5420/spi.c
@@ -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 @@
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;
}