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 01903b02bfd540371526e4b73983f865ff5bf5bc 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.
The interface: void *stream_start(void *); Called with a void *, which might be a pointer or pointer to stuct, depending on circumstances; returns a pointer to an opaque type.
int stream_read(void *stream, void **where, u32 len, u32 off); On memory-addressed ROMs, set *where to point to a buffer of 0 or more bytes, up to len bytes. This avoids unnecessary copies. On non-memory-addressed ROMs, 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(void *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.
Change-Id: I1e5e1b7c075ab36fe8729c60fa52d8406b6d26f0 Signed-off-by: Ronald G. Minnich rminnich@gmail.com --- src/Kconfig | 5 ++ src/drivers/realtek/Kconfig | 1 + src/include/lib.h | 16 ++++++ src/lib/Makefile.inc | 1 + src/lib/romstream.c | 65 ++++++++++++++++++++++++ src/mainboard/google/snow/bootblock.c | 96 ++++++++++++++++++++++++++++++++++- 6 files changed, 182 insertions(+), 2 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/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/lib.h b/src/include/lib.h index 9d81085..ff63349 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. + * There is a subtle design trick here. For rom streams which are memory-addressable, + * we don't want to copy the data. So we can return a pointer to the data in **where, along + * with the length of the available date. + * For spi streams, as on ARM, the caller must set *where to a data buffer. + * In any event, the implementation guarantee that on return, *where points to a data + * area and return the length of the area it points to, which is at most 'len' bytes + * and may be zero bytes. In this way, we can be efficient on machines with memory-addressed ROM. + */ +void *stream_start(void *v); +int stream_read(void *stream, void **where, u32 size, u32 off); +void stream_fini(void *stream); + #endif /* __ROMCC__ */ #endif /* __LIB_H__ */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 6796448..37d85d0 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
diff --git a/src/lib/romstream.c b/src/lib/romstream.c new file mode 100644 index 0000000..000479c --- /dev/null +++ b/src/lib/romstream.c @@ -0,0 +1,65 @@ +/* + * 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. + */ + +void * +stream_start(void *v) +{ + /* this seems not needed but we're allowing for future changes */ + u8 *romstream = v; + return romstream; +} + +/* This is a memory-addressable stream. So we will be setting *where to the address */ +int +stream_read(void *stream, void **where, u32 len, u32 off) +{ + u8 *romstream = stream; + u32 amount; + + if (off >= CONFIG_ROM_SIZE) + return 0; + + amount = CONFIG_ROM_SIZE - off; + if (amount > len) + amount = len; + *where = romstream+off; + + return amount; +} + +void +stream_fini(void *stream) +{ +} diff --git a/src/mainboard/google/snow/bootblock.c b/src/mainboard/google/snow/bootblock.c index d5ee0a3..65265d7 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,11 +2132,97 @@ int do_printk(int msg_level, const char *fmt, ...) return i; }
+void *stream_start(void *v) +{ +// struct exynos_spi *regs = (struct exynos_spi *)samsung_get_base_spi1(); + struct exynos_spi *regs = v; + + 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(void *stream, void **where, u32 len, u32 off) +{ + int upto, todo; + int i; + struct exynos_spi *regs = stream; + /* 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(void *stream) +{ + struct exynos_spi *regs = stream; + + /* + * 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) { /* FIXME: we should not need UART in bootblock, this is only done for testing purposes */ + void *stream; + void *where = (void *)CONFIG_SPI_IMAGE_HACK; + int len; i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); power_init(); clock_init(); @@ -2147,7 +2235,11 @@ void bootblock_mainboard_init(void) "\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); #if 0 /* FIXME: dump SRAM content for sanity checking */ uint32_t u;