firmware: Import of the boot code

This is what gets embedded in the bitstream and loads the
main software from flash.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
Sylvain Munaut 2023-03-11 23:54:51 +01:00
parent c85dc29b06
commit f4ee67209b
3 changed files with 231 additions and 0 deletions

24
firmware/boot/Makefile Normal file
View File

@ -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

193
firmware/boot/boot.S Normal file
View File

@ -0,0 +1,193 @@
/*
* boot.S
*
* SPI boot code
*
* Copyright (C) 2020-2023 Sylvain Munaut <tnt@246tNt.com>
* 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

View File

@ -0,0 +1,14 @@
MEMORY
{
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x0400
}
ENTRY(_start)
SECTIONS {
.text :
{
. = ALIGN(4);
*(.text.start)
*(.text)
*(.text*)
} >ROM
}