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/pld/certus.c | |
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/pld/certus.c')
-rw-r--r-- | src/pld/certus.c | 232 |
1 files changed, 232 insertions, 0 deletions
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); +} |