This is an automated email from Gerrit.

"Daniel Anselmi <danse...@gmx.ch>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/7822

-- gerrit

commit 3d26da17b3e902816238b0a86eb921bca711ac65
Author: Daniel Anselmi <danse...@gmx.ch>
Date:   Fri Feb 24 15:57:30 2023 +0100

    jtagspi/pld: add interface to get support from pld drivers
    
    Change-Id: I9563f26739589157b39a3664a73d91152cd13f77
    Signed-off-by: Daniel Anselmi <danse...@gmx.ch>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 12a8ca56df..89ad921668 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -5817,6 +5817,7 @@ flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 
$_TARGETNAME
 @c "cfi part_id" disabled
 @end deffn
 
+@anchor{jtagspi}
 @deffn {Flash Driver} {jtagspi}
 @cindex Generic JTAG2SPI driver
 @cindex SPI
@@ -5824,17 +5825,34 @@ flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 
$_TARGETNAME
 @cindex bscan_spi
 Several FPGAs and CPLDs can retrieve their configuration (bitstream) from a
 SPI flash connected to them. To access this flash from the host, the device
-is first programmed with a special proxy bitstream that
-exposes the SPI flash on the device's JTAG interface. The flash can then be
-accessed through JTAG.
+is first programmed with a special proxy bitstream that exposes the SPI flash
+on the device's JTAG interface or with dedicated JTAG instructions. The flash
+can then be accessed through JTAG.
 
-Since signaling between JTAG and SPI is compatible, all that is required for
+Since signalling between JTAG and SPI is compatible, all that is required for
 a proxy bitstream is to connect TDI-MOSI, TDO-MISO, TCK-CLK and activate
-the flash chip select when the JTAG state machine is in SHIFT-DR. Such
-a bitstream for several Xilinx FPGAs can be found in
+the flash chip select when the JTAG state machine is in SHIFT-DR.
+
+Such a bitstream for several Xilinx FPGAs can be found in
 @file{contrib/loaders/flash/fpga/xilinx_bscan_spi.py}. It requires
 @uref{https://github.com/m-labs/migen, migen} and a Xilinx toolchain to build.
 
+This mechanism with a proxy bitstream can also be used for FPGAs from Intel and
+Efinix. FPGAs from Lattice and Cologne Chip have dedicated JTAG instructions
+and procedure to connect the JTAG to the SPI signals and don't need a proxy
+bitstream. Support for these devices with dedicated procedure is provided by
+the pld drivers. For convenience the PLD drivers will provide the USERx code
+for FPGAs with a proxy bitstream. Currently the following PLD drives are able
+to support jtagspi:
+@itemize
+@item Efinix: proxy-bitstream
+@item Gatemate: dedicated procedure
+@item Intel/Altera: proxy-bitstream
+@item Lattice: dedicated procedure supporting ECP2, ECP3, ECP5, Certus and 
Certus Pro devices
+@item AMD/Xilinx: proxy-bitstream
+@end itemize
+
+
 This flash bank driver requires a target on a JTAG tap and will access that
 tap directly. Since no support from the target is needed, the target can be a
 "testee" dummy. Since the target does not expose the flash memory
@@ -5852,14 +5870,25 @@ command, see below.
 @item @var{ir} ... is loaded into the JTAG IR to map the flash as the JTAG DR.
 For the bitstreams generated from @file{xilinx_bscan_spi.py} this is the
 @var{USER1} instruction.
-@end itemize
+@example
+target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
+set _USER1_INSTR_CODE 0x02
+flash bank $_FLASHNAME jtagspi 0x0 0 0 0 \
+           $_TARGETNAME $_USER1_INSTR_CODE
+@end example
+
+@item The option @option{-pld} @var{name} is used to have support from the
+PLD driver of pld device @var{name}. The name is the name of the pld device
+given during creation of the pld device.
+Pld device names are shown by the @command{pld devices} command.
 
 @example
-target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga
-set _XILINX_USER1 0x02
-flash bank $_FLASHNAME spi 0x0 0 0 0 \
-           $_TARGETNAME $_XILINX_USER1
+target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
+set _JTAGSPI_CHAIN_ID $_CHIPNAME.pld
+flash bank $_FLASHNAME jtagspi 0x0 0 0 0 \
+           $_TARGETNAME -pld $_JTAGSPI_CHAIN_ID
 @end example
+@end itemize
 
 @deffn Command {jtagspi set} bank_id name total_size page_size read_cmd unused 
pprg_cmd mass_erase_cmd sector_size sector_erase_cmd
 Sets flash parameters: @var{name} human readable string, @var{total_size}
@@ -8579,7 +8608,8 @@ Accordingly, both are called PLDs here.
 
 As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND),
 OpenOCD maintains a list of PLDs available for use in various commands.
-Also, each such PLD requires a driver.
+Also, each such PLD requires a driver. PLD drivers may also be needed to 
program
+SPI flash connected to the FPGA to store the bitstream (@xref{jtagspi} for 
details).
 
 They are referenced by the name which was given when the pld was created or
 the number shown by the @command{pld devices} command.
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 534a7a804e..06d20eebad 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -89,6 +89,7 @@ NORHEADERS = \
        %D%/cfi.h \
        %D%/driver.h \
        %D%/imp.h \
+       %D%/jtagspi.h \
        %D%/non_cfi.h \
        %D%/ocl.h \
        %D%/sfdp.h \
diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c
index 6bb3af9b7d..0dfaa2757b 100644
--- a/src/flash/nor/jtagspi.c
+++ b/src/flash/nor/jtagspi.c
@@ -12,28 +12,65 @@
 #include <jtag/jtag.h>
 #include <flash/nor/spi.h>
 #include <helper/time_support.h>
+#include <pld/pld.h>
+#include "jtagspi.h"
 
 #define JTAGSPI_MAX_TIMEOUT 3000
 
 
+
 struct jtagspi_flash_bank {
        struct jtag_tap *tap;
        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 */
+       struct pld_jtagspi pld_jtagspi;
 };
 
-FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
+static int jtagspi_init_by_pld_driver(struct jtagspi_flash_bank *info, struct 
pld_device *device)
 {
-       struct jtagspi_flash_bank *info;
+       info->pld_jtagspi.pld_device = device;
+       if (!info->pld_jtagspi.pld_device->driver) {
+               LOG_ERROR("pld device has no associated driver");
+               return ERROR_FAIL;
+       }
+
+       struct pld_driver *pld_driver = info->pld_jtagspi.pld_device->driver;
+       if (!pld_driver->get_jtagspi_info) {
+               LOG_ERROR("pld driver does not support jtagspi");
+               return ERROR_FAIL;
+       }
+
+       int retval = pld_driver->get_jtagspi_info(&info->pld_jtagspi);
+       if (retval != ERROR_OK)
+               LOG_ERROR("unable to get jtagspi info from pld driver");
 
+       return retval;
+}
+
+FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
+{
        if (CMD_ARGC < 7)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       info = malloc(sizeof(struct jtagspi_flash_bank));
+       unsigned int ir = 0;
+       struct pld_device *device;
+       bool pld_suport = strcmp(CMD_ARGV[6], "-pld") == 0;
+       if (pld_suport) {
+               if (CMD_ARGC < 8)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               device = get_pld_device_by_name_or_numstr(CMD_ARGV[7]);
+               if (!device) {
+                       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;
@@ -46,20 +83,30 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
                return ERROR_FAIL;
        }
        info->tap = bank->target->tap;
+
+       info->pld_jtagspi.mode = JTAGSPI_MODE_PROXY_BITSTREAM;
+       info->pld_jtagspi.ir = ir;
+       info->pld_jtagspi.pld_device = NULL;
+       info->pld_jtagspi.connect_spi_to_jtag = NULL;
+       info->pld_jtagspi.disconnect_spi_from_jtag = NULL;
+       info->pld_jtagspi.get_facing_read_bits = NULL;
+       info->pld_jtagspi.get_trailing_write_bits = NULL;
+
        info->probed = false;
-       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
+
+       if (pld_suport)
+               return jtagspi_init_by_pld_driver(info, 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");
-       buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
+       LOG_DEBUG("loading jtagspi ir(0x%x)", info->pld_jtagspi.ir);
+       buf_set_u32(buf, 0, info->tap->ir_length, info->pld_jtagspi.ir);
        field.num_bits = info->tap->ir_length;
        field.out_value = buf;
        field.in_value = NULL;
@@ -72,6 +119,48 @@ static void flip_u8(const uint8_t *in, uint8_t *out, 
unsigned int len)
                out[i] = flip_u32(in[i], 8);
 }
 
+static int get_stuff_bits(struct jtagspi_flash_bank *info, unsigned int 
*facing_read_bits,
+                                               unsigned int 
*trailing_write_bits)
+{
+       if (info->pld_jtagspi.mode == JTAGSPI_MODE_PROXY_BITSTREAM) {
+               *facing_read_bits = jtag_tap_count_enabled();
+               *trailing_write_bits =  0;
+       } else {
+               if (info->pld_jtagspi.get_facing_read_bits) {
+                       int retval = 
info->pld_jtagspi.get_facing_read_bits(info->pld_jtagspi.pld_device,
+                                                                               
                                        facing_read_bits);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+               if (info->pld_jtagspi.get_trailing_write_bits) {
+                       int retval = 
info->pld_jtagspi.get_trailing_write_bits(info->pld_jtagspi.pld_device,
+                                                                               
                                        trailing_write_bits);
+                       if (retval != ERROR_OK)
+                               return retval;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int connect_spi_to_jtag(struct jtagspi_flash_bank *info)
+{
+       int retval = ERROR_OK;
+       if (info->pld_jtagspi.mode == JTAGSPI_MODE_PROXY_BITSTREAM)
+               jtagspi_set_user_ir(info);
+       else if (info->pld_jtagspi.connect_spi_to_jtag)
+               retval = 
info->pld_jtagspi.connect_spi_to_jtag(info->pld_jtagspi.pld_device);
+
+       return retval;
+}
+
+static int disconnect_spi_from_jtag(struct jtagspi_flash_bank *info)
+{
+       if (info->pld_jtagspi.mode != JTAGSPI_MODE_PROXY_BITSTREAM && 
info->pld_jtagspi.disconnect_spi_from_jtag)
+               return 
info->pld_jtagspi.disconnect_spi_from_jtag(info->pld_jtagspi.pld_device);
+       return ERROR_OK;
+}
+
 static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
                uint8_t *write_buffer, unsigned int write_len, uint8_t 
*data_buffer, int data_len)
 {
@@ -79,6 +168,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 +177,31 @@ 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;
+
+       int retval = get_stuff_bits(info, &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_jtagspi.mode == JTAGSPI_MODE_PROXY_BITSTREAM) {
+               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 +219,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 +236,27 @@ 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++;
+       }
+
+       retval  = connect_spi_to_jtag(info);
+       if (retval != ERROR_OK)
+               return retval;
 
-       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();
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
 
        if (is_read)
                flip_u8(data_buffer, data_buffer, data_len);
-       return retval;
+
+       return disconnect_spi_from_jtag(info);
 }
 
 COMMAND_HANDLER(jtagspi_handle_set)
diff --git a/src/flash/nor/jtagspi.h b/src/flash/nor/jtagspi.h
new file mode 100644
index 0000000000..671e460b4f
--- /dev/null
+++ b/src/flash/nor/jtagspi.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2022 by Daniel Anselmi <danse...@gmx.ch> */
+
+#ifndef OPENOCD_JTAG_SPI_H
+#define OPENOCD_JTAG_SPI_H
+
+enum jtagspi_mode_e {
+       JTAGSPI_MODE_PROXY_BITSTREAM,      /* special bitream using the jtag 
user instruction */
+       JTAGSPI_MODE_SPECIFIC_INSTRUCTION, /* jtag tap has specific instruction 
to access the spi port directly */
+};                                                            /* (without 
special bitstream) */
+
+#endif /* OPENOCD_JTAG_SPI_H */
diff --git a/src/pld/pld.h b/src/pld/pld.h
index b736e6ae20..cef747c034 100644
--- a/src/pld/pld.h
+++ b/src/pld/pld.h
@@ -9,6 +9,7 @@
 #define OPENOCD_PLD_PLD_H
 
 #include <helper/command.h>
+#include <flash/nor/jtagspi.h>
 
 struct pld_device;
 
@@ -20,12 +21,23 @@ struct pld_ipdbg_hub {
        unsigned int user_ir_code;
 };
 
+struct pld_jtagspi {
+       enum jtagspi_mode_e mode;
+       unsigned int ir; /* convenient for sea of gate mode */
+       struct pld_device *pld_device;
+       int (*connect_spi_to_jtag)(struct pld_device *pld_device);
+       int (*disconnect_spi_from_jtag)(struct pld_device *pld_device);
+       int (*get_facing_read_bits)(struct pld_device *pld_device, unsigned int 
*facing_read_bits);
+       int (*get_trailing_write_bits)(struct pld_device *pld_device, unsigned 
int *trailing_write_bits);
+};
+
 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 (*get_jtagspi_info)(struct pld_jtagspi *pld_jtagspi);
 };
 
 #define PLD_CREATE_COMMAND_HANDLER(name) \
diff --git a/tcl/cpld/jtagspi.cfg b/tcl/cpld/jtagspi.cfg
index 4c84792fe1..a7f02b9770 100644
--- a/tcl/cpld/jtagspi.cfg
+++ b/tcl/cpld/jtagspi.cfg
@@ -4,6 +4,8 @@ set _USER1 0x02
 
 if { [info exists JTAGSPI_IR] } {
        set _JTAGSPI_IR $JTAGSPI_IR
+} elseif {[info exists JTAGSPI_CHAIN_ID]} {
+       set _JTAGSPI_CHAIN_ID $JTAGSPI_CHAIN_ID
 } else {
        set _JTAGSPI_IR $_USER1
 }
@@ -21,7 +23,11 @@ if { [info exists FLASHNAME] } {
 }
 
 target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
-flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR
+if { [info exists _JTAGSPI_IR] } {
+       flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR
+} else {
+    flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME -pld $_JTAGSPI_CHAIN_ID
+}
 
 # initialize jtagspi flash
 # chain_id: identifier of pld (you can get a list with 'pld devices')
@@ -33,7 +39,9 @@ flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME 
$_JTAGSPI_IR
 proc jtagspi_init {chain_id proxy_bit {release_from_pwr_down_cmd -1}} {
        # load proxy bitstream $proxy_bit and probe spi flash
        global _FLASHNAME
-       pld load $chain_id $proxy_bit
+       if { $proxy_bit ne "" } {
+               pld load $chain_id $proxy_bit
+       }
        reset halt
        if {$release_from_pwr_down_cmd != -1} {
                jtagspi cmd $_FLASHNAME 0 $release_from_pwr_down_cmd

-- 

Reply via email to