From ce011ec1317eebdcec91f29d206869ac0a71c23a Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 6 Aug 2013 16:00:37 -0700 Subject: exynos5250: Implement support to boot with USB A-A firmware upload This patch implements the basic infrastructure required to use the USB A-A firmware upload feature on Exynos5 processors with Coreboot. It will require a corresponding host-side script that activates the feature and uploads the correct image parts in the correct order to harcoded target addresses, as described in the comments of alternate_cbfs.c. Also fixes a bug in the Google Snow mainboard where it would not correctly initialize the pinmux configuration for the SPI flash bus. During a normal SPI boot the IROM would already do that for you, but when booting from USB you have to do it yourself. Change-Id: I40a39f8f5d1d70b58dbf258015c1653a27097d67 Signed-off-by: Julius Werner Reviewed-on: https://gerrit.chromium.org/gerrit/64875 Reviewed-by: Stefan Reinauer Reviewed-by: Hung-Te Lin Commit-Queue: Gabe Black Reviewed-on: http://review.coreboot.org/4456 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/cpu/samsung/exynos5250/Makefile.inc | 6 +- src/cpu/samsung/exynos5250/alternate_cbfs.c | 110 ++++++++++++++++++++++++++++ src/cpu/samsung/exynos5250/alternate_cbfs.h | 44 +++++++++++ src/cpu/samsung/exynos5250/cpu.h | 16 ---- src/cpu/samsung/exynos5250/pinmux.c | 5 +- src/cpu/samsung/exynos5250/spi.c | 7 -- 6 files changed, 161 insertions(+), 27 deletions(-) create mode 100644 src/cpu/samsung/exynos5250/alternate_cbfs.c create mode 100644 src/cpu/samsung/exynos5250/alternate_cbfs.h (limited to 'src/cpu') diff --git a/src/cpu/samsung/exynos5250/Makefile.inc b/src/cpu/samsung/exynos5250/Makefile.inc index e029c672e6..6d7ae16c72 100644 --- a/src/cpu/samsung/exynos5250/Makefile.inc +++ b/src/cpu/samsung/exynos5250/Makefile.inc @@ -3,7 +3,7 @@ # image outside of CBFS INTERMEDIATE += exynos5250_add_bl1 -bootblock-y += spi.c +bootblock-y += spi.c alternate_cbfs.c bootblock-y += pinmux.c mct.c power.c # Clock is required for UART bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += clock_init.c @@ -16,7 +16,7 @@ bootblock-y += wakeup.c bootblock-y += gpio.c bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += timer.c -romstage-y += spi.c +romstage-y += spi.c alternate_cbfs.c romstage-y += clock.c romstage-y += clock_init.c romstage-y += pinmux.c # required by s3c24x0_i2c and uart. @@ -35,7 +35,7 @@ romstage-y += i2c.c #romstage-y += wdt.c romstage-y += cbmem.c -ramstage-y += spi.c +ramstage-y += spi.c alternate_cbfs.c ramstage-y += clock.c ramstage-y += clock_init.c ramstage-y += pinmux.c diff --git a/src/cpu/samsung/exynos5250/alternate_cbfs.c b/src/cpu/samsung/exynos5250/alternate_cbfs.c new file mode 100644 index 0000000000..15494863f2 --- /dev/null +++ b/src/cpu/samsung/exynos5250/alternate_cbfs.c @@ -0,0 +1,110 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include +#include /* This driver serves as a CBFS media source. */ +#include +#include +#include +#include "alternate_cbfs.h" +#include "spi.h" + +/* This allows USB A-A firmware upload from a compatible host in four parts: + * The first two are the bare BL1 and the Coreboot boot block, which are just + * written to their respective loading addresses. These transfers are initiated + * by the IROM / BL1, so this code has nothing to do with them. + * + * The third transfer is a valid CBFS image that contains only the romstage, + * and must be small enough to fit into alternate_cbfs_size[__BOOT_BLOCK__] in + * IRAM. It is loaded when this function gets called in the boot block, and + * the normal CBFS code extracts the romstage from it. + * + * The fourth transfer is also a CBFS image, but can be of arbitrary size and + * should contain all available stages/payloads/etc. It is loaded when this + * function is called a second time at the end of the romstage, and copied to + * alternate_cbfs_buffer[!__BOOT_BLOCK__] in DRAM. It will reside there for the + * 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) { +#ifdef __PRE_RAM__ + static int first_run = 1; + int (*irom_load_usb)(void) = *irom_load_image_from_usb_ptr; + + if (!first_run) + return 0; + + if (!irom_load_usb()) { + printk(BIOS_ERR, "Unable to load CBFS image via USB!\n"); + return -1; + } + + /* + * We need to trust the host/irom to copy the image to our + * alternate_cbfs_buffer address... there is no way to control or even + * check the transfer size or target address from our side. + */ + + printk(BIOS_DEBUG, "USB A-A transfer successful, CBFS image should now" + " be at %p\n", alternate_cbfs_buffer); + first_run = 0; +#endif + return 0; +} + +static int alternate_cbfs_close(struct cbfs_media *media) { return 0; } + +static size_t alternate_cbfs_read(struct cbfs_media *media, void *dest, + size_t offset, size_t count) { + ASSERT(offset + count < alternate_cbfs_size); + memcpy(dest, alternate_cbfs_buffer + offset, count); + return count; +} + +static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset, + size_t count) { + ASSERT(offset + count < alternate_cbfs_size); + return alternate_cbfs_buffer + offset; +} + +static void *alternate_cbfs_unmap(struct cbfs_media *media, + const void *buffer) { 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; +} + +int init_default_cbfs_media(struct cbfs_media *media) { + if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB) + return initialize_exynos_usb_cbfs_media(media); + + /* TODO: implement SDMMC (and possibly other) boot mode */ + + return initialize_exynos_spi_cbfs_media(media, + (void*)CONFIG_CBFS_CACHE_ADDRESS, CONFIG_CBFS_CACHE_SIZE); +} diff --git a/src/cpu/samsung/exynos5250/alternate_cbfs.h b/src/cpu/samsung/exynos5250/alternate_cbfs.h new file mode 100644 index 0000000000..a26fe61f87 --- /dev/null +++ b/src/cpu/samsung/exynos5250/alternate_cbfs.h @@ -0,0 +1,44 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef CPU_SAMSUNG_EXYNOS5250_ALTERNATE_CBFS_H +#define CPU_SAMSUNG_EXYNOS5250_ALTERNATE_CBFS_H + +/* These are pointers to function pointers. Double indirection! */ +void * * const irom_sdmmc_read_blocks_ptr = (void * *)0x02020030; +void * * const irom_msh_read_from_fifo_emmc_ptr = (void * *)0x02020044; +void * * const irom_msh_end_boot_op_emmc_ptr = (void * *)0x02020048; +void * * const irom_spi_sf_read_ptr = (void * *)0x02020058; +void * * const irom_load_image_from_usb_ptr = (void * *)0x02020070; + +#define SECONDARY_BASE_BOOT_USB 0xfeed0002 +u32 * const iram_secondary_base = (u32 *)0x02020018; + +#if defined(__BOOT_BLOCK__) + /* A small space in IRAM to hold the romstage-only image */ + void * const alternate_cbfs_buffer = (void *)CONFIG_CBFS_CACHE_ADDRESS; + size_t const alternate_cbfs_size = CONFIG_CBFS_CACHE_SIZE; +#else + /* Just put this anywhere in RAM that's far enough from anything else */ + /* TODO: Find a better way to "reserve" this region? */ + void * const alternate_cbfs_buffer = (void *)0x77400000; + size_t const alternate_cbfs_size = 0xc00000; +#endif + +#endif diff --git a/src/cpu/samsung/exynos5250/cpu.h b/src/cpu/samsung/exynos5250/cpu.h index 149de6abb4..f4ab3edb21 100644 --- a/src/cpu/samsung/exynos5250/cpu.h +++ b/src/cpu/samsung/exynos5250/cpu.h @@ -26,22 +26,6 @@ #define EXYNOS_PRO_ID 0x10000000 -/* Address of address of function that copys data from SD or MMC */ -#define EXYNOS_COPY_MMC_FNPTR_ADDR 0x02020030 - -/* Address of address of function that copys data from SPI */ -#define EXYNOS_COPY_SPI_FNPTR_ADDR 0x02020058 - -/* Address of address of function that copys data through USB */ -#define EXYNOS_COPY_USB_FNPTR_ADDR 0x02020070 - -/* Boot mode values */ -#define EXYNOS_USB_SECONDARY_BOOT 0xfeed0002 - -#define EXYNOS_IRAM_SECONDARY_BASE 0x02020018 - -#define EXYNOS_I2C_SPACING 0x10000 - /* EXYNOS5 */ #define EXYNOS5_GPIO_PART6_BASE 0x03860000 /* Z<6:0> */ #define EXYNOS5_PRO_ID 0x10000000 diff --git a/src/cpu/samsung/exynos5250/pinmux.c b/src/cpu/samsung/exynos5250/pinmux.c index b5406af8ba..89ce23ef69 100644 --- a/src/cpu/samsung/exynos5250/pinmux.c +++ b/src/cpu/samsung/exynos5250/pinmux.c @@ -134,8 +134,11 @@ static void exynos_pinmux_spi(int start, int cfg) { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { gpio_cfg_pin(start + i, GPIO_FUNC(cfg)); + gpio_set_pull(start + i, GPIO_PULL_NONE); + gpio_set_drv(start + i, GPIO_DRV_3X); + } } void exynos_pinmux_spi0(void) diff --git a/src/cpu/samsung/exynos5250/spi.c b/src/cpu/samsung/exynos5250/spi.c index 1c365dc5ca..e8b68b40ea 100644 --- a/src/cpu/samsung/exynos5250/spi.c +++ b/src/cpu/samsung/exynos5250/spi.c @@ -214,10 +214,3 @@ int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, return 0; } - -int init_default_cbfs_media(struct cbfs_media *media) { - return initialize_exynos_spi_cbfs_media( - media, - (void*)CONFIG_CBFS_CACHE_ADDRESS, - CONFIG_CBFS_CACHE_SIZE); -} -- cgit v1.2.3