This is an automated email from Gerrit.

"Daniel Anselmi <danse...@gmx.ch>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/7397

-- gerrit

commit 247e7f7fbf4226e39da03b74895d784988c905d0
Author: Daniel Anselmi <danse...@gmx.ch>
Date:   Mon Dec 12 09:49:51 2022 +0100

    pld: add support for lattice ecp5 devices
    
    Change-Id: Ib2f0933da3abe7429abca86d6aaa50ad85ce72c7
    Signed-off-by: Daniel Anselmi <danse...@gmx.ch>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index e8fcecc413..2ed8cc9a7a 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8500,10 +8500,15 @@ for FPGA @var{num}.
 
 
 @deffn {FPGA Driver} {lattice} [family]
-The FGPA families ECP2 and ECP3 by Lattice are supported.
+The FGPA families ECP2, ECP3 and ECP5 by Lattice are supported.
 This driver can be used to load the bitstream into the FPGA or read the status 
register and read/write the usercode register.
 
-The option @option{family} is one of @var{ecp2 ecp3}. This is needed when the 
JTAG ID of the device is not known by openocd (newer NX devices).
+The option @option{family} is one of @var{ecp2 ecp3 ecp5}. This is needed when 
the JTAG ID of the device is not known by openocd (newer NX devices).
+
+@example
+openocd -f board/ecp5_board.cfg -c "init" \
+       -c "pld load 0 ecp5_blinker_impl1.bit"
+@end example
 
 @deffn {Command} {lattice read_status} num
 Reads and displays the status register
diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am
index 7cff09e151..6abc9662a9 100644
--- a/src/pld/Makefile.am
+++ b/src/pld/Makefile.am
@@ -3,6 +3,7 @@
 noinst_LTLIBRARIES += %D%/libpld.la
 %C%_libpld_la_SOURCES = \
        %D%/ecp2_3.c \
+       %D%/ecp5.c \
        %D%/lattice.c \
        %D%/lattice_bit.c \
        %D%/pld.c \
@@ -10,6 +11,7 @@ noinst_LTLIBRARIES += %D%/libpld.la
        %D%/xilinx_bit.c \
        %D%/virtex2.c \
        %D%/ecp2_3.h \
+       %D%/ecp5.h \
        %D%/lattice.h \
        %D%/lattice_bit.h \
        %D%/pld.h \
diff --git a/src/pld/ecp5.c b/src/pld/ecp5.c
new file mode 100644
index 0000000000..c724103ab2
--- /dev/null
+++ b/src/pld/ecp5.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lattice.h"
+
+#define BYPASS               0xFF
+#define ISC_ENABLE           0xC6
+#define LSCC_READ_STATUS     0x3C
+#define ISC_ERASE            0x0E
+#define LSC_INIT_ADDRESS     0x46
+#define LSC_BITSTREAM_BURST  0x7A
+#define READ_USERCODE        0xC0
+#define ISC_DISABLE          0x26
+#define ISC_PROGRAM_USERCODE 0xC2
+#define PRELOAD              0x1C
+
+#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, LSCC_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 scan_field field;
+       uint8_t buffer[4];
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       if (lattice_device->family == certus) {
+               LOG_ERROR("writing usercode register not supported for certus 
devices");
+               return ERROR_FAIL;
+       }
+
+       lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(20000);
+
+       lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
+
+       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);
+
+       lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+       jtag_add_runtest(5, TAP_IDLE);
+       jtag_add_sleep(200000);
+
+       int 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)
+{
+       struct scan_field field;
+
+       lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+
+       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 latttice_ecp5_erase_sram(struct jtag_tap *tap)
+{
+       struct scan_field field;
+
+       lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
+
+       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)
+{
+       struct scan_field field;
+
+       lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
+       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)
+{
+       struct scan_field field;
+
+       lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       jtag_add_sleep(10000);
+
+       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);
+
+       lattice_set_instr(tap, BYPASS, TAP_IDLE);
+       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)
+{
+       lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       jtag_add_sleep(200000);
+       lattice_set_instr(tap, BYPASS, TAP_IDLE);
+       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 = latttice_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);
+}
diff --git a/src/pld/ecp5.h b/src/pld/ecp5.h
new file mode 100644
index 0000000000..7b0c86b4ad
--- /dev/null
+++ b/src/pld/ecp5.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Daniel Anselmi                                  *
+ *   danse...@gmx.ch                                                       *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_ECP5_H
+#define OPENOCD_PLD_ECP5_H
+
+#include "lattice.h"
+
+int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t 
out, bool do_idle);
+int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, 
uint32_t out);
+int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, 
uint32_t usercode);
+int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file);
+
+#endif /* OPENOCD_PLD_ECP5_H */
diff --git a/src/pld/lattice.c b/src/pld/lattice.c
index a612a5463a..a3cfabd2cc 100644
--- a/src/pld/lattice.c
+++ b/src/pld/lattice.c
@@ -14,6 +14,7 @@
 #include "pld.h"
 #include "lattice_bit.h"
 #include "ecp2_3.h"
+#include "ecp5.h"
 
 #define PRELOAD              0x1C
 
@@ -39,6 +40,16 @@ static const struct lattice_devices_elem lattice_devices[] = 
{
        {0x01012043,  675, ecp3 /* ecp3 lae3-35ea & lfe3-35ea*/},
        {0x01014043, 1077, ecp3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && 
lfe3-95e*/},
        {0x01015043, 1326, ecp3 /* ecp3 lfe3-150e*/},
+       {0x21111043,  409, ecp5}, /* "LAE5U-12F & LFE5U-12F" */
+       {0x41111043,  409, ecp5}, /* "LFE5U-25F" */
+       {0x41112043,  510, ecp5}, /* "LFE5U-45F" */
+       {0x41113043,  750, ecp5}, /* "LFE5U-85F" */
+       {0x81111043,  409, ecp5}, /* "LFE5UM5G-25F" */
+       {0x81112043,  510, ecp5}, /* "LFE5UM5G-45F" */
+       {0x81113043,  750, ecp5}, /* "LFE5UM5G-85F" */
+       {0x01111043,  409, ecp5}, /* "LAE5UM-25F" */
+       {0x01112043,  510, ecp5}, /* "LAE5UM-45F" */
+       {0x01113043,  750, ecp5}, /* "LAE5UM-85F" */
 };
 
 void lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t 
endstate)
@@ -128,6 +139,8 @@ static int lattice_read_usercode(struct lattice_pld_device 
*lattice_device, uint
 
        if (lattice_device->family == ecp2 || lattice_device->family == ecp3)
                return lattice_ecp2_3_read_usercode(tap, usercode, out);
+       else if (lattice_device->family == ecp5)
+               return lattice_ecp5_read_usercode(tap, usercode, out);
 
        return ERROR_FAIL;
 }
@@ -153,6 +166,8 @@ static int lattice_write_usercode(struct lattice_pld_device 
*lattice_device, uin
 {
        if (lattice_device->family == ecp2 || lattice_device->family == ecp3)
                return lattice_ecp2_3_write_usercode(lattice_device, usercode);
+       else if (lattice_device->family == ecp5)
+               return lattice_ecp5_write_usercode(lattice_device, usercode);
 
        return ERROR_FAIL;
 }
@@ -165,6 +180,8 @@ static int lattice_read_status_u32(struct 
lattice_pld_device *lattice_device, ui
 
        if (lattice_device->family == ecp2 || lattice_device->family == ecp3)
                return lattice_ecp2_3_read_status(lattice_device->tap, status, 
out, do_idle);
+       else if (lattice_device->family == ecp5)
+               return lattice_ecp5_read_status(lattice_device->tap, status, 
out, do_idle);
 
        return ERROR_FAIL;
 }
@@ -209,6 +226,7 @@ static int lattice_load_command(struct pld_device 
*pld_device, const char *filen
        if (retval != ERROR_OK)
                return retval;
 
+       uint32_t id = tap->idcode;
        retval = ERROR_FAIL;
        switch (lattice_device->family) {
        case ecp2:
@@ -217,6 +235,12 @@ static int lattice_load_command(struct pld_device 
*pld_device, const char *filen
        case ecp3:
                retval = lattice_ecp3_load(lattice_device, &bit_file);
                break;
+       case 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;
@@ -248,6 +272,8 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command)
                        family = ecp2;
                } else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) {
                        family = ecp3;
+               } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
+                       family = ecp5;
                } else {
                        LOG_ERROR("unknown family");
                        free(lattice_device);
@@ -371,7 +397,8 @@ COMMAND_HANDLER(lattice_read_status_command_handler)
                return retval;
 
        uint32_t status;
-       retval = lattice_read_status_u32(lattice_device, &status, 0x0, false);
+       const bool do_idle = lattice_device->family == ecp5;
+       retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle);
        if (retval == ERROR_OK)
                command_print(CMD, "0x%8.8" PRIx32 "", status);
 
diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg
new file mode 100644
index 0000000000..427037b71f
--- /dev/null
+++ b/tcl/board/ecp5_evaluation.cfg
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Lattice ECP5 evaluation Kit
+# https://www.latticesemi.com/view_document?document_id=52479
+#
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 0
+ftdi layout_init 0x0008 0x008b
+reset_config none
+transport select jtag
+adapter speed 6000
+
+source [find fpga/lattice_ecp5.cfg]
+
+#openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load 0 
shared_folder/ecp5_blinker_impl1.bit"
+#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0
diff --git a/tcl/fpga/lattice_ecp5.cfg b/tcl/fpga/lattice_ecp5.cfg
index a94ada7404..41442492e9 100644
--- a/tcl/fpga/lattice_ecp5.cfg
+++ b/tcl/fpga/lattice_ecp5.cfg
@@ -26,3 +26,5 @@ jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 
0x1 \
        -expected-id 0x21111043 -expected-id 0x41111043 -expected-id 0x41112043 
\
        -expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 
\
        -expected-id 0x81113043
+
+pld device lattice $_CHIPNAME.tap

-- 

Reply via email to