diff --git a/src/arch/riscv/rom_media.c b/src/arch/riscv/rom_media.c index 8d3376c181..f18030c49f 100644 --- a/src/arch/riscv/rom_media.c +++ b/src/arch/riscv/rom_media.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2013 The Chromium OS Authors. All rights reserved. + * Copyright 2015 Google Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,40 +17,59 @@ * along with this program; if not, write to the Free Software * Foundation, Inc. */ +#include #include +#include #include -#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 -#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; diff --git a/src/arch/x86/lib/Makefile.inc b/src/arch/x86/lib/Makefile.inc index c7e8b626a6..e308be91bc 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/soc/nvidia/tegra124/cbfs.c b/src/arch/x86/lib/mmap_boot.c similarity index 64% rename from src/soc/nvidia/tegra124/cbfs.c rename to src/arch/x86/lib/mmap_boot.c index d82ca9a961..eb7b23e2b1 100644 --- a/src/soc/nvidia/tegra124/cbfs.c +++ b/src/arch/x86/lib/mmap_boot.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright 2013 Google Inc. + * Copyright 2015 Google Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,13 +17,15 @@ * Foundation, Inc. */ +#include -#include /* This driver serves as a CBFS media source. */ -#include -#include +/* The ROM is memory mapped just below 4GiB. Form a pointer for the base. */ +#define rom_base ((void *)(uintptr_t)(-(int32_t)CONFIG_ROM_SIZE)) -int init_default_cbfs_media(struct cbfs_media *media) +static const struct mem_region_device boot_dev = + MEM_REGION_DEV_INIT(rom_base, CONFIG_ROM_SIZE); + +const struct region_device *boot_device_ro(void) { - return initialize_tegra_spi_cbfs_media(media, - _cbfs_cache, _cbfs_cache_size); + return &boot_dev.rdev; } diff --git a/src/arch/x86/lib/rom_media.c b/src/arch/x86/lib/rom_media.c index 659e5e4f9b..d4663c7f60 100644 --- a/src/arch/x86/lib/rom_media.c +++ b/src/arch/x86/lib/rom_media.c @@ -17,6 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc. */ + +#include #include #include @@ -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; diff --git a/src/cpu/allwinner/a10/bootblock_media.c b/src/cpu/allwinner/a10/bootblock_media.c index a5863b6faf..a585bcaaa8 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 * Subject to the GNU GPL v2, or (at your option) any later version. */ +#include #include #include +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 9824fc396a..79724eea5d 100644 --- a/src/cpu/ti/am335x/bootblock_media.c +++ b/src/cpu/ti/am335x/bootblock_media.c @@ -17,11 +17,21 @@ * Foundation, Inc. */ +#include #include #include #include #include +/* 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 a8c945b91c..dd05fb6dee 100644 --- a/src/cpu/ti/am335x/nand.c +++ b/src/cpu/ti/am335x/nand.c @@ -17,10 +17,16 @@ * Foundation, Inc. */ +#include #include +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 0000000000..0848ea5bab --- /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 + +/* 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 11562bd059..adc4990942 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/soc/nvidia/tegra132/cbfs.c b/src/lib/boot_device.c similarity index 61% rename from src/soc/nvidia/tegra132/cbfs.c rename to src/lib/boot_device.c index 7aeb59bc94..e0353fc1ab 100644 --- a/src/soc/nvidia/tegra132/cbfs.c +++ b/src/lib/boot_device.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 /* This driver serves as a CBFS media source. */ -#include -#include +#include -int init_default_cbfs_media(struct cbfs_media *media) +void __attribute__((weak)) boot_device_init(void) { - return initialize_tegra_spi_cbfs_media(media, - _cbfs_cache, _cbfs_cache_size); + /* Provide weak do-nothing init. */ +} + +int boot_device_ro_subregion(const struct region *sub, + struct region_device *subrd) +{ + const struct region_device *boot_dev; + + boot_dev = boot_device_ro(); + + if (boot_dev == NULL) + return -1; + + return rdev_chain(subrd, boot_dev, region_offset(sub), region_sz(sub)); } diff --git a/src/lib/cbfs_spi.c b/src/lib/cbfs_spi.c index 6c8d78db75..6758220dfd 100644 --- a/src/lib/cbfs_spi.c +++ b/src/lib/cbfs_spi.c @@ -23,17 +23,52 @@ * SPI. */ +#include #include +#include #include #include -/* 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; } diff --git a/src/mainboard/emulation/qemu-armv7/media.c b/src/mainboard/emulation/qemu-armv7/media.c index 8c71263e67..e0f22515cd 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 #include #include #include #include -/* 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 78054f4511..46ce59d757 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/include/soc/spi.h b/src/soc/nvidia/tegra124/include/soc/spi.h index ab046323b1..cfa3cd2b57 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 683edd1cf0..0cf54956d3 100644 --- a/src/soc/nvidia/tegra124/spi.c +++ b/src/soc/nvidia/tegra124/spi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include @@ -800,12 +802,6 @@ int spi_xfer(struct spi_slave *slave, const void *dout, return ret; } -/* SPI as CBFS media. */ -struct tegra_spi_media { - struct spi_slave *slave; - struct cbfs_simple_buffer buffer; -}; - static int tegra_spi_cbfs_open(struct cbfs_media *media) { DEBUG_SPI("tegra_spi_cbfs_open\n"); @@ -823,16 +819,17 @@ static int tegra_spi_cbfs_close(struct cbfs_media *media) #define JEDEC_FAST_READ_DUAL 0x3b #define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05 -static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, - size_t offset, size_t count) +static struct spi_slave *boot_slave; + +static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest, + size_t offset, size_t count) { - struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context; u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE]; unsigned int read_cmd_bytes; int ret = count; struct tegra_spi_channel *channel; - channel = to_tegra_spi(spi->slave->bus); + channel = to_tegra_spi(boot_slave->bus); if (channel->dual_mode) { /* @@ -853,9 +850,9 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, spi_read_cmd[2] = (offset >> 8) & 0xff; spi_read_cmd[3] = offset & 0xff; - spi_claim_bus(spi->slave); + spi_claim_bus(boot_slave); - if (spi_xfer(spi->slave, spi_read_cmd, + if (spi_xfer(boot_slave, spi_read_cmd, read_cmd_bytes, NULL, 0) < 0) { ret = -1; printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n", @@ -866,7 +863,7 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, if (channel->dual_mode) { setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT); } - if (spi_xfer(spi->slave, NULL, 0, dest, count)) { + if (spi_xfer(boot_slave, NULL, 0, dest, count)) { ret = -1; printk(BIOS_ERR, "%s: Failed to transfer %u bytes\n", __func__, count); @@ -876,56 +873,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, tegra_spi_cbfs_read_exit: /* de-assert /CS */ - spi_release_bus(spi->slave); - return (ret < 0) ? 0 : ret; + spi_release_bus(boot_slave); + return ret; +} + +static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, + size_t offset, size_t count) +{ + const struct region_device *boot_dev; + + boot_dev = media->context; + + printk(BIOS_ERR, "%s: reading %zx bytes from %zx\n", + __func__, count, offset); + if (rdev_readat(boot_dev, dest, offset, count) < 0) + return 0; + + return count; } static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset, size_t count) { - struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; + const struct region_device *boot_dev; void *map; + DEBUG_SPI("tegra_spi_cbfs_map\n"); - map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count); + + boot_dev = media->context; + + map = rdev_mmap(boot_dev, offset, count); + + if (map == NULL) + map = (void *)-1; + return map; } static void *tegra_spi_cbfs_unmap(struct cbfs_media *media, const void *address) { - struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; + const struct region_device *boot_dev; + DEBUG_SPI("tegra_spi_cbfs_unmap\n"); - return cbfs_simple_buffer_unmap(&spi->buffer, address); + + boot_dev = media->context; + + rdev_munmap(boot_dev, (void *)address); + + return NULL; } -int initialize_tegra_spi_cbfs_media(struct cbfs_media *media, - void *buffer_address, - size_t buffer_size) +int init_default_cbfs_media(struct cbfs_media *media) { - // TODO Replace static variable to support multiple streams. - static struct tegra_spi_media context; - static struct tegra_spi_channel *channel; - - channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1]; - channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT; - DEBUG_SPI("Initializing CBFS media on SPI\n"); - context.slave = &channel->slave; - context.buffer.allocated = context.buffer.last_allocate = 0; - context.buffer.buffer = buffer_address; - context.buffer.size = buffer_size; - media->context = (void*)&context; + boot_device_init(); + + media->context = (void *)boot_device_ro(); media->open = tegra_spi_cbfs_open; media->close = tegra_spi_cbfs_close; media->read = tegra_spi_cbfs_read; media->map = tegra_spi_cbfs_map; media->unmap = tegra_spi_cbfs_unmap; -#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1 - channel->dual_mode = 1; -#endif - return 0; } @@ -937,3 +948,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) return &channel->slave; } + +static const struct region_device_ops tegra_spi_ops = { + .mmap = mmap_helper_rdev_mmap, + .munmap = mmap_helper_rdev_munmap, + .readat = tegra_spi_readat, +}; + +static struct mmap_helper_region_device mdev = + MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE); + +const struct region_device *boot_device_ro(void) +{ + return &mdev.rdev; +} + +void boot_device_init(void) +{ + struct tegra_spi_channel *boot_chan; + + boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1]; + boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT; + +#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1 + boot_chan->dual_mode = 1; +#endif + boot_slave = &boot_chan->slave; + + mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size); +} diff --git a/src/soc/nvidia/tegra132/Makefile.inc b/src/soc/nvidia/tegra132/Makefile.inc index 365dab314f..c192055cdf 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/include/soc/spi.h b/src/soc/nvidia/tegra132/include/soc/spi.h index 2fd9562599..4c91c27c7f 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 7ca66e1ad8..1650057fab 100644 --- a/src/soc/nvidia/tegra132/spi.c +++ b/src/soc/nvidia/tegra132/spi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include @@ -815,12 +817,6 @@ int spi_xfer(struct spi_slave *slave, const void *dout, return ret; } -/* SPI as CBFS media. */ -struct tegra_spi_media { - struct spi_slave *slave; - struct cbfs_simple_buffer buffer; -}; - static int tegra_spi_cbfs_open(struct cbfs_media *media) { DEBUG_SPI("tegra_spi_cbfs_open\n"); @@ -838,16 +834,17 @@ static int tegra_spi_cbfs_close(struct cbfs_media *media) #define JEDEC_FAST_READ_DUAL 0x3b #define JEDEC_FAST_READ_DUAL_OUTSIZE 0x05 -static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, - size_t offset, size_t count) +static struct spi_slave *boot_slave; + +static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest, + size_t offset, size_t count) { - struct tegra_spi_media *spi = (struct tegra_spi_media *)media->context; u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE]; unsigned int read_cmd_bytes; int ret = count; struct tegra_spi_channel *channel; - channel = to_tegra_spi(spi->slave->bus); + channel = to_tegra_spi(boot_slave->bus); if (channel->dual_mode) { /* @@ -868,9 +865,9 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, spi_read_cmd[2] = (offset >> 8) & 0xff; spi_read_cmd[3] = offset & 0xff; - spi_claim_bus(spi->slave); + spi_claim_bus(boot_slave); - if (spi_xfer(spi->slave, spi_read_cmd, + if (spi_xfer(boot_slave, spi_read_cmd, read_cmd_bytes, NULL, 0) < 0) { ret = -1; printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n", @@ -881,7 +878,7 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, if (channel->dual_mode) { setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT); } - if (spi_xfer(spi->slave, NULL, 0, dest, count)) { + if (spi_xfer(boot_slave, NULL, 0, dest, count)) { ret = -1; printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n", __func__, count); @@ -891,56 +888,70 @@ static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, tegra_spi_cbfs_read_exit: /* de-assert /CS */ - spi_release_bus(spi->slave); - return (ret < 0) ? 0 : ret; + spi_release_bus(boot_slave); + return ret; +} + +static size_t tegra_spi_cbfs_read(struct cbfs_media *media, void *dest, + size_t offset, size_t count) +{ + const struct region_device *boot_dev; + + boot_dev = media->context; + + DEBUG_SPI("%s: reading %zx bytes from %zx\n", __func__, count, offset); + + if (rdev_readat(boot_dev, dest, offset, count) < 0) + return 0; + + return count; } static void *tegra_spi_cbfs_map(struct cbfs_media *media, size_t offset, size_t count) { - struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; + const struct region_device *boot_dev; void *map; + DEBUG_SPI("tegra_spi_cbfs_map\n"); - map = cbfs_simple_buffer_map(&spi->buffer, media, offset, count); + + boot_dev = media->context; + + map = rdev_mmap(boot_dev, offset, count); + + if (map == NULL) + map = (void *)-1; + return map; } static void *tegra_spi_cbfs_unmap(struct cbfs_media *media, const void *address) { - struct tegra_spi_media *spi = (struct tegra_spi_media*)media->context; + const struct region_device *boot_dev; + DEBUG_SPI("tegra_spi_cbfs_unmap\n"); - return cbfs_simple_buffer_unmap(&spi->buffer, address); + + boot_dev = media->context; + + rdev_munmap(boot_dev, (void *)address); + + return NULL; } -int initialize_tegra_spi_cbfs_media(struct cbfs_media *media, - void *buffer_address, - size_t buffer_size) +int init_default_cbfs_media(struct cbfs_media *media) { - // TODO Replace static variable to support multiple streams. - static struct tegra_spi_media context; - static struct tegra_spi_channel *channel; - - channel = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1]; - channel->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT; - DEBUG_SPI("Initializing CBFS media on SPI\n"); - context.slave = &channel->slave; - context.buffer.allocated = context.buffer.last_allocate = 0; - context.buffer.buffer = buffer_address; - context.buffer.size = buffer_size; - media->context = (void*)&context; + boot_device_init(); + + media->context = (void *)boot_device_ro(); media->open = tegra_spi_cbfs_open; media->close = tegra_spi_cbfs_close; media->read = tegra_spi_cbfs_read; media->map = tegra_spi_cbfs_map; media->unmap = tegra_spi_cbfs_unmap; -#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1 - channel->dual_mode = 1; -#endif - return 0; } @@ -952,3 +963,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs) return &channel->slave; } + +static const struct region_device_ops tegra_spi_ops = { + .mmap = mmap_helper_rdev_mmap, + .munmap = mmap_helper_rdev_munmap, + .readat = tegra_spi_readat, +}; + +static struct mmap_helper_region_device mdev = + MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE); + +const struct region_device *boot_device_ro(void) +{ + return &mdev.rdev; +} + +void boot_device_init(void) +{ + struct tegra_spi_channel *boot_chan; + + boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1]; + boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT; + +#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1 + boot_chan->dual_mode = 1; +#endif + boot_slave = &boot_chan->slave; + + mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size); +} 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 +#include #include /* This driver serves as a CBFS media source. */ #include #include @@ -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; } } 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 +#include /* 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 #include +#include #include #include #include #include #include +#include #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; } diff --git a/src/soc/samsung/exynos5420/alternate_cbfs.c b/src/soc/samsung/exynos5420/alternate_cbfs.c index b30ed6bff7..9bba748a84 100644 --- a/src/soc/samsung/exynos5420/alternate_cbfs.c +++ b/src/soc/samsung/exynos5420/alternate_cbfs.c @@ -20,6 +20,7 @@ #include #include +#include #include /* This driver serves as a CBFS media source. */ #include #include @@ -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; } } diff --git a/src/soc/samsung/exynos5420/include/soc/spi.h b/src/soc/samsung/exynos5420/include/soc/spi.h index cf778003be..77d5ffc8c7 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 +#include /* 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 5f298036ef..2edc3374dd 100644 --- a/src/soc/samsung/exynos5420/spi.c +++ b/src/soc/samsung/exynos5420/spi.c @@ -26,6 +26,7 @@ #include #include #include +#include #define EXYNOS_SPI_MAX_TRANSFER_BYTES (65535) @@ -242,76 +243,43 @@ static int exynos_spi_read(struct spi_slave *slave, void *dest, uint32_t len, return len; } -// SPI as CBFS media. -struct exynos_spi_media { - struct spi_slave *slave; - struct cbfs_simple_buffer buffer; -}; +static struct exynos_spi_slave *boot_slave; -static int exynos_spi_cbfs_open(struct cbfs_media *media) +static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest, + size_t offset, size_t count) { - struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; - DEBUG_SPI("exynos_spi_cbfs_open\n"); - return spi_claim_bus(spi->slave); -} - -static int exynos_spi_cbfs_close(struct cbfs_media *media) -{ - struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; - DEBUG_SPI("exynos_spi_cbfs_close\n"); - spi_release_bus(spi->slave); - return 0; -} - -static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest, - size_t offset, size_t count) -{ - struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; - int bytes; DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count); - bytes = exynos_spi_read(spi->slave, dest, count, offset); - return bytes; + return exynos_spi_read(&boot_slave->slave, dest, count, offset); } -static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset, - size_t count) +static void *exynos_spi_map(const struct region_device *rdev, + size_t offset, size_t count) { - struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; DEBUG_SPI("exynos_spi_cbfs_map\n"); // exynos: spi_rx_tx may work in 4 byte-width-transmission mode and // requires buffer memory address to be aligned. if (count % 4) count += 4 - (count % 4); - return cbfs_simple_buffer_map(&spi->buffer, media, offset, count); + return mmap_helper_rdev_mmap(rdev, offset, count); } -static void *exynos_spi_cbfs_unmap(struct cbfs_media *media, - const void *address) +static const struct region_device_ops exynos_spi_ops = { + .mmap = exynos_spi_map, + .munmap = mmap_helper_rdev_munmap, + .readat = exynos_spi_readat, +}; + +static struct mmap_helper_region_device mdev = + MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE); + +void exynos_init_spi_boot_device(void) { - struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context; - DEBUG_SPI("exynos_spi_cbfs_unmap\n"); - return cbfs_simple_buffer_unmap(&spi->buffer, address); + boot_slave = &exynos_spi_slaves[1]; + + mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size); } -int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, - void *buffer_address, - size_t buffer_size) +const struct region_device *exynos_spi_boot_device(void) { - // TODO Replace static variable to support multiple streams. - static struct exynos_spi_media context; - static struct exynos_spi_slave *eslave = &exynos_spi_slaves[1]; - DEBUG_SPI("initialize_exynos_spi_cbfs_media\n"); - - context.slave = &eslave->slave; - context.buffer.allocated = context.buffer.last_allocate = 0; - context.buffer.buffer = buffer_address; - context.buffer.size = buffer_size; - media->context = (void*)&context; - media->open = exynos_spi_cbfs_open; - media->close = exynos_spi_cbfs_close; - media->read = exynos_spi_cbfs_read; - media->map = exynos_spi_cbfs_map; - media->unmap = exynos_spi_cbfs_unmap; - - return 0; + return &mdev.rdev; }