gateware: Initial import of all common parts

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/gateware/common/fw/.gitignore b/gateware/common/fw/.gitignore
new file mode 100644
index 0000000..03515f6
--- /dev/null
+++ b/gateware/common/fw/.gitignore
@@ -0,0 +1,3 @@
+*.elf
+*.bin
+*.hex
diff --git a/gateware/common/fw/Makefile b/gateware/common/fw/Makefile
new file mode 100644
index 0000000..3fef9a5
--- /dev/null
+++ b/gateware/common/fw/Makefile
@@ -0,0 +1,22 @@
+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
+
+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
+	./bin2hex.py $< $@
+
+clean:
+	rm -f *.bin *.hex *.elf *.o
+
+.PHONY: clean
diff --git a/gateware/common/fw/bin2hex.py b/gateware/common/fw/bin2hex.py
new file mode 100755
index 0000000..43ba263
--- /dev/null
+++ b/gateware/common/fw/bin2hex.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+#
+# Converts binary into something that can be used by `readmemh`
+#
+# Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
+# SPDX-License-Identifier: MIT
+#
+
+import struct
+import sys
+
+
+def main(argv0, in_name, out_name):
+	with open(in_name, 'rb') as in_fh, open(out_name, 'w') as out_fh:
+		while True:
+			b = in_fh.read(4)
+			if len(b) < 4:
+				break
+			out_fh.write('%08x\n' % struct.unpack('<I', b))
+
+if __name__ == '__main__':
+	main(*sys.argv)
diff --git a/gateware/common/fw/boot.S b/gateware/common/fw/boot.S
new file mode 100644
index 0000000..df4f41b
--- /dev/null
+++ b/gateware/common/fw/boot.S
@@ -0,0 +1,144 @@
+/*
+ * boot.S
+ *
+ * SPI boot code
+ *
+ * Copyright (C) 2020 Sylvain Munaut <tnt@246tNt.com>
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef APP_FLASH_ADDR
+#define APP_FLASH_ADDR 0x00100000
+#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
+
+	// 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
+
+
+	.equ    SPI_BASE, 0x80000000
+	.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
+
+
+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
+
+
+// Params:
+//  a0 - destination pointer
+//  a1 - length (bytes)
+//  a2 - flash offset
+//
+
+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
+
+
+// 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/gateware/common/fw/lnk-boot.lds b/gateware/common/fw/lnk-boot.lds
new file mode 100644
index 0000000..7a0304f
--- /dev/null
+++ b/gateware/common/fw/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
+}