aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--iceprog/iceprog.c157
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");