--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lattice.h"
+#include "lattice_cmd.h"
+
+#define ISC_PROGRAM_USERCODE 0xC2
+
+#define STATUS_DONE_BIT 0x00000100
+#define STATUS_ERROR_BITS 0x00020040
+#define STATUS_FEA_OTP 0x00004000
+#define STATUS_FAIL_FLAG 0x00002000
+#define STATUS_BUSY_FLAG 0x00001000
+#define REGISTER_ALL_BITS_1 0xffffffff
+
+int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle)
+{
+ return lattice_read_u32_register(tap, LSC_READ_STATUS, status, out, do_idle);
+}
+
+int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out)
+{
+ return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, true);
+}
+
+int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(20000);
+
+ retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint8_t buffer[4];
+ struct scan_field field;
+ h_u32_to_le(buffer, usercode);
+ field.num_bits = 32;
+ field.out_value = buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(2000);
+
+ retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(200000);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1);
+}
+
+static int lattice_ecp5_enable_sram_programming(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 0x0;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(10000);
+
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_erase_sram(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 1;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(200000);
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_init_address(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 1;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(10000);
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file)
+{
+ int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(10000);
+
+ struct scan_field field;
+ field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8;
+ field.out_value = bit_file->raw_bit.data + bit_file->offset;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(100, TAP_IDLE);
+ jtag_add_sleep(10000);
+
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_exit_programming_mode(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(200000);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(1000);
+ return jtag_execute_queue();
+}
+
+int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_preload(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_enable_sram_programming(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t out = 0x0;
+ const uint32_t expected1 = 0x0;
+ const uint32_t mask1 = STATUS_ERROR_BITS | STATUS_FEA_OTP;
+ retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask1, true);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_erase_sram(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t mask2 = STATUS_FAIL_FLAG | STATUS_BUSY_FLAG;
+ retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask2, false);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_init_address(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_program_config_map(tap, bit_file);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_exit_programming_mode(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t expected2 = STATUS_DONE_BIT;
+ const uint32_t mask3 = STATUS_DONE_BIT | STATUS_FAIL_FLAG;
+ return lattice_verify_status_register_u32(lattice_device, out, expected2, mask3, false);
+}
#include "pld.h"
#include "lattice_bit.h"
#include "ecp2_3.h"
+#include "ecp5.h"
#define PRELOAD 0x1C
{0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/},
{0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/},
{0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/},
+ {0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */},
+ {0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */},
+ {0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */},
+ {0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */},
+ {0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */},
+ {0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */},
+ {0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */},
+ {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */},
+ {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */},
+ {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */},
};
int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate)
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
return lattice_ecp2_3_read_usercode(tap, usercode, out);
+ else if (lattice_device->family == LATTICE_ECP5)
+ return lattice_ecp5_read_usercode(tap, usercode, out);
return ERROR_FAIL;
}
{
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
return lattice_ecp2_3_write_usercode(lattice_device, usercode);
+ else if (lattice_device->family == LATTICE_ECP5)
+ return lattice_ecp5_write_usercode(lattice_device, usercode);
return ERROR_FAIL;
}
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle);
+ else if (lattice_device->family == LATTICE_ECP5)
+ return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle);
return ERROR_FAIL;
}
if (retval != ERROR_OK)
return retval;
+ uint32_t id = tap->idcode;
retval = ERROR_FAIL;
switch (lattice_device->family) {
case LATTICE_ECP2:
case LATTICE_ECP3:
retval = lattice_ecp3_load(lattice_device, &bit_file);
break;
+ case LATTICE_ECP5:
+ if (bit_file.has_id && id != bit_file.idcode)
+ LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.",
+ id, bit_file.idcode);
+ retval = lattice_ecp5_load(lattice_device, &bit_file);
+ break;
default:
LOG_ERROR("loading unknown device family");
break;
family = LATTICE_ECP2;
} else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) {
family = LATTICE_ECP3;
+ } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
+ family = LATTICE_ECP5;
} else {
command_print(CMD, "unknown family");
free(lattice_device);
return retval;
uint32_t status;
- retval = lattice_read_status_u32(lattice_device, &status, 0x0, false);
+ const bool do_idle = lattice_device->family == LATTICE_ECP5;
+ retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle);
if (retval == ERROR_OK)
command_print(CMD, "0x%8.8" PRIx32, status);