Patchwork Patch to add support for iCE40 FPGAs

login
register
about
Submitter Salvador Eduardo Tropea
Date 2016-04-11 13:31:56
Message ID <570BA74C.1010702@inti.gob.ar>
Download mbox | patch
Permalink /patch/4438/
State New
Headers show

Comments

Salvador Eduardo Tropea - 2016-04-11 13:31:56
Hi!

The following patch adds support to configure Lattice iCE40 FPGAs 
(formerly Silicon Blue parts). The support is to add support for the SPI 
flash memories attached to the FPGA.
iCE40 FPGAs read its configuration from an SPI memory.
This patch should support the HW-USBN-2B Lattice cable, but I used a 
generic FTDI FT2232 cable.
It works very well for the iCE40 Blink Evaluation Kit. This kit have an 
M25P10-A SPI flash.

Note that Lattice provides a tool for free, but I had problems with the 
command line version of the tool. Not to mention that the GUI version 
takes 1 minute, 6 seconds to configure the memory and flashrom 6 seconds ;-)

About the patch:
- The patch is for ft2232_spi.c file, it adds a new cable type to the 
ft2232_spi driver.
- The type is named ice40
- Lattice's cable used GPIOL0 as CS (named SS), for this reason the 
patch uses this pin.
- During the flash configuration the FPGA must in reset state. GPIOL3 
controls the RESET line (active low), this is the same line used by 
Lattice cable.
- Before even trying to detect a memory you must wake-up it. This is 
because the FPGA puts the memory to sleep. I know it sound a little bit 
crazy to send a command to a memory that you don't even know is there, 
but you can't detect it (read ID commands are ignored when the memory is 
in deep power down mode).
- At exit the patch puts the memory to sleep and disconnects the cable. 
This releases the reset and hence the FPGA boots from the memory. 
Ideally you should check if the FPGA successfully loaded the memory 
content. But for this you need to read the CDONE line, lamentably this 
line can't be accessed in the Blink kit.

Is this patch acceptable?

Regards, SET

Patch

Index: ft2232_spi.c
===================================================================
--- ft2232_spi.c	(revisión: 1955)
+++ ft2232_spi.c	(copia de trabajo)
@@ -102,6 +102,11 @@ 
 static uint8_t cs_bits = 0x08;
 static uint8_t pindir = 0x0b;
 static struct ftdi_context ftdic_context;
+/* SPI configuration memory for iCE40 FPGAs */
+static char ice40_mode = 0;
+/* iCE40 memory commands */
+#define RELEASE_FROM_POWER_DOWN 0xAB
+#define DEEP_POWER_DOWN         0xB9
 
 static const char *get_ft2232_devicename(int ft2232_vid, int ft2232_type)
 {
@@ -168,6 +173,28 @@ 
 	.write_aai	= default_spi_write_aai,
 };
 
+/* Put the data bits in the shutdown state. */
+static int ice40_deinit(void *ftdic)
+{
+	unsigned char buf[4];
+
+        /* Put the memory to sleep, saves power */
+	msg_pdbg("Memory power down\n");
+	buf[0] = DEEP_POWER_DOWN;
+	if (ft2232_spi_send_command(NULL,1,0,buf,NULL))
+		return -1;
+
+        /* Disconnect the cable to avoid contention */
+	msg_pdbg("Set data bits, cable disable\n");
+	buf[0] = SET_BITS_LOW;
+	buf[1] = 0;
+	buf[2] = 0; /* All inputs => HiZ */
+	if (send_buf((struct ftdi_context *)ftdic, buf, 3))
+		return -1;
+
+	return 0;
+}
+
 /* Returns 0 upon success, a negative number upon errors. */
 int ft2232_spi_init(void)
 {
@@ -273,6 +300,22 @@ 
 		} else if (!strcasecmp(arg, "google-servo-v2-legacy")) {
 			ft2232_vid = GOOGLE_VID;
 			ft2232_type = GOOGLE_SERVO_V2_PID0;
+		} else if (!strcasecmp(arg, "ice40")) {
+			/* HW-USBN-2B or generic FTDI cable */
+			ft2232_type = FTDI_FT2232H_PID;
+			channel_count = 2;
+			/* The IOL3 pin is used as system reset (needed to disable the FPGA)
+                        *      IOL0 pin is used instead of CS, called SS
+			*  value: 0x10  #RST=low, SS=high, DI=low, DO=low, SK=low
+			*    dir: 0x93  #RST=output, SS=output, DI=input, DO=output, SK=output */
+			cs_bits = 0x10;
+			pindir = 0x93;
+			ice40_mode = 1;
+			if (register_shutdown(ice40_deinit,ftdic)) {
+				msg_perr("Error: Unable to register shutdown sequence.\n");
+				return -9;
+			}
+
 		} else {
 			msg_perr("Error: Invalid device type specified.\n");
 			free(arg);
@@ -420,6 +463,14 @@ 
 
 	register_spi_master(&spi_master_ft2232);
 
+	/* iCE40 mode: memory wake-up */
+	if (ice40_mode) {
+		msg_pdbg("Memory wake-up\n");
+		buf[0] = RELEASE_FROM_POWER_DOWN;
+		if (ft2232_spi_send_command(NULL,1,0,buf,NULL))
+			msg_perr("Unable to send wake-up command.\n");
+	}
+
 	return 0;
 
 ftdi_err: