diff options
author | Daniel Anselmi <danselmi@gmx.ch> | 2022-12-12 09:49:51 +0100 |
---|---|---|
committer | Antonio Borneo <borneo.antonio@gmail.com> | 2023-04-30 14:54:04 +0000 |
commit | e33eae340d3502ffab8c172c246bc392a093c2ea (patch) | |
tree | ed7cf6e30393ea712d7887a6168f284177639a10 /src | |
parent | cf596a61db7ebace9cf097ffcb332e4de0679398 (diff) | |
download | riscv-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>
Diffstat (limited to 'src')
-rw-r--r-- | src/pld/Makefile.am | 2 | ||||
-rw-r--r-- | src/pld/certus.c | 232 | ||||
-rw-r--r-- | src/pld/certus.h | 18 | ||||
-rw-r--r-- | src/pld/lattice.c | 83 | ||||
-rw-r--r-- | src/pld/lattice.h | 4 |
5 files changed, 331 insertions, 8 deletions
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 */ |