soc/software/bios: add autoconfiguration functionality for LiteSPI core
authorJan Kowalewski <jkowalewski@antmicro.com>
Fri, 15 May 2020 14:41:15 +0000 (16:41 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 20 May 2020 07:16:07 +0000 (09:16 +0200)
litex/soc/software/bios/main.c
litex/soc/software/bios/spi.c [new file with mode: 0644]
litex/soc/software/bios/spi.h [new file with mode: 0644]

index 2379dbee26a9dc0bad5bfe1cd86f32f4043cb419..e6765a59ccc3a86efe145fac39285670e2313432 100644 (file)
@@ -11,6 +11,7 @@
 // This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
 // This file is Copyright (c) 2016 Tim 'mithro' Ansell <mithro@mithis.com>
 // This file is Copyright (c) 2020 Franck Jullien <franck.jullien@gmail.com>
+// This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
 
 // 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 (file)
index 0000000..23b677c
--- /dev/null
@@ -0,0 +1,83 @@
+// This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
+// License: BSD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <crc.h>
+
+#include <generated/csr.h>
+#include <generated/mem.h>
+#include <hw/flags.h>
+#include <system.h>
+
+#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 (file)
index 0000000..961aef0
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __SPI_H
+#define __SPI_H
+
+#include <generated/csr.h>
+
+#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 */