aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Anselmi <danselmi@gmx.ch>2023-02-24 15:57:30 +0100
committerAntonio Borneo <borneo.antonio@gmail.com>2023-09-23 14:33:37 +0000
commitfe5ed48f40e4f1b36d74900d0d9b410affea6bdb (patch)
treeb10ee1879bf35cfefa890096461ec092d99833da /src
parent30375c6439ee97f60d729db747f01fb4eb2cf495 (diff)
downloadriscv-openocd-fe5ed48f40e4f1b36d74900d0d9b410affea6bdb.zip
riscv-openocd-fe5ed48f40e4f1b36d74900d0d9b410affea6bdb.tar.gz
riscv-openocd-fe5ed48f40e4f1b36d74900d0d9b410affea6bdb.tar.bz2
jtagspi/pld: add interface to get support from pld drivers
Jtagspi is using a proxy bitstream to "connect" JTAG to the SPI pins. This is not possible with all FPGA vendors/families. In this cases a dedicated procedure is needed to establish such a connection. This patch adds a jtagspi-mode for these cases. It also adds the needed interfaces to jtagspi and the pld-driver so the driver can select the mode and provide the necessary procedures. For the cases where a proxy bitstream is needed, the pld driver will select the mode and provide instruction code needed in this case. Change-Id: I9563f26739589157b39a3664a73d91152cd13f77 Signed-off-by: Daniel Anselmi <danselmi@gmx.ch> Reviewed-on: https://review.openocd.org/c/openocd/+/7822 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/flash/nor/jtagspi.c119
-rw-r--r--src/pld/pld.c91
-rw-r--r--src/pld/pld.h14
3 files changed, 192 insertions, 32 deletions
diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c
index 6bb3af9..4b97539 100644
--- a/src/flash/nor/jtagspi.c
+++ b/src/flash/nor/jtagspi.c
@@ -12,6 +12,7 @@
#include <jtag/jtag.h>
#include <flash/nor/spi.h>
#include <helper/time_support.h>
+#include <pld/pld.h>
#define JTAGSPI_MAX_TIMEOUT 3000
@@ -21,19 +22,44 @@ struct jtagspi_flash_bank {
struct flash_device dev;
char devname[32];
bool probed;
- bool always_4byte; /* use always 4-byte address except for basic read 0x03 */
- uint32_t ir;
- unsigned int addr_len; /* address length in bytes */
+ bool always_4byte; /* use always 4-byte address except for basic read 0x03 */
+ unsigned int addr_len; /* address length in bytes */
+ struct pld_device *pld_device; /* if not NULL, the PLD has special instructions for JTAGSPI */
+ uint32_t ir; /* when !pld_device, this instruction code is used in
+ jtagspi_set_user_ir to connect through a proxy bitstream */
};
FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
{
- struct jtagspi_flash_bank *info;
-
if (CMD_ARGC < 7)
return ERROR_COMMAND_SYNTAX_ERROR;
- info = malloc(sizeof(struct jtagspi_flash_bank));
+ unsigned int ir = 0;
+ struct pld_device *device = NULL;
+ if (strcmp(CMD_ARGV[6], "-pld") == 0) {
+ if (CMD_ARGC < 8)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ device = get_pld_device_by_name_or_numstr(CMD_ARGV[7]);
+ if (device) {
+ bool has_jtagspi_instruction = false;
+ int retval = pld_has_jtagspi_instruction(device, &has_jtagspi_instruction);
+ if (retval != ERROR_OK)
+ return retval;
+ if (!has_jtagspi_instruction) {
+ retval = pld_get_jtagspi_userircode(device, &ir);
+ if (retval != ERROR_OK)
+ return retval;
+ device = NULL;
+ }
+ } else {
+ LOG_ERROR("pld device '#%s' is out of bounds or unknown", CMD_ARGV[7]);
+ return ERROR_FAIL;
+ }
+ } else {
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], ir);
+ }
+
+ struct jtagspi_flash_bank *info = calloc(1, sizeof(struct jtagspi_flash_bank));
if (!info) {
LOG_ERROR("no memory for flash bank info");
return ERROR_FAIL;
@@ -47,18 +73,19 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
}
info->tap = bank->target->tap;
info->probed = false;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
+
+ info->ir = ir;
+ info->pld_device = device;
return ERROR_OK;
}
-static void jtagspi_set_ir(struct flash_bank *bank)
+static void jtagspi_set_user_ir(struct jtagspi_flash_bank *info)
{
- struct jtagspi_flash_bank *info = bank->driver_priv;
struct scan_field field;
uint8_t buf[4] = { 0 };
- LOG_DEBUG("loading jtagspi ir");
+ LOG_DEBUG("loading jtagspi ir(0x%" PRIx32 ")", info->ir);
buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
field.num_bits = info->tap->ir_length;
field.out_value = buf;
@@ -79,6 +106,7 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
assert(data_buffer || data_len == 0);
struct scan_field fields[6];
+ struct jtagspi_flash_bank *info = bank->driver_priv;
LOG_DEBUG("cmd=0x%02x write_len=%d data_len=%d", cmd, write_len, data_len);
@@ -87,22 +115,34 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
if (is_read)
data_len = -data_len;
+ unsigned int facing_read_bits = 0;
+ unsigned int trailing_write_bits = 0;
+
+ if (info->pld_device) {
+ int retval = pld_get_jtagspi_stuff_bits(info->pld_device, &facing_read_bits, &trailing_write_bits);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
int n = 0;
const uint8_t marker = 1;
- fields[n].num_bits = 1;
- fields[n].out_value = &marker;
- fields[n].in_value = NULL;
- n++;
-
- /* transfer length = cmd + address + read/write,
- * -1 due to the counter implementation */
uint8_t xfer_bits[4];
- h_u32_to_be(xfer_bits, ((sizeof(cmd) + write_len + data_len) * CHAR_BIT) - 1);
- flip_u8(xfer_bits, xfer_bits, sizeof(xfer_bits));
- fields[n].num_bits = sizeof(xfer_bits) * CHAR_BIT;
- fields[n].out_value = xfer_bits;
- fields[n].in_value = NULL;
- n++;
+ if (!info->pld_device) { /* mode == JTAGSPI_MODE_PROXY_BITSTREAM */
+ facing_read_bits = jtag_tap_count_enabled();
+ fields[n].num_bits = 1;
+ fields[n].out_value = &marker;
+ fields[n].in_value = NULL;
+ n++;
+
+ /* transfer length = cmd + address + read/write,
+ * -1 due to the counter implementation */
+ h_u32_to_be(xfer_bits, ((sizeof(cmd) + write_len + data_len) * CHAR_BIT) - 1);
+ flip_u8(xfer_bits, xfer_bits, sizeof(xfer_bits));
+ fields[n].num_bits = sizeof(xfer_bits) * CHAR_BIT;
+ fields[n].out_value = xfer_bits;
+ fields[n].in_value = NULL;
+ n++;
+ }
flip_u8(&cmd, &cmd, sizeof(cmd));
fields[n].num_bits = sizeof(cmd) * CHAR_BIT;
@@ -120,10 +160,12 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
if (data_len > 0) {
if (is_read) {
- fields[n].num_bits = jtag_tap_count_enabled();
- fields[n].out_value = NULL;
- fields[n].in_value = NULL;
- n++;
+ if (facing_read_bits) {
+ fields[n].num_bits = facing_read_bits;
+ fields[n].out_value = NULL;
+ fields[n].in_value = NULL;
+ n++;
+ }
fields[n].out_value = NULL;
fields[n].in_value = data_buffer;
@@ -135,16 +177,33 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
fields[n].num_bits = data_len * CHAR_BIT;
n++;
}
+ if (!is_read && trailing_write_bits) {
+ fields[n].num_bits = trailing_write_bits;
+ fields[n].out_value = NULL;
+ fields[n].in_value = NULL;
+ n++;
+ }
+
+ if (info->pld_device) {
+ int retval = pld_connect_spi_to_jtag(info->pld_device);
+ if (retval != ERROR_OK)
+ return retval;
+ } else {
+ jtagspi_set_user_ir(info);
+ }
- jtagspi_set_ir(bank);
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
- struct jtagspi_flash_bank *info = bank->driver_priv;
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
int retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
if (is_read)
flip_u8(data_buffer, data_buffer, data_len);
- return retval;
+
+ if (info->pld_device)
+ return pld_disconnect_spi_from_jtag(info->pld_device);
+ return ERROR_OK;
}
COMMAND_HANDLER(jtagspi_handle_set)
diff --git a/src/pld/pld.c b/src/pld/pld.c
index c375418..81fb0c4 100644
--- a/src/pld/pld.c
+++ b/src/pld/pld.c
@@ -69,8 +69,95 @@ struct pld_device *get_pld_device_by_name_or_numstr(const char *str)
return get_pld_device_by_num(dev_num);
}
-/* @deffn {Config Command} {pld create} pld_name driver -chain-position tap_name [options]
-*/
+
+int pld_has_jtagspi_instruction(struct pld_device *pld_device, bool *has_instruction)
+{
+ *has_instruction = false; /* default is using a proxy bitstream */
+
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct pld_driver *pld_driver = pld_device->driver;
+ if (!pld_driver) {
+ LOG_ERROR("pld device has no associated driver");
+ return ERROR_FAIL;
+ }
+
+ if (pld_driver->has_jtagspi_instruction)
+ return pld_driver->has_jtagspi_instruction(pld_device, has_instruction);
+ /* else, take the default (proxy bitstream) */
+ return ERROR_OK;
+}
+
+int pld_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct pld_driver *pld_driver = pld_device->driver;
+ if (!pld_driver) {
+ LOG_ERROR("pld device has no associated driver");
+ return ERROR_FAIL;
+ }
+
+ if (pld_driver->get_jtagspi_userircode)
+ return pld_driver->get_jtagspi_userircode(pld_device, ir);
+
+ return ERROR_FAIL;
+}
+
+int pld_get_jtagspi_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits,
+ unsigned int *trailing_write_bits)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct pld_driver *pld_driver = pld_device->driver;
+ if (!pld_driver) {
+ LOG_ERROR("pld device has no associated driver");
+ return ERROR_FAIL;
+ }
+
+ if (pld_driver->get_stuff_bits)
+ return pld_driver->get_stuff_bits(pld_device, facing_read_bits, trailing_write_bits);
+
+ return ERROR_OK;
+}
+
+int pld_connect_spi_to_jtag(struct pld_device *pld_device)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct pld_driver *pld_driver = pld_device->driver;
+ if (!pld_driver) {
+ LOG_ERROR("pld device has no associated driver");
+ return ERROR_FAIL;
+ }
+
+ if (pld_driver->connect_spi_to_jtag)
+ return pld_driver->connect_spi_to_jtag(pld_device);
+
+ return ERROR_FAIL;
+}
+
+int pld_disconnect_spi_from_jtag(struct pld_device *pld_device)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct pld_driver *pld_driver = pld_device->driver;
+ if (!pld_driver) {
+ LOG_ERROR("pld device has no associated driver");
+ return ERROR_FAIL;
+ }
+
+ if (pld_driver->disconnect_spi_from_jtag)
+ return pld_driver->disconnect_spi_from_jtag(pld_device);
+
+ return ERROR_FAIL;
+}
+
COMMAND_HANDLER(handle_pld_create_command)
{
if (CMD_ARGC < 2)
diff --git a/src/pld/pld.h b/src/pld/pld.h
index b736e6a..5e2fcd2 100644
--- a/src/pld/pld.h
+++ b/src/pld/pld.h
@@ -20,12 +20,26 @@ struct pld_ipdbg_hub {
unsigned int user_ir_code;
};
+int pld_has_jtagspi_instruction(struct pld_device *device, bool *has_instruction);
+int pld_get_jtagspi_userircode(struct pld_device *pld_device, unsigned int *ir);
+
+int pld_get_jtagspi_stuff_bits(struct pld_device *pld_device, unsigned int *facing_read_bits,
+ unsigned int *trailing_write_bits);
+int pld_connect_spi_to_jtag(struct pld_device *pld_device);
+int pld_disconnect_spi_from_jtag(struct pld_device *pld_device);
+
struct pld_driver {
const char *name;
__PLD_CREATE_COMMAND((*pld_create_command));
const struct command_registration *commands;
int (*load)(struct pld_device *pld_device, const char *filename);
int (*get_ipdbg_hub)(int user_num, struct pld_device *pld_device, struct pld_ipdbg_hub *hub);
+ int (*has_jtagspi_instruction)(struct pld_device *device, bool *has_instruction);
+ int (*get_jtagspi_userircode)(struct pld_device *pld_device, unsigned int *ir);
+ int (*connect_spi_to_jtag)(struct pld_device *pld_device);
+ int (*disconnect_spi_from_jtag)(struct pld_device *pld_device);
+ int (*get_stuff_bits)(struct pld_device *pld_device, unsigned int *facing_read_bits,
+ unsigned int *trailing_write_bits);
};
#define PLD_CREATE_COMMAND_HANDLER(name) \