riscv-openocd/src/pld/lattice.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,
};