303 lines
8.1 KiB
C
303 lines
8.1 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 "ecp5.h"
|
|
#include "lattice.h"
|
|
#include "lattice_cmd.h"
|
|
|
|
#define ISC_PROGRAM_USERCODE 0xC2
|
|
|
|
#define STATUS_DONE_BIT 0x00000100
|
|
#define STATUS_ERROR_BITS 0x00020040
|
|
#define STATUS_FEA_OTP 0x00004000
|
|
#define STATUS_FAIL_FLAG 0x00002000
|
|
#define STATUS_BUSY_FLAG 0x00001000
|
|
#define REGISTER_ALL_BITS_1 0xffffffff
|
|
|
|
int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle)
|
|
{
|
|
return lattice_read_u32_register(tap, LSC_READ_STATUS, status, out, do_idle);
|
|
}
|
|
|
|
int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out)
|
|
{
|
|
return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, true);
|
|
}
|
|
|
|
int lattice_ecp5_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;
|
|
|
|
uint8_t buffer[4];
|
|
struct scan_field field;
|
|
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_ecp5_enable_sram_programming(struct jtag_tap *tap)
|
|
{
|
|
int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
struct scan_field field;
|
|
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);
|
|
jtag_add_sleep(10000);
|
|
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
static int lattice_ecp5_erase_sram(struct jtag_tap *tap)
|
|
{
|
|
int retval = lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
struct scan_field field;
|
|
uint8_t buffer = 1;
|
|
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);
|
|
jtag_add_sleep(200000);
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
static int lattice_ecp5_init_address(struct jtag_tap *tap)
|
|
{
|
|
int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
struct scan_field field;
|
|
uint8_t buffer = 1;
|
|
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);
|
|
jtag_add_sleep(10000);
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
static int lattice_ecp5_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file)
|
|
{
|
|
int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(2, TAP_IDLE);
|
|
jtag_add_sleep(10000);
|
|
|
|
struct scan_field field;
|
|
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);
|
|
retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(100, TAP_IDLE);
|
|
jtag_add_sleep(10000);
|
|
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
static int lattice_ecp5_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);
|
|
jtag_add_sleep(200000);
|
|
retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(2, TAP_IDLE);
|
|
jtag_add_sleep(1000);
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
int lattice_ecp5_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;
|
|
|
|
retval = lattice_ecp5_enable_sram_programming(tap);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
const uint32_t out = 0x0;
|
|
const uint32_t expected1 = 0x0;
|
|
const uint32_t mask1 = STATUS_ERROR_BITS | STATUS_FEA_OTP;
|
|
retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask1, true);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_erase_sram(tap);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
const uint32_t mask2 = STATUS_FAIL_FLAG | STATUS_BUSY_FLAG;
|
|
retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask2, false);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_init_address(tap);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_program_config_map(tap, bit_file);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_exit_programming_mode(tap);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
const uint32_t expected2 = STATUS_DONE_BIT;
|
|
const uint32_t mask3 = STATUS_DONE_BIT | STATUS_FAIL_FLAG;
|
|
return lattice_verify_status_register_u32(lattice_device, out, expected2, mask3, false);
|
|
}
|
|
|
|
int lattice_ecp5_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;
|
|
|
|
if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) == PROGRAM_SPI)
|
|
return ERROR_OK;
|
|
|
|
// erase configuration
|
|
int retval = lattice_preload(pld_device_info);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_enable_sram_programming(tap);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_erase_sram(tap);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_ecp5_exit_programming_mode(tap);
|
|
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;
|
|
|
|
struct scan_field field;
|
|
uint8_t buffer[2] = {0xfe, 0x68};
|
|
field.num_bits = 16;
|
|
field.out_value = buffer;
|
|
field.in_value = NULL;
|
|
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
|
|
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
int lattice_ecp5_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;
|
|
|
|
/* Connecting it again takes way too long to do it multiple times for writing
|
|
a bitstream (ca. 0.4s each access).
|
|
We just leave it connected since SCS will not be active when not in shift_dr state.
|
|
So there is no need to change instruction, just make sure we are not in shift dr state. */
|
|
jtag_add_runtest(2, TAP_IDLE);
|
|
return jtag_execute_queue();
|
|
}
|
|
|
|
int lattice_ecp5_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 = 0;
|
|
|
|
return ERROR_OK;
|
|
}
|
|
|
|
int lattice_ecp5_refresh(struct lattice_pld_device *lattice_device)
|
|
{
|
|
struct jtag_tap *tap = lattice_device->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_preload(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
jtag_add_runtest(2, 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();
|
|
}
|