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>
This commit is contained in:
parent
cf596a61db
commit
e33eae340d
|
@ -8497,10 +8497,10 @@ for FPGA @var{num}.
|
||||||
|
|
||||||
|
|
||||||
@deffn {FPGA Driver} {lattice} [family]
|
@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.
|
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
|
@deffn {Command} {lattice read_status} num
|
||||||
Reads and displays the status register
|
Reads and displays the status register
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
noinst_LTLIBRARIES += %D%/libpld.la
|
noinst_LTLIBRARIES += %D%/libpld.la
|
||||||
%C%_libpld_la_SOURCES = \
|
%C%_libpld_la_SOURCES = \
|
||||||
|
%D%/certus.c \
|
||||||
%D%/ecp2_3.c \
|
%D%/ecp2_3.c \
|
||||||
%D%/ecp5.c \
|
%D%/ecp5.c \
|
||||||
%D%/lattice.c \
|
%D%/lattice.c \
|
||||||
|
@ -10,6 +11,7 @@ noinst_LTLIBRARIES += %D%/libpld.la
|
||||||
%D%/raw_bit.c \
|
%D%/raw_bit.c \
|
||||||
%D%/xilinx_bit.c \
|
%D%/xilinx_bit.c \
|
||||||
%D%/virtex2.c \
|
%D%/virtex2.c \
|
||||||
|
%D%/certus.h \
|
||||||
%D%/ecp2_3.h \
|
%D%/ecp2_3.h \
|
||||||
%D%/ecp5.h \
|
%D%/ecp5.h \
|
||||||
%D%/lattice.h \
|
%D%/lattice.h \
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 */
|
|
@ -15,6 +15,7 @@
|
||||||
#include "lattice_bit.h"
|
#include "lattice_bit.h"
|
||||||
#include "ecp2_3.h"
|
#include "ecp2_3.h"
|
||||||
#include "ecp5.h"
|
#include "ecp5.h"
|
||||||
|
#include "certus.h"
|
||||||
|
|
||||||
#define PRELOAD 0x1C
|
#define PRELOAD 0x1C
|
||||||
|
|
||||||
|
@ -50,6 +51,9 @@ static const struct lattice_devices_elem lattice_devices[] = {
|
||||||
{0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */},
|
{0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */},
|
||||||
{0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */},
|
{0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */},
|
||||||
{0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */},
|
{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)
|
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;
|
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)
|
int lattice_preload(struct lattice_pld_device *lattice_device)
|
||||||
{
|
{
|
||||||
struct scan_field field;
|
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);
|
return lattice_ecp2_3_read_usercode(tap, usercode, out);
|
||||||
else if (lattice_device->family == LATTICE_ECP5)
|
else if (lattice_device->family == LATTICE_ECP5)
|
||||||
return lattice_ecp5_read_usercode(tap, usercode, out);
|
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;
|
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);
|
return lattice_ecp2_3_write_usercode(lattice_device, usercode);
|
||||||
else if (lattice_device->family == LATTICE_ECP5)
|
else if (lattice_device->family == LATTICE_ECP5)
|
||||||
return lattice_ecp5_write_usercode(lattice_device, usercode);
|
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;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -194,12 +223,22 @@ static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, ui
|
||||||
|
|
||||||
return ERROR_FAIL;
|
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,
|
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 expected, uint32_t mask, bool do_idle)
|
||||||
{
|
{
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
|
||||||
int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle);
|
int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -212,13 +251,28 @@ int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device
|
||||||
return ERROR_OK;
|
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)
|
static int lattice_load_command(struct pld_device *pld_device, const char *filename)
|
||||||
{
|
{
|
||||||
if (!pld_device)
|
if (!pld_device)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
struct lattice_pld_device *lattice_device = pld_device->driver_priv;
|
struct lattice_pld_device *lattice_device = pld_device->driver_priv;
|
||||||
|
|
||||||
if (!lattice_device || !lattice_device->tap)
|
if (!lattice_device || !lattice_device->tap)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
struct jtag_tap *tap = lattice_device->tap;
|
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);
|
retval = lattice_ecp3_load(lattice_device, &bit_file);
|
||||||
break;
|
break;
|
||||||
case LATTICE_ECP5:
|
case LATTICE_ECP5:
|
||||||
|
case LATTICE_CERTUS:
|
||||||
if (bit_file.has_id && id != bit_file.idcode)
|
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.",
|
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);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR("loading unknown device family");
|
LOG_ERROR("loading unknown device family");
|
||||||
|
@ -283,6 +341,8 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command)
|
||||||
family = LATTICE_ECP3;
|
family = LATTICE_ECP3;
|
||||||
} else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
|
} else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
|
||||||
family = LATTICE_ECP5;
|
family = LATTICE_ECP5;
|
||||||
|
} else if (strcasecmp(CMD_ARGV[2], "certus") == 0) {
|
||||||
|
family = LATTICE_CERTUS;
|
||||||
} else {
|
} else {
|
||||||
command_print(CMD, "unknown family");
|
command_print(CMD, "unknown family");
|
||||||
free(lattice_device);
|
free(lattice_device);
|
||||||
|
@ -405,11 +465,18 @@ COMMAND_HANDLER(lattice_read_status_command_handler)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
uint32_t status;
|
if (lattice_device->family == LATTICE_CERTUS) {
|
||||||
const bool do_idle = lattice_device->family == LATTICE_ECP5;
|
uint64_t status;
|
||||||
retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle);
|
retval = lattice_read_status_u64(lattice_device, &status, 0x0);
|
||||||
if (retval == ERROR_OK)
|
if (retval == ERROR_OK)
|
||||||
command_print(CMD, "0x%8.8" PRIx32, status);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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,
|
int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val,
|
||||||
uint32_t out_val, bool do_idle);
|
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,
|
int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out,
|
||||||
uint32_t expected, uint32_t mask);
|
uint32_t expected, uint32_t mask);
|
||||||
int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out,
|
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 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);
|
int lattice_preload(struct lattice_pld_device *lattice_device);
|
||||||
|
|
||||||
#endif /* OPENOCD_PLD_LATTICE_H */
|
#endif /* OPENOCD_PLD_LATTICE_H */
|
||||||
|
|
|
@ -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]
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue