Ronald G. Minnich (rminnich@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2184
-gerrit
commit 49acadcf850e7eb2a24cbb0a7e056c202c008047 Author: Ronald G. Minnich rminnich@gmail.com Date: Tue Jan 22 11:44:00 2013 -0800
DRAFT: implement a rom stream
Until this year, we had not needed a streaming construct since LinuxBIOS V1 in 2002. New ARM SOCs do require something that looks like a stream.
This is a proposed interface and sample implementation.
A stream is defined as: struct stream { u64 base; u32 size; };
The interface: struct stream *stream_start(struct stream *stream, u64 base, u32 size); Does anything that has to be done. For future 64-bit systems, base is a u64
int stream_read(struct stream *stream, void *where, u32 len, u32 off); Read 'len' bytes from stream 'stream' at offset 'off' to 'where'.
We assume any rom we'll ever see is 4G or less; hence the offset is a u32.
int stream_fini(struct stream *stream);
do what needs to be done to finish this stream; it might include turning off a SPI controller.
This compiles, but is not tested. I'll test when we get comments and get it right. Next in line is the SPI controller code. The sample stream source for spi is in bootblock.c. We've also put example usage in there. And, finally, modified the cbfs for arm to use the stream code.
I think this may finally be right. This definition of stream let us remove some ugly hacks from lib/cbfs_core.c I think.
As a bit of cleanup, with more needed, remove some spi stuff from spl_boot.c
Change-Id: I1e5e1b7c075ab36fe8729c60fa52d8406b6d26f0 Signed-off-by: Ronald G. Minnich rminnich@gmail.com --- src/Kconfig | 5 + src/arch/armv7/boot/coreboot_table.c | 1 + src/arch/armv7/include/arch/cbfs.h | 63 ++++++---- src/cpu/samsung/exynos5-common/Makefile.inc | 2 + src/cpu/samsung/exynos5-common/spi.c | 174 ++++++++++++++++++++++++++++ src/cpu/samsung/exynos5-common/spl_boot.c | 111 ------------------ src/drivers/realtek/Kconfig | 1 + src/include/cbfs.h | 1 + src/include/cbfs_core.h | 2 +- src/include/lib.h | 16 +++ src/lib/Makefile.inc | 2 + src/lib/cbfs.c | 2 +- src/lib/cbfs_core.c | 55 +++++---- src/lib/hardwaremain.c | 2 +- src/lib/romstream.c | 78 +++++++++++++ src/lib/selfboot.c | 2 +- src/mainboard/google/snow/bootblock.c | 101 +++++++++++++++- 17 files changed, 453 insertions(+), 165 deletions(-)
diff --git a/src/Kconfig b/src/Kconfig index 2c97327..7f12f3f 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -277,6 +277,11 @@ config HAVE_UART_MEMORY_MAPPED bool default n
+config ROMSTREAM + bool + default y if ARCH_X86 + default n if ARCH_ARMV7 + config HAVE_ACPI_RESUME bool default n diff --git a/src/arch/armv7/boot/coreboot_table.c b/src/arch/armv7/boot/coreboot_table.c index 86a004d..73aa73a 100644 --- a/src/arch/armv7/boot/coreboot_table.c +++ b/src/arch/armv7/boot/coreboot_table.c @@ -29,6 +29,7 @@ #include <version.h> #include <device/device.h> #include <stdlib.h> +#include <lib.h> #include <cbfs.h> #include <cbmem.h> #if CONFIG_USE_OPTION_TABLE diff --git a/src/arch/armv7/include/arch/cbfs.h b/src/arch/armv7/include/arch/cbfs.h index f060643..3bd68f4 100644 --- a/src/arch/armv7/include/arch/cbfs.h +++ b/src/arch/armv7/include/arch/cbfs.h @@ -32,13 +32,13 @@ static int cbfs_check_magic(struct cbfs_file *file) return strcmp(file->magic, CBFS_FILE_MAGIC) ? 0 : 1; }
+/* start and stop the stream each time. It's the simplest thing to do */ static unsigned long loadstage(const char* target) { unsigned long offset, align; + struct stream stream; struct cbfs_header *header = (struct cbfs_header *)(CONFIG_BOOTBLOCK_BASE + 0x40); - /* FIXME: magic offsets */ - // if (ntohl(header->magic) != CBFS_HEADER_MAGIC) - // printk(BIOS_ERR, "ERROR: No valid CBFS header found!\n"); + stream_start(&stream, 0x12d30000, 4*1048576);
offset = ntohl(header->offset); align = ntohl(header->align); @@ -50,13 +50,20 @@ static unsigned long loadstage(const char* target) printk(BIOS_INFO, "\talign: 0x%08x\n", ntohl(header->align)); printk(BIOS_INFO, "\toffset: 0x%08x\n", ntohl(header->offset)); while(1) { - struct cbfs_file *file; - struct cbfs_stage *stage; + struct cbfs_file f, *file = &f; + struct cbfs_stage s, *stage = &s; + int amount; /* FIXME: SPI image hack */ - file = (struct cbfs_file *)(offset + CONFIG_SPI_IMAGE_HACK); + amount = stream_read(&stream, (void *)file, sizeof(file), offset); + if (amount < sizeof(*file)){ + printk(BIOS_INFO, "Stream read of file header only returned %d bytes, wanted %d\n", + amount, sizeof(*file)); + goto fail; + } + if (!cbfs_check_magic(file)) { printk(BIOS_INFO, "magic is wrong, file: %p\n", file); - return 0; + goto fail; } if (!strcmp(CBFS_NAME(file), target)) { uint32_t load, entry; @@ -68,23 +75,29 @@ static unsigned long loadstage(const char* target) printk(BIOS_INFO, "\ttype: 0x%08x\n", ntohl(file->type)); printk(BIOS_INFO, "\tchecksum: 0x%08x\n", ntohl(file->checksum)); printk(BIOS_INFO, "\toffset: 0x%08x\n", ntohl(file->offset)); - /* exploit the fact that this is all word-aligned. */ - stage = CBFS_SUBHEADER(file); + offset += file->offset; + amount = stream_read(&stream, (void *)stage, + sizeof(*stage), offset); + if (amount < sizeof(*stage)){ + printk(BIOS_ERR, "Read stage: got %d, wanted %d\n", + amount, sizeof(stage)); + goto fail; + } load = stage->load; entry = stage->entry; int i; - u32 *to = (void *)load; - u32 *from = (void *)((u8 *)stage+sizeof(*stage)); - /* we could do memmove/memset here. But the math gets messy. - * far easier just to do what we want. - */ - printk(BIOS_INFO, "entry: 0x%08x, load: 0x%08x, " - "len: 0x%08x, memlen: 0x%08x\n", entry, - load, stage->len, stage->memlen); - for(i = 0; i < stage->len; i += 4) - *to++ = *from++; - for(; i < stage->memlen; i += 4) - *to++ = 0; + offset += sizeof(stage); + amount = stream_read(&stream, (void *)load, stage->len, offset); + if (amount < stage->len){ + printk(BIOS_ERR, "Stage read: got %d, wanted %d\n", + amount, stage->len); + + goto fail; + } + u32 *zero = (u32 *)(load + stage->len); + for(i = stage->len; i < stage->memlen; i += 4) + *zero++ = 0; + stream_fini(&stream); return entry; } int flen = ntohl(file->len); @@ -93,9 +106,13 @@ static unsigned long loadstage(const char* target) offset = ALIGN(offset + foffset + flen, align); printk(BIOS_INFO, "offset: 0x%08lx\n", offset); if (offset <= oldoffset) - return 0; + goto fail; if (offset > CONFIG_ROMSTAGE_SIZE) - return 0; + goto fail; } + + fail: + stream_fini(&stream); + return 0; } #endif diff --git a/src/cpu/samsung/exynos5-common/Makefile.inc b/src/cpu/samsung/exynos5-common/Makefile.inc index cad6cb3..4416dd1 100644 --- a/src/cpu/samsung/exynos5-common/Makefile.inc +++ b/src/cpu/samsung/exynos5-common/Makefile.inc @@ -1,2 +1,4 @@ #romstage-y += soc.c romstage-y += spl_boot.c +romstage-y += spi.c +ramstage-y += spi.c diff --git a/src/cpu/samsung/exynos5-common/spi.c b/src/cpu/samsung/exynos5-common/spi.c new file mode 100644 index 0000000..7129e6f --- /dev/null +++ b/src/cpu/samsung/exynos5-common/spi.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* FIXME(dhendrix): pulled in a lot of extra crap such as partition and string + libs*/ +#include <assert.h> +#include <common.h> +#include <stdlib.h> +#include <string.h> + +#include <console/console.h> +#include <console/loglevel.h> + +#include <config.h> +#include <spi.h> + +#include <cpu/samsung/exynos5250/gpio.h> +#include <cpu/samsung/exynos5250/clk.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/periph.h> +#include <cpu/samsung/exynos5250/pinmux.h> +#include <cpu/samsung/exynos5250/power.h> +#include <cpu/samsung/exynos5250/spi.h> + +#include <cpu/samsung/exynos5-common/cpu.h> +#include <cpu/samsung/exynos5-common/exynos5-common.h> + +#include <system.h> + +#include <arch/io.h> +#include <lib.h> + +#define OM_STAT (0x1f << 1) + +static void spi_rx_tx(struct exynos_spi *regs, int todo, + void *dinp, void const *doutp, int i) +{ + uint *rxp = (uint *)(dinp + (i * (32 * 1024))); + int rx_lvl, tx_lvl; + uint out_bytes, in_bytes; + + out_bytes = in_bytes = todo; + setbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt); + + while (in_bytes) { + uint32_t spi_sts; + int temp; + + spi_sts = readl(®s->spi_sts); + rx_lvl = ((spi_sts >> 15) & 0x7f); + tx_lvl = ((spi_sts >> 6) & 0x7f); + while (tx_lvl < 32 && out_bytes) { + temp = 0xffffffff; + writel(temp, ®s->tx_data); + out_bytes -= 4; + tx_lvl += 4; + } + while (rx_lvl >= 4 && in_bytes) { + temp = readl(®s->rx_data); + if (rxp) + *rxp++ = temp; + in_bytes -= 4; + rx_lvl -= 4; + } + } +} + +struct stream *stream_start(struct stream *stream, u64 base, u32 size) +{ +// struct exynos_spi *regs = (struct exynos_spi *)samsung_get_base_spi1(); + stream->base = base; + stream->size = size; + struct exynos_spi *regs = (void *)(u32)base; + + clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ + /* set the spi1 GPIO */ +// exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); + gpio_cfg_pin(GPIO_A24, 0x2); + gpio_cfg_pin(GPIO_A25, 0x2); + gpio_cfg_pin(GPIO_A26, 0x2); + gpio_cfg_pin(GPIO_A27, 0x2); + + /* set pktcnt and enable it */ + writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt); + /* set FB_CLK_SEL */ + writel(SPI_FB_DELAY_180, ®s->fb_clk); + /* set CH_WIDTH and BUS_WIDTH as word */ + setbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | + SPI_MODE_BUS_WIDTH_WORD); + clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */ + + /* clear rx and tx channel if set priveously */ + clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON); + + setbits_le32(®s->swap_cfg, SPI_RX_SWAP_EN | + SPI_RX_BYTE_SWAP | + SPI_RX_HWORD_SWAP); + + /* do a soft reset */ + setbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + + /* now set rx and tx channel ON */ + setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN); + clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ + return (void *)regs; +} + +int stream_read(struct stream *stream, void *where, u32 len, u32 off) +{ + int upto, todo; + int i; + struct exynos_spi *regs = (void *)(u32)stream->base; + if (off >= stream->size) + return 0; + /* Send read instruction (0x3h) followed by a 24 bit addr */ + writel((SF_READ_DATA_CMD << 24) | off, ®s->tx_data); + + /* waiting for TX done */ + while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE)); + + for (upto = 0, i = 0; upto < len; upto += todo, i++) { + todo = MIN(len - upto, (1 << 15)); + spi_rx_tx(regs, todo, (void *)(where), + (void *)(off), i); + } + + setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */ + + /* + * Let put controller mode to BYTE as + * SPI driver does not support WORD mode yet + */ + clrbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | + SPI_MODE_BUS_WIDTH_WORD); + writel(0, ®s->swap_cfg); + + return len; +} + +void stream_fini(struct stream *stream) +{ + struct exynos_spi *regs = (void *)(u32)stream->base; + + /* + * Flush spi tx, rx fifos and reset the SPI controller + * and clear rx/tx channel + */ + clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); +} + diff --git a/src/cpu/samsung/exynos5-common/spl_boot.c b/src/cpu/samsung/exynos5-common/spl_boot.c index ecff871..c60c55d 100644 --- a/src/cpu/samsung/exynos5-common/spl_boot.c +++ b/src/cpu/samsung/exynos5-common/spl_boot.c @@ -102,117 +102,6 @@ static int config_branch_prediction(int set_cr_z) return cr & CR_Z; }
-#if 0 -static void spi_rx_tx(struct exynos_spi *regs, int todo, - void *dinp, void const *doutp, int i) -{ - uint *rxp = (uint *)(dinp + (i * (32 * 1024))); - int rx_lvl, tx_lvl; - uint out_bytes, in_bytes; - - out_bytes = in_bytes = todo; - setbits_le32(®s->ch_cfg, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_CH_RST); - writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt); - - while (in_bytes) { - uint32_t spi_sts; - int temp; - - spi_sts = readl(®s->spi_sts); - rx_lvl = ((spi_sts >> 15) & 0x7f); - tx_lvl = ((spi_sts >> 6) & 0x7f); - while (tx_lvl < 32 && out_bytes) { - temp = 0xffffffff; - writel(temp, ®s->tx_data); - out_bytes -= 4; - tx_lvl += 4; - } - while (rx_lvl >= 4 && in_bytes) { - temp = readl(®s->rx_data); - if (rxp) - *rxp++ = temp; - in_bytes -= 4; - rx_lvl -= 4; - } - } -} -#endif - -/* FIXME(dhendrix): feels like exynos_spi_copy should go somewhere else... */ -#if 0 -/** - * Copy uboot from spi flash to RAM - * - * @parma uboot_size size of u-boot to copy - */ -static void exynos_spi_copy(unsigned int uboot_size) -{ - int upto, todo; - int i; -// struct exynos_spi *regs = (struct exynos_spi *)samsung_get_base_spi1(); - struct exynos_spi *regs = (struct exynos_spi *)0x12d30000; - - clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ - /* set the spi1 GPIO */ - exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); - - /* set pktcnt and enable it */ - writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt); - /* set FB_CLK_SEL */ - writel(SPI_FB_DELAY_180, ®s->fb_clk); - /* set CH_WIDTH and BUS_WIDTH as word */ - setbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | - SPI_MODE_BUS_WIDTH_WORD); - clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */ - - /* clear rx and tx channel if set priveously */ - clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON); - - setbits_le32(®s->swap_cfg, SPI_RX_SWAP_EN | - SPI_RX_BYTE_SWAP | - SPI_RX_HWORD_SWAP); - - /* do a soft reset */ - setbits_le32(®s->ch_cfg, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_CH_RST); - - /* now set rx and tx channel ON */ - setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN); - clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ - - /* Send read instruction (0x3h) followed by a 24 bit addr */ - writel((SF_READ_DATA_CMD << 24) | SPI_FLASH_UBOOT_POS, ®s->tx_data); - - /* waiting for TX done */ - while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE)); - - for (upto = 0, i = 0; upto < uboot_size; upto += todo, i++) { - todo = MIN(uboot_size - upto, (1 << 15)); - spi_rx_tx(regs, todo, (void *)(CONFIG_SYS_TEXT_BASE), - (void *)(SPI_FLASH_UBOOT_POS), i); - } - - setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */ - - /* - * Let put controller mode to BYTE as - * SPI driver does not support WORD mode yet - */ - clrbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | - SPI_MODE_BUS_WIDTH_WORD); - writel(0, ®s->swap_cfg); - - /* - * Flush spi tx, rx fifos and reset the SPI controller - * and clear rx/tx channel - */ - clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_CH_RST); - clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); -} -#endif - /* Copy U-Boot image to RAM */ static void copy_uboot_to_ram(void) { diff --git a/src/drivers/realtek/Kconfig b/src/drivers/realtek/Kconfig index 0799445..82b9e25 100644 --- a/src/drivers/realtek/Kconfig +++ b/src/drivers/realtek/Kconfig @@ -1,5 +1,6 @@ config RTL8168_ROM_DISABLE bool "Disable RTL8168 ROM" + depends on PCI default n help Just enough of a driver to make coreboot not look for an Option ROM. diff --git a/src/include/cbfs.h b/src/include/cbfs.h index b33e932..107b81b 100644 --- a/src/include/cbfs.h +++ b/src/include/cbfs.h @@ -50,6 +50,7 @@ #define _CBFS_H_
#include "cbfs_core.h" +#include <lib.h> #include <boot/coreboot_tables.h>
void *cbfs_load_payload(struct lb_memory *lb_mem, const char *name); diff --git a/src/include/cbfs_core.h b/src/include/cbfs_core.h index a3c54b1..a5a9541 100644 --- a/src/include/cbfs_core.h +++ b/src/include/cbfs_core.h @@ -192,5 +192,5 @@ void *cbfs_find_file(const char *name, int type);
/* returns 0 on success, -1 on failure */ int cbfs_decompress(int algo, void *src, void *dst, int len); -struct cbfs_header *get_cbfs_header(void); +struct cbfs_header *get_cbfs_header(struct stream *stream); #endif diff --git a/src/include/lib.h b/src/include/lib.h index 9d81085..5860226 100644 --- a/src/include/lib.h +++ b/src/include/lib.h @@ -53,5 +53,21 @@ void cache_as_ram_main(void); void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx); #endif
+/* definition is architecture-dependent but at minimum, for most architectures, + * defined in src/lib/romstream.c. There are so few systems that don't have + * memory mapped ROM that we yanked this years ago. Now, thanks to + * some ARM systems, it's back. + * A stream is a struct which contains a base (of arbitrary type, so u64) + * and a size (u32; will we ever have 4GB flash?) + */ +struct stream { + u64 base; + u32 size; +}; + +struct stream *stream_start(struct stream *stream, u64 base, u32 size); +int stream_read(struct stream *stream, void *where, u32 size, u32 off); +void stream_fini(struct stream *stream); + #endif /* __ROMCC__ */ #endif /* __LIB_H__ */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 6796448..c440228 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -36,6 +36,7 @@ romstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c romstage-$(CONFIG_CONSOLE_NE2K) += ne2k.c romstage-$(CONFIG_USBDEBUG) += usbdebug.c romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c +romstage-$(CONFIG_ROMSTREAM) += romstream.c romstage-y += compute_ip_checksum.c romstage-y += memmove.c
@@ -73,6 +74,7 @@ ramstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c ramstage-$(CONFIG_COVERAGE) += libgcov.c
ramstage-$(CONFIG_CONSOLE_NE2K) += ne2k.c +romstage-$(CONFIG_ROMSTREAM) += romstream.c
ifneq ($(CONFIG_HAVE_ARCH_MEMSET),y) smm-y += memset.c diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index 98672d4..cec3774 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -20,8 +20,8 @@ #include <types.h> #include <string.h> #include <console/console.h> -#include <cbfs.h> #include <lib.h> +#include <cbfs.h> #include <arch/byteorder.h>
// use CBFS core diff --git a/src/lib/cbfs_core.c b/src/lib/cbfs_core.c index 15cb68e..8ef27b3 100644 --- a/src/lib/cbfs_core.c +++ b/src/lib/cbfs_core.c @@ -54,21 +54,15 @@ * romstart() == 0xffffffff. This is a physical address. */
+#include <lib.h> #include <cbfs_core.h>
/* returns pointer to master header or 0xffffffff if not found */ -struct cbfs_header *get_cbfs_header(void) +struct cbfs_header *get_cbfs_header(struct stream *stream) { struct cbfs_header *header; - - /* find header */ - if (romstart() == 0xffffffff) { - header = (struct cbfs_header*)phys_to_virt(*(uint32_t*)phys_to_virt(romend() + CBFS_HEADPTR_ADDR)); - } else { - // FIXME: where's the master header on ARM (our current bottom-aligned platform)? - header = NULL; - } + stream_read(stream, &header, sizeof(header), 0); if (CBFS_HEADER_MAGIC != ntohl(header->magic)) { ERROR("Could not find valid CBFS master header at %p: %x vs %x.\n", header, CBFS_HEADER_MAGIC, ntohl(header->magic)); if (header->magic == 0xffffffff) { @@ -76,6 +70,7 @@ struct cbfs_header *get_cbfs_header(void) } return (void*)0xffffffff; } + return header; }
@@ -86,27 +81,37 @@ struct cbfs_header *get_cbfs_header(void) /* public API starts here*/ struct cbfs_file *cbfs_find(const char *name) { - struct cbfs_header *header = get_cbfs_header(); - if (header == (void*)0xffffffff) return NULL; + /* this is how we avoid globals in the rom stage. It's not pretty but it will work. + */ + struct stream stream; + u64 base; + u32 size;
- LOG("Looking for '%s'\n", name); - - void *data, *dataend, *origdata; - /* find first entry */ if (romstart() == 0xffffffff) { - data = (void*)phys_to_virt(romend()) - ntohl(header->romsize) + ntohl(header->offset); - dataend = (void*)phys_to_virt(romend()); + /* yuck. */ + base = (*(uint32_t*)phys_to_virt(romend() + CBFS_HEADPTR_ADDR)); } else { - data = (void*)phys_to_virt(romstart()) + ntohl(header->offset); - dataend = (void*)phys_to_virt(romstart()) + ntohl(header->romsize); + /* er, what, precisely? */ + base = 0; } - dataend -= ntohl(header->bootblocksize); + size = CONFIG_ROM_SIZE; + stream_start(&stream, base, size); + + struct cbfs_header *header = get_cbfs_header(&stream); + if (header == (void*)0xffffffff) return NULL; + + LOG("Looking for '%s'\n", name); + + void *data = NULL; + stream.size -= ntohl(header->bootblocksize);
int align = ntohl(header->align); + u32 offset = sizeof(*header);
- origdata = data; - while ((data < (dataend - 1)) && (data >= origdata)) { - struct cbfs_file *file = data; + while (1) { + struct cbfs_file f, *file = &f; + if (stream_read(&stream, file, sizeof(*file), offset) < sizeof(*file)) + break; if (memcmp(CBFS_FILE_MAGIC, file->magic, strlen(CBFS_FILE_MAGIC)) != 0) { // no file header found. corruption? // proceed in aligned steps to resynchronize @@ -117,15 +122,17 @@ struct cbfs_file *cbfs_find(const char *name) DEBUG("Check '%s'\n", CBFS_NAME(file)); if (strcmp(CBFS_NAME(file), name) == 0) { LOG("found.\n"); + stream_fini(&stream); return file; } void *olddata = data; data = phys_to_virt(CBFS_ALIGN(virt_to_phys(data) + ntohl(file->len) + ntohl(file->offset), align)); if (olddata > data) { LOG("Something is wrong here. File chain moved from %p to %p\n", olddata, data); - return NULL; + break; } } + stream_fini(&stream); return NULL; }
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c index eed243a..3bd0e40 100644 --- a/src/lib/hardwaremain.c +++ b/src/lib/hardwaremain.c @@ -34,8 +34,8 @@ it with the version available from LANL. #include <reset.h> #include <boot/tables.h> #include <boot/elf.h> -#include <cbfs.h> #include <lib.h> +#include <cbfs.h> #if CONFIG_HAVE_ACPI_RESUME #include <arch/acpi.h> #endif diff --git a/src/lib/romstream.c b/src/lib/romstream.c new file mode 100644 index 0000000..2c31afb --- /dev/null +++ b/src/lib/romstream.c @@ -0,0 +1,78 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 The ChromiumOS Authors. All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 <stdlib.h> +#include <lib.h> +#include <console/console.h> + +/* + * romstream. This is a very simple stream interface. + * The stream interface has three functions. The first, start, accepts a void * and a size and returns a void * + * which points to an opaque, and possibly internal, interface value. + * the second, read, accepts the opaque pointer, a data pointer, a length, and an offset and returns + * the number of bytes read or -1 if there is an error. + * The third, end, frees any internal stucts (if needed) and shuts do the stream (if needed) + * we assume that flash is 4G or less. + * The romstream is very simple: it's a u8 pointer. + */ + +struct stream * +stream_start(struct stream *stream, u64 base, u32 size) +{ + /* this seems not needed but we're allowing for future changes */ + u8 *romstream = v; +#ifdef CONFIG_X86 + stream->base = u64(phys_to_virt(base)); + stream->size = size; +#else +#error "using romstream on non-x86 is not supported?" +#endif + return romstream; +} + +/* This is a memory-addressable stream. So we will be setting *where to the address */ +int +stream_read(struct stream *stream, void *where, u32 len, u32 off) +{ + u8 *rom = (u8 *)stream->base; + u32 amount; + int i; + u8 *from, *to; + + if (off >= stream->size) + return 0; + + amount = stream->size - off; + if (amount > len) + amount = len; + + to = where; + from = rom + off; + + for(i = 0; i < amount; i++) + *from++ = *to++; + + return amount; +} + +void +stream_fini(void *stream) +{ +} diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c index c5fb62a..f49f74e 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -27,8 +27,8 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> -#include <cbfs.h> #include <lib.h> +#include <cbfs.h> #if CONFIG_COLLECT_TIMESTAMPS #include <timestamp.h> #endif diff --git a/src/mainboard/google/snow/bootblock.c b/src/mainboard/google/snow/bootblock.c index d5ee0a3..a3748b7 100644 --- a/src/mainboard/google/snow/bootblock.c +++ b/src/mainboard/google/snow/bootblock.c @@ -22,6 +22,7 @@
#include <stdlib.h> #include <types.h> +#include <lib.h> #include <arch/io.h> #include "cpu/samsung/exynos5250/clk.h" #include "cpu/samsung/exynos5250/cpu.h" @@ -358,6 +359,7 @@ void gpio_cfg_pin(int gpio, int cfg) writel(value, &bank->con); }
+#if 0 //static void exynos_spi_copy(unsigned int uboot_size) static void copy_romstage(uint32_t spi_addr, uint32_t sram_addr, unsigned int len) { @@ -428,7 +430,7 @@ static void copy_romstage(uint32_t spi_addr, uint32_t sram_addr, unsigned int le clrbits_le32(®s->ch_cfg, SPI_CH_RST); clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); } - +#endif /* Pull mode */ #define EXYNOS_GPIO_PULL_NONE 0x0 #define EXYNOS_GPIO_PULL_DOWN 0x1 @@ -2130,6 +2132,93 @@ int do_printk(int msg_level, const char *fmt, ...) return i; }
+struct stream *stream_start(struct stream *stream, u64 base, u32 size) +{ +// struct exynos_spi *regs = (struct exynos_spi *)samsung_get_base_spi1(); + stream->base = base; + stream->size = size; + struct exynos_spi *regs = (void *)(u32)base; + + clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ + /* set the spi1 GPIO */ +// exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); + gpio_cfg_pin(GPIO_A24, 0x2); + gpio_cfg_pin(GPIO_A25, 0x2); + gpio_cfg_pin(GPIO_A26, 0x2); + gpio_cfg_pin(GPIO_A27, 0x2); + + /* set pktcnt and enable it */ + writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt); + /* set FB_CLK_SEL */ + writel(SPI_FB_DELAY_180, ®s->fb_clk); + /* set CH_WIDTH and BUS_WIDTH as word */ + setbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | + SPI_MODE_BUS_WIDTH_WORD); + clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */ + + /* clear rx and tx channel if set priveously */ + clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON); + + setbits_le32(®s->swap_cfg, SPI_RX_SWAP_EN | + SPI_RX_BYTE_SWAP | + SPI_RX_HWORD_SWAP); + + /* do a soft reset */ + setbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + + /* now set rx and tx channel ON */ + setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN); + clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ + return (void *)regs; +} + +int stream_read(struct stream *stream, void *where, u32 len, u32 off) +{ + int upto, todo; + int i; + struct exynos_spi *regs = (void *)(u32)stream->base; + if (off >= stream->size) + return 0; + /* Send read instruction (0x3h) followed by a 24 bit addr */ + writel((SF_READ_DATA_CMD << 24) | off, ®s->tx_data); + + /* waiting for TX done */ + while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE)); + + for (upto = 0, i = 0; upto < len; upto += todo, i++) { + todo = MIN(len - upto, (1 << 15)); + spi_rx_tx(regs, todo, (void *)(where), + (void *)(off), i); + } + + setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */ + + /* + * Let put controller mode to BYTE as + * SPI driver does not support WORD mode yet + */ + clrbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | + SPI_MODE_BUS_WIDTH_WORD); + writel(0, ®s->swap_cfg); + + return len; +} + +void stream_fini(struct stream *stream) +{ + struct exynos_spi *regs = (void *)(u32)stream->base; + + /* + * Flush spi tx, rx fifos and reset the SPI controller + * and clear rx/tx channel + */ + clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); +} + + void bootblock_mainboard_init(void); void bootblock_mainboard_init(void) { @@ -2140,14 +2229,20 @@ void bootblock_mainboard_init(void) clock_init(); do_serial(); printk(BIOS_INFO, "%s: UART initialized\n", __func__); - +#if 0 /* Copy romstage data from SPI ROM to SRAM */ printk(BIOS_INFO, "Copying romstage:\n" "\tSPI offset: 0x%06x\n" "\tiRAM offset: 0x%08x\n" "\tSize: 0x%x\n", 0, CONFIG_SPI_IMAGE_HACK, CONFIG_ROMSTAGE_SIZE); - copy_romstage(0x0, CONFIG_SPI_IMAGE_HACK, CONFIG_ROMSTAGE_SIZE); + + stream = stream_start((void *)0x12d30000); + len = stream_read(stream, where, CONFIG_ROMSTAGE_SIZE, 0); + if (len < CONFIG_ROMSTAGE_SIZE) + printk(BIOS_ERR, "Did not read all of the SPI! Wanted %d, got %d\n", CONFIG_ROMSTAGE_SIZE, len); + stream_fini(stream); +#endif #if 0 /* FIXME: dump SRAM content for sanity checking */ uint32_t u;