diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 2379dbee2..e6765a59c 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -11,6 +11,7 @@ // This file is Copyright (c) 2018 Sergiusz Bazanski // This file is Copyright (c) 2016 Tim 'mithro' Ansell // This file is Copyright (c) 2020 Franck Jullien +// This file is Copyright (c) 2020 Antmicro // License: BSD @@ -43,6 +44,7 @@ #include "sdram.h" #include "sdcard.h" +#include "spi.h" #include "boot.h" #include "readline.h" #include "helpers.h" @@ -133,6 +135,9 @@ int main(int i, char **c) printf("Memory initialization failed\n"); printf("\n"); #endif +#ifdef CSR_SPI_BASE + spi_autoconfig(); +#endif if(sdr_ok) { printf("--============== \e[1mBoot\e[0m ==================--\n"); diff --git a/litex/soc/software/bios/spi.c b/litex/soc/software/bios/spi.c new file mode 100644 index 000000000..23b677c21 --- /dev/null +++ b/litex/soc/software/bios/spi.c @@ -0,0 +1,83 @@ +// This file is Copyright (c) 2020 Antmicro +// License: BSD + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "spi.h" + +#define DEBUG 0 +#define USER_DEFINED_DUMMY_BITS 0 + +static spi_mode spi_get_mode(void) +{ + return (spi_mode)spi_cfg_read(); +} + +static void spi_set_mode(spi_mode mode) +{ + spi_cfg_write((unsigned char)mode); +} + +int spi_frequency_test(void) +{ + unsigned int lowest_div = spi_clk_divisor_read(); + unsigned int crc = crc32((unsigned char *)SPIXIP_BASE, SPI_FLASH_BLOCK_SIZE); + unsigned int crc_test = crc; + +#if DEBUG + printf("Testing against CRC32: %08x\n\r", crc); +#endif + + if(spi_get_mode() != SPI_MODE_MMAP) { + spi_set_mode(SPI_MODE_MMAP); + } + + /* Check if block is erased (filled with 0xFF) */ + if(crc == CRC32_ERASED_FLASH) { + printf("Block of size %d, started on address 0x%x is erased. Cannot proceed with SPI frequency test.\n\r", SPI_FLASH_BLOCK_SIZE, SPIXIP_BASE); + return -1; + } + + for(int i = lowest_div; (crc == crc_test) && (i >= 0); i--) { + lowest_div = i; + spi_clk_divisor_write((uint32_t)i); + crc_test = crc32((unsigned char *)SPIXIP_BASE, SPI_FLASH_BLOCK_SIZE); +#if DEBUG + printf("[DIV: %d] %08x\n\r", i, crc_test); +#endif + } + lowest_div++; + printf("Maximum available frequency: %d Hz\n\r", (spi_sys_clk_freq_read()/(2*(1 + lowest_div)))); + + return lowest_div; +} + +void spi_dummy_bits_setup(unsigned int dummy_bits) +{ + spi_dummy_bits_write((uint32_t)dummy_bits); +#if DEBUG + printf("Dummy bits set to: %d\n\r", spi_dummy_bits_read()); +#endif +} + +void spi_autoconfig(void) +{ + int ret = spi_frequency_test(); + if(ret < 0) { + return; + } else { + spi_clk_divisor_write((uint32_t)ret); + } +#if (USER_DEFINED_DUMMY_BITS > 0) + spi_dummy_bits_setup(USER_DEFINED_DUMMY_BITS); +#endif +} + diff --git a/litex/soc/software/bios/spi.h b/litex/soc/software/bios/spi.h new file mode 100644 index 000000000..961aef0ca --- /dev/null +++ b/litex/soc/software/bios/spi.h @@ -0,0 +1,18 @@ +#ifndef __SPI_H +#define __SPI_H + +#include + +#define SPI_FLASH_BLOCK_SIZE 256 +#define CRC32_ERASED_FLASH 0xFEA8A821 + +typedef enum { + SPI_MODE_MMAP = 0, + SPI_MODE_MASTER = 1, +} spi_mode; + +int spi_frequency_test(void); +void spi_dummy_bits_setup(unsigned int dummy_bits); +void spi_autoconfig(void); + +#endif /* __SPI_H */