diff options
author | Clifford Wolf <clifford@clifford.at> | 2018-03-27 14:43:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-27 14:43:31 +0200 |
commit | 9b0603c4bc156b350918c3a8762ffac28b3de42b (patch) | |
tree | 96c299264a023bd16f4929f999096ec676e486fa /iceprog | |
parent | 4476d83f76fa0222be0b691fe27c1e0228266f82 (diff) | |
parent | a7ab72dd4ccfad5b86efd892d7c8cf21ed297ed6 (diff) | |
download | icestorm-9b0603c4bc156b350918c3a8762ffac28b3de42b.tar.gz icestorm-9b0603c4bc156b350918c3a8762ffac28b3de42b.tar.bz2 icestorm-9b0603c4bc156b350918c3a8762ffac28b3de42b.zip |
Merge pull request #131 from esden/iceprog_less_magic
Add MPSSE and Flash command definitions
Diffstat (limited to 'iceprog')
-rw-r--r-- | iceprog/iceprog.c | 157 |
1 files changed, 137 insertions, 20 deletions
diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c index ce1faba..c7e0061 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c @@ -42,6 +42,120 @@ static bool verbose = false; static bool ftdic_latency_set = false; static unsigned char ftdi_latency; +/* MPSSE engine command definitions */ +enum mpsse_cmd +{ + /* Mode commands */ + MC_SETB_LOW = 0x80, /* Set Data bits LowByte */ + MC_READB_LOW = 0x81, /* Read Data bits LowByte */ + MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */ + MC_READB_HIGH = 0x83, /* Read data bits HighByte */ + MC_LOOPBACK_EN = 0x84, /* Enable loopback */ + MC_LOOPBACK_DIS = 0x85, /* Disable loopback */ + MC_SET_CLK_DIV = 0x86, /* Set clock divisor */ + MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */ + MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */ + MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */ + MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */ + MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */ + MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */ + MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */ + MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */ + MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */ + MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */ + MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */ + MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */ + MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */ + MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */ + MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */ + MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */ + /* CPU mode commands */ + MC_CPU_RS = 0x90, /* CPUMode read short address */ + MC_CPU_RE = 0x91, /* CPUMode read extended address */ + MC_CPU_WS = 0x92, /* CPUMode write short address */ + MC_CPU_WE = 0x93, /* CPUMode write extended address */ +}; + +/* Transfer Command bits */ + +/* All byte based commands consist of: + * - Command byte + * - Length lsb + * - Length msb + * + * If data out is enabled the data follows after the above command bytes, + * otherwise no additional data is needed. + * - Data * n + * + * All bit based commands consist of: + * - Command byte + * - Length + * + * If data out is enabled a byte containing bitst to transfer follows. + * Otherwise no additional data is needed. Only up to 8 bits can be transferred + * per transaction when in bit mode. + */ + +/* b 0000 0000 + * |||| |||`- Data out negative enable. Update DO on negative clock edge. + * |||| ||`-- Bit count enable. When reset count represents bytes. + * |||| |`--- Data in negative enable. Latch DI on negative clock edge. + * |||| `---- LSB enable. When set clock data out LSB first. + * |||| + * |||`------ Data out enable + * ||`------- Data in enable + * |`-------- TMS mode enable + * `--------- Special command mode enable. See mpsse_cmd enum. + */ + +#define MC_DATA_TMS (0x40) /* When set use TMS mode */ +#define MC_DATA_IN (0x20) /* When set read data (Data IN) */ +#define MC_DATA_OUT (0x10) /* When set write data (Data OUT) */ +#define MC_DATA_LSB (0x08) /* When set input/output data LSB first. */ +#define MC_DATA_ICN (0x04) /* When set receive data on negative clock edge */ +#define MC_DATA_BITS (0x02) /* When set count bits not bytes */ +#define MC_DATA_OCN (0x01) /* When set update data on negative clock edge */ + +/* Flash command definitions */ +/* This command list is based on the Winbond W25Q128JV Datasheet */ +enum flash_cmd { + FC_WE = 0x06, /* Write Enable */ + FC_SRWE = 0x50, /* Volatile SR Write Enable */ + FC_WD = 0x04, /* Write Disable */ + FC_RPD = 0xAB, /* Release Power-Down, returns Device ID */ + FC_MFGID = 0x90, /* Read Manufacturer/Device ID */ + FC_JEDECID = 0x9F, /* Read JEDEC ID */ + FC_UID = 0x4B, /* Read Unique ID */ + FC_RD = 0x03, /* Read Data */ + FC_FR = 0x0B, /* Fast Read */ + FC_PP = 0x02, /* Page Program */ + FC_SE = 0x20, /* Sector Erase 4kb */ + FC_BE32 = 0x52, /* Block Erase 32kb */ + FC_BE64 = 0xD8, /* Block Erase 64kb */ + FC_CE = 0xC7, /* Chip Erase */ + FC_RSR1 = 0x05, /* Read Status Register 1 */ + FC_WSR1 = 0x01, /* Write Status Register 1 */ + FC_RSR2 = 0x35, /* Read Status Register 2 */ + FC_WSR2 = 0x31, /* Write Status Register 2 */ + FC_RSR3 = 0x15, /* Read Status Register 3 */ + FC_WSR3 = 0x11, /* Write Status Register 3 */ + FC_RSFDP = 0x5A, /* Read SFDP Register */ + FC_ESR = 0x44, /* Erase Security Register */ + FC_PSR = 0x42, /* Program Security Register */ + FC_RSR = 0x48, /* Read Security Register */ + FC_GBL = 0x7E, /* Global Block Lock */ + FC_GBU = 0x98, /* Global Block Unlock */ + FC_RBL = 0x3D, /* Read Block Lock */ + FC_IBL = 0x36, /* Individual Block Lock */ + FC_IBU = 0x39, /* Individual Block Unlock */ + FC_EPS = 0x75, /* Erase / Program Suspend */ + FC_EPR = 0x7A, /* Erase / Program Resume */ + FC_PD = 0xB9, /* Power-down */ + FC_QPI = 0x38, /* Enter QPI mode */ + FC_ERESET = 0x66, /* Enable Reset */ + FC_RESET = 0x99, /* Reset Device */ +}; + static void check_rx() { while (1) { @@ -96,7 +210,8 @@ static void send_spi(uint8_t *data, int n) if (n < 1) return; - send_byte(0x11); + /* Output only, update data on negative clock edge. */ + send_byte(MC_DATA_OUT | MC_DATA_OCN); send_byte(n - 1); send_byte((n - 1) >> 8); @@ -112,7 +227,8 @@ static void xfer_spi(uint8_t *data, int n) if (n < 1) return; - send_byte(0x31); + /* Input and output, update data on negative edge read on positive. */ + send_byte(MC_DATA_IN | MC_DATA_OUT | MC_DATA_OCN); send_byte(n - 1); send_byte((n - 1) >> 8); @@ -140,15 +256,15 @@ static void set_gpio(int slavesel_b, int creset_b) gpio |= 0x80; } - send_byte(0x80); - send_byte(gpio); - send_byte(0x93); + send_byte(MC_SETB_LOW); + send_byte(gpio); /* Value */ + send_byte(0x93); /* Direction */ } static int get_cdone() { uint8_t data; - send_byte(0x81); + send_byte(MC_READB_LOW); data = recv_byte(); // ADBUS6 (GPIOL2) return (data & 0x40) != 0; @@ -158,7 +274,7 @@ static void flash_read_id() { // fprintf(stderr, "read flash ID..\n"); - uint8_t data[21] = { 0x9F }; + uint8_t data[21] = { FC_JEDECID }; set_gpio(0, 0); xfer_spi(data, 21); set_gpio(1, 0); @@ -171,7 +287,7 @@ static void flash_read_id() static void flash_power_up() { - uint8_t data[1] = { 0xAB }; + uint8_t data[1] = { FC_RPD }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -179,7 +295,7 @@ static void flash_power_up() static void flash_power_down() { - uint8_t data[1] = { 0xB9 }; + uint8_t data[1] = { FC_PD }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -190,7 +306,7 @@ static void flash_write_enable() if (verbose) fprintf(stderr, "write enable..\n"); - uint8_t data[1] = { 0x06 }; + uint8_t data[1] = { FC_WE }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -200,7 +316,7 @@ static void flash_bulk_erase() { fprintf(stderr, "bulk erase..\n"); - uint8_t data[1] = { 0xc7 }; + uint8_t data[1] = { FC_CE }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -210,7 +326,7 @@ static void flash_64kB_sector_erase(int addr) { fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr); - uint8_t command[4] = { 0xd8, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; + uint8_t command[4] = { FC_BE64, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; set_gpio(0, 0); send_spi(command, 4); @@ -222,7 +338,7 @@ static void flash_prog(int addr, uint8_t *data, int n) if (verbose) fprintf(stderr, "prog 0x%06X +0x%03X..\n", addr, n); - uint8_t command[4] = { 0x02, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; + uint8_t command[4] = { FC_PP, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; set_gpio(0, 0); send_spi(command, 4); @@ -239,7 +355,7 @@ static void flash_read(int addr, uint8_t *data, int n) if (verbose) fprintf(stderr, "read 0x%06X +0x%03X..\n", addr, n); - uint8_t command[4] = { 0x03, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; + uint8_t command[4] = { FC_RD, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; set_gpio(0, 0); send_spi(command, 4); @@ -259,7 +375,7 @@ static void flash_wait() while (1) { - uint8_t data[2] = { 0x05 }; + uint8_t data[2] = { FC_RSR1 }; set_gpio(0, 0); xfer_spi(data, 2); @@ -641,16 +757,17 @@ int main(int argc, char **argv) ftdic_latency_set = true; + /* Enter MPSSE (Multi-Protocol Synchronous Serial Engine) mode. Set all pins to output. */ if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_MPSSE) < 0) { fprintf(stderr, "Failed to set BITMODE_MPSSE on iCE FTDI USB device.\n"); error(2); } // enable clock divide by 5 - send_byte(0x8b); + send_byte(MC_TCK_D5); // set 6 MHz clock - send_byte(0x86); + send_byte(MC_SET_CLK_DIV); send_byte(0x00); send_byte(0x00); @@ -712,13 +829,13 @@ int main(int argc, char **argv) send_spi(buffer, rc); } - // add 48 dummy bits - send_byte(0x8f); + // add 48 dummy bits (aka 6 bytes) + send_byte(MC_CLK_N8); send_byte(0x05); send_byte(0x00); // add 1 more dummy bit - send_byte(0x8e); + send_byte(MC_CLK_N); send_byte(0x00); fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); |