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/+/7398

-- gerrit

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

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

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 2ed8cc9a7a..765822db41 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8500,16 +8500,21 @@ for FPGA @var{num}.
 
 
 @deffn {FPGA Driver} {lattice} [family]
-The FGPA families ECP2, ECP3 and ECP5 by Lattice are supported.
+The FGPA families ECP2, ECP3, ECP5, Certus and CertusPro 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 ecp5}. 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 certus}. 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
 
+@example
+openocd -f board/certuspro_evaluation.cfg -c "init" \
+       -c "pld load 0 ecertuspro_blinker_impl1.bit"
+@end example
+
 @deffn {Command} {lattice read_status} num
 Reads and displays the status register
 for FPGA @var{num}.
diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am
index 6abc9662a9..f64a091736 100644
--- a/src/pld/Makefile.am
+++ b/src/pld/Makefile.am
@@ -2,6 +2,7 @@
 
 noinst_LTLIBRARIES += %D%/libpld.la
 %C%_libpld_la_SOURCES = \
+       %D%/certus.c \
        %D%/ecp2_3.c \
        %D%/ecp5.c \
        %D%/lattice.c \
@@ -10,6 +11,7 @@ noinst_LTLIBRARIES += %D%/libpld.la
        %D%/raw_bit.c \
        %D%/xilinx_bit.c \
        %D%/virtex2.c \
+       %D%/certus.h \
        %D%/ecp2_3.h \
        %D%/ecp5.h \
        %D%/lattice.h \
diff --git a/src/pld/certus.c b/src/pld/certus.c
new file mode 100644
index 0000000000..e9a128525f
--- /dev/null
+++ b/src/pld/certus.c
@@ -0,0 +1,222 @@
+// 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 ISC_ERASE            0x0E
+#define PRELOAD              0x1C
+#define ISC_DISABLE          0x26
+#define LSC_READ_STATUS      0x3C
+#define LSC_INIT_ADDRESS     0x46
+#define LSC_ENABLE_X         0x74
+#define LSC_REFRESH          0x79
+#define LSC_BITSTREAM_BURST  0x7A
+#define LSC_DEVICE_CTRL      0x7D
+#define READ_USERCODE        0xC0
+#define ISC_ENABLE           0xC6
+#define BYPASS               0xFF
+
+int lattice_certus_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file);
+
+int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, 
uint64_t out)
+{
+       return lattice_read_u64_register(tap, LSC_READ_STATUS, status, out);
+}
+
+int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, 
uint32_t out)
+{
+       return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, 
false);
+}
+
+int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, 
uint32_t usercode)
+{
+       LOG_ERROR("Not supported tto write usercode on certus devices");
+       return ERROR_FAIL;
+}
+
+static int lattice_certus_enable_transparent_mode(struct jtag_tap *tap)
+{
+       struct scan_field field;
+
+       lattice_set_instr(tap, LSC_ENABLE_X, 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);
+
+       return jtag_execute_queue();
+}
+
+static int lattice_certus_erase_device(struct lattice_pld_device 
*lattice_device)
+{
+       struct jtag_tap *tap = lattice_device->tap;
+       if (!tap)
+               return ERROR_FAIL;
+
+       lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE);
+
+       struct scan_field field;
+       uint8_t buffer = 8;
+       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);
+       int retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IDLE);
+       buffer = 0;
+       field.num_bits = 8;
+       field.out_value = &buffer;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
+       buffer = 0;
+       field.num_bits = 8;
+       field.out_value = &buffer;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       jtag_add_runtest(100, TAP_IDLE);
+       jtag_add_sleep(5000);
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* check done is cleared and fail is cleared */
+       const uint64_t status_done_flag =  0x100;
+       const uint64_t status_fail_flag = 0x2000;
+       return lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, 
status_done_flag | status_fail_flag);
+}
+
+static int lattice_certus_enable_programming(struct jtag_tap *tap)
+{
+       struct scan_field field;
+
+       lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       int retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+       uint8_t buffer = 0;
+       field.num_bits = 8;
+       field.out_value = &buffer;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       return jtag_execute_queue();
+}
+
+static int lattice_certus_init_address(struct jtag_tap *tap)
+{
+       lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       return jtag_execute_queue();
+}
+
+static int lattice_certus_exit_programming_mode(struct jtag_tap *tap)
+{
+       lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+       jtag_add_runtest(2, TAP_IDLE);
+       lattice_set_instr(tap, BYPASS, TAP_IDLE);
+       jtag_add_runtest(100, TAP_IDLE);
+       return jtag_execute_queue();
+}
+
+static int lattice_certus_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);
+
+       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);
+
+       return jtag_execute_queue();
+}
+
+int lattice_certus_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;
+
+       /*  check password protection is disabled */
+       const uint64_t status_pwd_protection = 0x20000;
+       retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, 
status_pwd_protection);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Password protection is set");
+               return retval;
+       }
+
+       retval = lattice_certus_enable_transparent_mode(tap);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Check the SRAM Erase Lock */
+       const uint64_t status_otp = 0x40;
+       retval = lattice_verify_status_register_u64(lattice_device, 0x0, 
status_otp, status_otp);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("NV User Feature Sector OTP is Set");
+               return retval;
+       }
+
+       /* Check the SRAM Lock */
+       const uint64_t status_write_protected = 0x400;
+       retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, 
status_write_protected);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("NV User Feature Sector OTP is Set");
+               return retval;
+       }
+
+       retval = lattice_certus_enable_programming(tap);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("failed to enable programming mode");
+               return retval;
+       }
+
+       retval = lattice_certus_erase_device(lattice_device);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("erasing device failed");
+               return retval;
+       }
+
+       retval = lattice_certus_init_address(tap);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = lattice_certus_program_config_map(tap, bit_file);
+       if (retval != ERROR_OK)
+               return retval;
+       const uint32_t expected = 0x100; // done
+       const uint32_t mask = expected |
+                       0x3000 | // Busy Flag and Fail Flag
+                       0xf000000; // BSE Error
+       retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x100, 
mask);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return lattice_certus_exit_programming_mode(tap);
+}
diff --git a/src/pld/certus.h b/src/pld/certus.h
new file mode 100644
index 0000000000..51defc5ca2
--- /dev/null
+++ b/src/pld/certus.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_CERTUS_H
+#define OPENOCD_PLD_CERTUS_H
+
+#include "lattice.h"
+
+int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, 
uint64_t out);
+int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, 
uint32_t out);
+int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, 
uint32_t usercode);
+int lattice_certus_load(struct lattice_pld_device *lattice_device, struct 
lattice_bit_file *bit_file);
+
+#endif /* OPENOCD_PLD_CERTUS_H */
diff --git a/src/pld/lattice.c b/src/pld/lattice.c
index a3cfabd2cc..8cd2f3f8b3 100644
--- a/src/pld/lattice.c
+++ b/src/pld/lattice.c
@@ -15,6 +15,7 @@
 #include "lattice_bit.h"
 #include "ecp2_3.h"
 #include "ecp5.h"
+#include "certus.h"
 
 #define PRELOAD              0x1C
 
@@ -50,6 +51,9 @@ static const struct lattice_devices_elem lattice_devices[] = {
        {0x01111043,  409, ecp5}, /* "LAE5UM-25F" */
        {0x01112043,  510, ecp5}, /* "LAE5UM-45F" */
        {0x01113043,  750, ecp5}, /* "LAE5UM-85F" */
+       {0x310f0043,  362, certus}, /* LFD2NX-17 */
+       {0x310f1043,  362, certus}, /* LFD2NX-40 */
+       {0x010f4043,  362, certus}, /* LFCPNX-100 */
 };
 
 void lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t 
endstate)
@@ -109,6 +113,25 @@ int lattice_read_u32_register(struct jtag_tap *tap, 
uint8_t cmd, uint32_t *in_va
        return retval;
 }
 
+int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t 
*in_val,
+                                                       uint64_t out_val)
+{
+       struct scan_field field;
+       uint8_t buffer[8];
+
+       lattice_set_instr(tap, cmd, TAP_IDLE);
+       h_u64_to_le(buffer, out_val);
+       field.num_bits = 64;
+       field.out_value = buffer;
+       field.in_value = buffer;
+       jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+       int retval = jtag_execute_queue();
+       if (retval == ERROR_OK)
+               *in_val = le_to_h_u64(buffer);
+
+       return retval;
+}
+
 int lattice_preload(struct lattice_pld_device *lattice_device)
 {
        struct scan_field field;
@@ -141,6 +164,8 @@ static int lattice_read_usercode(struct lattice_pld_device 
*lattice_device, uint
                return lattice_ecp2_3_read_usercode(tap, usercode, out);
        else if (lattice_device->family == ecp5)
                return lattice_ecp5_read_usercode(tap, usercode, out);
+       else if (lattice_device->family == certus)
+               return lattice_certus_read_usercode(tap, usercode, out);
 
        return ERROR_FAIL;
 }
@@ -168,6 +193,8 @@ static int lattice_write_usercode(struct lattice_pld_device 
*lattice_device, uin
                return lattice_ecp2_3_write_usercode(lattice_device, usercode);
        else if (lattice_device->family == ecp5)
                return lattice_ecp5_write_usercode(lattice_device, usercode);
+       else if (lattice_device->family == certus)
+               return lattice_certus_write_usercode(lattice_device, usercode);
 
        return ERROR_FAIL;
 }
@@ -185,12 +212,22 @@ static int lattice_read_status_u32(struct 
lattice_pld_device *lattice_device, ui
 
        return ERROR_FAIL;
 }
+static int lattice_read_status_u64(struct lattice_pld_device *lattice_device, 
uint64_t *status,
+                                                               uint64_t out)
+{
+       if (!lattice_device->tap)
+               return ERROR_FAIL;
+
+       if (lattice_device->family == certus)
+               return lattice_certus_read_status(lattice_device->tap, status, 
out);
+
+       return ERROR_FAIL;
+}
 
 int lattice_verify_status_register_u32(struct lattice_pld_device 
*lattice_device, uint32_t out,
                                                uint32_t expected, uint32_t 
mask, bool do_idle)
 {
        uint32_t status;
-
        int retval = lattice_read_status_u32(lattice_device, &status, out, 
do_idle);
        if (retval != ERROR_OK)
                return retval;
@@ -203,18 +240,33 @@ int lattice_verify_status_register_u32(struct 
lattice_pld_device *lattice_device
        return ERROR_OK;
 }
 
+int lattice_verify_status_register_u64(struct lattice_pld_device 
*lattice_device, uint64_t out,
+                                               uint64_t expected, uint64_t 
mask)
+{
+       uint64_t status;
+       int retval = lattice_read_status_u64(lattice_device, &status, out);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if ((status & mask) != expected) {
+               LOG_ERROR("verifying status register failed got: 0x%08" PRIx64 
" expected: 0x%08" PRIx64,
+                       status & mask, expected);
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
 static int lattice_load_command(struct pld_device *pld_device, const char 
*filename)
 {
        if (!pld_device)
                return ERROR_FAIL;
 
        struct lattice_pld_device *lattice_device = pld_device->driver_priv;
-
        if (!lattice_device || !lattice_device->tap)
                return ERROR_FAIL;
        struct jtag_tap *tap = lattice_device->tap;
 
-       if (!tap->hasidcode)
+       if (!tap || !tap->hasidcode)
                return ERROR_FAIL;
 
        int retval = lattice_check_device_family(lattice_device);
@@ -236,10 +288,14 @@ static int lattice_load_command(struct pld_device 
*pld_device, const char *filen
                retval = lattice_ecp3_load(lattice_device, &bit_file);
                break;
        case ecp5:
+       case certus:
                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);
+               if (lattice_device->family == ecp5)
+                       retval = lattice_ecp5_load(lattice_device, &bit_file);
+               else
+                       retval = lattice_certus_load(lattice_device, &bit_file);
                break;
        default:
                LOG_ERROR("loading unknown device family");
@@ -274,6 +330,8 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command)
                        family = ecp3;
                } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
                        family = ecp5;
+               } else if (strcasecmp(CMD_ARGV[2], "certus") == 0) {
+                       family = certus;
                } else {
                        LOG_ERROR("unknown family");
                        free(lattice_device);
@@ -396,11 +454,18 @@ COMMAND_HANDLER(lattice_read_status_command_handler)
        if (retval != ERROR_OK)
                return retval;
 
-       uint32_t status;
-       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);
+       if (lattice_device->family == certus) {
+               uint64_t status;
+               retval = lattice_read_status_u64(lattice_device, &status, 0x0);
+               if (retval == ERROR_OK)
+                       command_print(CMD, "0x%016" PRIx64 "", status);
+       } else {
+               uint32_t status;
+               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);
+       }
 
        return retval;
 }
diff --git a/src/pld/lattice.h b/src/pld/lattice.h
index c91af805aa..d8517bddbd 100644
--- a/src/pld/lattice.h
+++ b/src/pld/lattice.h
@@ -21,10 +21,14 @@ struct lattice_pld_device {
 void lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t 
endstate);
 int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t 
*in_val,
                                                        uint32_t out_val, bool 
do_idle);
+int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t 
*in_val,
+                                                       uint64_t out_val);
 int lattice_verify_usercode(struct lattice_pld_device *lattice_device, 
uint32_t out,
                                                uint32_t expected, uint32_t 
mask);
 int lattice_verify_status_register_u32(struct lattice_pld_device 
*lattice_device, uint32_t out,
                                                uint32_t expected, uint32_t 
mask, bool do_idle);
+int lattice_verify_status_register_u64(struct lattice_pld_device 
*lattice_device, uint64_t out,
+                                               uint64_t expected, uint64_t 
mask);
 int lattice_preload(struct lattice_pld_device *lattice_device);
 
 #endif /* OPENOCD_PLD_LATTICE_H */
diff --git a/tcl/board/certuspro_evaluation.cfg 
b/tcl/board/certuspro_evaluation.cfg
new file mode 100644
index 0000000000..5ff2a1e329
--- /dev/null
+++ b/tcl/board/certuspro_evaluation.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# 
https://www.latticesemi.com/products/developmentboardsandkits/certuspro-nx-versa-board
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 0
+ftdi layout_init 0x0008 0x008b
+reset_config none
+transport select jtag
+adapter speed 10000
+
+source [find fpga/lattice_certuspro.cfg]
diff --git a/tcl/fpga/lattice_certus.cfg b/tcl/fpga/lattice_certus.cfg
new file mode 100644
index 0000000000..95b6e59d8b
--- /dev/null
+++ b/tcl/fpga/lattice_certus.cfg
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+       set _CHIPNAME $_CHIPNAME
+} else {
+       set _CHIPNAME certus
+}
+
+# Lattice Certus
+#
+# Certus NX LFD2NX-17     0x310f0043
+# Certus NX LFD2NX-40     0x310f1043
+
+
+jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \
+       -expected-id 0x310F1043 -expected-id 0x310F0043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_certuspro.cfg b/tcl/fpga/lattice_certuspro.cfg
new file mode 100644
index 0000000000..c15a379aea
--- /dev/null
+++ b/tcl/fpga/lattice_certuspro.cfg
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+       set _CHIPNAME $_CHIPNAME
+} else {
+       set _CHIPNAME certuspro
+}
+
+# Lattice CertusPro
+#
+# 0x010f4043 - LFCPNX-100
+# 0x     043 - LFCPNX-50
+
+jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \
+       -expected-id 0x010f4043
+#    -expected-id 0x01112043
+
+pld device lattice $_CHIPNAME.tap

-- 

Reply via email to