add tercel speed-up but missing id for arty a7 at the moment
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 4 May 2022 11:44:33 +0000 (12:44 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 4 May 2022 12:03:33 +0000 (13:03 +0100)
coldboot/Makefile
coldboot/coldboot.c
coldboot/micron_n25q_flash.h [new file with mode: 0644]
coldboot/tercel.c [new file with mode: 0644]
coldboot/tercel_spi.h [new file with mode: 0644]
src/ls2.py

index 6b5d26f83ac9295117b8f98408ee1241aa9ad25e..da80dc807e9ba8e8b58da9bfecf435bb867fd388 100644 (file)
@@ -59,8 +59,10 @@ calibration.o: ../libgram/src/calibration.c
 powerpc.lds: powerpc.lds.S
        $(CC) $(CFLAGS) -P -E powerpc.lds.S -o powerpc.lds
 
-coldboot.elf: coldboot.o head.o ../lib/console.o $(GRAMOBJS) powerpc.lds
-       $(LD) $(LDFLAGS) -o $@ coldboot.o head.o ../lib/console.o $(GRAMOBJS)
+OBJS := coldboot.o tercel.o head.o ../lib/console.o $(GRAMOBJS)
+
+coldboot.elf: $(OBJS) powerpc.lds
+       $(LD) $(LDFLAGS) -o $@ $(OBJS)
 
 coldboot.bin: coldboot.elf
        $(OBJCOPY) -O binary $^ $@
index 6c7b8cccd20db70dc318c8875906aebed78f2b55..e5d97a1e3a34ae8e331d5e0628c7057276f42cee 100644 (file)
@@ -92,47 +92,8 @@ void isr(void) {
 
 }
 
-// WARNING
-// KESTREL SPECIFIC
-#define TERCEL_SPI_REG_SYS_PHY_CFG1     0x10
-#define TERCEL_SPI_REG_SYS_FLASH_CFG5       0x24
-#define TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK   0xff
-#define TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT  0
-#define TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK   0x1
-#define TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT  0
-static inline uint32_t read_tercel_register(uint8_t reg)
-{
-       return readl((unsigned long)(SPI_FCTRL_BASE+reg));
-}
-
-static inline void write_tercel_register(uint8_t reg, uint32_t value)
-{
-       writel(value, (unsigned long)(SPI_FCTRL_BASE+reg));
-}
-
-// TODO: need to use this
-// https://gitlab.raptorengineering.com/kestrel-collaboration/kestrel-firmware/bare-metal-firmware/-/blob/master/main.c#L2328
-
-/* this is a "level 1" speed-up, which gets an initial improvement of 10-50x
- * over the default speed (which is a scant 100 bytes per second).
- */
-static void crank_up_qspi_level1(void)
-{
-    // WARNING: KESTREL SPECIFIC
-    // Set SPI clock cycle divider to 1
-    uint32_t dword;
-    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
-    dword &= ~(TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK <<
-               TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT);
-    dword |= ((1 & TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK) <<
-                   TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT);
-    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
-    // Enable read merging
-    dword = read_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5);
-    dword |= (TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK <<
-              TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT);
-    write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5, dword);
-}
+extern void crank_up_qspi_level1(void);
+extern int host_spi_flash_init(void);
 
 static bool fl_read(void *dst, uint32_t offset, uint32_t size)
 {
@@ -270,6 +231,8 @@ int main(void) {
     if (ftr & SYS_REG_INFO_HAS_SPI_FLASH) {
         // speed up the QSPI to at least a sane level
         crank_up_qspi_level1();
+        // run at saner level
+        host_spi_flash_init();
 
         puts("SPI Offset: ");
         spi_offs = readl(SYSCON_BASE + SYS_REG_SPI_INFO);
@@ -299,7 +262,7 @@ int main(void) {
         //volatile uint8_t *qspi_bytes = (uint8_t*)spi_offs;
          // let's not, eh? writel(0xDEAF0123, (unsigned long)&(qspi[0]));
          // tmp = readl((unsigned long)&(qspi[0]));
-        for (int i=0;i<2;i++) {
+        for (int i=0;i<10;i++) {
           tmp = readl((unsigned long)&(qspi[i]));
           uart_writeuint32(tmp);
           puts(" ");
@@ -555,7 +518,8 @@ int main(void) {
         volatile uint32_t *mem = (uint32_t*)0x1000000;
         fl_read(mem,       // destination in RAM
                 0x600000,  // offset into QSPI
-                0x1000000); // length - shorter (testing) 0x8000); 
+                0x8000); // length - shorter (testing) 0x8000);
+                //0x1000000); // length 
         puts("dump mem\n");
         for (int i=0;i<256;i++) {
           tmp = readl((unsigned long)&(mem[i]));
diff --git a/coldboot/micron_n25q_flash.h b/coldboot/micron_n25q_flash.h
new file mode 100644 (file)
index 0000000..66712c8
--- /dev/null
@@ -0,0 +1,29 @@
+// © 2020 Raptor Engineering, LLC
+//
+// Released under the terms of the GPL v3
+// See the LICENSE file for full details
+
+uint32_t micron_n25q_spi_device_ids[] = { 0x20ba2010, 0x20ba2110 };
+
+const char *micron_n25q_spi_device_names[] = { "Micron N25Q 512Mb", "Micron N25Q 1024Mb" };
+
+#define MICRON_N25Q_SPI_FAST_READ_DUMMY_CLOCK_CYCLES 10
+
+#define MICRON_N25Q_SPI_3BA_SPI_READ_CMD 0x03
+#define MICRON_N25Q_SPI_4BA_SPI_READ_CMD 0x13
+
+// NOTE: QSPI mode unavailable for single read, use Write Disable command as plaecholder
+#define MICRON_N25Q_SPI_3BA_QSPI_READ_CMD 0x04
+#define MICRON_N25Q_SPI_4BA_QSPI_READ_CMD 0x04
+
+#define MICRON_N25Q_SPI_3BA_SPI_FAST_READ_CMD  0x0b
+#define MICRON_N25Q_SPI_4BA_SPI_FAST_READ_CMD  0x0c
+#define MICRON_N25Q_SPI_3BA_QSPI_FAST_READ_CMD 0xeb
+#define MICRON_N25Q_SPI_4BA_QSPI_FAST_READ_CMD 0xec
+
+// NOTE: The same command code is used for both QSPI 3BA and QSPI 4BA extended quad input writes, thus the device must be placed in either 3BA or 4BA mode prior
+// to issuing PAGE PROGRAM
+#define MICRON_N25Q_SPI_3BA_SPI_PAGE_PROGRAM_CMD  0x02
+#define MICRON_N25Q_SPI_4BA_SPI_PAGE_PROGRAM_CMD  0x12
+#define MICRON_N25Q_SPI_3BA_QSPI_PAGE_PROGRAM_CMD 0x38
+#define MICRON_N25Q_SPI_4BA_QSPI_PAGE_PROGRAM_CMD 0x38
diff --git a/coldboot/tercel.c b/coldboot/tercel.c
new file mode 100644 (file)
index 0000000..e17f763
--- /dev/null
@@ -0,0 +1,288 @@
+// Copyright (C) 2020 - 2021 Raptor Engineering, LLC
+//
+// Released under the terms of the GPL v3
+// See the LICENSE file for full details
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "console.h"
+#include "microwatt_soc.h"
+#include "io.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "micron_n25q_flash.h"
+#include "tercel_spi.h"
+
+#define ALLOW_SPI_QUAD_MODE 1
+
+static inline uint8_t read_tercel_reg8(uint8_t reg)
+{
+       return readb((unsigned long)(SPI_FCTRL_BASE+reg));
+}
+
+static inline void write_tercel_reg8(uint8_t reg, uint8_t value)
+{
+       writeb(value, (unsigned long)(SPI_FCTRL_BASE+reg));
+}
+
+static inline uint32_t read_tercel_register(uint8_t reg)
+{
+       return readl((unsigned long)(SPI_FCTRL_BASE+reg));
+}
+
+static inline void write_tercel_register(uint8_t reg, uint32_t value)
+{
+       writel(value, (unsigned long)(SPI_FCTRL_BASE+reg));
+}
+
+static uint32_t read_host_spi_flash_id(void)
+{
+    uint32_t flash_id = 0;
+
+    // Set user mode
+    write_tercel_register(TERCEL_SPI_REG_SYS_CORE_CTL1,
+                          read_tercel_register(TERCEL_SPI_REG_SYS_CORE_CTL1) |
+                              (TERCEL_SPI_ENABLE_USER_MODE_MASK << TERCEL_SPI_ENABLE_USER_MODE_SHIFT));
+
+    // Send Flash ID command
+    write_tercel_reg8(0, 0x9e);
+
+    // Read response
+    flash_id = (flash_id << 8) | read_tercel_reg8(0);
+    flash_id = (flash_id << 8) | read_tercel_reg8(0);
+    flash_id = (flash_id << 8) | read_tercel_reg8(0);
+    flash_id = (flash_id << 8) | read_tercel_reg8(0);
+
+    // Clear user mode
+    write_tercel_register(TERCEL_SPI_REG_SYS_CORE_CTL1,
+                          read_tercel_register(TERCEL_SPI_REG_SYS_CORE_CTL1) &
+                              ~(TERCEL_SPI_ENABLE_USER_MODE_MASK <<
+                              TERCEL_SPI_ENABLE_USER_MODE_SHIFT));
+
+    return flash_id;
+}
+
+
+/* this is a "level 1" speed-up, which gets an initial improvement of 10-50x
+ * over the default speed (which is a scant 100 bytes per second).
+ */
+void crank_up_qspi_level1(void)
+{
+    // WARNING: KESTREL SPECIFIC
+    // Set SPI clock cycle divider to 1
+    uint32_t dword;
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK <<
+               TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT);
+    dword |= ((1 & TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK) <<
+                   TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+    // Enable read merging
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5);
+    dword |= (TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK <<
+              TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5, dword);
+}
+
+extern void uart_writeuint32(uint32_t val);
+
+// level 2 speedup
+int host_spi_flash_init(void)
+{
+    int i;
+    uint32_t dword;
+    uint32_t flash_device_id;
+
+    if ((read_tercel_register(TERCEL_SPI_REG_DEVICE_ID_HIGH) !=
+                                TERCEL_SPI_DEVICE_ID_HIGH) ||
+        (read_tercel_register(TERCEL_SPI_REG_DEVICE_ID_LOW) !=
+                                TERCEL_SPI_DEVICE_ID_LOW))
+    {
+        return -1;
+    }
+
+    uint32_t tercel_version;
+    tercel_version = read_tercel_register(TERCEL_SPI_REG_DEVICE_VERSION);
+    puts("Raptor Tercel SPI master found, device version ");
+    uart_writeuint32((tercel_version >> TERCEL_SPI_VERSION_MAJOR_SHIFT) &
+                           TERCEL_SPI_VERSION_MAJOR_MASK);
+    uart_writeuint32((tercel_version >> TERCEL_SPI_VERSION_MINOR_SHIFT) &
+                           TERCEL_SPI_VERSION_MINOR_MASK);
+    uart_writeuint32((tercel_version >> TERCEL_SPI_VERSION_PATCH_SHIFT) &
+                           TERCEL_SPI_VERSION_PATCH_MASK);
+    puts("\n");
+
+    flash_device_id = read_host_spi_flash_id();
+    puts("Flash ID ");
+    uart_writeuint32(flash_device_id);
+    puts("\n");
+    for (i = 0; i < (sizeof(micron_n25q_spi_device_ids) /
+                     sizeof(micron_n25q_spi_device_ids[0])); i++)
+    {
+        if (flash_device_id == micron_n25q_spi_device_ids[i])
+        {
+            puts(micron_n25q_spi_device_names[i]);
+            puts(" Flash device detected, configuring\n");
+
+            // Set up Flash-specific commands
+            dword = 0;
+            dword |= (MICRON_N25Q_SPI_4BA_QSPI_READ_CMD
+                            & TERCEL_SPI_4BA_QSPI_CMD_MASK) <<
+                            TERCEL_SPI_4BA_QSPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_3BA_QSPI_READ_CMD
+                            & TERCEL_SPI_3BA_QSPI_CMD_MASK) <<
+                            TERCEL_SPI_3BA_QSPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_4BA_SPI_READ_CMD &
+                            TERCEL_SPI_4BA_SPI_CMD_MASK) <<
+                            TERCEL_SPI_4BA_SPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_3BA_SPI_READ_CMD &
+                            TERCEL_SPI_3BA_SPI_CMD_MASK) <<
+                            TERCEL_SPI_3BA_SPI_CMD_SHIFT;
+            write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG1, dword);
+
+            dword = 0;
+            dword |= (MICRON_N25Q_SPI_4BA_QSPI_FAST_READ_CMD
+                            & TERCEL_SPI_4BA_QSPI_CMD_MASK) <<
+                            TERCEL_SPI_4BA_QSPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_3BA_QSPI_FAST_READ_CMD
+                            & TERCEL_SPI_3BA_QSPI_CMD_MASK) <<
+                            TERCEL_SPI_3BA_QSPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_4BA_SPI_FAST_READ_CMD &
+                            TERCEL_SPI_4BA_SPI_CMD_MASK) <<
+                            TERCEL_SPI_4BA_SPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_3BA_SPI_FAST_READ_CMD &
+                            TERCEL_SPI_3BA_SPI_CMD_MASK) <<
+                            TERCEL_SPI_3BA_SPI_CMD_SHIFT;
+            write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG2, dword);
+
+            dword = 0;
+            dword |= (MICRON_N25Q_SPI_4BA_QSPI_PAGE_PROGRAM_CMD
+                            & TERCEL_SPI_4BA_QSPI_CMD_MASK) <<
+                            TERCEL_SPI_4BA_QSPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_3BA_QSPI_PAGE_PROGRAM_CMD
+                            & TERCEL_SPI_3BA_QSPI_CMD_MASK) <<
+                            TERCEL_SPI_3BA_QSPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_4BA_SPI_PAGE_PROGRAM_CMD &
+                            TERCEL_SPI_4BA_SPI_CMD_MASK) <<
+                            TERCEL_SPI_4BA_SPI_CMD_SHIFT;
+            dword |= (MICRON_N25Q_SPI_3BA_SPI_PAGE_PROGRAM_CMD &
+                            TERCEL_SPI_3BA_SPI_CMD_MASK) <<
+                            TERCEL_SPI_3BA_SPI_CMD_SHIFT;
+            write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG3, dword);
+
+            // Enable extended QSPI read/write operations
+            dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+            dword |= TERCEL_SPI_PHY_QSPI_EXT_READ_EN_MASK <<
+                                TERCEL_SPI_PHY_QSPI_EXT_READ_EN_SHIFT;
+            dword |= TERCEL_SPI_PHY_QSPI_EXT_WRITE_EN_MASK <<
+                                TERCEL_SPI_PHY_QSPI_EXT_WRITE_EN_SHIFT;
+            write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+
+            break;
+        }
+    }
+
+    // Set SPI core to automatic mode
+    write_tercel_register(TERCEL_SPI_REG_SYS_CORE_CTL1,
+                          read_tercel_register(TERCEL_SPI_REG_SYS_CORE_CTL1) &
+                              ~(TERCEL_SPI_ENABLE_USER_MODE_MASK <<
+                              TERCEL_SPI_ENABLE_USER_MODE_SHIFT));
+
+    // Set extra CS delay cycle count to 0
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_MASK <<
+                    TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_SHIFT);
+    dword |= ((0 & TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_MASK) <<
+                    TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+
+    // Set maximum CS assert cycle count to 10000
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG4);
+    dword &= ~(TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_MASK <<
+                TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_SHIFT);
+    dword |= ((10000 & TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_MASK) <<
+                TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG4, dword);
+
+    // Set SPI fast read dummy cycles to
+    // MICRON_N25Q_SPI_FAST_READ_DUMMY_CLOCK_CYCLES
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_DUMMY_CYCLES_MASK <<
+                    TERCEL_SPI_PHY_DUMMY_CYCLES_SHIFT);
+    dword |= ((MICRON_N25Q_SPI_FAST_READ_DUMMY_CLOCK_CYCLES
+                    & TERCEL_SPI_PHY_DUMMY_CYCLES_MASK) <<
+                    TERCEL_SPI_PHY_DUMMY_CYCLES_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+
+    // Enable SPI fast read functionality
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_FAST_READ_ENABLE_MASK <<
+                    TERCEL_SPI_PHY_FAST_READ_ENABLE_SHIFT);
+    dword |= ((1 & TERCEL_SPI_PHY_FAST_READ_ENABLE_MASK) <<
+                TERCEL_SPI_PHY_FAST_READ_ENABLE_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+
+    // Set SPI controller to 4BA mode
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_4BA_ENABLE_MASK <<
+                TERCEL_SPI_PHY_4BA_ENABLE_SHIFT);
+    dword |= ((TERCEL_SPI_PHY_4BA_MODE & TERCEL_SPI_PHY_4BA_ENABLE_MASK)
+                << TERCEL_SPI_PHY_4BA_ENABLE_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+
+#if (ALLOW_SPI_QUAD_MODE)
+    // Set SPI controller to QSPI mode
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_IO_TYPE_MASK << TERCEL_SPI_PHY_IO_TYPE_SHIFT);
+    dword |= ((TERCEL_SPI_PHY_IO_TYPE_QUAD & TERCEL_SPI_PHY_IO_TYPE_MASK)
+                    << TERCEL_SPI_PHY_IO_TYPE_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+#endif
+
+    // Set SPI clock cycle divider to 5
+    dword = read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1);
+    dword &= ~(TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK <<
+                TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT);
+    dword |= ((5 & TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK) <<
+                TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT);
+    write_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
+
+    // Calculate and dump configured SPI clock speed
+    uint8_t spi_divisor =
+        (read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1)
+        >> TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT) &
+        TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK;
+    spi_divisor = (spi_divisor + 1) * 2;
+    uint8_t spi_dummy_cycles =
+        (read_tercel_register(TERCEL_SPI_REG_SYS_PHY_CFG1)
+        >> TERCEL_SPI_PHY_DUMMY_CYCLES_SHIFT) &
+        TERCEL_SPI_PHY_DUMMY_CYCLES_MASK;
+    puts("Flash controller frequency ");
+    uart_writeuint32((read_tercel_register(TERCEL_SPI_REG_SYS_CLK_FREQ) /
+           spi_divisor) / 1000000);
+    puts("\nbus frequency ");
+    uart_writeuint32(read_tercel_register(TERCEL_SPI_REG_SYS_CLK_FREQ) / 
+                     1000000);
+    puts("\ndummy cycles");
+    uart_writeuint32(spi_dummy_cycles);
+    puts("\n");
+
+    // Enable read merging
+    write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5,
+                          read_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5) |
+                              (TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK <<
+                              TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT));
+
+    // Enable write merging
+    write_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5,
+                          read_tercel_register(TERCEL_SPI_REG_SYS_FLASH_CFG5)
+                          |
+                              (TERCEL_SPI_FLASH_EN_MULTCYC_WRITE_MASK <<
+                              TERCEL_SPI_FLASH_EN_MULTCYC_WRITE_SHIFT));
+
+    return 0;
+}
+
diff --git a/coldboot/tercel_spi.h b/coldboot/tercel_spi.h
new file mode 100644 (file)
index 0000000..bd4a9d5
--- /dev/null
@@ -0,0 +1,68 @@
+// © 2020 Raptor Engineering, LLC
+//
+// Released under the terms of the GPL v3
+// See the LICENSE file for full details
+
+#define TERCEL_SPI_REG_DEVICE_ID_HIGH 0x0
+#define TERCEL_SPI_REG_DEVICE_ID_LOW  0x4
+#define TERCEL_SPI_REG_DEVICE_VERSION 0x8
+#define TERCEL_SPI_REG_SYS_CLK_FREQ   0xc
+#define TERCEL_SPI_REG_SYS_PHY_CFG1   0x10
+#define TERCEL_SPI_REG_SYS_FLASH_CFG1 0x14
+#define TERCEL_SPI_REG_SYS_FLASH_CFG2 0x18
+#define TERCEL_SPI_REG_SYS_FLASH_CFG3 0x1c
+#define TERCEL_SPI_REG_SYS_FLASH_CFG4 0x20
+#define TERCEL_SPI_REG_SYS_FLASH_CFG5 0x24
+#define TERCEL_SPI_REG_SYS_CORE_CTL1  0x28
+#define TERCEL_SPI_REG_SYS_CORE_DATA1 0x2c
+
+#define TERCEL_SPI_DEVICE_ID_HIGH 0x7c525054
+#define TERCEL_SPI_DEVICE_ID_LOW  0x5350494d
+
+#define TERCEL_SPI_VERSION_MAJOR_MASK  0xffff
+#define TERCEL_SPI_VERSION_MAJOR_SHIFT 16
+#define TERCEL_SPI_VERSION_MINOR_MASK  0xff
+#define TERCEL_SPI_VERSION_MINOR_SHIFT 8
+#define TERCEL_SPI_VERSION_PATCH_MASK  0xff
+#define TERCEL_SPI_VERSION_PATCH_SHIFT 0
+
+#define TERCEL_SPI_ENABLE_USER_MODE_MASK        0x1
+#define TERCEL_SPI_ENABLE_USER_MODE_SHIFT       0x0
+#define TERCEL_SPI_PHY_DUMMY_CYCLES_MASK        0xff
+#define TERCEL_SPI_PHY_DUMMY_CYCLES_SHIFT       8
+#define TERCEL_SPI_PHY_CLOCK_DIVISOR_MASK       0xff
+#define TERCEL_SPI_PHY_CLOCK_DIVISOR_SHIFT      0
+#define TERCEL_SPI_PHY_IO_TYPE_MASK             0x3
+#define TERCEL_SPI_PHY_IO_TYPE_SHIFT            16
+#define TERCEL_SPI_PHY_4BA_ENABLE_MASK          0x1
+#define TERCEL_SPI_PHY_4BA_ENABLE_SHIFT         18
+#define TERCEL_SPI_PHY_FAST_READ_ENABLE_MASK    0x1
+#define TERCEL_SPI_PHY_FAST_READ_ENABLE_SHIFT   19
+#define TERCEL_SPI_PHY_QSPI_EXT_READ_EN_MASK    0x1
+#define TERCEL_SPI_PHY_QSPI_EXT_READ_EN_SHIFT   20
+#define TERCEL_SPI_PHY_QSPI_EXT_WRITE_EN_MASK   0x1
+#define TERCEL_SPI_PHY_QSPI_EXT_WRITE_EN_SHIFT  21
+#define TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_MASK   0xff
+#define TERCEL_SPI_PHY_CS_EXTRA_IDLE_CYC_SHIFT  24
+#define TERCEL_SPI_FLASH_EN_MULTCYC_WRITE_MASK  0x1
+#define TERCEL_SPI_FLASH_EN_MULTCYC_WRITE_SHIFT 1
+#define TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK   0x1
+#define TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT  0
+#define TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_MASK   0xffffffff
+#define TERCEL_SPI_FLASH_CS_EN_LIMIT_CYC_SHIFT  0
+
+#define TERCEL_SPI_3BA_SPI_CMD_MASK   0xff
+#define TERCEL_SPI_3BA_SPI_CMD_SHIFT  0
+#define TERCEL_SPI_4BA_SPI_CMD_MASK   0xff
+#define TERCEL_SPI_4BA_SPI_CMD_SHIFT  8
+#define TERCEL_SPI_3BA_QSPI_CMD_MASK  0xff
+#define TERCEL_SPI_3BA_QSPI_CMD_SHIFT 16
+#define TERCEL_SPI_4BA_QSPI_CMD_MASK  0xff
+#define TERCEL_SPI_4BA_QSPI_CMD_SHIFT 24
+
+#define TERCEL_SPI_PHY_IO_TYPE_SINGLE 0x0
+#define TERCEL_SPI_PHY_IO_TYPE_QUAD   0x2
+
+#define TERCEL_SPI_PHY_3BA_MODE 0x0
+#define TERCEL_SPI_PHY_4BA_MODE 0x1
+
index 53c379252f4f6d64db3d329704652b4b0c7cc3e6..db1cf375388b198132276e7664100836e7f8f6fa 100644 (file)
@@ -871,7 +871,7 @@ def build_platform(fpga, firmware):
         clk_freq = 50e6
         dram_clk_freq = 100e6
     if fpga == 'arty_a7':
-        clk_freq = 24e6 # urrr "working" with the QSPI core (25 mhz does not)
+        clk_freq = 23.0e6 # urrr "working" with the QSPI core (25 mhz does not)
     if fpga == 'ulx3s':
         clk_freq = 40.0e6
     if fpga == 'orangecrab':
@@ -1104,6 +1104,10 @@ def build_platform(fpga, firmware):
         #os.environ['NMIGEN_synth_opts'] = '-abc9'
         os.environ['NMIGEN_synth_opts'] = '-nowidelut'
 
+    if toolchain == 'yosys_nextpnr':
+        # add --seed 2 to arty a7 compile-time options
+        os.environ['NMIGEN_nextpnr_opts'] = '--seed 6'
+
     if platform is not None:
         # build and upload it
         if fpga == 'isim':