coreboot: introduce boot_device
The boot_device is a region_device that represents the device from which coreboot retrieves and boots its stages. The existing cbfs implementations use the boot_device as the intermediary for accessing the CBFS region. Also, there's currently only support for a read-only view of the boot_device. i.e. one cannot write to the boot_device using this view. However, a writable boot_device could be added in the future. Change-Id: Ic0da796ab161b8025c90631be3423ba6473ad31c Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/10216 Tested-by: build bot (Jenkins) Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com> Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
parent
def0fb57df
commit
c6588c5af9
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
|
@ -17,40 +17,59 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc.
|
||||
*/
|
||||
#include <boot_device.h>
|
||||
#include <cbfs.h>
|
||||
#include <console/console.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef LIBPAYLOAD
|
||||
# define printk(x...)
|
||||
# define init_default_cbfs_media libpayload_init_default_cbfs_media
|
||||
extern int libpayload_init_default_cbfs_media(struct cbfs_media *media);
|
||||
#else
|
||||
# include <console/console.h>
|
||||
#endif
|
||||
/* This assumes that the CBFS resides at 0x0, which is true for the default
|
||||
* configuration. */
|
||||
static const struct mem_region_device gboot_dev =
|
||||
MEM_REGION_DEV_INIT(NULL, CONFIG_ROM_SIZE);
|
||||
|
||||
// Implementation of memory-mapped ROM media source on X86.
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
return &gboot_dev.rdev;
|
||||
}
|
||||
|
||||
static int rom_media_open(struct cbfs_media *media) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *rom_media_map(struct cbfs_media *media, size_t offset, size_t count) {
|
||||
const struct region_device *boot_dev;
|
||||
void *ptr;
|
||||
printk(BIOS_INFO, "%s: media %p, offset %lx, size %ld.\n", __func__, media, offset, count);
|
||||
|
||||
ptr = (void*)offset;
|
||||
printk(BIOS_INFO, "%s: media %p, offset %lx, size %ld.\n", __func__, media, offset, count);
|
||||
boot_dev = media->context;
|
||||
|
||||
ptr = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (ptr == NULL)
|
||||
return (void *)-1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *rom_media_unmap(struct cbfs_media *media, const void *address) {
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t rom_media_read(struct cbfs_media *media, void *dest, size_t offset,
|
||||
size_t count) {
|
||||
void *ptr = rom_media_map(media, offset, count);
|
||||
memcpy(dest, ptr, count);
|
||||
rom_media_unmap(media, ptr);
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -59,25 +78,8 @@ static int rom_media_close(struct cbfs_media *media) {
|
|||
}
|
||||
|
||||
static int init_rom_media_cbfs(struct cbfs_media *media) {
|
||||
/* this assumes that the CBFS resides at 0x0,
|
||||
* which is true for the default configuration
|
||||
*/
|
||||
int32_t *cbfs_header_ptr = (int32_t*)(uintptr_t)(CONFIG_CBFS_SIZE - 4);
|
||||
uint64_t cbfs_header_offset = CONFIG_CBFS_SIZE + *cbfs_header_ptr;
|
||||
struct cbfs_header *header = (struct cbfs_header*) cbfs_header_offset;
|
||||
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
|
||||
printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
|
||||
printk(BIOS_ERR, "Expected %08lx and got %08lx\n", (unsigned long) CBFS_HEADER_MAGIC, (unsigned long) ntohl(header->magic));
|
||||
return -1;
|
||||
} else {
|
||||
uint32_t romsize = ntohl(header->romsize);
|
||||
media->context = (void*)(uintptr_t)romsize;
|
||||
#if defined(CONFIG_ROM_SIZE)
|
||||
if (CONFIG_ROM_SIZE != romsize)
|
||||
printk(BIOS_INFO, "Warning: rom size unmatch (%d/%d)\n",
|
||||
CONFIG_ROM_SIZE, romsize);
|
||||
#endif
|
||||
}
|
||||
boot_device_init();
|
||||
media->context = (void *)boot_device_ro();
|
||||
media->open = rom_media_open;
|
||||
media->close = rom_media_close;
|
||||
media->map = rom_media_map;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -17,6 +17,8 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <boot_device.h>
|
||||
#include <cbfs.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -36,14 +38,19 @@ static int x86_rom_open(struct cbfs_media *media) {
|
|||
|
||||
static void *x86_rom_map(struct cbfs_media *media, size_t offset, size_t count) {
|
||||
void *ptr;
|
||||
// Some address (ex, pointer to master header) may be given in memory
|
||||
// mapped location. To workaround that, we handle >0xf0000000 as real
|
||||
// memory pointer.
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
/* Extremely large offsets are considered relative to end of region. */
|
||||
if ((uint32_t)offset > (uint32_t)0xf0000000)
|
||||
ptr = (void*)offset;
|
||||
else
|
||||
ptr = (void*)(0 - (uint32_t)media->context + offset);
|
||||
offset += region_device_sz(boot_dev);
|
||||
|
||||
ptr = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (ptr == NULL)
|
||||
return (void *)-1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
@ -53,7 +60,13 @@ static void *x86_rom_unmap(struct cbfs_media *media, const void *address) {
|
|||
|
||||
static size_t x86_rom_read(struct cbfs_media *media, void *dest, size_t offset,
|
||||
size_t count) {
|
||||
void *ptr = x86_rom_map(media, offset, count);
|
||||
void *ptr;
|
||||
|
||||
ptr = x86_rom_map(media, offset, count);
|
||||
|
||||
if (ptr == (void *)-1)
|
||||
return 0;
|
||||
|
||||
memcpy(dest, ptr, count);
|
||||
x86_rom_unmap(media, ptr);
|
||||
return count;
|
||||
|
@ -63,30 +76,14 @@ static int x86_rom_close(struct cbfs_media *media) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init_x86rom_cbfs_media(struct cbfs_media *media);
|
||||
int init_x86rom_cbfs_media(struct cbfs_media *media) {
|
||||
// On X86, we always keep a reference of pointer to CBFS header in
|
||||
// 0xfffffffc, and the pointer is still a memory-mapped address.
|
||||
// Since the CBFS core always use ROM offset, we need to figure out
|
||||
// header->romsize even before media is initialized.
|
||||
struct cbfs_header *header = (struct cbfs_header*)
|
||||
*(uint32_t*)(0xfffffffc);
|
||||
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
|
||||
#if defined(CONFIG_ROM_SIZE)
|
||||
printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
|
||||
media->context = (void*)CONFIG_ROM_SIZE;
|
||||
#else
|
||||
static int init_x86rom_cbfs_media(struct cbfs_media *media) {
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
|
||||
if (media->context == NULL)
|
||||
return -1;
|
||||
#endif
|
||||
} else {
|
||||
uint32_t romsize = ntohl(header->romsize);
|
||||
media->context = (void*)romsize;
|
||||
#if defined(CONFIG_ROM_SIZE)
|
||||
if (CONFIG_ROM_SIZE != romsize)
|
||||
printk(BIOS_INFO, "Warning: rom size unmatch (%d/%d)\n",
|
||||
CONFIG_ROM_SIZE, romsize);
|
||||
#endif
|
||||
}
|
||||
|
||||
media->open = x86_rom_open;
|
||||
media->close = x86_rom_close;
|
||||
media->map = x86_rom_map;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,21 @@
|
|||
* Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <boot_device.h>
|
||||
#include <cbfs.h>
|
||||
#include <console/console.h>
|
||||
#include <string.h>
|
||||
#include <symbols.h>
|
||||
|
||||
/* FIXME: No idea how big the internal SRAM actually is. */
|
||||
static const struct mem_region_device gboot_dev =
|
||||
MEM_REGION_DEV_INIT(_dram, CONFIG_ROM_SIZE);
|
||||
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
return &gboot_dev.rdev;
|
||||
}
|
||||
|
||||
static int dummy_open(struct cbfs_media *media)
|
||||
{
|
||||
return 0;
|
||||
|
@ -35,33 +45,48 @@ static int dummy_close(struct cbfs_media *media)
|
|||
static void * on_chip_memory_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count)
|
||||
{
|
||||
return _dram + offset;
|
||||
const struct region_device *boot_dev;
|
||||
void *ptr;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
ptr = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (ptr == NULL)
|
||||
return (void *)-1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void * dummy_unmap(struct cbfs_media *media, const void *address)
|
||||
{
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t on_chip_memory_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
void *ptr = media->map(media, offset, count);
|
||||
memcpy(dest, ptr, count);
|
||||
media->unmap(media, ptr);
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
struct cbfs_header *header =
|
||||
(struct cbfs_header *)(_dram + CONFIG_CBFS_HEADER_ROM_OFFSET);
|
||||
|
||||
if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
|
||||
printk(BIOS_ERR, "Invalid CBFS master header at %p\n", header);
|
||||
return -1;
|
||||
}
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
media->open = dummy_open;
|
||||
media->close = dummy_close;
|
||||
media->map = on_chip_memory_map;
|
||||
|
|
|
@ -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;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2014 Google Inc.
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,12 +17,22 @@
|
|||
* Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <cbfs.h> /* This driver serves as a CBFS media source. */
|
||||
#include <soc/spi.h>
|
||||
#include <symbols.h>
|
||||
#include <boot_device.h>
|
||||
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
void __attribute__((weak)) boot_device_init(void)
|
||||
{
|
||||
return initialize_tegra_spi_cbfs_media(media,
|
||||
_cbfs_cache, _cbfs_cache_size);
|
||||
/* Provide weak do-nothing init. */
|
||||
}
|
||||
|
||||
int boot_device_ro_subregion(const struct region *sub,
|
||||
struct region_device *subrd)
|
||||
{
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = boot_device_ro();
|
||||
|
||||
if (boot_dev == NULL)
|
||||
return -1;
|
||||
|
||||
return rdev_chain(subrd, boot_dev, region_offset(sub), region_sz(sub));
|
||||
}
|
|
@ -23,17 +23,52 @@
|
|||
* SPI.
|
||||
*/
|
||||
|
||||
#include <boot_device.h>
|
||||
#include <cbfs.h>
|
||||
#include <region.h>
|
||||
#include <spi_flash.h>
|
||||
#include <symbols.h>
|
||||
|
||||
/* SPI flash as CBFS media. */
|
||||
struct cbfs_spi_context {
|
||||
struct spi_flash *spi_flash_info;
|
||||
struct cbfs_simple_buffer buffer;
|
||||
static struct spi_flash *spi_flash_info;
|
||||
|
||||
static ssize_t spi_readat(const struct region_device *rd, void *b,
|
||||
size_t offset, size_t size)
|
||||
{
|
||||
if (spi_flash_info->read(spi_flash_info, offset, size, b))
|
||||
return -1;
|
||||
return size;
|
||||
}
|
||||
|
||||
static const struct region_device_ops spi_ops = {
|
||||
.mmap = mmap_helper_rdev_mmap,
|
||||
.munmap = mmap_helper_rdev_munmap,
|
||||
.readat = spi_readat,
|
||||
};
|
||||
|
||||
static struct cbfs_spi_context spi_context;
|
||||
static struct mmap_helper_region_device mdev =
|
||||
MMAP_HELPER_REGION_INIT(&spi_ops, 0, CONFIG_ROM_SIZE);
|
||||
|
||||
void boot_device_init(void)
|
||||
{
|
||||
int bus = CONFIG_BOOT_MEDIA_SPI_BUS;
|
||||
int cs = 0;
|
||||
|
||||
if (spi_flash_info != NULL)
|
||||
return;
|
||||
|
||||
spi_flash_info = spi_flash_probe(bus, cs);
|
||||
|
||||
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
|
||||
}
|
||||
|
||||
/* Return the CBFS boot device. */
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
if (spi_flash_info == NULL)
|
||||
return NULL;
|
||||
|
||||
return &mdev.rdev;
|
||||
}
|
||||
|
||||
static int cbfs_media_open(struct cbfs_media *media)
|
||||
{
|
||||
|
@ -49,52 +84,58 @@ static size_t cbfs_media_read(struct cbfs_media *media,
|
|||
void *dest, size_t offset,
|
||||
size_t count)
|
||||
{
|
||||
struct cbfs_spi_context *context = media->context;
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
return context->spi_flash_info->read
|
||||
(context->spi_flash_info, offset, count, dest) ? 0 : count;
|
||||
boot_dev = media->context;
|
||||
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void *cbfs_media_map(struct cbfs_media *media,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
struct cbfs_spi_context *context = media->context;
|
||||
const struct region_device *boot_dev;
|
||||
void *ptr;
|
||||
|
||||
return cbfs_simple_buffer_map(&context->buffer, media, offset, count);
|
||||
boot_dev = media->context;
|
||||
|
||||
ptr = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (ptr == NULL)
|
||||
return (void *)-1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *cbfs_media_unmap(struct cbfs_media *media,
|
||||
const void *address)
|
||||
{
|
||||
struct cbfs_spi_context *context = media->context;
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
return cbfs_simple_buffer_unmap(&context->buffer, address);
|
||||
boot_dev = media->context;
|
||||
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int init_cbfs_media_context(void)
|
||||
{
|
||||
if (!spi_context.spi_flash_info) {
|
||||
|
||||
spi_context.spi_flash_info = spi_flash_probe
|
||||
(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
|
||||
|
||||
if (!spi_context.spi_flash_info)
|
||||
return -1;
|
||||
|
||||
spi_context.buffer.buffer = (void *)_cbfs_cache;
|
||||
spi_context.buffer.size = _cbfs_cache_size;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
media->context = &spi_context;
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
|
||||
if (media->context == NULL)
|
||||
return -1;
|
||||
|
||||
media->open = cbfs_media_open;
|
||||
media->close = cbfs_media_close;
|
||||
media->read = cbfs_media_read;
|
||||
media->map = cbfs_media_map;
|
||||
media->unmap = cbfs_media_unmap;
|
||||
|
||||
return init_cbfs_media_context();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
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 (void*)(offset + 0x10000);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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,
|
||||
static struct spi_slave *boot_slave;
|
||||
|
||||
static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context;
|
||||
u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
|
||||
unsigned int read_cmd_bytes;
|
||||
int ret = count;
|
||||
struct tegra_spi_channel *channel;
|
||||
|
||||
channel = to_tegra_spi(spi->slave->bus);
|
||||
channel = to_tegra_spi(boot_slave->bus);
|
||||
|
||||
if (channel->dual_mode) {
|
||||
/*
|
||||
|
@ -853,9 +850,9 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
spi_read_cmd[2] = (offset >> 8) & 0xff;
|
||||
spi_read_cmd[3] = offset & 0xff;
|
||||
|
||||
spi_claim_bus(spi->slave);
|
||||
spi_claim_bus(boot_slave);
|
||||
|
||||
if (spi_xfer(spi->slave, spi_read_cmd,
|
||||
if (spi_xfer(boot_slave, spi_read_cmd,
|
||||
read_cmd_bytes, NULL, 0) < 0) {
|
||||
ret = -1;
|
||||
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
|
||||
|
@ -866,7 +863,7 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
if (channel->dual_mode) {
|
||||
setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
|
||||
}
|
||||
if (spi_xfer(spi->slave, NULL, 0, dest, count)) {
|
||||
if (spi_xfer(boot_slave, NULL, 0, dest, count)) {
|
||||
ret = -1;
|
||||
printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n",
|
||||
__func__, count);
|
||||
|
@ -876,56 +873,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
|
||||
tegra_spi_cbfs_read_exit:
|
||||
/* de-assert /CS */
|
||||
spi_release_bus(spi->slave);
|
||||
return (ret < 0) ? 0 : ret;
|
||||
spi_release_bus(boot_slave);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
printk(BIOS_ERR, "%s: reading %zx bytes from %zx\n",
|
||||
__func__, count, offset);
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count)
|
||||
{
|
||||
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
|
||||
const struct region_device *boot_dev;
|
||||
void *map;
|
||||
|
||||
DEBUG_SPI("tegra_spi_cbfs_map\n");
|
||||
map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
map = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (map == NULL)
|
||||
map = (void *)-1;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *address)
|
||||
{
|
||||
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
DEBUG_SPI("tegra_spi_cbfs_unmap\n");
|
||||
return cbfs_simple_buffer_unmap(&spi->buffer, address);
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
|
||||
void *buffer_address,
|
||||
size_t buffer_size)
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
// TODO Replace static variable to support multiple streams.
|
||||
static struct tegra_spi_media context;
|
||||
static struct tegra_spi_channel *channel;
|
||||
|
||||
channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
|
||||
channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
|
||||
|
||||
DEBUG_SPI("Initializing CBFS media on SPI\n");
|
||||
|
||||
context.slave = &channel->slave;
|
||||
context.buffer.allocated = context.buffer.last_allocate = 0;
|
||||
context.buffer.buffer = buffer_address;
|
||||
context.buffer.size = buffer_size;
|
||||
media->context = (void*)&context;
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
media->open = tegra_spi_cbfs_open;
|
||||
media->close = tegra_spi_cbfs_close;
|
||||
media->read = tegra_spi_cbfs_read;
|
||||
media->map = tegra_spi_cbfs_map;
|
||||
media->unmap = tegra_spi_cbfs_unmap;
|
||||
|
||||
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
|
||||
channel->dual_mode = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -937,3 +948,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
|
|||
|
||||
return &channel->slave;
|
||||
}
|
||||
|
||||
static const struct region_device_ops tegra_spi_ops = {
|
||||
.mmap = mmap_helper_rdev_mmap,
|
||||
.munmap = mmap_helper_rdev_munmap,
|
||||
.readat = tegra_spi_readat,
|
||||
};
|
||||
|
||||
static struct mmap_helper_region_device mdev =
|
||||
MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE);
|
||||
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
return &mdev.rdev;
|
||||
}
|
||||
|
||||
void boot_device_init(void)
|
||||
{
|
||||
struct tegra_spi_channel *boot_chan;
|
||||
|
||||
boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
|
||||
boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
|
||||
|
||||
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
|
||||
boot_chan->dual_mode = 1;
|
||||
#endif
|
||||
boot_slave = &boot_chan->slave;
|
||||
|
||||
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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,
|
||||
static struct spi_slave *boot_slave;
|
||||
|
||||
static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context;
|
||||
u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
|
||||
unsigned int read_cmd_bytes;
|
||||
int ret = count;
|
||||
struct tegra_spi_channel *channel;
|
||||
|
||||
channel = to_tegra_spi(spi->slave->bus);
|
||||
channel = to_tegra_spi(boot_slave->bus);
|
||||
|
||||
if (channel->dual_mode) {
|
||||
/*
|
||||
|
@ -868,9 +865,9 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
spi_read_cmd[2] = (offset >> 8) & 0xff;
|
||||
spi_read_cmd[3] = offset & 0xff;
|
||||
|
||||
spi_claim_bus(spi->slave);
|
||||
spi_claim_bus(boot_slave);
|
||||
|
||||
if (spi_xfer(spi->slave, spi_read_cmd,
|
||||
if (spi_xfer(boot_slave, spi_read_cmd,
|
||||
read_cmd_bytes, NULL, 0) < 0) {
|
||||
ret = -1;
|
||||
printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
|
||||
|
@ -881,7 +878,7 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
if (channel->dual_mode) {
|
||||
setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
|
||||
}
|
||||
if (spi_xfer(spi->slave, NULL, 0, dest, count)) {
|
||||
if (spi_xfer(boot_slave, NULL, 0, dest, count)) {
|
||||
ret = -1;
|
||||
printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
|
||||
__func__, count);
|
||||
|
@ -891,56 +888,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
|||
|
||||
tegra_spi_cbfs_read_exit:
|
||||
/* de-assert /CS */
|
||||
spi_release_bus(spi->slave);
|
||||
return (ret < 0) ? 0 : ret;
|
||||
spi_release_bus(boot_slave);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
DEBUG_SPI("%s: reading %zx bytes from %zx\n", __func__, count, offset);
|
||||
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count)
|
||||
{
|
||||
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
|
||||
const struct region_device *boot_dev;
|
||||
void *map;
|
||||
|
||||
DEBUG_SPI("tegra_spi_cbfs_map\n");
|
||||
map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
map = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (map == NULL)
|
||||
map = (void *)-1;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static void *tegra_spi_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *address)
|
||||
{
|
||||
struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context;
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
DEBUG_SPI("tegra_spi_cbfs_unmap\n");
|
||||
return cbfs_simple_buffer_unmap(&spi->buffer, address);
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int initialize_tegra_spi_cbfs_media(struct cbfs_media *media,
|
||||
void *buffer_address,
|
||||
size_t buffer_size)
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
// TODO Replace static variable to support multiple streams.
|
||||
static struct tegra_spi_media context;
|
||||
static struct tegra_spi_channel *channel;
|
||||
|
||||
channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
|
||||
channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
|
||||
|
||||
DEBUG_SPI("Initializing CBFS media on SPI\n");
|
||||
|
||||
context.slave = &channel->slave;
|
||||
context.buffer.allocated = context.buffer.last_allocate = 0;
|
||||
context.buffer.buffer = buffer_address;
|
||||
context.buffer.size = buffer_size;
|
||||
media->context = (void*)&context;
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
media->open = tegra_spi_cbfs_open;
|
||||
media->close = tegra_spi_cbfs_close;
|
||||
media->read = tegra_spi_cbfs_read;
|
||||
media->map = tegra_spi_cbfs_map;
|
||||
media->unmap = tegra_spi_cbfs_unmap;
|
||||
|
||||
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
|
||||
channel->dual_mode = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -952,3 +963,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
|
|||
|
||||
return &channel->slave;
|
||||
}
|
||||
|
||||
static const struct region_device_ops tegra_spi_ops = {
|
||||
.mmap = mmap_helper_rdev_mmap,
|
||||
.munmap = mmap_helper_rdev_munmap,
|
||||
.readat = tegra_spi_readat,
|
||||
};
|
||||
|
||||
static struct mmap_helper_region_device mdev =
|
||||
MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE);
|
||||
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
return &mdev.rdev;
|
||||
}
|
||||
|
||||
void boot_device_init(void)
|
||||
{
|
||||
struct tegra_spi_channel *boot_chan;
|
||||
|
||||
boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
|
||||
boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
|
||||
|
||||
#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
|
||||
boot_chan->dual_mode = 1;
|
||||
#endif
|
||||
boot_slave = &boot_chan->slave;
|
||||
|
||||
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
|
||||
#include <assert.h>
|
||||
#include <boot_device.h>
|
||||
#include <cbfs.h> /* This driver serves as a CBFS media source. */
|
||||
#include <console/console.h>
|
||||
#include <soc/alternate_cbfs.h>
|
||||
|
@ -45,7 +46,7 @@
|
|||
* rest of the firmware's lifetime and all subsequent stages (which will not
|
||||
* have __PRE_RAM__ defined) can just directly reference it there.
|
||||
*/
|
||||
static int usb_cbfs_open(struct cbfs_media *media)
|
||||
static int usb_cbfs_open(void)
|
||||
{
|
||||
#ifdef __PRE_RAM__
|
||||
static int first_run = 1;
|
||||
|
@ -80,7 +81,7 @@ static int usb_cbfs_open(struct cbfs_media *media)
|
|||
* this seems like a safer approach. It also makes it easy to pass our image
|
||||
* down to payloads.
|
||||
*/
|
||||
static int sdmmc_cbfs_open(struct cbfs_media *media)
|
||||
static int sdmmc_cbfs_open(void)
|
||||
{
|
||||
#ifdef __PRE_RAM__
|
||||
/*
|
||||
|
@ -111,66 +112,109 @@ static int sdmmc_cbfs_open(struct cbfs_media *media)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int alternate_cbfs_close(struct cbfs_media *media) { return 0; }
|
||||
static int exynos_cbfs_open(struct cbfs_media *media) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_cbfs_close(struct cbfs_media *media) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t exynos_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count) {
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
static size_t alternate_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
ASSERT(offset + count < _cbfs_cache_size);
|
||||
memcpy(dest, _cbfs_cache + offset, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count)
|
||||
{
|
||||
ASSERT(offset + count < _cbfs_cache_size);
|
||||
return _cbfs_cache + offset;
|
||||
static void *exynos_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count) {
|
||||
const struct region_device *boot_dev;
|
||||
void *ptr;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
ptr = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (ptr == NULL)
|
||||
return (void *)-1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *alternate_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *buffer) { return 0; }
|
||||
static void *exynos_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *address) {
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
|
||||
boot_dev = media->context;
|
||||
|
||||
media->open = sdmmc_cbfs_open;
|
||||
media->close = alternate_cbfs_close;
|
||||
media->read = alternate_cbfs_read;
|
||||
media->map = alternate_cbfs_map;
|
||||
media->unmap = alternate_cbfs_unmap;
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
|
||||
|
||||
media->open = usb_cbfs_open;
|
||||
media->close = alternate_cbfs_close;
|
||||
media->read = alternate_cbfs_read;
|
||||
media->map = alternate_cbfs_map;
|
||||
media->unmap = alternate_cbfs_unmap;
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
|
||||
if (media->context == NULL)
|
||||
return -1;
|
||||
|
||||
media->open = exynos_cbfs_open;
|
||||
media->close = exynos_cbfs_close;
|
||||
media->read = exynos_cbfs_read;
|
||||
media->map = exynos_cbfs_map;
|
||||
media->unmap = exynos_cbfs_unmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mem_region_device alternate_rdev = MEM_REGION_DEV_INIT(NULL, 0);
|
||||
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB)
|
||||
return initialize_exynos_usb_cbfs_media(media);
|
||||
return &alternate_rdev.rdev;
|
||||
|
||||
switch (exynos_power->om_stat & OM_STAT_MASK) {
|
||||
case OM_STAT_SDMMC:
|
||||
return initialize_exynos_sdmmc_cbfs_media(media);
|
||||
return &alternate_rdev.rdev;
|
||||
case OM_STAT_SPI:
|
||||
return initialize_exynos_spi_cbfs_media(media,
|
||||
_cbfs_cache, _cbfs_cache_size);
|
||||
return exynos_spi_boot_device();
|
||||
default:
|
||||
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
|
||||
exynos_power->om_stat);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void boot_device_init(void)
|
||||
{
|
||||
mem_region_device_init(&alternate_rdev, _cbfs_cache, _cbfs_cache_size);
|
||||
|
||||
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) {
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
|
||||
usb_cbfs_open();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (exynos_power->om_stat & OM_STAT_MASK) {
|
||||
case OM_STAT_SDMMC:
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
|
||||
sdmmc_cbfs_open();
|
||||
break;
|
||||
case OM_STAT_SPI:
|
||||
exynos_init_spi_boot_device();
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
|
||||
exynos_power->om_stat);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
|
||||
#include <arch/io.h>
|
||||
#include <assert.h>
|
||||
#include <boot_device.h>
|
||||
#include <console/console.h>
|
||||
#include <soc/clk.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <soc/spi.h>
|
||||
#include <stdlib.h>
|
||||
#include <symbols.h>
|
||||
|
||||
#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
|
||||
# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
|
||||
|
@ -144,70 +146,47 @@ int exynos_spi_close(struct exynos_spi *regs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// SPI as CBFS media.
|
||||
struct exynos_spi_media {
|
||||
struct exynos_spi *regs;
|
||||
struct cbfs_simple_buffer buffer;
|
||||
};
|
||||
static struct exynos_spi *boot_slave_regs;
|
||||
|
||||
static int exynos_spi_cbfs_open(struct cbfs_media *media) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_open\n");
|
||||
return exynos_spi_open(spi->regs);
|
||||
}
|
||||
|
||||
static int exynos_spi_cbfs_close(struct cbfs_media *media) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_close\n");
|
||||
return exynos_spi_close(spi->regs);
|
||||
}
|
||||
|
||||
static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
int bytes;
|
||||
DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
|
||||
bytes = exynos_spi_read(spi->regs, dest, count, offset);
|
||||
// Flush and re-open the device.
|
||||
exynos_spi_close(spi->regs);
|
||||
exynos_spi_open(spi->regs);
|
||||
exynos_spi_open(boot_slave_regs);
|
||||
bytes = exynos_spi_read(boot_slave_regs, dest, count, offset);
|
||||
exynos_spi_close(boot_slave_regs);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
static void *exynos_spi_map(const struct region_device *rdev,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
DEBUG_SPI("exynos_spi_cbfs_map\n");
|
||||
// See exynos_spi_rx_tx for I/O alignment limitation.
|
||||
// exynos: spi_rx_tx may work in 4 byte-width-transmission mode and
|
||||
// requires buffer memory address to be aligned.
|
||||
if (count % 4)
|
||||
count += 4 - (count % 4);
|
||||
return cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
|
||||
return mmap_helper_rdev_mmap(rdev, offset, count);
|
||||
}
|
||||
|
||||
static void *exynos_spi_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *address) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_unmap\n");
|
||||
return cbfs_simple_buffer_unmap(&spi->buffer, address);
|
||||
static const struct region_device_ops exynos_spi_ops = {
|
||||
.mmap = exynos_spi_map,
|
||||
.munmap = mmap_helper_rdev_munmap,
|
||||
.readat = exynos_spi_readat,
|
||||
};
|
||||
|
||||
static struct mmap_helper_region_device mdev =
|
||||
MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE);
|
||||
|
||||
void exynos_init_spi_boot_device(void)
|
||||
{
|
||||
boot_slave_regs = (void *)EXYNOS5_SPI1_BASE;
|
||||
|
||||
mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
|
||||
}
|
||||
|
||||
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
|
||||
void *buffer_address,
|
||||
size_t buffer_size) {
|
||||
// TODO Replace static variable to support multiple streams.
|
||||
static struct exynos_spi_media context;
|
||||
DEBUG_SPI("initialize_exynos_spi_cbfs_media\n");
|
||||
|
||||
context.regs = (void*)EXYNOS5_SPI1_BASE;
|
||||
context.buffer.allocated = context.buffer.last_allocate = 0;
|
||||
context.buffer.buffer = buffer_address;
|
||||
context.buffer.size = buffer_size;
|
||||
media->context = (void*)&context;
|
||||
media->open = exynos_spi_cbfs_open;
|
||||
media->close = exynos_spi_cbfs_close;
|
||||
media->read = exynos_spi_cbfs_read;
|
||||
media->map = exynos_spi_cbfs_map;
|
||||
media->unmap = exynos_spi_cbfs_unmap;
|
||||
|
||||
return 0;
|
||||
const struct region_device *exynos_spi_boot_device(void)
|
||||
{
|
||||
return &mdev.rdev;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <arch/cache.h>
|
||||
#include <assert.h>
|
||||
#include <boot_device.h>
|
||||
#include <cbfs.h> /* This driver serves as a CBFS media source. */
|
||||
#include <console/console.h>
|
||||
#include <soc/alternate_cbfs.h>
|
||||
|
@ -46,7 +47,7 @@
|
|||
* rest of the firmware's lifetime and all subsequent stages (which will not
|
||||
* have __PRE_RAM__ defined) can just directly reference it there.
|
||||
*/
|
||||
static int usb_cbfs_open(struct cbfs_media *media)
|
||||
static int usb_cbfs_open(void)
|
||||
{
|
||||
#ifdef __PRE_RAM__
|
||||
static int first_run = 1;
|
||||
|
@ -84,7 +85,7 @@ static int usb_cbfs_open(struct cbfs_media *media)
|
|||
* this seems like a safer approach. It also makes it easy to pass our image
|
||||
* down to payloads.
|
||||
*/
|
||||
static int sdmmc_cbfs_open(struct cbfs_media *media)
|
||||
static int sdmmc_cbfs_open(void)
|
||||
{
|
||||
#ifdef __PRE_RAM__
|
||||
/*
|
||||
|
@ -118,66 +119,109 @@ static int sdmmc_cbfs_open(struct cbfs_media *media)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int alternate_cbfs_close(struct cbfs_media *media) { return 0; }
|
||||
static int exynos_cbfs_open(struct cbfs_media *media) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_cbfs_close(struct cbfs_media *media) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t exynos_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count) {
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
if (rdev_readat(boot_dev, dest, offset, count) < 0)
|
||||
return 0;
|
||||
|
||||
static size_t alternate_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count)
|
||||
{
|
||||
ASSERT(offset + count < _cbfs_cache_size);
|
||||
memcpy(dest, _cbfs_cache + offset, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count)
|
||||
{
|
||||
ASSERT(offset + count < _cbfs_cache_size);
|
||||
return _cbfs_cache + offset;
|
||||
static void *exynos_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count) {
|
||||
const struct region_device *boot_dev;
|
||||
void *ptr;
|
||||
|
||||
boot_dev = media->context;
|
||||
|
||||
ptr = rdev_mmap(boot_dev, offset, count);
|
||||
|
||||
if (ptr == NULL)
|
||||
return (void *)-1;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *alternate_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *buffer) { return 0; }
|
||||
static void *exynos_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *address) {
|
||||
const struct region_device *boot_dev;
|
||||
|
||||
static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
|
||||
boot_dev = media->context;
|
||||
|
||||
media->open = sdmmc_cbfs_open;
|
||||
media->close = alternate_cbfs_close;
|
||||
media->read = alternate_cbfs_read;
|
||||
media->map = alternate_cbfs_map;
|
||||
media->unmap = alternate_cbfs_unmap;
|
||||
rdev_munmap(boot_dev, (void *)address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
|
||||
|
||||
media->open = usb_cbfs_open;
|
||||
media->close = alternate_cbfs_close;
|
||||
media->read = alternate_cbfs_read;
|
||||
media->map = alternate_cbfs_map;
|
||||
media->unmap = alternate_cbfs_unmap;
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int init_default_cbfs_media(struct cbfs_media *media)
|
||||
{
|
||||
boot_device_init();
|
||||
|
||||
media->context = (void *)boot_device_ro();
|
||||
|
||||
if (media->context == NULL)
|
||||
return -1;
|
||||
|
||||
media->open = exynos_cbfs_open;
|
||||
media->close = exynos_cbfs_close;
|
||||
media->read = exynos_cbfs_read;
|
||||
media->map = exynos_cbfs_map;
|
||||
media->unmap = exynos_cbfs_unmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mem_region_device alternate_rdev = MEM_REGION_DEV_INIT(NULL, 0);
|
||||
|
||||
const struct region_device *boot_device_ro(void)
|
||||
{
|
||||
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB)
|
||||
return initialize_exynos_usb_cbfs_media(media);
|
||||
return &alternate_rdev.rdev;
|
||||
|
||||
switch (exynos_power->om_stat & OM_STAT_MASK) {
|
||||
case OM_STAT_SDMMC:
|
||||
return initialize_exynos_sdmmc_cbfs_media(media);
|
||||
return &alternate_rdev.rdev;
|
||||
case OM_STAT_SPI:
|
||||
return initialize_exynos_spi_cbfs_media(media,
|
||||
_cbfs_cache, _cbfs_cache_size);
|
||||
return exynos_spi_boot_device();
|
||||
default:
|
||||
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
|
||||
exynos_power->om_stat);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void boot_device_init(void)
|
||||
{
|
||||
mem_region_device_init(&alternate_rdev, _cbfs_cache, _cbfs_cache_size);
|
||||
|
||||
if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) {
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
|
||||
usb_cbfs_open();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (exynos_power->om_stat & OM_STAT_MASK) {
|
||||
case OM_STAT_SDMMC:
|
||||
printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
|
||||
sdmmc_cbfs_open();
|
||||
break;
|
||||
case OM_STAT_SPI:
|
||||
exynos_init_spi_boot_device();
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
|
||||
exynos_power->om_stat);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <spi_flash.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <symbols.h>
|
||||
|
||||
#define EXYNOS_SPI_MAX_TRANSFER_BYTES (65535)
|
||||
|
||||
|
@ -242,76 +243,43 @@ static int exynos_spi_read(struct spi_slave *slave, void *dest, uint32_t len,
|
|||
return len;
|
||||
}
|
||||
|
||||
// SPI as CBFS media.
|
||||
struct exynos_spi_media {
|
||||
struct spi_slave *slave;
|
||||
struct cbfs_simple_buffer buffer;
|
||||
};
|
||||
static struct exynos_spi_slave *boot_slave;
|
||||
|
||||
static int exynos_spi_cbfs_open(struct cbfs_media *media)
|
||||
{
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue