/* * boot.S * * Boot code * * Copyright (C) 2020-2022 Sylvain Munaut * 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