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/+/7353
-- gerrit commit 628421a3d343d1db2da4bdfc8913172d6fb4980b Author: Daniel Anselmi <danse...@gmx.ch> Date: Fri Oct 14 00:57:12 2022 +0200 pld: add support lattice certus and certuspro devices Change-Id: If401b1f66bc4db0a49ea1603fa36af7f0bdbce32 Signed-off-by: Daniel Anselmi <danse...@gmx.ch> diff --git a/doc/openocd.texi b/doc/openocd.texi index 8cca4ab98b..d41e7f4163 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8552,6 +8552,26 @@ openocd -f trion_t20_bga256.cfg \ @end example @end deffn +@deffn {FPGA Driver} {certus} +Certus and CertusPro are FPGA families sold by Lattice. +This driver can be used to load the bitstream into the FPGA. + +@example +openocd -f board/certuspro_evaluation.cfg -c "init" \ + -c "pld load 0 ecertuspro_blinker_impl1.bit" +@end example + +@deffn {Command} {certus read_status} num +Reads and displays the status register +for FPGA @var{num}. +@end deffn + +@deffn {Command} {certus read_user} num +Reads and displays the user register +for FPGA @var{num}. +@end deffn +@end deffn + @node General Commands @chapter General Commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 78124fb3d4..b587824945 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -6,14 +6,15 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/xilinx_bit.c \ %D%/virtex2.c \ %D%/raw_bit.c \ - %D%/ecp_bit.c \ - %D%/ecp.c \ + %D%/lattice_bit.c \ + %D%/lattice.c \ %D%/ecp2_3.c \ %D%/ecp5.c \ + %D%/certus.c \ %D%/efinix.c \ %D%/pld.h \ %D%/xilinx_bit.h \ %D%/virtex2.h \ %D%/raw_bit.h \ - %D%/ecp_bit.h \ - %D%/ecp.h + %D%/lattice_bit.h \ + %D%/lattice.h diff --git a/src/pld/certus.c b/src/pld/certus.c new file mode 100644 index 0000000000..805b42de19 --- /dev/null +++ b/src/pld/certus.c @@ -0,0 +1,384 @@ +// 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" +#include "pld.h" +#include "lattice_bit.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 + +#define PRELOAD_LENGTH 362 + +static int certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out) +{ + return lattice_read_u64_register(tap, LSC_READ_STATUS, status, out); +} + +static int certus_read_user(struct jtag_tap *tap, uint32_t *status, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, status, out, false); +} + +static int 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 certus_verify_status_register(struct jtag_tap *tap, uint64_t out_val, + uint64_t expected, uint64_t mask) +{ + uint64_t status; + + int retval = certus_read_status(tap, &status, out_val); + if (retval != ERROR_OK) + return retval; + + if ((status & mask) != expected) { + LOG_ERROR("verifying status register failed got: 0x%016" PRIx64 " expected: 0x%016" PRIx64, + status & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int certus_erase_device(struct jtag_tap *tap) +{ + struct scan_field field; + + lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE); + + 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 certus_verify_status_register(tap, 0x0, 0x0, status_done_flag | status_fail_flag); +} + +static int 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 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 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 certus_program_fuse_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(); +} + +static int certus_load(struct jtag_tap *tap, struct lattice_bit_file *bit_file) +{ + int retval = lattice_preload(tap, PRELOAD, PRELOAD_LENGTH); + if (retval != ERROR_OK) + return retval; + + /* check password protection is disabled */ + const uint64_t status_pwd_protection = 0x20000; + retval = certus_verify_status_register(tap, 0x0, 0x0, status_pwd_protection); + if (retval != ERROR_OK) { + LOG_ERROR("Password protection is set"); + return retval; + } + + retval = certus_enable_transparent_mode(tap); + if (retval != ERROR_OK) + return retval; + + /* Check the SRAM Erase Lock */ + const uint64_t status_otp = 0x40; + retval = certus_verify_status_register(tap, 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 = certus_verify_status_register(tap, 0x0, 0x0, status_write_protected); + if (retval != ERROR_OK) { + LOG_ERROR("NV User Feature Sector OTP is Set"); + return retval; + } + + retval = certus_enable_programming(tap); + if (retval != ERROR_OK) { + LOG_ERROR("failed to enable programming mode"); + return retval; + } + + retval = certus_erase_device(tap); + if (retval != ERROR_OK) { + LOG_ERROR("erasing device failed"); + return retval; + } + + retval = certus_init_address(tap); + if (retval != ERROR_OK) + return retval; + + retval = certus_program_fuse_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 = certus_verify_status_register(tap, 0x0, 0x100, mask); + if (retval != ERROR_OK) + return retval; + + return certus_exit_programming_mode(tap); +} + +static int certus_load_command(struct pld_device *pld_device, const char *filename) +{ + struct lattice_bit_file bit_file; + + if (!pld_device || !pld_device->driver_priv) + return ERROR_FAIL; + + struct lattice_pld_device *certus_info = pld_device->driver_priv; + if (!certus_info || !certus_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = certus_info->tap; + + if (!tap->hasidcode) + return ERROR_FAIL; + uint32_t id = tap->idcode; + + int retval = lattice_read_file(&bit_file, filename, true); + if (retval != ERROR_OK) + return retval; + + if (bit_file.has_id && id != bit_file.idcode) + LOG_WARNING("id on device and bit-stream don't match!"); + + retval = certus_load(tap, &bit_file); + free(bit_file.raw_bit.data); + return retval; +} + +static int certus_read_status_register(struct pld_device *pld_device, uint64_t *status) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *certus_info = pld_device->driver_priv; + + if (!certus_info || !certus_info->tap) + return ERROR_FAIL; + + return certus_read_status(certus_info->tap, status, 0x0); +} + +static int certus_read_user_register(struct pld_device *pld_device, uint32_t *user) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *certus_info = pld_device->driver_priv; + + if (!certus_info || !certus_info->tap) + return ERROR_FAIL; + + return certus_read_user(certus_info->tap, user, 0x0); +} + +COMMAND_HANDLER(certus_read_status_command_handler) +{ + int dev_id; + uint64_t status; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + int retval = certus_read_status_register(device, &status); + if (retval == ERROR_OK) + command_print(CMD, "0x%016" PRIx64 "", status); + + return retval; +} + +COMMAND_HANDLER(certus_read_user_register_command_handler) +{ + int dev_id; + uint32_t user; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + int retval = certus_read_user_register(device, &user); + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32 "", user); + + return retval; +} + +PLD_DEVICE_COMMAND_HANDLER(certus_pld_device_command) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + struct lattice_pld_device *certus_info = malloc(sizeof(struct lattice_pld_device)); + if (!certus_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + certus_info->tap = tap; + + pld->driver_priv = certus_info; + + return ERROR_OK; +} + +static const struct command_registration certus_exec_command_handlers[] = { + { + .name = "read_status", + .mode = COMMAND_EXEC, + .handler = certus_read_status_command_handler, + .help = "reading status register from FPGA", + .usage = "num_pld", + }, { + .name = "read_user", + .mode = COMMAND_EXEC, + .handler = certus_read_user_register_command_handler, + .help = "reading user register from FPGA", + .usage = "num_pld", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration certus_command_handler[] = { + { + .name = "certus", + .mode = COMMAND_ANY, + .help = "certus specific commands", + .usage = "", + .chain = certus_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct pld_driver certus_pld = { + .name = "certus", + .commands = certus_command_handler, + .pld_device_command = &certus_pld_device_command, + .load = &certus_load_command, +}; diff --git a/src/pld/ecp.h b/src/pld/ecp.h deleted file mode 100644 index 9a627ca035..0000000000 --- a/src/pld/ecp.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/*************************************************************************** - * Copyright (C) 2022 by Daniel Anselmi * - * danse...@gmx.ch * - ***************************************************************************/ - -#ifndef OPENOCD_PLD_ECP_H -#define OPENOCD_PLD_ECP_H - -#include <jtag/jtag.h> - -struct ecp_pld_device { - struct jtag_tap *tap; -}; - -struct ecp_devices_preload_length_elem { - uint32_t id; - size_t preload_length; -}; - -void ecp_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate); -int ecp_read_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, - uint32_t out_val, bool do_idle); -int ecp_get_preload_length(uint32_t id, const struct ecp_devices_preload_length_elem *elems, - size_t num_elems, size_t *length); -int ecp_preload(struct jtag_tap *tap, size_t length); - -#endif /* OPENOCD_PLD_ECP_H */ diff --git a/src/pld/ecp2_3.c b/src/pld/ecp2_3.c index 99519fb9fe..987094c6dc 100644 --- a/src/pld/ecp2_3.c +++ b/src/pld/ecp2_3.c @@ -9,9 +9,9 @@ #include "config.h" #endif -#include "ecp.h" +#include "lattice.h" #include "pld.h" -#include "ecp_bit.h" +#include "lattice_bit.h" #define LSCC_REFRESH 0x23 #define ISC_ENABLE 0x15 @@ -23,6 +23,7 @@ #define BYPASS 0xFF #define LSCC_READ_STATUS 0x53 #define LSCC_BITSTREAM_BURST 0x02 +#define PRELOAD 0x1C #define STATUS_DONE_BIT 0x00020000 #define STATUS_ERROR_BITS_ECP2 0x00040003 @@ -30,7 +31,7 @@ #define REGISTER_ALL_BITS_1 0xffffffff #define REGISTER_ALL_BITS_0 0x00000000 -static const struct ecp_devices_preload_length_elem ecp2_devices_preload_length[] = { +static const struct lattice_devices_preload_length_elem ecp2_devices_preload_length[] = { {0x01270043, 654 /* ecp2-6e */}, {0x01271043, 643 /* ecp2-12e */}, {0x01272043, 827 /* ecp2-20e */}, @@ -44,7 +45,7 @@ static const struct ecp_devices_preload_length_elem ecp2_devices_preload_length[ {0x0127D043, 1311 /* ecp2m100e */}, }; -static const struct ecp_devices_preload_length_elem ecp3_devices_preload_length[] = { +static const struct lattice_devices_preload_length_elem ecp3_devices_preload_length[] = { {0x01010043, 467 /* ecp3 lae3-17ea & lfe3-17ea*/}, {0x01012043, 675 /* ecp3 lae3-35ea & lfe3-35ea*/}, {0x01014043, 1077 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/}, @@ -53,13 +54,13 @@ static const struct ecp_devices_preload_length_elem ecp3_devices_preload_length[ static int ecp2_get_preload_length(uint32_t id, size_t *length) { - return ecp_get_preload_length(id, ecp2_devices_preload_length, + return lattice_get_preload_length(id, ecp2_devices_preload_length, ARRAY_SIZE(ecp2_devices_preload_length), length); } static int ecp3_get_preload_length(uint32_t id, size_t *length) { - return ecp_get_preload_length(id, ecp3_devices_preload_length, + return lattice_get_preload_length(id, ecp3_devices_preload_length, ARRAY_SIZE(ecp3_devices_preload_length), length); } @@ -75,17 +76,17 @@ static int ecp2_3_preload(struct jtag_tap *tap, bool is_ecp3) if (retval != ERROR_OK) return retval; - return ecp_preload(tap, length); + return lattice_preload(tap, PRELOAD, length); } static int ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out) { - return ecp_read_register(tap, LSCC_READ_STATUS, status, out, false); + return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, false); } static int ecp2_3_read_user(struct jtag_tap *tap, uint32_t *user, uint32_t out) { - return ecp_read_register(tap, READ_USERCODE, user, out, false); + return lattice_read_u32_register(tap, READ_USERCODE, user, out, false); } static int ecp2_3_verify_usercode(struct jtag_tap *tap, uint32_t out, @@ -125,10 +126,10 @@ static int ecp2_erase_device(struct jtag_tap *tap) struct scan_field field; uint8_t buffer[4] = {0, 0, 0, 0}; - ecp_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); - ecp_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); + lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); field.num_bits = 32; field.out_value = buffer; field.in_value = NULL; @@ -136,7 +137,7 @@ static int ecp2_erase_device(struct jtag_tap *tap) jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); - ecp_set_instr(tap, ISC_ERASE, TAP_IDLE); + lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(100000); /* after erasing check all bits in user register are cleared */ @@ -152,7 +153,7 @@ static int ecp3_erase_device(struct jtag_tap *tap) uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff}; /* program user code with all bits set */ - ecp_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); + lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); field.num_bits = 32; field.out_value = buffer; field.in_value = NULL; @@ -168,11 +169,11 @@ static int ecp3_erase_device(struct jtag_tap *tap) if (retval != ERROR_OK) return retval; - ecp_set_instr(tap, ISC_ERASE, TAP_IDLE); + lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000000); - ecp_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); @@ -183,10 +184,10 @@ static int ecp3_erase_device(struct jtag_tap *tap) static int ecp2_3_exit_programming_mode(struct jtag_tap *tap) { - ecp_set_instr(tap, ISC_DISABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(200000); - ecp_set_instr(tap, BYPASS, TAP_IDLE); + lattice_set_instr(tap, BYPASS, TAP_IDLE); jtag_add_runtest(100, TAP_IDLE); jtag_add_sleep(1000); return jtag_execute_queue(); @@ -197,11 +198,11 @@ static int ecp2_3_write_user(struct jtag_tap *tap, uint32_t user) struct scan_field field; uint8_t buffer[4]; - ecp_set_instr(tap, ISC_ENABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); - ecp_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); + lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); h_u32_to_le(buffer, user); field.num_bits = 32; @@ -211,20 +212,20 @@ static int ecp2_3_write_user(struct jtag_tap *tap, uint32_t user) jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); - ecp_set_instr(tap, ISC_DISABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(200000); return jtag_execute_queue(); } -static int ecp2_3_program_fuse_map(struct jtag_tap *tap, struct ecp_bit_file *bit_file) +static int ecp2_3_program_fuse_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { struct scan_field field; - ecp_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); - ecp_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE); + lattice_set_instr(tap, LSCC_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; @@ -234,7 +235,7 @@ static int ecp2_3_program_fuse_map(struct jtag_tap *tap, struct ecp_bit_file *bi return jtag_execute_queue(); } -static int ecp3_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) +static int ecp3_load(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { /* Program Bscan register */ int retval = ecp2_3_preload(tap, true); @@ -242,10 +243,10 @@ static int ecp3_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) return retval; /* Enable the programming mode */ - ecp_set_instr(tap, LSCC_REFRESH, TAP_IDLE); + lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(50000); - ecp_set_instr(tap, ISC_ENABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); @@ -268,15 +269,15 @@ static int ecp3_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) return ecp2_3_verify_status_register(tap, out, expected, mask); } -static int ecp2_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) +static int ecp2_load(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { int retval = ecp2_3_preload(tap, false); if (retval != ERROR_OK) return retval; /* Enable the programming mode */ - ecp_set_instr(tap, LSCC_REFRESH, TAP_IDLE); - ecp_set_instr(tap, ISC_ENABLE, TAP_IDLE); + lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); + lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); @@ -302,7 +303,7 @@ static int ecp2_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) static int ecp2_3_read_status_register(struct pld_device *pld_device, uint32_t *status) { - struct ecp_pld_device *ecp2_3_info; + struct lattice_pld_device *ecp2_3_info; if (!pld_device) return ERROR_FAIL; @@ -317,7 +318,7 @@ static int ecp2_3_read_status_register(struct pld_device *pld_device, uint32_t * static int ecp2_3_read_user_register(struct pld_device *pld_device, uint32_t *user) { - struct ecp_pld_device *ecp2_3_info; + struct lattice_pld_device *ecp2_3_info; if (!pld_device) return ERROR_FAIL; @@ -332,7 +333,7 @@ static int ecp2_3_read_user_register(struct pld_device *pld_device, uint32_t *us static int ecp2_3_write_user_register(struct pld_device *pld_device, uint32_t user) { - struct ecp_pld_device *ecp2_3_info; + struct lattice_pld_device *ecp2_3_info; if (!pld_device) return ERROR_FAIL; @@ -414,8 +415,8 @@ COMMAND_HANDLER(ecp2_3_write_user_register_command_handler) static int ecp2_3_load(struct pld_device *pld_device, const char *filename) { - struct ecp_pld_device *ecp2_3_info; - struct ecp_bit_file bit_file; + struct lattice_pld_device *ecp2_3_info; + struct lattice_bit_file bit_file; if (!pld_device || !pld_device->driver_priv) return ERROR_FAIL; @@ -429,7 +430,7 @@ static int ecp2_3_load(struct pld_device *pld_device, const char *filename) return ERROR_FAIL; uint32_t id = tap->idcode; - int retval = ecp_read_file(&bit_file, filename, false); + int retval = lattice_read_file(&bit_file, filename, false); if (retval != ERROR_OK) return retval; @@ -453,7 +454,7 @@ static int ecp2_3_load(struct pld_device *pld_device, const char *filename) PLD_DEVICE_COMMAND_HANDLER(ecp2_3_pld_device_command) { - struct ecp_pld_device *ecp2_3_info; + struct lattice_pld_device *ecp2_3_info; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -464,7 +465,7 @@ PLD_DEVICE_COMMAND_HANDLER(ecp2_3_pld_device_command) return ERROR_FAIL; } - ecp2_3_info = malloc(sizeof(struct ecp_pld_device)); + ecp2_3_info = malloc(sizeof(struct lattice_pld_device)); if (!ecp2_3_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; diff --git a/src/pld/ecp5.c b/src/pld/ecp5.c index d6c2970793..11e0996ee9 100644 --- a/src/pld/ecp5.c +++ b/src/pld/ecp5.c @@ -9,9 +9,9 @@ #include "config.h" #endif -#include "ecp.h" +#include "lattice.h" #include "pld.h" -#include "ecp_bit.h" +#include "lattice_bit.h" #define BYPASS 0xFF #define ISC_ENABLE 0xC6 @@ -22,6 +22,7 @@ #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 @@ -29,7 +30,7 @@ #define STATUS_FAIL_FLAG 0x00002000 #define STATUS_BUSY_FLAG 0x00001000 -static const struct ecp_devices_preload_length_elem ecp5_devices_preload_length[] = { +static const struct lattice_devices_preload_length_elem ecp5_devices_preload_length[] = { {0x21111043, 409}, /* "LAE5U-12F & LFE5U-12F" */ {0x41111043, 409}, /* "LFE5U-25F" */ {0x41112043, 510}, /* "LFE5U-45F" */ @@ -44,7 +45,7 @@ static const struct ecp_devices_preload_length_elem ecp5_devices_preload_length[ static int ecp5_get_preload_length(uint32_t id, size_t *length) { - return ecp_get_preload_length(id, ecp5_devices_preload_length, ARRAY_SIZE(ecp5_devices_preload_length), length); + return lattice_get_preload_length(id, ecp5_devices_preload_length, ARRAY_SIZE(ecp5_devices_preload_length), length); } static int ecp5_preload(struct jtag_tap *tap) @@ -55,24 +56,24 @@ static int ecp5_preload(struct jtag_tap *tap) if (retval != ERROR_OK) return retval; - return ecp_preload(tap, length); + return lattice_preload(tap, PRELOAD, length); } static int ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) { - return ecp_read_register(tap, LSCC_READ_STATUS, status, out, do_idle); + return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, do_idle); } static int ecp5_read_user(struct jtag_tap *tap, uint32_t *user, uint32_t out) { - return ecp_read_register(tap, READ_USERCODE, user, out, true); + return lattice_read_u32_register(tap, READ_USERCODE, user, out, true); } static int ecp5_enable_sram_programming(struct jtag_tap *tap) { struct scan_field field; - ecp_set_instr(tap, ISC_ENABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); uint8_t buffer = 0x0; field.num_bits = 8; @@ -89,7 +90,7 @@ static int ecp5_erase_sram(struct jtag_tap *tap) { struct scan_field field; - ecp_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); + lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); uint8_t buffer = 1; field.num_bits = 8; @@ -105,7 +106,7 @@ static int ecp5_init_address(struct jtag_tap *tap) { struct scan_field field; - ecp_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); + lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); uint8_t buffer = 1; field.num_bits = 8; field.out_value = &buffer; @@ -137,11 +138,11 @@ static int ecp5_write_user(struct jtag_tap *tap, uint32_t user) struct scan_field field; uint8_t buffer[4]; - ecp_set_instr(tap, ISC_ENABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(20000); - ecp_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); + lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); h_u32_to_le(buffer, user); field.num_bits = 32; @@ -151,7 +152,7 @@ static int ecp5_write_user(struct jtag_tap *tap, uint32_t user) jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(2000); - ecp_set_instr(tap, ISC_DISABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); jtag_add_runtest(5, TAP_IDLE); jtag_add_sleep(200000); @@ -160,20 +161,20 @@ static int ecp5_write_user(struct jtag_tap *tap, uint32_t user) static int ecp5_exit_programming_mode(struct jtag_tap *tap) { - ecp_set_instr(tap, ISC_DISABLE, TAP_IDLE); + lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(200000); - ecp_set_instr(tap, BYPASS, TAP_IDLE); + lattice_set_instr(tap, BYPASS, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(1000); return jtag_execute_queue(); } -static int ecp5_program_fuse_map(struct jtag_tap *tap, struct ecp_bit_file *bit_file) +static int ecp5_program_fuse_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { struct scan_field field; - ecp_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); + lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(10000); @@ -182,14 +183,14 @@ static int ecp5_program_fuse_map(struct jtag_tap *tap, struct ecp_bit_file *bit_ field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); - ecp_set_instr(tap, BYPASS, 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 ecp5_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) +static int ecp5_load(struct jtag_tap *tap, struct lattice_bit_file *bit_file) { int retval = ecp5_preload(tap); if (retval != ERROR_OK) @@ -234,12 +235,12 @@ static int ecp5_load(struct jtag_tap *tap, struct ecp_bit_file *bit_file) static int ecp5_load_command(struct pld_device *pld_device, const char *filename) { - struct ecp_bit_file bit_file; + struct lattice_bit_file bit_file; if (!pld_device || !pld_device->driver_priv) return ERROR_FAIL; - struct ecp_pld_device *ecp5_info = pld_device->driver_priv; + struct lattice_pld_device *ecp5_info = pld_device->driver_priv; if (!ecp5_info || !ecp5_info->tap) return ERROR_FAIL; struct jtag_tap *tap = ecp5_info->tap; @@ -248,11 +249,11 @@ static int ecp5_load_command(struct pld_device *pld_device, const char *filename return ERROR_FAIL; uint32_t id = tap->idcode; - int retval = ecp_read_file(&bit_file, filename, true); + int retval = lattice_read_file(&bit_file, filename, true); if (retval != ERROR_OK) return retval; - if (!bit_file.encrypted && id != bit_file.idcode) + if (bit_file.has_id && id != bit_file.idcode) LOG_WARNING("id on device and bit-stream don't match!"); retval = ecp5_load(tap, &bit_file); @@ -265,7 +266,7 @@ static int ecp5_read_status_register(struct pld_device *pld_device, uint32_t *st if (!pld_device) return ERROR_FAIL; - struct ecp_pld_device *ecp5_info = pld_device->driver_priv; + struct lattice_pld_device *ecp5_info = pld_device->driver_priv; if (!ecp5_info || !ecp5_info->tap) return ERROR_FAIL; @@ -278,7 +279,7 @@ static int ecp5_read_user_register(struct pld_device *pld_device, uint32_t *user if (!pld_device) return ERROR_FAIL; - struct ecp_pld_device *ecp5_info = pld_device->driver_priv; + struct lattice_pld_device *ecp5_info = pld_device->driver_priv; if (!ecp5_info || !ecp5_info->tap) return ERROR_FAIL; @@ -291,7 +292,7 @@ static int ecp5_write_user_register(struct pld_device *pld_device, uint32_t user if (!pld_device) return ERROR_FAIL; - struct ecp_pld_device *ecp5_info = pld_device->driver_priv; + struct lattice_pld_device *ecp5_info = pld_device->driver_priv; if (!ecp5_info || !ecp5_info->tap) return ERROR_FAIL; @@ -374,7 +375,7 @@ PLD_DEVICE_COMMAND_HANDLER(ecp5_pld_device_command) return ERROR_FAIL; } - struct ecp_pld_device *ecp5_info = malloc(sizeof(struct ecp_pld_device)); + struct lattice_pld_device *ecp5_info = malloc(sizeof(struct lattice_pld_device)); if (!ecp5_info) { LOG_ERROR("Out of memory"); return ERROR_FAIL; diff --git a/src/pld/ecp.c b/src/pld/lattice.c similarity index 65% rename from src/pld/ecp.c rename to src/pld/lattice.c index 4a805cdb6f..db0ec2c52d 100644 --- a/src/pld/ecp.c +++ b/src/pld/lattice.c @@ -9,11 +9,10 @@ #include "config.h" #endif -#include "ecp.h" +#include "lattice.h" -#define PRELOAD 0x1C -void ecp_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) +void lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) { struct scan_field field; @@ -26,13 +25,13 @@ void ecp_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate free(t); } -int ecp_read_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) { struct scan_field field; uint8_t buffer[4]; - ecp_set_instr(tap, cmd, TAP_IDLE); + lattice_set_instr(tap, cmd, TAP_IDLE); if (do_idle) { jtag_add_runtest(2, TAP_IDLE); jtag_add_sleep(1000); @@ -50,7 +49,26 @@ int ecp_read_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, return retval; } -int ecp_get_preload_length(uint32_t id, const struct ecp_devices_preload_length_elem *elems, +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_get_preload_length(uint32_t id, const struct lattice_devices_preload_length_elem *elems, size_t num_elems, size_t *length) { for (size_t i = 0; i < num_elems; ++i) { @@ -63,12 +81,12 @@ int ecp_get_preload_length(uint32_t id, const struct ecp_devices_preload_length_ } -int ecp_preload(struct jtag_tap *tap, size_t length) +int lattice_preload(struct jtag_tap *tap, uint8_t preload_cmd, size_t length) { struct scan_field field; size_t sz_bytes = DIV_ROUND_UP(length, 8); - ecp_set_instr(tap, PRELOAD, TAP_IDLE); + lattice_set_instr(tap, preload_cmd, TAP_IDLE); uint8_t *buffer = malloc(sz_bytes); if (!buffer) { LOG_ERROR("Out of memory"); diff --git a/src/pld/lattice.h b/src/pld/lattice.h new file mode 100644 index 0000000000..8f6f1ca882 --- /dev/null +++ b/src/pld/lattice.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danse...@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_H +#define OPENOCD_PLD_LATTICE_H + +#include <jtag/jtag.h> + +struct lattice_pld_device { + struct jtag_tap *tap; +}; + +struct lattice_devices_preload_length_elem { + uint32_t id; + size_t preload_length; +}; + +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_get_preload_length(uint32_t id, const struct lattice_devices_preload_length_elem *elems, + size_t num_elems, size_t *length); +int lattice_preload(struct jtag_tap *tap, uint8_t preload_cmd, size_t length); + +#endif /* OPENOCD_PLD_LATTICE_H */ diff --git a/src/pld/ecp_bit.c b/src/pld/lattice_bit.c similarity index 84% rename from src/pld/ecp_bit.c rename to src/pld/lattice_bit.c index db0ba2b6ac..0d4795c65e 100644 --- a/src/pld/ecp_bit.c +++ b/src/pld/lattice_bit.c @@ -8,7 +8,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "ecp_bit.h" +#include "lattice_bit.h" #include "raw_bit.h" #include "pld.h" #include <sys/stat.h> @@ -22,16 +22,14 @@ #define SEEK_ID 4 #define DONE 5 -static int ecp_read_bit_file(struct ecp_bit_file *bit_file, const char *filename, bool v5) +static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *filename, enum bit_file_version version) { int retval = cpld_read_raw_bit_file(&bit_file->raw_bit, filename); if (retval != ERROR_OK) return retval; - bit_file->idcode = 0; bit_file->part = 0; - - bit_file->encrypted = false; + bit_file->has_id = false; int state = SEEK_HEADER_START; for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) { switch (state) { @@ -46,7 +44,7 @@ static int ecp_read_bit_file(struct ecp_bit_file *bit_file, const char *filename LOG_INFO("part found: %s\n", bit_file->part); } else if (bit_file->raw_bit.data[pos] == 0xff && bit_file->raw_bit.data[pos - 1] == 0) { bit_file->offset = pos; - state = (v5) ? SEEK_PREAMBLE : DONE; + state = (version != ecp2_3) ? SEEK_PREAMBLE : DONE; } break; case SEEK_PREAMBLE: @@ -59,7 +57,11 @@ static int ecp_read_bit_file(struct ecp_bit_file *bit_file, const char *filename if (bit_file->raw_bit.data[pos - 1] == 0xbf && bit_file->raw_bit.data[pos - 2] == 0xff && bit_file->raw_bit.data[pos - 3] == 0xff) { - bit_file->encrypted = 1; + state = DONE; + } + if (bit_file->raw_bit.data[pos - 1] == 0xbe && + bit_file->raw_bit.data[pos - 2] == 0xff && + bit_file->raw_bit.data[pos - 3] == 0xff) { state = DONE; } } @@ -67,6 +69,7 @@ static int ecp_read_bit_file(struct ecp_bit_file *bit_file, const char *filename case SEEK_ID: if (pos + 7 < bit_file->raw_bit.length && bit_file->raw_bit.data[pos] == 0xe2) { bit_file->idcode = be_to_h_u32(&bit_file->raw_bit.data[pos + 4]); + bit_file->has_id = true; state = DONE; } break; @@ -86,7 +89,7 @@ static int ecp_read_bit_file(struct ecp_bit_file *bit_file, const char *filename return ERROR_OK; } -int ecp_read_file(struct ecp_bit_file *bit_file, const char *filename, bool v5) +int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum bit_file_version version) { struct stat input_stat; @@ -116,7 +119,7 @@ int ecp_read_file(struct ecp_bit_file *bit_file, const char *filename, bool v5) } if (strcasecmp(file_suffix_pos, ".bit") == 0) - return ecp_read_bit_file(bit_file, filename, v5); + return lattice_read_bit_file(bit_file, filename, version); LOG_ERROR("Filetype not supported"); return ERROR_PLD_FILE_LOAD_FAILED; diff --git a/src/pld/ecp_bit.h b/src/pld/lattice_bit.h similarity index 63% rename from src/pld/ecp_bit.h rename to src/pld/lattice_bit.h index 6570acd77c..d1a8633ee3 100644 --- a/src/pld/ecp_bit.h +++ b/src/pld/lattice_bit.h @@ -5,22 +5,24 @@ * danse...@gmx.ch * ***************************************************************************/ -#ifndef OPENOCD_PLD_ECP_BIT_H -#define OPENOCD_PLD_ECP_BIT_H +#ifndef OPENOCD_PLD_LATTICE_BIT_H +#define OPENOCD_PLD_LATTICE_BIT_H #include "helper/types.h" #include "raw_bit.h" -struct ecp_bit_file { +struct lattice_bit_file { struct raw_bit_file raw_bit; size_t offset; uint32_t idcode; const char *part; /* reuses memory in raw_bit_file */ - bool encrypted; + bool has_id; }; -int ecp_read_file(struct ecp_bit_file *bit_file, const char *filename, bool v5); +enum bit_file_version {ecp2_3, ecp5, certus}; +int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum bit_file_version version); -#endif /* OPENOCD_PLD_ECP_BIT_H */ + +#endif /* OPENOCD_PLD_LATTICE_BIT_H */ diff --git a/src/pld/pld.c b/src/pld/pld.c index 34a0283781..97c894e585 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -21,8 +21,11 @@ extern struct pld_driver virtex2_pld; extern struct pld_driver ecp2_3_pld; extern struct pld_driver ecp5_pld; extern struct pld_driver trion_pld; +extern struct pld_driver certus_pld; + static struct pld_driver *pld_drivers[] = { + &certus_pld, &ecp2_3_pld, &ecp5_pld, &trion_pld, 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..bfd1c16b3c --- /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 certus $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_certuspro.cfg b/tcl/fpga/lattice_certuspro.cfg new file mode 100644 index 0000000000..d328c1d995 --- /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 certus $_CHIPNAME.tap --