From 8a2e8a89b77c18ee2aa3d6c085d460bd9e71de6e Mon Sep 17 00:00:00 2001 From: Andrey Petrov Date: Fri, 27 Mar 2015 11:09:44 -0700 Subject: mec1322: initial version of lfw loader This is an initial version of the loader. Error handling is very basic, sysjump support is missing. BUG=chrome-os-partner:37510 BRANCH=strago-mec TEST=make buildall; manually tested booting/copying on Strago Change-Id: I13627974308609b15640e81707b95c6f1ce9f365 Signed-off-by: Andrey Petrov Reviewed-on: https://chromium-review.googlesource.com/262781 Reviewed-by: Randall Spangler Reviewed-by: Vincent Palatin Commit-Queue: Divya Jyothi Tested-by: Divya Jyothi --- chip/mec1322/build.mk | 31 +++++- chip/mec1322/lfw/ec_lfw.c | 240 +++++++++++++++++++++++++++++++++++++++++++++ chip/mec1322/lfw/ec_lfw.h | 21 ++++ chip/mec1322/lfw/ec_lfw.ld | 91 +++++++++++++++++ 4 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 chip/mec1322/lfw/ec_lfw.c create mode 100644 chip/mec1322/lfw/ec_lfw.h create mode 100644 chip/mec1322/lfw/ec_lfw.ld diff --git a/chip/mec1322/build.mk b/chip/mec1322/build.mk index 98907cbae6..5f32ae74c9 100755 --- a/chip/mec1322/build.mk +++ b/chip/mec1322/build.mk @@ -30,9 +30,36 @@ SCRIPTDIR:=./chip/${CHIP}/util CHIP_SPI_SIZE_KB?=256 # Command to convert $^ to $@.tmp -cmd_obj_to_bin = $(OBJCOPY) --gap-fill=0xff -O binary $^ $@.tmp1 ; \ +cmd_obj_to_bin = $(OBJCOPY) --gap-fill=0xff -O binary $< $@.tmp1 ; \ ${SCRIPTDIR}/pack_ec.py -o $@.tmp -i $@.tmp1 \ - --loader_file ${SCRIPTDIR}/ecloader.bin \ + --loader_file $(mec1322-lfw-flat) \ --payload_key ${SCRIPTDIR}/rsakey_sign_payload.pem \ --header_key ${SCRIPTDIR}/rsakey_sign_header.pem \ --spi_size=${CHIP_SPI_SIZE_KB} ; rm -f $@.tmp1 + +mec1322-lfw = chip/mec1322/lfw/ec_lfw +mec1322-lfw-flat = $(out)/$(mec1322-lfw)-lfw.flat + +# build these specifically for lfw with -lfw suffix +objs_lfw = $(patsubst %, $(out)/%-lfw.o, \ + $(addprefix common/, util gpio) \ + $(addprefix chip/$(CHIP)/, spi dma gpio clock hwtimer) \ + core/$(CORE)/cpu $(mec1322-lfw)) + +# reuse version.o (and its dependencies) from main board +objs_lfw += $(out)/common/version.o + +dirs-y+=chip/$(CHIP)/lfw + +# objs with -lfw suffix are to include lfw's gpio +$(out)/%-lfw.o: private CC+=-Iboard/$(BOARD)/lfw +$(out)/%-lfw.o: %.c + $(call quiet,c_to_o,CC ) + +# let lfw's elf link only with selected objects +$(out)/%-lfw.elf: private objs = $(objs_lfw) +$(out)/%-lfw.elf: %.ld $(objs_lfw) + $(call quiet,elf,LD ) + +# final image needs lfw loader +$(out)/$(PROJECT).bin: $(mec1322-lfw-flat) diff --git a/chip/mec1322/lfw/ec_lfw.c b/chip/mec1322/lfw/ec_lfw.c new file mode 100644 index 0000000000..52699c9743 --- /dev/null +++ b/chip/mec1322/lfw/ec_lfw.c @@ -0,0 +1,240 @@ +/* Copyright 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * MEC1322 SoC little FW + * + */ + +#include + +#include "config.h" +#include "gpio.h" +#include "spi.h" +#include "spi_flash.h" +#include "util.h" +#include "timer.h" +#include "dma.h" +#include "registers.h" +#include "cpu.h" +#include "clock.h" +#include "system.h" +#include "version.h" +#include "hwtimer.h" +#include "gpio_list.h" + +#include "ec_lfw.h" + +static uintptr_t *const image_type = (uintptr_t *const) SHARED_RAM_LOADER_RORW; + + +__attribute__ ((section(".intvector"))) +const struct int_vector_t hdr_int_vect = { + (void *)0x11FA00, /* init sp, unused, set by MEC ROM loader*/ + &lfw_main, /* reset vector */ + &fault_handler, /* NMI handler */ + &fault_handler, /* HardFault handler */ + &fault_handler, /* MPU fault handler */ + &fault_handler /* Bus fault handler */ +}; + +void timer_init() +{ + uint32_t val = 0; + + /* Ensure timer is not running */ + MEC1322_TMR32_CTL(0) &= ~(1 << 5); + + /* Enable timer */ + MEC1322_TMR32_CTL(0) |= (1 << 0); + + val = MEC1322_TMR32_CTL(0); + + /* Pre-scale = 48 -> 1MHz -> Period = 1us */ + val = (val & 0xffff) | (47 << 16); + + MEC1322_TMR32_CTL(0) = val; + + /* Set preload to use the full 32 bits of the timer */ + MEC1322_TMR32_PRE(0) = 0xffffffff; + + /* Override the count */ + MEC1322_TMR32_CNT(0) = 0xffffffff; + + /* Auto restart */ + MEC1322_TMR32_CTL(0) |= (1 << 3); + + /* Start counting in timer 0 */ + MEC1322_TMR32_CTL(0) |= (1 << 5); + +} + +static int spi_flash_readloc(uint8_t *buf_usr, + unsigned int offset, + unsigned int bytes) +{ + uint8_t cmd[4] = {SPI_FLASH_READ, + (offset >> 16) & 0xFF, + (offset >> 8) & 0xFF, + offset & 0xFF}; + + if (offset + bytes > CONFIG_SPI_FLASH_SIZE) + return EC_ERROR_INVAL; + + return spi_transaction(cmd, 4, buf_usr, bytes); +} + +int spi_rwimage_load(void) +{ + uint8_t *buf = (uint8_t *) (CONFIG_FW_RW_OFF + CONFIG_FLASH_BASE); + uint32_t i; + + memset((void *)buf, 0xFF, (CONFIG_FW_RW_SIZE - 4)); + + spi_enable(1); + + for (i = 0; i < CONFIG_FW_RW_SIZE; i += SPI_CHUNK_SIZE) + spi_flash_readloc(&buf[i], + CONFIG_RW_IMAGE_FLASHADDR + i, + SPI_CHUNK_SIZE); + + spi_enable(0); + + return 0; + +} + +void udelay(unsigned us) +{ + uint32_t t0 = __hw_clock_source_read(); + while (__hw_clock_source_read() - t0 < us) + ; +} + +void usleep(unsigned us) +{ + udelay(us); +} + +int timestamp_expired(timestamp_t deadline, const timestamp_t *now) +{ + timestamp_t now_val; + + if (!now) { + now_val = get_time(); + now = &now_val; + } + + return ((uint32_t)(now->le.lo - deadline.le.lo) >= 0); +} + + +timestamp_t get_time(void) +{ + timestamp_t ts; + + ts.le.hi = 0; + ts.le.lo = __hw_clock_source_read(); + return ts; +} + +void uart_write_c(char c) +{ + /* Wait for space in transmit FIFO. */ + while (!(MEC1322_UART_LSR & (1 << 5))) + ; + MEC1322_UART_TB = c; +} + +void uart_puts(const char *str) +{ + if (!str || !*str) + return; + + do { + uart_write_c(*str++); + } while (*str); +} + +void fault_handler(void) +{ + uart_puts("EXCEPTION!\nTriggering watchdog reset\n"); + /* trigger reset in 1 ms */ + MEC1322_WDG_LOAD = 1; + MEC1322_WDG_CTL |= 1; + while (1) + ; + +} + +void jump_to_image(uintptr_t init_addr) +{ + void (*resetvec)(void) = (void(*)(void))init_addr; + resetvec(); +} + +void uart_init(void) +{ + /* Set UART to reset on VCC1_RESET instaed of nSIO_RESET */ + MEC1322_UART_CFG &= ~(1 << 1); + + /* Baud rate = 115200. 1.8432MHz clock. Divisor = 1 */ + + /* Set CLK_SRC = 0 */ + MEC1322_UART_CFG &= ~(1 << 0); + + /* Set DLAB = 1 */ + MEC1322_UART_LCR |= (1 << 7); + + /* PBRG0/PBRG1 */ + MEC1322_UART_PBRG0 = 1; + MEC1322_UART_PBRG1 = 0; + + /* Set DLAB = 0 */ + MEC1322_UART_LCR &= ~(1 << 7); + + /* Set word length to 8-bit */ + MEC1322_UART_LCR |= (1 << 0) | (1 << 1); + + /* Enable FIFO */ + MEC1322_UART_FCR = (1 << 0); + + /* Activate UART */ + MEC1322_UART_ACT |= (1 << 0); + + gpio_config_module(MODULE_UART, 1); +} + +void lfw_main() +{ + + uintptr_t init_addr; + + /* install vector table */ + *((uintptr_t *) 0xe000ed08) = (uintptr_t) &hdr_int_vect; + + timer_init(); + clock_init(); + cpu_init(); + dma_init(); + uart_init(); + + uart_puts("littlefw"); + uart_puts(version_data.version); + uart_puts("\n"); + + switch (*image_type) { + case SYSTEM_IMAGE_RW: + init_addr = CONFIG_FW_RW_OFF + CONFIG_FLASH_BASE; + spi_rwimage_load(); + case SYSTEM_IMAGE_RO: + default: + init_addr = CONFIG_FW_RO_OFF + CONFIG_FLASH_BASE; + } + + jump_to_image(*(uintptr_t *)(init_addr + 4)); + + /* should never get here */ + while (1) + ; +} diff --git a/chip/mec1322/lfw/ec_lfw.h b/chip/mec1322/lfw/ec_lfw.h new file mode 100644 index 0000000000..b7f9f6359f --- /dev/null +++ b/chip/mec1322/lfw/ec_lfw.h @@ -0,0 +1,21 @@ +/* Copyright 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * MEC1322 SoC little FW + * + */ + +void lfw_main(void) __attribute__ ((noreturn, naked)); +void fault_handler(void) __attribute__((naked)); + +struct int_vector_t { + void *stack_ptr; + void *reset_vector; + void *nmi; + void *hard_fault; + void *bus_fault; + void *usage_fault; +}; + +#define SPI_CHUNK_SIZE 1024 diff --git a/chip/mec1322/lfw/ec_lfw.ld b/chip/mec1322/lfw/ec_lfw.ld new file mode 100644 index 0000000000..091c1ed6ff --- /dev/null +++ b/chip/mec1322/lfw/ec_lfw.ld @@ -0,0 +1,91 @@ +/* Copyright 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * MEC1322 SoC little FW + * + */ + +/* Memory Spaces Definitions */ +MEMORY +{ + VECTOR(r ) : ORIGIN = 0x100000, LENGTH = 24 + SRAM (xrw) : ORIGIN = 0x100018, LENGTH = 0x1000 - LENGTH(VECTOR) +} + +/* + * The entry point is informative, for debuggers and simulators, + * since the Cortex-M vector points to it anyway. + */ +ENTRY(lfw_main) + +/* Sections Definitions */ + +SECTIONS +{ + + /* + * The vector table goes first + */ + .intvector : + { + . = ALIGN(4); + KEEP(*(.intvector)) + } > VECTOR + + /* + * The program code is stored in the .text section, + * which goes to FLASH. + */ + + .text : + { + *(.text .text.*) /* all remaining code */ + *(.rodata .rodata.*) /* read-only data (constants) */ + } >SRAM + + . = ALIGN(4); + + .data : + { + . = ALIGN(4); + + __data_start__ = . ; + *(.data_begin .data_begin.*) + + *(.data .data.*) + + *(.data_end .data_end.*) + . = ALIGN(4); + + __data_end__ = . ; + + } > SRAM + + + /* + * The uninitialised data section. NOLOAD is used to avoid + * the "section `.bss' type changed to PROGBITS" warning + */ + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start__ = .; /* standard newlib definition */ + *(.bss_begin .bss_begin.*) + + *(.bss .bss.*) + *(COMMON) + + *(.bss_end .bss_end.*) + . = ALIGN(4); + __bss_end__ = .; /* standard newlib definition */ + } >SRAM + + /* Padding */ + + .fill : { + FILL(0xFF); + . = ORIGIN(SRAM) + LENGTH(SRAM) - 1; + BYTE(0xFF); /* emit at least a byte to make linker happy */ + } +} -- cgit v1.2.1