/*
 * boot.S
 *
 * Boot code
 *
 * Copyright (C) 2020-2022 Sylvain Munaut <tnt@246tNt.com>
 * SPDX-License-Identifier: MIT
 */

// #define BOOT_DEBUG
// (also set UART_DIV for the board below !)

#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

	.equ	UART_BASE, 0x81000000
	.equ	UART_DIV, 22	// 24 MHz / (22+2) ~= 1 Mbaud

	.section .text.start
	.global _start
_start:
	// Debug
#ifdef BOOT_DEBUG
	// Set UART divisor
	li	a0, UART_BASE
	li	a1, UART_DIV
	sw	a1, 4(a0)

	// Output 'a'
	li	a1, 97
	sw	a1, 0(a0)
#endif

	// SPI init
	jal	spi_init

	// Debug
#ifdef BOOT_DEBUG
	// Output 'b'
	li	a0, UART_BASE
	li	a1, 98
	sw	a1, 0(a0)
#endif

	// Load 64k from flash to SPRAM
	li	a0, APP_SRAM_ADDR
	li	a1, APP_FLASH_ADDR
	li	a2, APP_SIZE
	jal	spi_load

	// Debug
#ifdef BOOT_DEBUG
	// Output 'c'
	li	a0, UART_BASE
	li	a1, 99
	sw	a1, 0(a0)
#endif

	// Jump to main code in SPRAM
	j	APP_SRAM_ADDR


// ---------------------------------------------------------------------------
// SPI
// ---------------------------------------------------------------------------

	.equ    SPI_BASE, 0x83000000
	.equ    SPI_CSR,  4 * 0x00
	.equ	SPI_RF,   4 * 0x03


spi_init:

	li	t5, SPI_BASE

	// PSRAM init
	// ----------

	// Request external control
	li	t0, 0x00000012
	sw	t0, SPI_CSR(t5)

	// Enable QSPI (0x35)
	li	t0, 0x35000000
	sw	t0, 0x40(t5)

	// Read and discard response
	lw	t0, SPI_RF(t5)

	// Common tail
	j	_spi_done



//
// a0	Destination address in memory
// a1	Source address in flash
// a2	Length
//
// 35:34 0 - SPI
//       1 - QPI_RD
//       2 - QPI_WR
//       3 - QPI_CMD
// 33:32 len

#define _SPI		0
#define _QPI_RD		1
#define _QPI_WR		2
#define _QPI_CMD	3

#define SPI_CMD(c,l) (0x40 | ((c) << 4) | (((l)-1) << 2))

spi_load:
	// Prepare accesses
	li	t5, SPI_BASE

	// Request external control
	li	t0, 0x00000002
	sw	t0, SPI_CSR(t5)

	// Issue SPI fast-read command
	li	t0, 0x0b000000
	or	t0, t0, a1
	sw	t0, SPI_CMD(_SPI, 4)(t5)
	lw	t0, SPI_RF(t5)

	// Skip dummy cycles
	sw	zero, SPI_CMD(_SPI, 1)(t5)
	lw	zero, SPI_RF(t5)

	// Read loop
1:
		// Read a word
	sw	zero, SPI_CMD(_SPI, 4)(t5)
	lw	t0, SPI_RF(t5)

		// Endian swap
	slli	t1, t0, 24
	srli	t2, t0, 24
	or	t1, t1, t2
	li	t3, 0xff0000
	and	t2, t0, t3
	srli	t2, t2, 8
	or	t1, t1, t2
	slli	t2, t0, 8
	and	t2, t2, t3
	or	t1, t1, t2

		// Store it
	sw	t1, 0(a0)
	addi	a0, a0, 4

		// Done ?
	addi	a2, a2, -4
	blt	zero, a2, 1b

_spi_done:
	// Release external control
	li	t0, 0x00000004
	sw	t0, SPI_CSR(t5)

	// Wait for release
1:
	lw	t0, SPI_CSR(t5)
	andi	t0, t0, 4
	bne	t0, zero, 1b

	// Return
	ret
