From b3749083dfbf25f9d5d2589c14333e9ca0c52ecb Mon Sep 17 00:00:00 2001 From: Saurabh Singh Date: Fri, 13 Oct 2023 22:51:47 -0400 Subject: [PATCH] boot: make bootloader multitarget --- sw/bootloader/Makefile | 44 ++++++--- sw/bootloader/atombones.h | 15 +++ sw/bootloader/flashboot.h | 58 +++++++++++ sw/bootloader/hydrogensoc.h | 97 +++++++++++++++++++ sw/bootloader/main.c | 185 +++++------------------------------- sw/bootloader/tinystdio.h | 3 + 6 files changed, 229 insertions(+), 173 deletions(-) create mode 100644 sw/bootloader/atombones.h create mode 100644 sw/bootloader/flashboot.h create mode 100644 sw/bootloader/hydrogensoc.h create mode 100644 sw/bootloader/tinystdio.h diff --git a/sw/bootloader/Makefile b/sw/bootloader/Makefile index 83ad3fe9..9a0c5be5 100644 --- a/sw/bootloader/Makefile +++ b/sw/bootloader/Makefile @@ -1,19 +1,41 @@ -EXEC:= bootloader.elf +EXEC:= bootloader -CFLAGS:= -mabi=ilp32 -march=rv32i -nostartfiles -ffreestanding -DTARGET_HYDROGENSOC -Os +RVPREFIX:= riscv64-unknown-elf + +CFLAGS:= -mabi=ilp32 -march=rv32i -nostartfiles -ffreestanding -Os CFLAGS+= -I $(RVATOM_LIB)/include -LFLAGS:= -L $(RVATOM_LIB)/ -T $(RVATOM_LIB)/link/link_boot_hydrogensoc.ld -lcatom -Xlinker -Map $(EXEC).map -Wl,--gc-sections +LFLAGS:= -L $(RVATOM_LIB)/ -T $(RVATOM_LIB)/link/link_bootloader.ld -lcatom -Xlinker -Map $(EXEC).map -Wl,--gc-sections + +CONVELF_ARGS:= -t elf -c + +ifeq ($(MAKECMDGOALS),clean) +else + ifeq ($(soctarget), atombones) + CFLAGS += -DTARGET_ATOMBONES -DTARGET_HEADER='"atombones.h"' + else + ifeq ($(soctarget), hydrogensoc) + CFLAGS += -DTARGET_HYDROGENSOC -DTARGET_HEADER='"hydrogensoc.h"' + else + $(error Invalid SoC target: $(soctarget)) + endif + endif +endif + + +default: $(EXEC).elf $(EXEC).objdump $(EXEC).bin $(EXEC).hex + +$(EXEC).elf: main.c crt0.S + $(RVPREFIX)-gcc $(CFLAGS) -o $@ $^ $(LFLAGS) -default: boot +$(EXEC).objdump: $(EXEC).elf + $(RVPREFIX)-objdump -htd $< > $@ -.PHONY: boot -boot: $(EXEC) +$(EXEC).bin: $(EXEC).elf + $(RVPREFIX)-objcopy -O binary $< $@ -$(EXEC): main.c crt0.S - riscv64-unknown-elf-gcc $(CFLAGS) -o $@ $^ $(LFLAGS) - riscv64-unknown-elf-objdump -htd $@ > $@.objdump - python3 $$RVATOM/scripts/convelf.py -t elf -j hydrogensoc.json --keep-temp $(EXEC) -c +$(EXEC).hex: $(EXEC).elf + convelf.py $(CONVELF_ARGS) -m="BOOTROM:0x00010000:8192:h:$@" $< .PHONY: clean clean: - rm -f *.o *.objdump *.map *.elf *.hex \ No newline at end of file + rm -f *.o *.objdump *.map *.elf *.hex *.bin \ No newline at end of file diff --git a/sw/bootloader/atombones.h b/sw/bootloader/atombones.h new file mode 100644 index 00000000..2e3b2f0f --- /dev/null +++ b/sw/bootloader/atombones.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +extern uint32_t __approm_start; + +/** + * @brief Platform specific initialization + * + * @return void* address to jump to after boot + */ +void * platform_init() { + // Jump to start of approm + return (void *) &__approm_start; +} \ No newline at end of file diff --git a/sw/bootloader/flashboot.h b/sw/bootloader/flashboot.h new file mode 100644 index 00000000..95b5def0 --- /dev/null +++ b/sw/bootloader/flashboot.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +// Flash definitions +#define FLASH_CMD_READ 0x03 +#define SPI_REG_SCKDIV_OFFSET 0x00 +#define SPI_REG_SCTRL_OFFSET 0x04 +#define SPI_REG_TDATA_OFFSET 0x08 +#define SPI_REG_RDATA_OFFSET 0x0c +#define SPI_REG_CSCTRL_OFFSET 0x10 +#define SPI_REG_DCTRL_OFFSET 0x14 + +/** + * @brief Copies Data from FLAST to dest + * + * @param dest dest buffer + * @param src_addr source address in flash + * @param len + * @return int + */ +int flashcpy(uint8_t *dest, uint32_t src_addr, uint32_t len) { + struct SPI_Config cfg = { + .base_addr = SPI_ADDR, + .enable = true, + .pha = false, + .pol = false, + .lsb_first = false, + .baudrate = 1000000, + .device_num = 0, + .cs_mode = CSMODE_DISABLE, + .post_cs_low_delay = 1, + .pre_cs_high_delay = 1, + .loopback_enable=false + }; + spi_init(&cfg); + + // select + REG32(cfg.base_addr, SPI_REG_CSCTRL_OFFSET) = bitset(REG32(cfg.base_addr, SPI_REG_CSCTRL_OFFSET), 24+cfg.device_num); + spi_transfer(&cfg, FLASH_CMD_READ); + spi_transfer(&cfg, src_addr >> 16); + spi_transfer(&cfg, src_addr >> 8); + spi_transfer(&cfg, src_addr); + + while(len--) { + REG8(cfg.base_addr, SPI_REG_TDATA_OFFSET) = 0x0; + while(REG32(SPI_ADDR, SPI_REG_SCTRL_OFFSET) >> 31) + asm volatile(""); + *(dest++) = REG8(cfg.base_addr, SPI_REG_RDATA_OFFSET); + } + + // deselect + REG32(cfg.base_addr, SPI_REG_CSCTRL_OFFSET) = bitclear(REG32(cfg.base_addr, SPI_REG_CSCTRL_OFFSET), 24+cfg.device_num); + cfg.cs_mode = CSMODE_AUTO; + spi_init(&cfg); + return 0; +} \ No newline at end of file diff --git a/sw/bootloader/hydrogensoc.h b/sw/bootloader/hydrogensoc.h new file mode 100644 index 00000000..3d4fc712 --- /dev/null +++ b/sw/bootloader/hydrogensoc.h @@ -0,0 +1,97 @@ +#pragma once + +#include "gpio.h" +#include "time.h" +#include "mmio.h" +#include "spi.h" + +#include "flashboot.h" + +#define STRINGIFY(s) #s +#define EXPAND_AND_STRINGIFY(s) STRINGIFY(s) + +extern uint32_t __approm_start; +extern uint32_t __approm_size; + + +//-------------------- Configuration -------------------- +#define BOOTLED_PIN 0 +#define BOOTMODE_PIN0 8 +#define BOOTMODE_PIN1 9 + +// Address offset at which image resides +#define FLASH_IMG_OFFSET 0x000c0000 + +// Size of Image +#define FLASH_IMG_SIZE 32 * 1024 // 32 KB + +// number of flashes to indicate entering of bootloader +#define START_LED_FLASHES 3 + +// number of flashes to indicate entering of user application +#define END_LED_FLASHES 1 +//------------------------------------------------------- + + +/** + * @brief Blink BOOTLED + * + * @param pin led pin + * @param count number of times to blink + * @param time_period time_period in of one ON & OFF + */ +void led_blink(int pin, int count, int time_period) +{ + for(int i=0; i> 1); + gpio_write(pin, LOW); + sleep_ms(time_period >> 1); + } +} + + +/** + * @brief Platform specific initialization + * + * @return void* address to jump to after boot + */ +void * platform_init() { + // Initialize GPIO + gpio_setmode(BOOTLED_PIN, OUTPUT); + gpio_setmode(BOOTMODE_PIN0, INPUT); + gpio_setmode(BOOTMODE_PIN1, INPUT); + + // Blink LED START_LED_FLASHES times (signal entering of bootloader) + led_blink(BOOTLED_PIN, START_LED_FLASHES, 50); + + // get bootmode + uint8_t bootmode = (uint8_t)gpio_read(BOOTMODE_PIN0) + | (((uint8_t)gpio_read(BOOTMODE_PIN1)) << 1); + /** + * Bootmode: + * 0b00: flashboot + * 0b01: jump to ram + * default: infinite loop + */ + if (bootmode == 0b00) { + // Bootmode: flash boot + P(puts("flashboot: Copying from " EXPAND_AND_STRINGIFY(FLASH_IMG_OFFSET) "\n");) + // copy from flash + flashcpy((uint8_t *)&__approm_start, FLASH_IMG_OFFSET, FLASH_IMG_SIZE); + } else if (bootmode == 0b01) { + // Bootmode: jump to ram + } else { + // Bootmode: Infinite loop + while(1){ + asm volatile(""); + } + } + + // Blink single (signal jump to user code) + led_blink(BOOTLED_PIN, END_LED_FLASHES, 50); + + // Jump to start of approm + return (void *) &__approm_start; +} diff --git a/sw/bootloader/main.c b/sw/bootloader/main.c index 99b08d4d..8c9b0569 100644 --- a/sw/bootloader/main.c +++ b/sw/bootloader/main.c @@ -1,191 +1,52 @@ -#include "platform.h" #include -#include "gpio.h" -#include "serial.h" -#include "time.h" -#include "mmio.h" -#include "spi.h" - -//--------------------- Settings ----------------------------- -#define BOOTLED_PIN 0 -#define BOOTMODE_PIN0 8 -#define BOOTMODE_PIN1 9 - -// Address offset at which image resides -#define FLASH_IMG_OFFSET 0x000c0000 - -// Size of Image -#define FLASH_IMG_SIZE 32 * 1024 // 32 KB +#include "platform.h" +#include "stdio.h" -// Enable/Disable UART +// Enable Prints through UART #define ENABLE_UART -// number of flashes to indicate entering of bootloader -#define START_LED_FLASHES 3 - -// number of flashes to indicate entering of user application -#define END_LED_FLASHES 1 - // Clear screen at start of bootloader -// #define CLS_AT_START - -//------------------------------------------------------------ -#define STRINGIFY(s) #s -#define EXPAND_AND_STRINGIFY(s) STRINGIFY(s) +#define CLS_AT_START #ifdef ENABLE_UART -#define D(x) x + #define P(x) x #else -#define D(x) + #define P(x) #endif -extern uint32_t __approm_start; -extern uint32_t __approm_size; +// include target specific header +#include TARGET_HEADER typedef void (*fnc_ptr)(void); -//********************** Tiny STDIO ********************** -#ifdef ENABLE_UART -void putchar(char c) -{ - if(c == '\n') - serial_write('\r'); - serial_write(c); -} - -void puts(char *ptr) -{ - while (*ptr) - putchar(*ptr++); -} -#endif - -// ********************** LED ********************** -void led_blink(int pin, int count, int delay) -{ - for(int i=0; i> 16); - spi_transfer(&cfg, addr >> 8); - spi_transfer(&cfg, addr); - - while(len--) { - REG8(cfg.base_addr, SPI_REG_TDATA_OFFSET) = 0x0; - while(REG32(SPI_ADDR, SPI_REG_SCTRL_OFFSET) >> 31) - asm volatile(""); - *(buf++) = REG8(cfg.base_addr, SPI_REG_RDATA_OFFSET); - } - - // deselect - REG32(cfg.base_addr, SPI_REG_CSCTRL_OFFSET) = bitclear(REG32(cfg.base_addr, SPI_REG_CSCTRL_OFFSET), 24+cfg.device_num); - cfg.cs_mode = CSMODE_AUTO; - spi_init(&cfg); -} - +int main() { + //********* Platform agnostic initialization ********** + serial_init(UART_BAUD_115200); -int main() -{ - // ********** Initialize ********** - // Initialize GPIO - gpio_setmode(BOOTLED_PIN, OUTPUT); - gpio_setmode(BOOTMODE_PIN0, INPUT); - gpio_setmode(BOOTMODE_PIN1, INPUT); - - #ifdef ENABLE_UART - // Initialize UART - REG32(UART_ADDR, UART_REG_DIV) = 102; - uint32_t lcr = 0; - lcr |= UART_REG_LCR_RXEN; - lcr |= UART_REG_LCR_TXEN; - REG32(UART_ADDR, UART_REG_LCR) = lcr; - // clear any garbage from data register by reading it once - REG32(UART_ADDR, UART_REG_RBR); - #endif - - // Blink LED START_LED_FLASHES times (signal entering of bootloader) - led_blink(BOOTLED_PIN, START_LED_FLASHES, 50); // Print header #ifdef CLS_AT_START - D(putchar(0x1b); putchar('c');) // clear screen + P(putchar(0x1b); putchar('c');) // clear screen #else - D(putchar('\n');) + P(putchar('\n');) #endif + P(puts("***** RISC-V Atom Bootloader *****\n");) - D(puts("***** RISC-V Atom Bootloader *****\n");) - // get bootmode - uint8_t bootmode = (uint8_t)gpio_read(BOOTMODE_PIN0) - | (((uint8_t)gpio_read(BOOTMODE_PIN1)) << 1); - - /** - * Bootmode: - * 0b00: flashboot - * 0b01: jump to ram - * default: infinite loop - */ - if (bootmode == 0b00) { - // Bootmode: flash boot - D(puts("flashboot: Copying from " EXPAND_AND_STRINGIFY(FLASH_IMG_OFFSET) "\n");) - // copy from flash - flash_copy((uint8_t *)&__approm_start, FLASH_IMG_OFFSET, FLASH_IMG_SIZE); - } else if (bootmode == 0b01) { - // Bootmode: jump to ram - } else { - // Bootmode: Infinite loop - while(1){ - asm volatile(""); - } + // ********** Platform specific initialization ********** + void * jump_addr = platform_init(); + if(jump_addr == NULL) { + P(puts("boot-panic: platform initialization failed\n");) + goto panic; } - D(puts("Jumping to ram\n" "----------------------------------\n");) - - // Blink single (signal jump to user code) - led_blink(BOOTLED_PIN, END_LED_FLASHES, 50); - // Jump - fnc_ptr app_main = (fnc_ptr)(&__approm_start); + fnc_ptr app_main = (fnc_ptr) jump_addr; app_main(); - // ** UNREACHABLE ** - D(puts("Err: unreachable\n");) - gpio_write(BOOTLED_PIN, HIGH); + +panic: + P(puts("boot-panic: failed to boot\n");) while(1) { asm volatile(""); } diff --git a/sw/bootloader/tinystdio.h b/sw/bootloader/tinystdio.h new file mode 100644 index 00000000..97b13088 --- /dev/null +++ b/sw/bootloader/tinystdio.h @@ -0,0 +1,3 @@ +#pragma once + +#define UART_INIT \ No newline at end of file