[coreboot-gerrit] Patch set updated for coreboot: 9411ae8 coreboot: introduce boot_device

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Mon May 18 22:20:10 CEST 2015


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10216

-gerrit

commit 9411ae897befe8ea76158d637c865692c6bb8855
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Fri May 15 13:15:34 2015 -0500

    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 at chromium.org>
---
 src/arch/riscv/rom_media.c                   |  66 +++++++--------
 src/arch/x86/lib/Makefile.inc                |   3 +
 src/arch/x86/lib/mmap_boot.c                 |  31 +++++++
 src/arch/x86/lib/rom_media.c                 |  57 ++++++-------
 src/cpu/allwinner/a10/bootblock_media.c      |   8 +-
 src/cpu/ti/am335x/bootblock_media.c          |  47 ++++++++---
 src/cpu/ti/am335x/nand.c                     |  10 ++-
 src/include/boot_device.h                    |  41 ++++++++++
 src/lib/Makefile.inc                         |   6 ++
 src/lib/boot_device.c                        |  38 +++++++++
 src/lib/cbfs_spi.c                           |  97 +++++++++++++++-------
 src/mainboard/emulation/qemu-armv7/media.c   |  45 +++++++---
 src/soc/nvidia/tegra124/Makefile.inc         |   4 -
 src/soc/nvidia/tegra124/cbfs.c               |  29 -------
 src/soc/nvidia/tegra124/include/soc/spi.h    |   5 --
 src/soc/nvidia/tegra124/spi.c                | 116 +++++++++++++++++---------
 src/soc/nvidia/tegra132/Makefile.inc         |   4 -
 src/soc/nvidia/tegra132/cbfs.c               |  28 -------
 src/soc/nvidia/tegra132/include/soc/spi.h    |   5 --
 src/soc/nvidia/tegra132/spi.c                | 116 +++++++++++++++++---------
 src/soc/samsung/exynos5250/alternate_cbfs.c  | 118 ++++++++++++++++++---------
 src/soc/samsung/exynos5250/include/soc/spi.h |   9 +-
 src/soc/samsung/exynos5250/spi.c             |  85 ++++++++-----------
 src/soc/samsung/exynos5420/alternate_cbfs.c  | 118 ++++++++++++++++++---------
 src/soc/samsung/exynos5420/include/soc/spi.h |   9 +-
 src/soc/samsung/exynos5420/spi.c             |  78 ++++++------------
 26 files changed, 713 insertions(+), 460 deletions(-)

diff --git a/src/arch/riscv/rom_media.c b/src/arch/riscv/rom_media.c
index e00e0fb..484f1ee 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
@@ -18,40 +18,59 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  * MA 02110-1301 USA
  */
+#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);
+	boot_dev = media->context;
+
+	ptr = rdev_mmap(boot_dev, offset, count);
+
+	if (ptr == NULL)
+		return (void *)-1;
 
-	ptr = (void*)offset;
 	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;
 }
 
@@ -60,25 +79,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;
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 += 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
diff --git a/src/arch/x86/lib/mmap_boot.c b/src/arch/x86/lib/mmap_boot.c
new file mode 100644
index 0000000..eb7b23e
--- /dev/null
+++ b/src/arch/x86/lib/mmap_boot.c
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#include <boot_device.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))
+
+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 &boot_dev.rdev;
+}
diff --git a/src/arch/x86/lib/rom_media.c b/src/arch/x86/lib/rom_media.c
index ed2122c..c2c4721 100644
--- a/src/arch/x86/lib/rom_media.c
+++ b/src/arch/x86/lib/rom_media.c
@@ -18,6 +18,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
  * MA 02110-1301 USA
  */
+
+#include <boot_device.h>
 #include <cbfs.h>
 #include <string.h>
 
@@ -37,14 +39,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;
 }
 
@@ -54,7 +61,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;
@@ -64,30 +77,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;
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 at 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 93a2d18..702d91a 100644
--- a/src/cpu/ti/am335x/bootblock_media.c
+++ b/src/cpu/ti/am335x/bootblock_media.c
@@ -17,11 +17,21 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#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;
diff --git a/src/cpu/ti/am335x/nand.c b/src/cpu/ti/am335x/nand.c
index ddab389..7e67e97 100644
--- a/src/cpu/ti/am335x/nand.c
+++ b/src/cpu/ti/am335x/nand.c
@@ -17,10 +17,16 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#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 88254b9..11725c4 100644
--- a/src/lib/Makefile.inc
+++ b/src/lib/Makefile.inc
@@ -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
 
diff --git a/src/lib/boot_device.c b/src/lib/boot_device.c
new file mode 100644
index 0000000..e0353fc
--- /dev/null
+++ b/src/lib/boot_device.c
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include <boot_device.h>
+
+void __attribute__((weak)) boot_device_init(void)
+{
+	/* 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 81e6ec3..6637cdc 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 @@ 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;
+
+	boot_dev = media->context;
+
+	ptr = rdev_mmap(boot_dev, offset, count);
 
-	return cbfs_simple_buffer_map(&context->buffer, media, 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;
+
+	boot_dev = media->context;
+
+	rdev_munmap(boot_dev, (void *)address);
 
-	return cbfs_simple_buffer_unmap(&context->buffer, address);
+	return NULL;
 }
 
-static int init_cbfs_media_context(void)
+int init_default_cbfs_media(struct cbfs_media *media)
 {
-	if (!spi_context.spi_flash_info) {
-
-		spi_context.spi_flash_info = spi_flash_probe
-			(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
+	boot_device_init();
 
-		if (!spi_context.spi_flash_info)
-			return -1;
+	media->context = (void *)boot_device_ro();
 
-		spi_context.buffer.buffer = (void *)_cbfs_cache;
-		spi_context.buffer.size = _cbfs_cache_size;
-	}
-	return 0;
+	if (media->context == NULL)
+		return -1;
 
-}
-int init_default_cbfs_media(struct cbfs_media *media)
-{
-	media->context = &spi_context;
 	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 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;
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 @@ 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
diff --git a/src/soc/nvidia/tegra124/cbfs.c b/src/soc/nvidia/tegra124/cbfs.c
deleted file mode 100644
index 33a7258..0000000
--- a/src/soc/nvidia/tegra124/cbfs.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2013 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-#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/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 @@ 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__ */
diff --git a/src/soc/nvidia/tegra124/spi.c b/src/soc/nvidia/tegra124/spi.c
index e1d022a..6fbb3c4 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 @@ 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);
-}
 
-int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
-				     void *buffer_address,
-				     size_t buffer_size)
-{
-	// TODO Replace static variable to support multiple streams.
-	static struct tegra_spi_media context;
-	static struct tegra_spi_channel *channel;
+	boot_dev = media->context;
 
-	channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
-	channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
+	rdev_munmap(boot_dev, (void *)address);
 
+	return NULL;
+}
+
+int init_default_cbfs_media(struct cbfs_media *media)
+{
 	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);
+}
diff --git a/src/soc/nvidia/tegra132/Makefile.inc b/src/soc/nvidia/tegra132/Makefile.inc
index 44976d1..e8c8d83 100644
--- a/src/soc/nvidia/tegra132/Makefile.inc
+++ b/src/soc/nvidia/tegra132/Makefile.inc
@@ -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
diff --git a/src/soc/nvidia/tegra132/cbfs.c b/src/soc/nvidia/tegra132/cbfs.c
deleted file mode 100644
index 2efd48b..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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#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 @@ 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__ */
diff --git a/src/soc/nvidia/tegra132/spi.c b/src/soc/nvidia/tegra132/spi.c
index 6d9fa1f..746e96e 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 @@ 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);
-}
 
-int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
-				     void *buffer_address,
-				     size_t buffer_size)
-{
-	// TODO Replace static variable to support multiple streams.
-	static struct tegra_spi_media context;
-	static struct tegra_spi_channel *channel;
+	boot_dev = media->context;
 
-	channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
-	channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
+	rdev_munmap(boot_dev, (void *)address);
 
+	return NULL;
+}
+
+int init_default_cbfs_media(struct cbfs_media *media)
+{
 	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);
+}
diff --git a/src/soc/samsung/exynos5250/alternate_cbfs.c b/src/soc/samsung/exynos5250/alternate_cbfs.c
index 9f873bf..d6aa6e6 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 @@ 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;
+	return NULL;
 }
 
-static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
+int init_default_cbfs_media(struct cbfs_media *media)
 {
-	printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
+	boot_device_init();
 
-	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;
+	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;
 }
 
-int init_default_cbfs_media(struct cbfs_media *media)
+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 &alternate_rdev.rdev;
+	case OM_STAT_SPI:
+		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:
-		return initialize_exynos_sdmmc_cbfs_media(media);
+		printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
+		sdmmc_cbfs_open();
+		break;
 	case OM_STAT_SPI:
-		return initialize_exynos_spi_cbfs_media(media,
-			_cbfs_cache, _cbfs_cache_size);
+		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;
 	}
 }
diff --git a/src/soc/samsung/exynos5250/include/soc/spi.h b/src/soc/samsung/exynos5250/include/soc/spi.h
index 4301d42..95045b5 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_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
diff --git a/src/soc/samsung/exynos5250/spi.c b/src/soc/samsung/exynos5250/spi.c
index fed3aa7..5cef916 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 @@ 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 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 struct exynos_spi *boot_slave_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,
+};
 
-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;
+static struct mmap_helper_region_device mdev =
+	MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE);
 
-	return 0;
+void exynos_init_spi_boot_device(void)
+{
+	boot_slave_regs = (void *)EXYNOS5_SPI1_BASE;
+
+	mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
+}
+
+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 45489f1..9e1d323 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 @@ 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;
+	return NULL;
 }
 
-static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
+int init_default_cbfs_media(struct cbfs_media *media)
 {
-	printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
+	boot_device_init();
 
-	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;
+	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;
 }
 
-int init_default_cbfs_media(struct cbfs_media *media)
+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 &alternate_rdev.rdev;
+	case OM_STAT_SPI:
+		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:
-		return initialize_exynos_sdmmc_cbfs_media(media);
+		printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
+		sdmmc_cbfs_open();
+		break;
 	case OM_STAT_SPI:
-		return initialize_exynos_spi_cbfs_media(media,
-			_cbfs_cache, _cbfs_cache_size);
+		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;
 	}
 }
diff --git a/src/soc/samsung/exynos5420/include/soc/spi.h b/src/soc/samsung/exynos5420/include/soc/spi.h
index 78cca6f..17e6083 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 @@ 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
diff --git a/src/soc/samsung/exynos5420/spi.c b/src/soc/samsung/exynos5420/spi.c
index 3d71f79..056dfe2 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 @@ 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 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 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 struct exynos_spi_slave *boot_slave;
 
-static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
-				   size_t offset, size_t count)
+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;
-	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;
 }



More information about the coreboot-gerrit mailing list