mirror of
git://git.code.sf.net/p/openocd/code
synced 2025-07-26 23:40:22 +10:00
Provide jtagspi with specific procedures to be able to use jtagspi for programming spi-flash devices on lattice ecp2 and ecp3 devices. Change-Id: I39028aba47a74a0479be16d52d318f4bff7f2ed4 Signed-off-by: Daniel Anselmi <danselmi@gmx.ch> Reviewed-on: https://review.openocd.org/c/openocd/+/7823 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
307 lines
8.6 KiB
C
307 lines
8.6 KiB
C
// 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 "ecp2_3.h"
|
|
#include "lattice.h"
|
|
|
|
#define LSCC_REFRESH 0x23
|
|
#define ISC_ENABLE 0x15
|
|
#define LSCC_RESET_ADDRESS 0x21
|
|
#define ISC_PROGRAM_USERCODE 0x1A
|
|
#define ISC_ERASE 0x03
|
|
#define READ_USERCODE 0x17
|
|
#define ISC_DISABLE 0x1E
|
|
#define LSCC_READ_STATUS 0x53
|
|
#define LSCC_BITSTREAM_BURST 0x02
|
|
#define PROGRAM_SPI 0x3A
|
|
|
|
#define STATUS_DONE_BIT 0x00020000
|
|
#define STATUS_ERROR_BITS_ECP2 0x00040003
|
|
#define STATUS_ERROR_BITS_ECP3 0x00040007
|
|
#define REGISTER_ALL_BITS_1 0xffffffff
|
|
#define REGISTER_ALL_BITS_0 0x00000000
|
|
|
|
int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle)
|
|
{
|
|
return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, do_idle);
|
|
}
|
|
|
|
int lattice_ecp2_3_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_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
|
|
{
|
|
struct jtag_tap *tap = lattice_device->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(20000);
|
|
|
|
retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
struct scan_field field;
|
|
uint8_t buffer[4];
|
|
h_u32_to_le(buffer, usercode);
|
|
field.num_bits = 32;
|
|
field.out_value = buffer;
|
|
field.in_value = NULL;
|
|
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(2000);
|
|
|
|
retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(200000);
|
|
|
|
retval = jtag_execute_queue();
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1);
|
|
}
|
|
|
|
static int lattice_ecp2_3_erase_device(struct lattice_pld_device *lattice_device)
|
|
{
|
|
struct jtag_tap *tap = lattice_device->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
/* program user code with all bits set */
|
|
int retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
struct scan_field field;
|
|
uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff};
|
|
field.num_bits = 32;
|
|
field.out_value = buffer;
|
|
field.in_value = NULL;
|
|
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(2000);
|
|
|
|
/* verify every bit is set */
|
|
const uint32_t out = REGISTER_ALL_BITS_1;
|
|
const uint32_t mask = REGISTER_ALL_BITS_1;
|
|
const uint32_t expected_pre = REGISTER_ALL_BITS_1;
|
|
retval = lattice_verify_usercode(lattice_device, out, expected_pre, mask);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
if (lattice_device->family == LATTICE_ECP2)
|
|
jtag_add_sleep(100000);
|
|
else
|
|
jtag_add_sleep(2000000);
|
|
|
|
retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(2000);
|
|
|
|
/* after erasing check all bits in user register are cleared */
|
|
const uint32_t expected_post = REGISTER_ALL_BITS_0;
|
|
return lattice_verify_usercode(lattice_device, out, expected_post, mask);
|
|
}
|
|
|
|
static int lattice_ecp2_3_program_config_map(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_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(2000);
|
|
|
|
struct scan_field field;
|
|
retval = lattice_set_instr(tap, LSCC_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);
|
|
jtag_add_runtest(256, TAP_IDLE);
|
|
jtag_add_sleep(2000);
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
static int lattice_ecp2_3_exit_programming_mode(struct lattice_pld_device *lattice_device)
|
|
{
|
|
struct jtag_tap *tap = lattice_device->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(200000);
|
|
retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(100, TAP_IDLE);
|
|
jtag_add_sleep(1000);
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
int lattice_ecp2_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;
|
|
|
|
/* Enable the programming mode */
|
|
retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(20000);
|
|
|
|
/* Erase the device */
|
|
retval = lattice_ecp2_3_erase_device(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
/* Program Fuse Map */
|
|
retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp2_3_exit_programming_mode(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
const uint32_t out = REGISTER_ALL_BITS_1;
|
|
const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP2;
|
|
const uint32_t expected = STATUS_DONE_BIT;
|
|
return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false);
|
|
}
|
|
|
|
int lattice_ecp3_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;
|
|
|
|
/* Program Bscan register */
|
|
int retval = lattice_preload(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
/* Enable the programming mode */
|
|
retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(500000);
|
|
retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(5, TAP_IDLE);
|
|
jtag_add_sleep(20000);
|
|
|
|
retval = lattice_ecp2_3_erase_device(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
/* Program Fuse Map */
|
|
retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp2_3_exit_programming_mode(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
const uint32_t out = REGISTER_ALL_BITS_1;
|
|
const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP3;
|
|
const uint32_t expected = STATUS_DONE_BIT;
|
|
return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false);
|
|
}
|
|
|
|
int lattice_ecp2_3_connect_spi_to_jtag(struct lattice_pld_device *pld_device_info)
|
|
{
|
|
if (!pld_device_info)
|
|
return ERROR_FAIL;
|
|
|
|
struct jtag_tap *tap = pld_device_info->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
// erase configuration
|
|
int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
// connect jtag to spi pins
|
|
retval = lattice_set_instr(tap, PROGRAM_SPI, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
int lattice_ecp2_3_disconnect_spi_from_jtag(struct lattice_pld_device *pld_device_info)
|
|
{
|
|
if (!pld_device_info)
|
|
return ERROR_FAIL;
|
|
|
|
struct jtag_tap *tap = pld_device_info->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
int lattice_ecp2_3_get_facing_read_bits(struct lattice_pld_device *pld_device_info, unsigned int *facing_read_bits)
|
|
{
|
|
if (!pld_device_info)
|
|
return ERROR_FAIL;
|
|
|
|
*facing_read_bits = 1;
|
|
|
|
return ERROR_OK;
|
|
}
|