diff --git a/firmware/boot/Makefile b/firmware/boot/Makefile new file mode 100644 index 0000000..52889ee --- /dev/null +++ b/firmware/boot/Makefile @@ -0,0 +1,24 @@ +CROSS ?= riscv-none-embed- + +CC := $(CROSS)gcc +OBJCOPY := $(CROSS)objcopy + +CFLAGS=-Wall -Os -march=rv32i -mabi=ilp32 -ffreestanding -flto -nostartfiles -fomit-frame-pointer -Wl,--gc-section --specs=nano.specs + + +all: boot.hex + + +boot.elf: lnk-boot.lds boot.S + $(CC) $(CFLAGS) -Wl,-Bstatic,-T,lnk-boot.lds,--strip-debug -DAPP_FLASH_ADDR=0x000a0000 -o $@ boot.S + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +%.hex: %.bin + hexdump boot.bin -ve '1/4 "%08x\n"' $< > $@ + +clean: + rm -f *.bin *.hex *.elf *.o + +.PHONY: clean diff --git a/firmware/boot/boot.S b/firmware/boot/boot.S new file mode 100644 index 0000000..f1978e3 --- /dev/null +++ b/firmware/boot/boot.S @@ -0,0 +1,193 @@ +/* + * boot.S + * + * SPI boot code + * + * Copyright (C) 2020-2023 Sylvain Munaut + * SPDX-License-Identifier: MIT + */ + +#ifndef APP_FLASH_ADDR +#define APP_FLASH_ADDR 0x000a0000 +#endif + +#ifndef APP_SRAM_ADDR +#define APP_SRAM_ADDR 0x00020000 +#endif + +#ifndef APP_SIZE +#define APP_SIZE 0x00010000 +#endif + + .section .text.start + .global _start +_start: + + // SPI init + jal spi_init + jal spi_wakeup + + // Read from flash to SRAM + li a0, APP_SRAM_ADDR + li a1, APP_SIZE + li a2, APP_FLASH_ADDR + jal spi_flash_read + + // Setup reboot code + li t0, 0x0002006f + sw t0, 0(zero) + + // Jump to main code + j APP_SRAM_ADDR + + +// --------------------------------------------------------------------------- +// SB_SPI driver code +// --------------------------------------------------------------------------- + +// Register definitions + + .equ SPI_BASE, 0x81000000 + + .equ SPICR0, 4 * 0x08 + .equ SPICR1, 4 * 0x09 + .equ SPICR2, 4 * 0x0a + .equ SPIBR, 4 * 0x0b + .equ SPISR, 4 * 0x0c + .equ SPITXDR, 4 * 0x0d + .equ SPIRXDR, 4 * 0x0e + .equ SPICSR, 4 * 0x0f + + +// Initializes te SPI hardware +// +// Clobbers a0, a1 + +spi_init: + li a0, SPI_BASE + + li a1, 0xff + sw a1, SPICR0(a0) + + li a1, 0x80 + sw a1, SPICR1(a0) + + li a1, 0xc0 + sw a1, SPICR2(a0) + + li a1, 0x03 + sw a1, SPIBR(a0) + + li a1, 0x0f + sw a1, SPICSR(a0) + + ret + + +// +// Wake up flash +// +spi_wakeup: + + mv s2, ra + + // Setup CS + li t0, SPI_BASE + li t1, 0x0e + sw t1, SPICSR(t0) + + // Send command + li a0, 0xAB + jal _spi_do_one + + // Release CS + li t0, SPI_BASE + li t1, 0x0f + sw t1, SPICSR(t0) + + // Wait a bit + li s1, 0x10000 +1: + addi s1, s1, -1 + bne s1, zero, 1b + + // Done + jr s2 + + +// Reads a block of memory from SPI flash +// +// Params: +// a0 - destination pointer +// a1 - length (bytes) +// a2 - flash offset +// Clobbers t0, t1, s0, s1, s2 + +spi_flash_read: + // Save params + mv s0, a0 + mv s1, a1 + mv s2, ra + + // Setup CS + li t0, SPI_BASE + li t1, 0x0e + sw t1, SPICSR(t0) + + // Send command + li a0, 0x03 + jal _spi_do_one + + srli a0, a2, 16 + and a0, a0, 0xff + jal _spi_do_one + + srli a0, a2, 8 + and a0, a0, 0xff + jal _spi_do_one + + and a0, a2, 0xff + jal _spi_do_one + + // Read loop +_spi_loop: + li a0, 0x00 + jal _spi_do_one + sb a0, 0(s0) + addi s0, s0, 1 + addi s1, s1, -1 + bne s1, zero, _spi_loop + + // Release CS + li t0, SPI_BASE + li t1, 0x0f + sw t1, SPICSR(t0) + + // Done + jr s2 + + +// Performs a single 8 bit SPI xfer +// +// Params: a0 - Data to TX +// Returns: a0 - RX data +// Clobbers t0, t1 + +_spi_do_one: + li t0, SPI_BASE + li t1, 0x08 + + // Write TX data + sw a0, SPITXDR(t0) + + // Wait for RXRDY +1: + lw a0, SPISR(t0) + and a0, a0, t1 + bne a0, t1, 1b + + // Read RX data + lw a0, SPIRXDR(t0) + + // Done + ret diff --git a/firmware/boot/lnk-boot.lds b/firmware/boot/lnk-boot.lds new file mode 100644 index 0000000..7a0304f --- /dev/null +++ b/firmware/boot/lnk-boot.lds @@ -0,0 +1,14 @@ +MEMORY +{ + ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x0400 +} +ENTRY(_start) +SECTIONS { + .text : + { + . = ALIGN(4); + *(.text.start) + *(.text) + *(.text*) + } >ROM +}