Selaa lähdekoodia

ESP32 code for FPGA link; test code and fixes

Implement the ESP32 side of the FPGA link.

Fix byte ordering issue in esp.sv.

Link works, DIO at 40 MHz.
H. Peter Anvin 2 vuotta sitten
vanhempi
commit
1725fbb91d

+ 3 - 0
esp32/max80/fpga.h

@@ -6,3 +6,6 @@
 
 extern_c int fpga_program_spz(spz_stream *spz);
 extern_c int fpga_reset(void);
+
+extern_c int fpga_service_start(void);
+extern_c void fpga_service_stop(void);

+ 0 - 0
esp32/max80/fpga.c → esp32/max80/fpgajtag.c


+ 209 - 0
esp32/max80/fpgasvc.c

@@ -0,0 +1,209 @@
+#include "common.h"
+#include "config.h"
+#include "fpga.h"
+
+#include <driver/gpio.h>
+#include <driver/spi_common.h>
+#include <driver/spi_master.h>
+
+#define PIN_FPGA_INT	 9
+#define PIN_FPGA_CS	10
+#define PIN_FPGA_IO0	11
+#define PIN_FPGA_CLK	12
+#define PIN_FPGA_IO1	13
+
+#define FPGA_SPI_HOST	FSPI	/* SPI2 */
+
+#define FPGA_PRIORITY	3
+
+static spi_bus_config_t spi_bus_config = {
+    .data0_io_num    = PIN_FPGA_IO0,
+    .data1_io_num    = PIN_FPGA_IO1,
+    .sclk_io_num     = PIN_FPGA_CLK,
+    .data2_io_num    = -1,
+    .data3_io_num    = -1,
+    .data4_io_num    = -1,
+    .data5_io_num    = -1,
+    .data6_io_num    = -1,
+    .data7_io_num    = -1,
+    .max_transfer_sz = 4096,
+    .flags           = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_DUAL
+};
+
+static const spi_device_interface_config_t spi_device_interface_config = {
+    .command_bits     =  8,
+    .address_bits     = 32,
+    .dummy_bits       =  0,
+    .mode             =  0,
+    .cs_ena_pretrans  =  0,
+    .cs_ena_posttrans =  0,
+    .clock_speed_hz   = SPI_MASTER_FREQ_40M,
+    .spics_io_num     = PIN_FPGA_CS,
+    .flags            = SPI_DEVICE_HALFDUPLEX,
+    .queue_size       =  4	/* Maybe? */
+};
+
+static spi_device_handle_t spi_handle;
+static TaskHandle_t fpga_task;
+static SemaphoreHandle_t spi_mutex;
+
+#define NOTIFY_INDEX 0
+
+static void ARDUINO_ISR_ATTR fpga_interrupt(void)
+{
+    BaseType_t do_wakeup = pdFALSE;
+
+    if (!fpga_task)
+	return;
+
+    xTaskNotifyIndexedFromISR(fpga_task, NOTIFY_INDEX, 1, eSetBits, &do_wakeup);
+    if (do_wakeup)
+	portYIELD_FROM_ISR(do_wakeup);
+}
+
+static void fpga_service_task(void *);
+
+int fpga_service_start(void)
+{
+    esp_err_t err;
+
+    pinMode(PIN_FPGA_INT, INPUT_PULLUP);
+
+    if (!spi_mutex) {
+	spi_mutex = xSemaphoreCreateMutex();
+	if (!spi_mutex)
+	    goto failed;
+    }
+
+    xSemaphoreTake(spi_mutex, portMAX_DELAY);
+
+    err = spi_bus_initialize(FPGA_SPI_HOST, &spi_bus_config, SPI_DMA_CH_AUTO);
+    if (err)
+	goto failed;
+
+    err = spi_bus_add_device(FPGA_SPI_HOST, &spi_device_interface_config,
+			     &spi_handle);
+    if (err)
+	goto failed;
+
+    /* Only device on this bus, so acquire it permanently */
+    spi_device_acquire_bus(spi_handle, portMAX_DELAY);
+
+    xSemaphoreGive(spi_mutex);
+
+    if (!fpga_task) {
+	if (xTaskCreate(fpga_service_task, "fpga_svc", 4096, NULL,
+			FPGA_PRIORITY, &fpga_task) != pdPASS)
+	    goto failed;
+
+	attachInterrupt(PIN_FPGA_INT, fpga_interrupt, FALLING);
+	esp_register_shutdown_handler(fpga_service_stop);
+    }
+
+    /* All good! */
+    printf("[FPGA] FPGA services started\n");
+    return 0;
+
+failed:
+    printf("[FPGA] Failed to initialize FPGA SPI bus\n");
+    if (spi_mutex)
+	xSemaphoreGive(spi_mutex);
+
+    fpga_service_stop();
+    return -1;
+}
+
+void fpga_service_stop(void)
+{
+    if (spi_mutex) {
+	xSemaphoreTake(spi_mutex, portMAX_DELAY);
+
+	if (fpga_task) {
+	    esp_unregister_shutdown_handler(fpga_service_stop);
+	    detachInterrupt(PIN_FPGA_INT);
+	    vTaskDelete(fpga_task);
+	    fpga_task = NULL;
+	}
+
+	if (spi_handle) {
+	    spi_device_release_bus(spi_handle);
+	    spi_bus_remove_device(spi_handle);
+	    spi_bus_free(FPGA_SPI_HOST);
+	    spi_handle = NULL;
+	}
+
+	xSemaphoreGive(spi_mutex);
+    }
+    printf("[FPGA] FPGA services stopped\n");
+}
+
+#define FPGA_CMD_IRQ1	(1 << 0)
+#define FPGA_CMD_IRQ2	(2 << 0)
+#define FPGA_CMD_IRQ3	(3 << 0)
+#define FPGA_CMD_ACK1	(1 << 2)
+#define FPGA_CMD_ACK2	(2 << 2)
+#define FPGA_CMD_ACK3	(3 << 2)
+#define FPGA_CMD_WR	(0 << 4)
+#define FPGA_CMD_RD	(1 << 4)
+
+#define FPGA_HDR_ADDR	0x40000000
+
+static esp_err_t fpga_io(uint8_t cmd, uint32_t addr, void *data, size_t len)
+{
+    spi_transaction_ext_t trans;
+    esp_err_t err;
+
+    memset(&trans, 0, sizeof trans);
+    trans.base.flags   =
+	SPI_TRANS_MODE_DIO |
+	SPI_TRANS_VARIABLE_DUMMY |
+	SPI_TRANS_MULTILINE_CMD |
+	SPI_TRANS_MULTILINE_ADDR;
+    trans.command_bits =  8;
+    trans.address_bits = 32;
+
+    trans.base.cmd    = cmd;
+    trans.base.addr   = addr;
+    if (cmd & FPGA_CMD_RD) {
+	trans.dummy_bits     = 16; /* 16 cycles = 32 bits */
+	trans.base.rx_buffer = data;
+	trans.base.rxlength  = len << 3;
+    } else {
+	trans.base.tx_buffer = data;
+	trans.base.length    = len << 3;
+    }
+
+    xSemaphoreTake(spi_mutex, portMAX_DELAY);
+    err = spi_device_transmit(spi_handle, (spi_transaction_t *)&trans);
+    xSemaphoreGive(spi_mutex);
+
+    return err;
+}
+
+static void fpga_service_task(void *dummy)
+{
+    (void)dummy;
+    uint32_t head[8];
+
+    while (1) {
+	vTaskDelay(10 * configTICK_RATE_HZ);
+
+	fpga_io(FPGA_CMD_RD|FPGA_CMD_ACK1, FPGA_HDR_ADDR,
+		head, sizeof head);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(head); i++) {
+	    printf("[FPGA] head[%u] = 0x%08x (%u)\n",
+		   i, head[i], head[i]);
+	}
+    }
+
+    while (1) {
+	while (!digitalRead(PIN_FPGA_INT)) {
+	    printf("[FPGA] FPGA signals ready\n");
+
+	}
+
+	/* Wait until an interrupt is received */
+	xTaskNotifyWaitIndexed(NOTIFY_INDEX, 0, 1, NULL, portMAX_DELAY);
+    }
+}

+ 2 - 0
esp32/max80/fwupdate.c

@@ -332,6 +332,8 @@ int firmware_update(read_func_t read_data, token_t token)
 	return Z_MEM_ERROR;
     }
 
+    fpga_service_stop();
+
     spz->read_data = read_data;
     spz->token = token;
 

+ 4 - 2
esp32/max80/httpd.c

@@ -8,6 +8,8 @@
 #include <incbin.h>
 #include <unzipLIB.h>
 
+#define HTTPD_PRIORITY	4
+
 static httpd_handle_t httpd;
 static const char fallback_language[] = "en"; /* For unknown language */
 static const char redir_filename[] = "_redir"; /* For a directory "file" */
@@ -779,8 +781,8 @@ void my_httpd_start(void)
     if (httpd)
 	return;
 
-    config.task_priority    = 2;
-    config.max_open_sockets = 8;
+    config.task_priority    = HTTPD_PRIORITY;
+    config.max_open_sockets = 10;
 
     printf("[HTTP] Default stack size: %zu\n", config.stack_size);
     config.stack_size <<= 2;

+ 5 - 1
esp32/max80/max80.ino

@@ -28,6 +28,10 @@ static void dump_config()
 
 static void init_hw()
 {
+    // Start out with disabled shared I/O pins
+    for (int i = 1; i <= 18; i++)
+	pinMode(i, INPUT);
+
     // Configure USB power control
     pinMode(7, OUTPUT);		// USB_PWR_EN
     digitalWrite(7, 1);		// Disable power sourcing
@@ -47,7 +51,7 @@ void setup() {
     init_hw();
     init_config();
     SetupWiFi();
-    //fpga_services_start();
+    fpga_service_start();
     printf("[RDY]\n");
     dump_config();
     led_set(LED_BLUE, LED_ON);	// Software ready

+ 4 - 0
esp32/max80/spiflash.c

@@ -131,13 +131,17 @@ static int spiflash_wait_status(uint8_t mask, uint8_t val)
 	uint8_t sr1 = spiflash_read_status(ROM_READ_SR1);
 
 	if ((sr1 & mask) == val) {
+#if DEBUG > 1
 	    CMSG("ok\n");
+#endif
 	    return 0;
 	}
 
 	yield();
     }
+#if DEBUG > 1
     CMSG("timeout\n");
+#endif
     return -1;
 }
 

BIN
esp32/output/max80.ino.bin


+ 16 - 7
fpga/esp.sv

@@ -79,7 +79,7 @@ module esp (
 
    reg [ 4:0] spi_cmd;
    reg [31:0] spi_shr;
-   reg [15:0] spi_ctr;
+   reg [ 3:0] spi_ctr;
    reg [ 3:0] cpu_irq;
    reg [ 3:1] spi_irq;
    reg [ 1:0] spi_out;
@@ -97,10 +97,10 @@ module esp (
      if (~rst_n)
        begin
 	  spi_state <= st_cmd;
-	  spi_cmd   <= 5'b0;
+	  spi_cmd   <= 'b0;
 	  spi_ctr   <= 4'd3;	// 8 bits needed for this state
-	  cpu_irq   <= 3'b000;
-	  spi_irq   <= 3'b000;
+	  cpu_irq   <= 'b0;
+	  spi_irq   <= 'b0;
 	  spi_oe    <= 1'b0;
        end
      else
@@ -112,7 +112,7 @@ module esp (
 	       spi_state  <= st_cmd;
 	       spi_ctr    <= 4'd3;
 	       spi_oe     <= 1'b0;
-	       spi_cmd    <= 5'b0;
+	       spi_cmd    <= 'b0;
 	       for (int i = 1; i < 4; i++)
 		 if (spi_cmd[1:0] == i)
 		   cpu_irq[i] <= 1'b1;
@@ -127,8 +127,17 @@ module esp (
 		 end
 	       else
 		 begin
-		    spi_shr   <= mem_rdata;
-		    mem_wdata <= spi_indata;
+		    // Transfer data to/from memory controller, but
+		    // we have to shuffle endianness...
+		    spi_shr[31:24]   <= mem_rdata[ 7: 0];
+		    spi_shr[23:16]   <= mem_rdata[15: 8];
+		    spi_shr[15: 8]   <= mem_rdata[23:16];
+		    spi_shr[ 7: 0]   <= mem_rdata[31:24];
+
+		    mem_wdata[31:24] <= spi_indata[ 7: 0];
+		    mem_wdata[23:16] <= spi_indata[15: 8];
+		    mem_wdata[15: 8] <= spi_indata[23:16];
+		    mem_wdata[ 7: 0] <= spi_indata[31:24];
 
 		    if (mem_valid)
 		      cpu_irq[0] <= 1'b1; // Overrun/underrun

+ 3 - 3
fpga/max80.qpf

@@ -19,15 +19,15 @@
 #
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 02:50:13  May 01, 2022
+# Date created = 06:01:40  May 01, 2022
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "02:50:13  May 01, 2022"
+DATE = "06:01:40  May 01, 2022"
 
 # Revisions
 
-PROJECT_REVISION = "v1"
 PROJECT_REVISION = "v2"
+PROJECT_REVISION = "v1"
 PROJECT_REVISION = "bypass"

BIN
fpga/output/bypass.jic


BIN
fpga/output/bypass.rbf.gz


BIN
fpga/output/bypass.rpd.gz


BIN
fpga/output/bypass.sof


BIN
fpga/output/bypass.svf.gz


BIN
fpga/output/bypass.xsvf.gz


BIN
fpga/output/v1.fw


BIN
fpga/output/v1.jic


BIN
fpga/output/v1.rbf.gz


BIN
fpga/output/v1.rpd.gz


BIN
fpga/output/v1.sof


BIN
fpga/output/v1.svf.gz


BIN
fpga/output/v1.xsvf.gz


BIN
fpga/output/v2.fw


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.rbf.gz


BIN
fpga/output/v2.rpd.gz


BIN
fpga/output/v2.sof


BIN
fpga/output/v2.svf.gz


BIN
fpga/output/v2.xsvf.gz


+ 1 - 1
fpga/v2.qsf

@@ -210,4 +210,4 @@ set_global_assignment -name EDA_WRITE_NODES_FOR_POWER_ESTIMATION ALL_NODES -sect
 set_global_assignment -name EDA_TEST_BENCH_ENABLE_STATUS TEST_BENCH_MODE -section_id eda_simulation
 set_global_assignment -name EDA_NATIVELINK_SIMULATION_TEST_BENCH testclk -section_id eda_simulation
 set_global_assignment -name EDA_TEST_BENCH_DESIGN_INSTANCE_NAME max80 -section_id eda_simulation
-set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 1 - 1
rv32/checksum.h

@@ -1,4 +1,4 @@
 #ifndef CHECKSUM_H
 #define CHECKSUM_H
-#define SDRAM_SUM 0xd671717c
+#define SDRAM_SUM 0x77dade67
 #endif

+ 5 - 0
rv32/ioregs.h

@@ -152,6 +152,11 @@
 
 #define RANDOM_DATA		IODEVRL(RANDOM,0)
 
+#define ESP_CPU_IRQ		IODEVL(ESP,0)
+#define ESP_CPU_IRQ_CLR		IODEVL(ESP,1)
+#define ESP_SPI_IRQ		IODEVL(ESP,2)
+#define ESP_SPI_IRQ_SET		IODEVL(ESP,3)
+
 #define VJTAG_CPUCMD		IODEVRL(VJTAG,0)
 #define VJTAG_CPUINFO		IODEVL(VJTAG,1)
 #define VJTAG_CPUSTATUS		IODEVL(VJTAG,2)

+ 6 - 1
rv32/system.c

@@ -15,6 +15,7 @@ struct dram_io_head {
     size_t   hlen;
     void    *dptr;
     size_t   dlen;
+    uint32_t board;
 };
 struct dram_io_head __dram_io_head dram_io_head;
 
@@ -285,13 +286,17 @@ static void __noinline late_init(void)
     dram_io_head.hlen  = sizeof dram_io_head;
     dram_io_head.dptr  = dram_io;
     dram_io_head.dlen  = sizeof dram_io;
+    dram_io_head.board = SYS_BOARDCFG;
     dram_io_head.magic = DRAM_IO_MAGIC;
 
     static const char dram_io_test[] = "Hej tomtebuggar slå i glasen!";
     memcpy(dram_io_head.dptr, dram_io_test, sizeof dram_io_test);
- 
+
     /* Release WAIT# if asserted */
     ABC_BUSCTL = 0;
 
+    /* Let ESP know we are ready... */
+    ESP_SPI_IRQ_SET = (1 << 1);
+
     set_leds(0);
 }