664 lines
19 KiB
C
664 lines
19 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 "lattice.h"
|
|
#include <jtag/jtag.h>
|
|
#include "pld.h"
|
|
#include "lattice_bit.h"
|
|
#include "ecp2_3.h"
|
|
#include "ecp5.h"
|
|
#include "certus.h"
|
|
|
|
#define PRELOAD 0x1C
|
|
#define USER1 0x32
|
|
#define USER2 0x38
|
|
|
|
|
|
struct lattice_devices_elem {
|
|
uint32_t id;
|
|
size_t preload_length;
|
|
enum lattice_family_e family;
|
|
};
|
|
|
|
static const struct lattice_devices_elem lattice_devices[] = {
|
|
{0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */},
|
|
{0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */},
|
|
{0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */},
|
|
{0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */},
|
|
{0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */},
|
|
{0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */},
|
|
{0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */},
|
|
{0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */},
|
|
{0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */},
|
|
{0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */},
|
|
{0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */},
|
|
{0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/},
|
|
{0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/},
|
|
{0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/},
|
|
{0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/},
|
|
{0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */},
|
|
{0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */},
|
|
{0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */},
|
|
{0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */},
|
|
{0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */},
|
|
{0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */},
|
|
{0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */},
|
|
{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)
|
|
{
|
|
struct scan_field field;
|
|
field.num_bits = tap->ir_length;
|
|
void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
|
|
if (!t) {
|
|
LOG_ERROR("Out of memory");
|
|
return ERROR_FAIL;
|
|
}
|
|
field.out_value = t;
|
|
buf_set_u32(t, 0, field.num_bits, new_instr);
|
|
field.in_value = NULL;
|
|
jtag_add_ir_scan(tap, &field, endstate);
|
|
free(t);
|
|
return ERROR_OK;
|
|
}
|
|
|
|
static int lattice_check_device_family(struct lattice_pld_device *lattice_device)
|
|
{
|
|
if (lattice_device->family != LATTICE_UNKNOWN && lattice_device->preload_length != 0)
|
|
return ERROR_OK;
|
|
|
|
if (!lattice_device->tap || !lattice_device->tap->has_idcode)
|
|
return ERROR_FAIL;
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) {
|
|
if (lattice_devices[i].id == lattice_device->tap->idcode) {
|
|
if (lattice_device->family == LATTICE_UNKNOWN)
|
|
lattice_device->family = lattice_devices[i].family;
|
|
if (lattice_device->preload_length == 0)
|
|
lattice_device->preload_length = lattice_devices[i].preload_length;
|
|
return ERROR_OK;
|
|
}
|
|
}
|
|
LOG_ERROR("Unknown id! Specify family and preload-length manually.");
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
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];
|
|
|
|
int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
if (do_idle) {
|
|
jtag_add_runtest(2, TAP_IDLE);
|
|
jtag_add_sleep(1000);
|
|
}
|
|
|
|
h_u32_to_le(buffer, out_val);
|
|
field.num_bits = 32;
|
|
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_u32(buffer);
|
|
|
|
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;
|
|
size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8);
|
|
|
|
int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
uint8_t *buffer = malloc(sz_bytes);
|
|
if (!buffer) {
|
|
LOG_ERROR("Out of memory");
|
|
return ERROR_FAIL;
|
|
}
|
|
memset(buffer, 0xff, sz_bytes);
|
|
|
|
field.num_bits = lattice_device->preload_length;
|
|
field.out_value = buffer;
|
|
field.in_value = NULL;
|
|
jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE);
|
|
retval = jtag_execute_queue();
|
|
free(buffer);
|
|
return retval;
|
|
}
|
|
|
|
static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint32_t *usercode, uint32_t out)
|
|
{
|
|
struct jtag_tap *tap = lattice_device->tap;
|
|
if (!tap)
|
|
return ERROR_FAIL;
|
|
|
|
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
|
|
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;
|
|
}
|
|
|
|
int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out,
|
|
uint32_t expected, uint32_t mask)
|
|
{
|
|
uint32_t usercode;
|
|
|
|
int retval = lattice_read_usercode(lattice_device, &usercode, out);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
if ((usercode & mask) != expected) {
|
|
LOG_ERROR("verifying user code register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32,
|
|
usercode & mask, expected);
|
|
return ERROR_FAIL;
|
|
}
|
|
return ERROR_OK;
|
|
}
|
|
|
|
static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
|
|
{
|
|
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
|
|
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;
|
|
}
|
|
|
|
static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, uint32_t *status,
|
|
uint32_t out, bool do_idle)
|
|
{
|
|
if (!lattice_device->tap)
|
|
return ERROR_FAIL;
|
|
|
|
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
|
|
return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle);
|
|
else if (lattice_device->family == LATTICE_ECP5)
|
|
return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle);
|
|
|
|
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;
|
|
|
|
if ((status & mask) != expected) {
|
|
LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32,
|
|
status & mask, expected);
|
|
return ERROR_FAIL;
|
|
}
|
|
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;
|
|
|
|
if (!tap || !tap->has_idcode)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_check_device_family(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
struct lattice_bit_file bit_file;
|
|
retval = lattice_read_file(&bit_file, filename, lattice_device->family);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
uint32_t id = tap->idcode;
|
|
retval = ERROR_FAIL;
|
|
switch (lattice_device->family) {
|
|
case LATTICE_ECP2:
|
|
retval = lattice_ecp2_load(lattice_device, &bit_file);
|
|
break;
|
|
case LATTICE_ECP3:
|
|
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);
|
|
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");
|
|
break;
|
|
}
|
|
free(bit_file.raw_bit.data);
|
|
return retval;
|
|
}
|
|
|
|
static int lattice_get_ipdbg_hub(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub)
|
|
{
|
|
if (!pld_device)
|
|
return ERROR_FAIL;
|
|
|
|
struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
|
|
|
|
if (!pld_device_info || !pld_device_info->tap)
|
|
return ERROR_FAIL;
|
|
|
|
hub->tap = pld_device_info->tap;
|
|
|
|
if (user_num == 1) {
|
|
hub->user_ir_code = USER1;
|
|
} else if (user_num == 2) {
|
|
hub->user_ir_code = USER2;
|
|
} else {
|
|
LOG_ERROR("lattice devices only have user register 1 & 2");
|
|
return ERROR_FAIL;
|
|
}
|
|
return ERROR_OK;
|
|
}
|
|
|
|
static int lattice_connect_spi_to_jtag(struct pld_device *pld_device)
|
|
{
|
|
if (!pld_device)
|
|
return ERROR_FAIL;
|
|
|
|
struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
|
|
|
|
int retval = lattice_check_device_family(pld_device_info);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3)
|
|
return lattice_ecp2_3_connect_spi_to_jtag(pld_device_info);
|
|
else if (pld_device_info->family == LATTICE_ECP5)
|
|
return lattice_ecp5_connect_spi_to_jtag(pld_device_info);
|
|
else if (pld_device_info->family == LATTICE_CERTUS)
|
|
return lattice_certus_connect_spi_to_jtag(pld_device_info);
|
|
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
static int lattice_disconnect_spi_from_jtag(struct pld_device *pld_device)
|
|
{
|
|
if (!pld_device)
|
|
return ERROR_FAIL;
|
|
|
|
struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
|
|
|
|
int retval = lattice_check_device_family(pld_device_info);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3)
|
|
return lattice_ecp2_3_disconnect_spi_from_jtag(pld_device_info);
|
|
else if (pld_device_info->family == LATTICE_ECP5)
|
|
return lattice_ecp5_disconnect_spi_from_jtag(pld_device_info);
|
|
else if (pld_device_info->family == LATTICE_CERTUS)
|
|
return lattice_certus_disconnect_spi_from_jtag(pld_device_info);
|
|
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
static int lattice_get_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits,
|
|
unsigned int *trailing_write_bits)
|
|
{
|
|
if (!pld_device)
|
|
return ERROR_FAIL;
|
|
|
|
struct lattice_pld_device *pld_device_info = pld_device->driver_priv;
|
|
|
|
int retval = lattice_check_device_family(pld_device_info);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
if (pld_device_info->family == LATTICE_ECP2 || pld_device_info->family == LATTICE_ECP3)
|
|
return lattice_ecp2_3_get_facing_read_bits(pld_device_info, facing_read_bits);
|
|
else if (pld_device_info->family == LATTICE_ECP5)
|
|
return lattice_ecp5_get_facing_read_bits(pld_device_info, facing_read_bits);
|
|
else if (pld_device_info->family == LATTICE_CERTUS)
|
|
return lattice_certus_get_facing_read_bits(pld_device_info, facing_read_bits);
|
|
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
static int lattice_has_jtagspi_instruction(struct pld_device *device, bool *has_instruction)
|
|
{
|
|
*has_instruction = true;
|
|
return ERROR_OK;
|
|
}
|
|
|
|
PLD_CREATE_COMMAND_HANDLER(lattice_pld_create_command)
|
|
{
|
|
if (CMD_ARGC != 4 && CMD_ARGC != 6)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
if (strcmp(CMD_ARGV[2], "-chain-position") != 0)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[3]);
|
|
if (!tap) {
|
|
command_print(CMD, "Tap: %s does not exist", CMD_ARGV[3]);
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
/* id is not known yet -> postpone lattice_check_device_family() */
|
|
enum lattice_family_e family = LATTICE_UNKNOWN;
|
|
if (CMD_ARGC == 6) {
|
|
if (strcmp(CMD_ARGV[4], "-family") != 0)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
if (strcasecmp(CMD_ARGV[5], "ecp2") == 0) {
|
|
family = LATTICE_ECP2;
|
|
} else if (strcasecmp(CMD_ARGV[5], "ecp3") == 0) {
|
|
family = LATTICE_ECP3;
|
|
} else if (strcasecmp(CMD_ARGV[5], "ecp5") == 0) {
|
|
family = LATTICE_ECP5;
|
|
} else if (strcasecmp(CMD_ARGV[5], "certus") == 0) {
|
|
family = LATTICE_CERTUS;
|
|
} else {
|
|
command_print(CMD, "unknown family");
|
|
return ERROR_FAIL;
|
|
}
|
|
}
|
|
|
|
struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device));
|
|
if (!lattice_device) {
|
|
LOG_ERROR("Out of memory");
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
lattice_device->tap = tap;
|
|
lattice_device->family = family;
|
|
lattice_device->preload_length = 0;
|
|
|
|
pld->driver_priv = lattice_device;
|
|
|
|
return ERROR_OK;
|
|
}
|
|
|
|
COMMAND_HANDLER(lattice_read_usercode_register_command_handler)
|
|
{
|
|
uint32_t usercode;
|
|
|
|
if (CMD_ARGC != 1)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
|
|
if (!device) {
|
|
command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
struct lattice_pld_device *lattice_device = device->driver_priv;
|
|
if (!lattice_device)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_check_device_family(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
retval = lattice_read_usercode(lattice_device, &usercode, 0x0);
|
|
if (retval == ERROR_OK)
|
|
command_print(CMD, "0x%8.8" PRIx32, usercode);
|
|
|
|
return retval;
|
|
}
|
|
|
|
COMMAND_HANDLER(lattice_set_preload_command_handler)
|
|
{
|
|
unsigned int preload_length;
|
|
|
|
if (CMD_ARGC != 2)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
|
|
if (!device) {
|
|
command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length);
|
|
|
|
struct lattice_pld_device *lattice_device = device->driver_priv;
|
|
|
|
if (!lattice_device)
|
|
return ERROR_FAIL;
|
|
|
|
lattice_device->preload_length = preload_length;
|
|
|
|
return ERROR_OK;
|
|
}
|
|
|
|
COMMAND_HANDLER(lattice_write_usercode_register_command_handler)
|
|
{
|
|
uint32_t usercode;
|
|
|
|
if (CMD_ARGC != 2)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
|
|
if (!device) {
|
|
command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode);
|
|
|
|
struct lattice_pld_device *lattice_device = device->driver_priv;
|
|
if (!lattice_device)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_check_device_family(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
return lattice_write_usercode(lattice_device, usercode);
|
|
}
|
|
|
|
COMMAND_HANDLER(lattice_read_status_command_handler)
|
|
{
|
|
if (CMD_ARGC != 1)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
|
|
if (!device) {
|
|
command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
struct lattice_pld_device *lattice_device = device->driver_priv;
|
|
if (!lattice_device)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_check_device_family(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
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;
|
|
}
|
|
|
|
COMMAND_HANDLER(lattice_refresh_command_handler)
|
|
{
|
|
if (CMD_ARGC != 1)
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
struct pld_device *device = get_pld_device_by_name_or_numstr(CMD_ARGV[0]);
|
|
if (!device) {
|
|
command_print(CMD, "pld device '#%s' is out of bounds or unknown", CMD_ARGV[0]);
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
struct lattice_pld_device *lattice_device = device->driver_priv;
|
|
if (!lattice_device)
|
|
return ERROR_FAIL;
|
|
|
|
int retval = lattice_check_device_family(lattice_device);
|
|
if (retval != ERROR_OK)
|
|
return retval;
|
|
|
|
if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
|
|
return lattice_ecp2_3_refresh(lattice_device);
|
|
else if (lattice_device->family == LATTICE_ECP5)
|
|
return lattice_ecp5_refresh(lattice_device);
|
|
else if (lattice_device->family == LATTICE_CERTUS)
|
|
return lattice_certus_refresh(lattice_device);
|
|
|
|
return ERROR_FAIL;
|
|
}
|
|
|
|
static const struct command_registration lattice_exec_command_handlers[] = {
|
|
{
|
|
.name = "read_status",
|
|
.mode = COMMAND_EXEC,
|
|
.handler = lattice_read_status_command_handler,
|
|
.help = "reading status register from FPGA",
|
|
.usage = "pld_name",
|
|
}, {
|
|
.name = "read_user",
|
|
.mode = COMMAND_EXEC,
|
|
.handler = lattice_read_usercode_register_command_handler,
|
|
.help = "reading usercode register from FPGA",
|
|
.usage = "pld_name",
|
|
}, {
|
|
.name = "write_user",
|
|
.mode = COMMAND_EXEC,
|
|
.handler = lattice_write_usercode_register_command_handler,
|
|
.help = "writing usercode register to FPGA",
|
|
.usage = "pld_name value",
|
|
}, {
|
|
.name = "set_preload",
|
|
.mode = COMMAND_ANY,
|
|
.handler = lattice_set_preload_command_handler,
|
|
.help = "set length for preload (device specific)",
|
|
.usage = "pld_name value",
|
|
}, {
|
|
.name = "refresh",
|
|
.mode = COMMAND_EXEC,
|
|
.handler = lattice_refresh_command_handler,
|
|
.help = "refresh from configuration memory",
|
|
.usage = "pld_name",
|
|
},
|
|
COMMAND_REGISTRATION_DONE
|
|
};
|
|
|
|
static const struct command_registration lattice_command_handler[] = {
|
|
{
|
|
.name = "lattice",
|
|
.mode = COMMAND_ANY,
|
|
.help = "lattice specific commands",
|
|
.usage = "",
|
|
.chain = lattice_exec_command_handlers,
|
|
},
|
|
COMMAND_REGISTRATION_DONE
|
|
};
|
|
|
|
struct pld_driver lattice_pld = {
|
|
.name = "lattice",
|
|
.commands = lattice_command_handler,
|
|
.pld_create_command = &lattice_pld_create_command,
|
|
.load = &lattice_load_command,
|
|
.get_ipdbg_hub = lattice_get_ipdbg_hub,
|
|
.has_jtagspi_instruction = lattice_has_jtagspi_instruction,
|
|
.connect_spi_to_jtag = lattice_connect_spi_to_jtag,
|
|
.disconnect_spi_from_jtag = lattice_disconnect_spi_from_jtag,
|
|
.get_stuff_bits = lattice_get_stuff_bits,
|
|
};
|