summaryrefslogtreecommitdiff
path: root/src/soc/samsung/exynos5250
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2015-05-15 13:15:34 -0500
committerAaron Durbin <adurbin@chromium.org>2015-05-26 22:32:47 +0200
commitc6588c5af94e568bddd8111c3fca736f464042cf (patch)
tree0efa16d6948cfde369932fd18dec46102f807c2f /src/soc/samsung/exynos5250
parentdef0fb57dfd91e6599c622a7b2769164a5c02ef0 (diff)
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>
Diffstat (limited to 'src/soc/samsung/exynos5250')
-rw-r--r--src/soc/samsung/exynos5250/alternate_cbfs.c118
-rw-r--r--src/soc/samsung/exynos5250/include/soc/spi.h9
-rw-r--r--src/soc/samsung/exynos5250/spi.c85
3 files changed, 116 insertions, 96 deletions
diff --git a/src/soc/samsung/exynos5250/alternate_cbfs.c b/src/soc/samsung/exynos5250/alternate_cbfs.c
index 2e2aeec562..546018a35a 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 92236aecba..298db1a851 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 4f32487623..adf31e4e78 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;
}