diff options
| author | Clifford Wolf <clifford@clifford.at> | 2018-08-19 15:21:18 +0200 | 
|---|---|---|
| committer | Clifford Wolf <clifford@clifford.at> | 2018-08-19 15:21:18 +0200 | 
| commit | c02a4000f4cef8d4d9e76757f55ea4920667e1e8 (patch) | |
| tree | 8a35c5f91d7881d1ca49848314d36ab16f169457 /iceprog | |
| parent | 7e732889f0dfa7b8b8d6aaf91133d6819018d07e (diff) | |
| parent | 22e8b744dace15be42459ab00f5f140aa5368786 (diff) | |
| download | icestorm-c02a4000f4cef8d4d9e76757f55ea4920667e1e8.tar.gz icestorm-c02a4000f4cef8d4d9e76757f55ea4920667e1e8.tar.bz2 icestorm-c02a4000f4cef8d4d9e76757f55ea4920667e1e8.zip | |
Merge branch 'esden-iceprog-work'
Diffstat (limited to 'iceprog')
| -rw-r--r-- | iceprog/iceprog.c | 301 | 
1 files changed, 243 insertions, 58 deletions
| diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c index 29d4c22..550a23d 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c @@ -2,6 +2,7 @@   *  iceprog -- simple programming tool for FTDI-based Lattice iCE programmers   *   *  Copyright (C) 2015  Clifford Wolf <clifford@clifford.at> + *  Copyright (C) 2018  Piotr Esden-Tempski <piotr@esden.net>   *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above @@ -36,6 +37,23 @@  #include <sys/types.h>  #include <sys/stat.h> +// --------------------------------------------------------- +// MPSSE / FTDI definitions +// --------------------------------------------------------- + +/* FTDI bank pinout typically used for iCE dev boards + * BUS IO | Signal | Control + * -------+--------+-------------- + * xDBUS0 |    SCK | MPSSE + * xDBUS1 |   MOSI | MPSSE + * xDBUS2 |   MISO | MPSSE + * xDBUS3 |     nc | + * xDBUS4 |     CS | GPIO + * xDBUS5 |     nc | + * xDBUS6 |  CDONE | GPIO + * xDBUS7 | CRESET | GPIO + */ +  static struct ftdi_context ftdic;  static bool ftdic_open = false;  static bool verbose = false; @@ -76,6 +94,10 @@ enum mpsse_cmd  	MC_CPU_WE = 0x93, /* CPUMode write extended address */  }; +// --------------------------------------------------------- +// FLASH definitions +// --------------------------------------------------------- +  /* Transfer Command bits */  /* All byte based commands consist of: @@ -146,6 +168,7 @@ enum flash_cmd {  	FC_GBL = 0x7E, /* Global Block Lock */  	FC_GBU = 0x98, /* Global Block Unlock */  	FC_RBL = 0x3D, /* Read Block Lock */ +	FC_RPR = 0x3C, /* Read Sector Protection Registers (adesto) */  	FC_IBL = 0x36, /* Individual Block Lock */  	FC_IBU = 0x39, /* Individual Block Unlock */  	FC_EPS = 0x75, /* Erase / Program Suspend */ @@ -156,6 +179,10 @@ enum flash_cmd {  	FC_RESET = 0x99, /* Reset Device */  }; +// --------------------------------------------------------- +// MPSSE / FTDI function implementations +// --------------------------------------------------------- +  static void check_rx()  {  	while (1) { @@ -270,17 +297,83 @@ static int get_cdone()  	return (data & 0x40) != 0;  } -static void flash_read_id() +// --------------------------------------------------------- +// FLASH function implementations +// --------------------------------------------------------- + +// the FPGA reset is released so also FLASH chip select should be deasserted +static void flash_release_reset()  { -	// fprintf(stderr, "read flash ID..\n"); +	set_gpio(1, 1); +} -	uint8_t data[21] = { FC_JEDECID }; +// FLASH chip select assert +// should only happen while FPGA reset is asserted +static void flash_chip_select() +{  	set_gpio(0, 0); -	xfer_spi(data, 21); +} + +// FLASH chip select deassert +static void flash_chip_deselect() +{  	set_gpio(1, 0); +} + +// SRAM reset is the same as flash_chip_select() +// For ease of code reading we use this function instead +static void sram_reset() +{ +	// Asserting chip select and reset lines +	set_gpio(0, 0); +} + +// SRAM chip select assert +// When accessing FPGA SRAM the reset should be released +static void sram_chip_select() +{ +	set_gpio(0, 1); +} +static void flash_read_id() +{ +	/* JEDEC ID structure: +	 * Byte No. | Data Type +	 * ---------+---------- +	 *        0 | FC_JEDECID Request Command +	 *        1 | MFG ID +	 *        2 | Dev ID 1 +	 *        3 | Dev ID 2 +	 *        4 | Ext Dev Str Len +	 */ + +	uint8_t data[260] = { FC_JEDECID }; +	int len = 5; // command + 4 response bytes + +	if (verbose) +		fprintf(stderr, "read flash ID..\n"); + +	flash_chip_select(); + +	// Write command and read first 4 bytes +	xfer_spi(data, len); + +	if (data[4] == 0xFF) +		fprintf(stderr, "Extended Device String Length is 0xFF, " +				"this is likely a read error. Ignorig...\n"); +	else { +		// Read extended JEDEC ID bytes +		if (data[4] != 0) { +			len += data[4]; +			xfer_spi(data + 5, len - 5); +		} +	} + +	flash_chip_deselect(); + +	// TODO: Add full decode of the JEDEC ID.  	fprintf(stderr, "flash ID:"); -	for (int i = 1; i < 21; i++) +	for (int i = 1; i < len; i++)  		fprintf(stderr, " 0x%02X", data[i]);  	fprintf(stderr, "\n");  } @@ -288,28 +381,94 @@ static void flash_read_id()  static void flash_power_up()  {  	uint8_t data[1] = { FC_RPD }; -	set_gpio(0, 0); +	flash_chip_select();  	xfer_spi(data, 1); -	set_gpio(1, 0); +	flash_chip_deselect();  }  static void flash_power_down()  {  	uint8_t data[1] = { FC_PD }; -	set_gpio(0, 0); +	flash_chip_select();  	xfer_spi(data, 1); -	set_gpio(1, 0); +	flash_chip_deselect(); +} + +static uint8_t flash_read_status() +{ +	uint8_t data[2] = { FC_RSR1 }; + +	flash_chip_select(); +	xfer_spi(data, 2); +	flash_chip_deselect(); + +	if (verbose) { +		fprintf(stderr, "SR1: 0x%02X\n", data[1]); +		fprintf(stderr, " - SPRL: %s\n", +			((data[1] & (1 << 7)) == 0) ?  +				"unlocked" :  +				"locked"); +		fprintf(stderr, " -  SPM: %s\n", +			((data[1] & (1 << 6)) == 0) ? +				"Byte/Page Prog Mode" : +				"Sequential Prog Mode"); +		fprintf(stderr, " -  EPE: %s\n", +			((data[1] & (1 << 5)) == 0) ? +				"Erase/Prog success" : +				"Erase/Prog error"); +		fprintf(stderr, "-  SPM: %s\n", +			((data[1] & (1 << 4)) == 0) ? +				"~WP asserted" : +				"~WP deasserted"); +		fprintf(stderr, " -  SWP: "); +		switch((data[1] >> 2) & 0x3) { +			case 0: +				fprintf(stderr, "All sectors unprotected\n"); +				break; +			case 1: +				fprintf(stderr, "Some sectors protected\n"); +				break; +			case 2: +				fprintf(stderr, "Reserved (xxxx 10xx)\n"); +				break; +			case 3: +				fprintf(stderr, "All sectors protected\n"); +				break; +		} +		fprintf(stderr, " -  WEL: %s\n", +			((data[1] & (1 << 1)) == 0) ? +				"Not write enabled" : +				"Write enabled"); +		fprintf(stderr, " - ~RDY: %s\n", +			((data[1] & (1 << 0)) == 0) ? +				"Ready" : +				"Busy"); +	} + +	usleep(1000); + +	return data[1];  }  static void flash_write_enable()  { +	if (verbose) { +		fprintf(stderr, "status before enable:\n"); +		flash_read_status(); +	} +  	if (verbose)  		fprintf(stderr, "write enable..\n");  	uint8_t data[1] = { FC_WE }; -	set_gpio(0, 0); +	flash_chip_select();  	xfer_spi(data, 1); -	set_gpio(1, 0); +	flash_chip_deselect(); + +	if (verbose) { +		fprintf(stderr, "status after enable:\n"); +		flash_read_status(); +	}  }  static void flash_bulk_erase() @@ -317,9 +476,9 @@ static void flash_bulk_erase()  	fprintf(stderr, "bulk erase..\n");  	uint8_t data[1] = { FC_CE }; -	set_gpio(0, 0); +	flash_chip_select();  	xfer_spi(data, 1); -	set_gpio(1, 0); +	flash_chip_deselect();  }  static void flash_64kB_sector_erase(int addr) @@ -328,9 +487,9 @@ static void flash_64kB_sector_erase(int addr)  	uint8_t command[4] = { FC_BE64, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; -	set_gpio(0, 0); +	flash_chip_select();  	send_spi(command, 4); -	set_gpio(1, 0); +	flash_chip_deselect();  }  static void flash_prog(int addr, uint8_t *data, int n) @@ -340,10 +499,10 @@ static void flash_prog(int addr, uint8_t *data, int n)  	uint8_t command[4] = { FC_PP, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; -	set_gpio(0, 0); +	flash_chip_select();  	send_spi(command, 4);  	send_spi(data, n); -	set_gpio(1, 0); +	flash_chip_deselect();  	if (verbose)  		for (int i = 0; i < n; i++) @@ -357,11 +516,11 @@ static void flash_read(int addr, uint8_t *data, int n)  	uint8_t command[4] = { FC_RD, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; -	set_gpio(0, 0); +	flash_chip_select();  	send_spi(command, 4);  	memset(data, 0, n);  	xfer_spi(data, n); -	set_gpio(1, 0); +	flash_chip_deselect();  	if (verbose)  		for (int i = 0; i < n; i++) @@ -373,52 +532,72 @@ static void flash_wait()  	if (verbose)  		fprintf(stderr, "waiting.."); +	int count = 0;  	while (1)  	{  		uint8_t data[2] = { FC_RSR1 }; -		set_gpio(0, 0); +		flash_chip_select();  		xfer_spi(data, 2); -		set_gpio(1, 0); - -		if ((data[1] & 0x01) == 0) -			break; - -		if (verbose) { -			fprintf(stderr, "."); -			fflush(stdout); +		flash_chip_deselect(); + +		if ((data[1] & 0x01) == 0) { +			if (count < 2) { +				count++; +				if (verbose) { +					fprintf(stderr, "r"); +					fflush(stderr); +				} +			} else { +				if (verbose) { +					fprintf(stderr, "R"); +					fflush(stderr); +				} +				break; +			} +		} else { +			if (verbose) { +				fprintf(stderr, "."); +				fflush(stderr); +			} +			count = 0;  		} +  		usleep(1000);  	}  	if (verbose)  		fprintf(stderr, "\n"); +  }  static void flash_disable_protection()  {  	fprintf(stderr, "disable flash protection...\n"); -  //WRSR 0x00 -	uint8_t data[2] = { 0x01, 0x00 }; -	set_gpio(0, 0); +	// Write Status Register 1 <- 0x00 +	uint8_t data[2] = { FC_WSR1, 0x00 }; +	flash_chip_select();  	xfer_spi(data, 2); -	set_gpio(1, 0); +	flash_chip_deselect();  	flash_wait(); -	//RDSR -	data[0] = 0x5; +	// Read Status Register 1 +	data[0] = FC_RSR1; -	set_gpio(0, 0);\ +	flash_chip_select();  	xfer_spi(data, 2); -	set_gpio(1, 0); +	flash_chip_deselect(); -	if(data[1] != 0x00) +	if (data[1] != 0x00)  		fprintf(stderr, "failed to disable protection, SR now equal to 0x%02x (expected 0x00)\n", data[1]);  } +// --------------------------------------------------------- +// iceprog implementation +// ---------------------------------------------------------  static void help(const char *progname)  { @@ -519,14 +698,15 @@ int main(int argc, char **argv)  		{NULL, 0, NULL, 0}  	}; +	/* Decode command line parameters */  	int opt;  	char *endptr;  	while ((opt = getopt_long(argc, argv, "d:I:rR:e:o:cbnStvp", long_options, NULL)) != -1) {  		switch (opt) { -		case 'd': +		case 'd': /* device string */  			devstr = optarg;  			break; -		case 'I': +		case 'I': /* FTDI Chip interface select */  			if (!strcmp(optarg, "A"))  				ifnum = INTERFACE_A;  			else if (!strcmp(optarg, "B")) @@ -540,10 +720,10 @@ int main(int argc, char **argv)  				return EXIT_FAILURE;  			}  			break; -		case 'r': +		case 'r': /* Read 256 bytes to file */  			read_mode = true;  			break; -		case 'R': +		case 'R': /* Read n bytes to file */  			read_mode = true;  			read_size = strtol(optarg, &endptr, 0);  			if (*endptr == '\0') @@ -557,7 +737,7 @@ int main(int argc, char **argv)  				return EXIT_FAILURE;  			}  			break; -		case 'e': +		case 'e': /* Erase blocks as if we were writing n bytes */  			erase_mode = true;  			erase_size = strtol(optarg, &endptr, 0);  			if (*endptr == '\0') @@ -571,7 +751,7 @@ int main(int argc, char **argv)  				return EXIT_FAILURE;  			}  			break; -		case 'o': +		case 'o': /* set address offset */  			rw_offset = strtol(optarg, &endptr, 0);  			if (*endptr == '\0')  				/* ok */; @@ -584,25 +764,25 @@ int main(int argc, char **argv)  				return EXIT_FAILURE;  			}  			break; -		case 'c': +		case 'c': /* do not write just check */  			check_mode = true;  			break; -		case 'b': +		case 'b': /* bulk erase before writing */  			bulk_erase = true;  			break; -		case 'n': +		case 'n': /* do not erase before writing */  			dont_erase = true;  			break; -		case 'S': +		case 'S': /* write to sram directly */  			prog_sram = true;  			break; -		case 't': +		case 't': /* just read flash id */  			test_mode = true;  			break; -		case 'v': +		case 'v': /* provide verbose output */  			verbose = true;  			break; -		case 'p': +		case 'p': /* disable flash protect before erase/write */  			disable_protect = true;  			break;  		case -2: @@ -615,6 +795,8 @@ int main(int argc, char **argv)  		}  	} +	/* Make sure that the combination of provided parameters makes sense */ +  	if (read_mode + erase_mode + check_mode + prog_sram + test_mode > 1) {  		fprintf(stderr, "%s: options `-r'/`-R', `-e`, `-c', `-S', and `-t' are mutually exclusive\n", my_name);  		return EXIT_FAILURE; @@ -810,15 +992,14 @@ int main(int argc, char **argv)  	fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); -	set_gpio(1, 1); +	flash_release_reset();  	usleep(100000); -  	if (test_mode)  	{  		fprintf(stderr, "reset..\n"); -		set_gpio(1, 0); +		flash_chip_deselect();  		usleep(250000);  		fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); @@ -829,7 +1010,7 @@ int main(int argc, char **argv)  		flash_power_down(); -		set_gpio(1, 1); +		flash_release_reset();  		usleep(250000);  		fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); @@ -842,10 +1023,10 @@ int main(int argc, char **argv)  		fprintf(stderr, "reset..\n"); -		set_gpio(0, 0); +		sram_reset();  		usleep(100); -		set_gpio(0, 1); +		sram_chip_select();  		usleep(2000);  		fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); @@ -877,7 +1058,7 @@ int main(int argc, char **argv)  		fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low");  	} -	else +	else /* program flash */  	{  		// ---------------------------------------------------------  		// Reset @@ -885,7 +1066,7 @@ int main(int argc, char **argv)  		fprintf(stderr, "reset..\n"); -		set_gpio(1, 0); +		flash_chip_deselect();  		usleep(250000);  		fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); @@ -925,6 +1106,10 @@ int main(int argc, char **argv)  					for (int addr = begin_addr; addr < end_addr; addr += 0x10000) {  						flash_write_enable();  						flash_64kB_sector_erase(addr); +						if (verbose) { +							fprintf(stderr, "Status after block erase:\n"); +							flash_read_status(); +						}  						flash_wait();  					}  				} | 
