aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Anselmi <danselmi@gmx.ch>2022-12-12 09:49:51 +0100
committerAntonio Borneo <borneo.antonio@gmail.com>2023-04-30 14:54:04 +0000
commite33eae340d3502ffab8c172c246bc392a093c2ea (patch)
treeed7cf6e30393ea712d7887a6168f284177639a10
parentcf596a61db7ebace9cf097ffcb332e4de0679398 (diff)
downloadriscv-openocd-e33eae340d3502ffab8c172c246bc392a093c2ea.zip
riscv-openocd-e33eae340d3502ffab8c172c246bc392a093c2ea.tar.gz
riscv-openocd-e33eae340d3502ffab8c172c246bc392a093c2ea.tar.bz2
pld: add support for lattice certus devices
Change-Id: Ic50a724e5793000fca11f35ba848c2d317c3cbab Signed-off-by: Daniel Anselmi <danselmi@gmx.ch> Reviewed-on: https://review.openocd.org/c/openocd/+/7398 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
-rw-r--r--doc/openocd.texi4
-rw-r--r--src/pld/Makefile.am2
-rw-r--r--src/pld/certus.c232
-rw-r--r--src/pld/certus.h18
-rw-r--r--src/pld/lattice.c83
-rw-r--r--src/pld/lattice.h4
-rw-r--r--tcl/board/certuspro_evaluation.cfg14
-rw-r--r--tcl/fpga/lattice_certus.cfg18
-rw-r--r--tcl/fpga/lattice_certuspro.cfg18
9 files changed, 383 insertions, 10 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 2d3ccfe..24de2ce 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8497,10 +8497,10 @@ 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).
@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 459792f..8ad4296 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 0000000..692ea19
--- /dev/null
+++ b/src/pld/certus.c
@@ -0,0 +1,232 @@
+// 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 LSC_ENABLE_X 0x74
+#define LSC_REFRESH 0x79
+#define LSC_DEVICE_CTRL 0x7D
+
+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 to write usercode on certus devices");
+ return ERROR_FAIL;
+}
+
+static int lattice_certus_enable_transparent_mode(struct jtag_tap *tap)
+{
+ struct scan_field field;
+
+ int retval = lattice_set_instr(tap, LSC_ENABLE_X, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ 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;
+
+ int retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ 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);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ 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;
+
+ retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ 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;
+
+ int retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ 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)
+{
+ int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ return jtag_execute_queue();
+}
+
+static int lattice_certus_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);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ 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;
+
+ int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ 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 0000000..51defc5
--- /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 *
+ * danselmi@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 f3d9c0d..4ab5f63 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, LATTICE_ECP5 /* "LAE5UM-25F" */},
{0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */},
{0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */},
+ {0x310f0043, 362, LATTICE_CERTUS /* LFD2NX-17 */},
+ {0x310f1043, 362, LATTICE_CERTUS /* LFD2NX-40 */},
+ {0x010f4043, 362, LATTICE_CERTUS /* LFCPNX-100 */},
};
int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate)
@@ -116,6 +120,27 @@ 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];
+
+ int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ 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);
+ 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;
@@ -150,6 +175,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 == LATTICE_ECP5)
return lattice_ecp5_read_usercode(tap, usercode, out);
+ else if (lattice_device->family == LATTICE_CERTUS)
+ return lattice_certus_read_usercode(tap, usercode, out);
return ERROR_FAIL;
}
@@ -177,6 +204,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 == LATTICE_ECP5)
return lattice_ecp5_write_usercode(lattice_device, usercode);
+ else if (lattice_device->family == LATTICE_CERTUS)
+ return lattice_certus_write_usercode(lattice_device, usercode);
return ERROR_FAIL;
}
@@ -194,12 +223,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 == LATTICE_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;
@@ -212,13 +251,28 @@ 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;
@@ -245,10 +299,14 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen
retval = lattice_ecp3_load(lattice_device, &bit_file);
break;
case LATTICE_ECP5:
+ case LATTICE_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 == LATTICE_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");
@@ -283,6 +341,8 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command)
family = LATTICE_ECP3;
} else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
family = LATTICE_ECP5;
+ } else if (strcasecmp(CMD_ARGV[2], "certus") == 0) {
+ family = LATTICE_CERTUS;
} else {
command_print(CMD, "unknown family");
free(lattice_device);
@@ -405,11 +465,18 @@ COMMAND_HANDLER(lattice_read_status_command_handler)
if (retval != ERROR_OK)
return retval;
- uint32_t status;
- 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);
+ if (lattice_device->family == LATTICE_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 == 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);
+ }
return retval;
}
diff --git a/src/pld/lattice.h b/src/pld/lattice.h
index 6d692cb..9a76a4e 100644
--- a/src/pld/lattice.h
+++ b/src/pld/lattice.h
@@ -23,10 +23,14 @@ struct lattice_pld_device {
int 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 0000000..5ff2a1e
--- /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 0000000..95b6e59
--- /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 0000000..c15a379
--- /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