aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/loaders/flash/fpga/xilinx_bscan_spi.py362
-rw-r--r--doc/openocd.texi5
-rw-r--r--src/flash/nor/jtagspi.c60
-rw-r--r--tcl/cpld/jtagspi.cfg8
4 files changed, 342 insertions, 93 deletions
diff --git a/contrib/loaders/flash/fpga/xilinx_bscan_spi.py b/contrib/loaders/flash/fpga/xilinx_bscan_spi.py
index fa4ec2ac..4246aa2f 100755
--- a/contrib/loaders/flash/fpga/xilinx_bscan_spi.py
+++ b/contrib/loaders/flash/fpga/xilinx_bscan_spi.py
@@ -13,8 +13,11 @@
# GNU General Public License for more details.
#
-from migen import *
-from migen.build.generic_platform import *
+import unittest
+
+import migen as mg
+import migen.build.generic_platform as mb
+from migen.genlib import io
from migen.build import xilinx
@@ -25,59 +28,256 @@ behind FPGAs.
Bitstream binaries built with this script are available at:
https://github.com/jordens/bscan_spi_bitstreams
-JTAG signalling is connected directly to SPI signalling. CS_N is
-asserted when the JTAG IR contains the USER1 instruction and the state is
-SHIFT-DR. Xilinx bscan cells sample TDO on falling TCK and forward it.
-MISO requires sampling on rising CLK and leads to one cycle of latency.
+A JTAG2SPI transfer consists of:
+
+1. an arbitrary number of 0 bits (from BYPASS registers in front of the
+ JTAG2SPI DR)
+2. a marker bit (1) indicating the start of the JTAG2SPI transaction
+3. 32 bits (big endian) describing the length of the SPI transaction
+4. a number of SPI clock cycles (corresponding to 3.) with CS_N asserted
+5. an arbitrary number of cycles (to shift MISO/TDO data through subsequent
+ BYPASS registers)
+
+Notes:
+
+* The JTAG2SPI DR is 1 bit long (due to different sampling edges of
+ {MISO,MOSI}/{TDO,TDI}).
+* MOSI is TDI with half a cycle delay.
+* TDO is MISO with half a cycle delay.
+* CAPTURE-DR needs to be performed before SHIFT-DR on the BYPASSed TAPs in
+ JTAG chain to clear the BYPASS registers to 0.
https://github.com/m-labs/migen
"""
-class Spartan3(Module):
+class JTAG2SPI(mg.Module):
+ def __init__(self, spi=None, bits=32):
+ self.jtag = mg.Record([
+ ("sel", 1),
+ ("shift", 1),
+ ("capture", 1),
+ ("tck", 1),
+ ("tdi", 1),
+ ("tdo", 1),
+ ])
+ self.cs_n = mg.TSTriple()
+ self.clk = mg.TSTriple()
+ self.mosi = mg.TSTriple()
+ self.miso = mg.TSTriple()
+
+ # # #
+
+ self.cs_n.o.reset = mg.Constant(1)
+ self.mosi.o.reset_less = True
+ bits = mg.Signal(bits, reset_less=True)
+ head = mg.Signal(max=len(bits), reset=len(bits) - 1)
+ self.clock_domains.cd_sys = mg.ClockDomain()
+ self.submodules.fsm = mg.FSM("IDLE")
+ if spi is not None:
+ self.specials += [
+ self.cs_n.get_tristate(spi.cs_n),
+ self.mosi.get_tristate(spi.mosi),
+ self.miso.get_tristate(spi.miso),
+ ]
+ if hasattr(spi, "clk"): # 7 Series drive it fixed
+ self.specials += self.clk.get_tristate(spi.clk)
+ # self.specials += io.DDROutput(1, 0, spi.clk, self.clk.o)
+ self.comb += [
+ self.cd_sys.rst.eq(self.jtag.sel & self.jtag.capture),
+ self.cd_sys.clk.eq(self.jtag.tck),
+ self.cs_n.oe.eq(self.jtag.sel),
+ self.clk.oe.eq(self.jtag.sel),
+ self.mosi.oe.eq(self.jtag.sel),
+ self.miso.oe.eq(0),
+ # Do not suppress CLK toggles outside CS_N asserted.
+ # Xilinx USRCCLK0 requires three dummy cycles to do anything
+ # https://www.xilinx.com/support/answers/52626.html
+ # This is fine since CS_N changes only on falling CLK.
+ self.clk.o.eq(~self.jtag.tck),
+ self.jtag.tdo.eq(self.miso.i),
+ ]
+ # Latency calculation (in half cycles):
+ # 0 (falling TCK, rising CLK):
+ # JTAG adapter: set TDI
+ # 1 (rising TCK, falling CLK):
+ # JTAG2SPI: sample TDI -> set MOSI
+ # SPI: set MISO
+ # 2 (falling TCK, rising CLK):
+ # SPI: sample MOSI
+ # JTAG2SPI (BSCAN primitive): sample MISO -> set TDO
+ # 3 (rising TCK, falling CLK):
+ # JTAG adapter: sample TDO
+ self.fsm.act("IDLE",
+ mg.If(self.jtag.tdi & self.jtag.sel & self.jtag.shift,
+ mg.NextState("HEAD")
+ )
+ )
+ self.fsm.act("HEAD",
+ mg.If(head == 0,
+ mg.NextState("XFER")
+ )
+ )
+ self.fsm.act("XFER",
+ mg.If(bits == 0,
+ mg.NextState("IDLE")
+ ),
+ )
+ self.sync += [
+ self.mosi.o.eq(self.jtag.tdi),
+ self.cs_n.o.eq(~self.fsm.ongoing("XFER")),
+ mg.If(self.fsm.ongoing("HEAD"),
+ bits.eq(mg.Cat(self.jtag.tdi, bits)),
+ head.eq(head - 1)
+ ),
+ mg.If(self.fsm.ongoing("XFER"),
+ bits.eq(bits - 1)
+ )
+ ]
+
+
+class JTAG2SPITest(unittest.TestCase):
+ def setUp(self):
+ self.bits = 8
+ self.dut = JTAG2SPI(bits=self.bits)
+
+ def test_instantiate(self):
+ pass
+
+ def test_initial_conditions(self):
+ def check():
+ yield
+ self.assertEqual((yield self.dut.cs_n.oe), 0)
+ self.assertEqual((yield self.dut.mosi.oe), 0)
+ self.assertEqual((yield self.dut.miso.oe), 0)
+ self.assertEqual((yield self.dut.clk.oe), 0)
+ mg.run_simulation(self.dut, check())
+
+ def test_enable(self):
+ def check():
+ yield self.dut.jtag.sel.eq(1)
+ yield self.dut.jtag.shift.eq(1)
+ yield
+ self.assertEqual((yield self.dut.cs_n.oe), 1)
+ self.assertEqual((yield self.dut.mosi.oe), 1)
+ self.assertEqual((yield self.dut.miso.oe), 0)
+ self.assertEqual((yield self.dut.clk.oe), 1)
+ mg.run_simulation(self.dut, check())
+
+ def run_seq(self, tdi, tdo, spi=None):
+ yield self.dut.jtag.sel.eq(1)
+ yield
+ yield self.dut.jtag.shift.eq(1)
+ for di in tdi:
+ yield self.dut.jtag.tdi.eq(di)
+ yield
+ tdo.append((yield self.dut.jtag.tdo))
+ if spi is not None:
+ v = []
+ for k in "cs_n clk mosi miso".split():
+ t = getattr(self.dut, k)
+ v.append("{}>".format((yield t.o)) if (yield t.oe)
+ else "<{}".format((yield t.i)))
+ spi.append(" ".join(v))
+ yield self.dut.jtag.sel.eq(0)
+ yield
+ yield self.dut.jtag.shift.eq(0)
+ yield
+
+ def test_shift(self):
+ bits = 8
+ data = 0x81
+ tdi = [0, 0, 1] # dummy from BYPASS TAPs and marker
+ tdi += [((bits - 1) >> j) & 1 for j in range(self.bits - 1, -1, -1)]
+ tdi += [(data >> j) & 1 for j in range(bits)]
+ tdi += [0, 0, 0, 0] # dummy from BYPASS TAPs
+ tdo = []
+ spi = []
+ mg.run_simulation(self.dut, self.run_seq(tdi, tdo, spi))
+ # print(tdo)
+ for l in spi:
+ print(l)
+
+
+class Spartan3(mg.Module):
macro = "BSCAN_SPARTAN3"
toolchain = "ise"
def __init__(self, platform):
platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup"
- self.clock_domains.cd_jtag = ClockDomain(reset_less=True)
- spi = platform.request("spiflash")
- shift = Signal()
- tdo = Signal()
- sel1 = Signal()
- self.comb += [
- self.cd_jtag.clk.eq(spi.clk),
- spi.cs_n.eq(~shift | ~sel1),
+ self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
+ self.specials += [
+ mg.Instance(
+ self.macro,
+ o_SHIFT=j2s.jtag.shift, o_SEL1=j2s.jtag.sel,
+ o_CAPTURE=j2s.jtag.capture,
+ o_DRCK1=j2s.jtag.tck,
+ o_TDI=j2s.jtag.tdi, i_TDO1=j2s.jtag.tdo,
+ i_TDO2=0),
]
- self.sync.jtag += tdo.eq(spi.miso)
- self.specials += Instance(self.macro,
- o_DRCK1=spi.clk, o_SHIFT=shift,
- o_TDI=spi.mosi, i_TDO1=tdo, i_TDO2=0,
- o_SEL1=sel1)
+ platform.add_period_constraint(j2s.jtag.tck, 6)
class Spartan3A(Spartan3):
macro = "BSCAN_SPARTAN3A"
-class Spartan6(Module):
+class Spartan6(mg.Module):
toolchain = "ise"
def __init__(self, platform):
platform.toolchain.bitgen_opt += " -g compress -g UnusedPin:Pullup"
- self.clock_domains.cd_jtag = ClockDomain(reset_less=True)
- spi = platform.request("spiflash")
- shift = Signal()
- tdo = Signal()
- sel = Signal()
- self.comb += self.cd_jtag.clk.eq(spi.clk), spi.cs_n.eq(~shift | ~sel)
- self.sync.jtag += tdo.eq(spi.miso)
- self.specials += Instance("BSCAN_SPARTAN6", p_JTAG_CHAIN=1,
- o_TCK=spi.clk, o_SHIFT=shift, o_SEL=sel,
- o_TDI=spi.mosi, i_TDO=tdo)
-
-
-class Series7(Module):
+ self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
+ # clk = mg.Signal()
+ self.specials += [
+ mg.Instance(
+ "BSCAN_SPARTAN6", p_JTAG_CHAIN=1,
+ o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel,
+ o_CAPTURE=j2s.jtag.capture,
+ o_DRCK=j2s.jtag.tck,
+ o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo),
+ # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck)
+ ]
+ platform.add_period_constraint(j2s.jtag.tck, 6)
+
+
+class Series7(mg.Module):
+ toolchain = "vivado"
+
+ def __init__(self, platform):
+ platform.toolchain.bitstream_commands.extend([
+ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
+ "set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]"
+ ])
+ self.submodules.j2s = j2s = JTAG2SPI(platform.request("spiflash"))
+ # clk = mg.Signal()
+ self.specials += [
+ mg.Instance(
+ "BSCANE2", p_JTAG_CHAIN=1,
+ o_SHIFT=j2s.jtag.shift, o_SEL=j2s.jtag.sel,
+ o_CAPTURE=j2s.jtag.capture,
+ o_DRCK=j2s.jtag.tck,
+ o_TDI=j2s.jtag.tdi, i_TDO=j2s.jtag.tdo),
+ mg.Instance(
+ "STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0,
+ i_KEYCLEARB=0, i_PACK=1,
+ i_USRCCLKO=j2s.clk.o, i_USRCCLKTS=~j2s.clk.oe,
+ i_USRDONEO=1, i_USRDONETS=1),
+ # mg.Instance("BUFG", i_I=clk, o_O=j2s.jtag.tck)
+ ]
+ platform.add_period_constraint(j2s.jtag.tck, 6)
+ try:
+ self.comb += [
+ platform.request("user_sma_gpio_p").eq(j2s.cs_n.i),
+ platform.request("user_sma_gpio_n").eq(j2s.clk.o),
+ platform.request("user_sma_clock_p").eq(j2s.mosi.o),
+ platform.request("user_sma_clock_n").eq(j2s.miso.i),
+ ]
+ except mb.ConstraintError:
+ pass
+
+
+class Ultrascale(mg.Module):
toolchain = "vivado"
def __init__(self, platform):
@@ -85,20 +285,33 @@ class Series7(Module):
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
"set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design]",
])
- self.clock_domains.cd_jtag = ClockDomain(reset_less=True)
- spi = platform.request("spiflash")
- clk = Signal()
- shift = Signal()
- tdo = Signal()
- sel = Signal()
- self.comb += self.cd_jtag.clk.eq(clk), spi.cs_n.eq(~shift | ~sel)
- self.sync.jtag += tdo.eq(spi.miso)
- self.specials += Instance("BSCANE2", p_JTAG_CHAIN=1,
- o_SHIFT=shift, o_TCK=clk, o_SEL=sel,
- o_TDI=spi.mosi, i_TDO=tdo)
- self.specials += Instance("STARTUPE2", i_CLK=0, i_GSR=0, i_GTS=0,
- i_KEYCLEARB=0, i_PACK=1, i_USRCCLKO=clk,
- i_USRCCLKTS=0, i_USRDONEO=1, i_USRDONETS=1)
+ self.submodules.j2s0 = j2s0 = JTAG2SPI()
+ self.submodules.j2s1 = j2s1 = JTAG2SPI(platform.request("spiflash"))
+ di = mg.Signal(4)
+ self.comb += mg.Cat(j2s0.mosi.i, j2s0.miso.i).eq(di)
+ self.specials += [
+ mg.Instance("BSCANE2", p_JTAG_CHAIN=1,
+ o_SHIFT=j2s0.jtag.shift, o_SEL=j2s0.jtag.sel,
+ o_CAPTURE=j2s0.jtag.capture,
+ o_DRCK=j2s0.jtag.tck,
+ o_TDI=j2s0.jtag.tdi, i_TDO=j2s0.jtag.tdo),
+ mg.Instance("BSCANE2", p_JTAG_CHAIN=2,
+ o_SHIFT=j2s1.jtag.shift, o_SEL=j2s1.jtag.sel,
+ o_CAPTURE=j2s1.jtag.capture,
+ o_DRCK=j2s1.jtag.tck,
+ o_TDI=j2s1.jtag.tdi, i_TDO=j2s1.jtag.tdo),
+ mg.Instance("STARTUPE3", i_GSR=0, i_GTS=0,
+ i_KEYCLEARB=0, i_PACK=1,
+ i_USRDONEO=1, i_USRDONETS=1,
+ i_USRCCLKO=mg.Mux(j2s0.clk.oe, j2s0.clk.o, j2s1.clk.o),
+ i_USRCCLKTS=~(j2s0.clk.oe | j2s1.clk.oe),
+ i_FCSBO=j2s0.cs_n.o, i_FCSBTS=~j2s0.cs_n.oe,
+ o_DI=di,
+ i_DO=mg.Cat(j2s0.mosi.o, j2s0.miso.o, 0, 0),
+ i_DTS=mg.Cat(~j2s0.mosi.oe, ~j2s0.miso.oe, 1, 1))
+ ]
+ platform.add_period_constraint(j2s0.jtag.tck, 6)
+ platform.add_period_constraint(j2s1.jtag.tck, 6)
class XilinxBscanSpi(xilinx.XilinxPlatform):
@@ -124,6 +337,7 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
("fbg484-1", 2): ["L16", None, "H18", "H19", "G18", "F19"],
("fbg676-1", 1): ["C23", None, "B24", "A25", "B22", "A22"],
("ffg901-1", 1): ["V26", None, "R30", "T30", "R28", "T28"],
+ ("ffg900-1", 1): ["U19", None, "P24", "R25", "R20", "R21"],
("ffg1156-1", 1): ["V30", None, "AA33", "AA34", "Y33", "Y34"],
("ffg1157-1", 1): ["AL33", None, "AN33", "AN34", "AK34", "AL34"],
("ffg1158-1", 1): ["C24", None, "A23", "A24", "B26", "A26"],
@@ -132,6 +346,9 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
("flg1155-1", 1): ["AL28", None, "AE28", "AF28", "AJ29", "AJ30"],
("flg1932-1", 1): ["V32", None, "T33", "R33", "U31", "T31"],
("flg1926-1", 1): ["AK33", None, "AN34", "AN35", "AJ34", "AK34"],
+
+ ("ffva1156-2-e", 1): ["G26", None, "M20", "L20", "R21", "R22"],
+ ("ffva1156-2-e", "sayma"): ["K21", None, "M20", "L20", "R21", "R22"],
}
pinouts = {
@@ -181,6 +398,7 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
"xc7a75t": ("csg324-1", 1, "LVCMOS25", Series7),
"xc7k160t": ("fbg484-1", 2, "LVCMOS25", Series7),
"xc7k325t": ("fbg676-1", 1, "LVCMOS25", Series7),
+ "xc7k325t-debug": ("ffg900-1", 1, "LVCMOS25", Series7),
"xc7k355t": ("ffg901-1", 1, "LVCMOS25", Series7),
"xc7k410t": ("fbg676-1", 1, "LVCMOS25", Series7),
"xc7k420t": ("ffg1156-1", 1, "LVCMOS25", Series7),
@@ -197,35 +415,53 @@ class XilinxBscanSpi(xilinx.XilinxPlatform):
"xc7vx550t": ("ffg1158-1", 1, "LVCMOS18", Series7),
"xc7vx690t": ("ffg1157-1", 1, "LVCMOS18", Series7),
"xc7vx980t": ("ffg1926-1", 1, "LVCMOS18", Series7),
+
+ "xcku040": ("ffva1156-2-e", 1, "LVCMOS18", Ultrascale),
+ "xcku040-sayma": ("ffva1156-2-e", "sayma", "LVCMOS18", Ultrascale),
}
def __init__(self, device, pins, std, toolchain="ise"):
+ ios = [self.make_spi(0, pins, std, toolchain)]
+ if device == "xc7k325t-ffg900-1": # debug
+ ios += [
+ ("user_sma_clock_p", 0, mb.Pins("L25"), mb.IOStandard("LVCMOS25")),
+ ("user_sma_clock_n", 0, mb.Pins("K25"), mb.IOStandard("LVCMOS25")),
+ ("user_sma_gpio_p", 0, mb.Pins("Y23"), mb.IOStandard("LVCMOS25")),
+ ("user_sma_gpio_n", 0, mb.Pins("Y24"), mb.IOStandard("LVCMOS25")),
+ ]
+ xilinx.XilinxPlatform.__init__(self, device, ios, toolchain=toolchain)
+
+ @staticmethod
+ def make_spi(i, pins, std, toolchain):
+ pu = "PULLUP" if toolchain == "ise" else "PULLUP TRUE"
+ pd = "PULLDOWN" if toolchain == "ise" else "PULLDOWN TRUE"
cs_n, clk, mosi, miso = pins[:4]
- io = ["spiflash", 0,
- Subsignal("cs_n", Pins(cs_n)),
- Subsignal("mosi", Pins(mosi)),
- Subsignal("miso", Pins(miso), Misc("PULLUP")),
- IOStandard(std),
- ]
+ io = ["spiflash", i,
+ mb.Subsignal("cs_n", mb.Pins(cs_n), mb.Misc(pu)),
+ mb.Subsignal("mosi", mb.Pins(mosi), mb.Misc(pu)),
+ mb.Subsignal("miso", mb.Pins(miso), mb.Misc(pu)),
+ mb.IOStandard(std),
+ ]
if clk:
- io.append(Subsignal("clk", Pins(clk)))
+ io.append(mb.Subsignal("clk", mb.Pins(clk), mb.Misc(pd)))
for i, p in enumerate(pins[4:]):
- io.append(Subsignal("pullup{}".format(i), Pins(p), Misc("PULLUP")))
- xilinx.XilinxPlatform.__init__(self, device, [io], toolchain=toolchain)
+ io.append(mb.Subsignal("pullup{}".format(i), mb.Pins(p),
+ mb.Misc(pu)))
+ return io
@classmethod
- def make(cls, device, errors=False):
- pkg, id, std, Top = cls.pinouts[device]
+ def make(cls, target, errors=False):
+ pkg, id, std, Top = cls.pinouts[target]
pins = cls.packages[(pkg, id)]
+ device = target.split("-", 1)[0]
platform = cls("{}-{}".format(device, pkg), pins, std, Top.toolchain)
top = Top(platform)
- name = "bscan_spi_{}".format(device)
- dir = "build_{}".format(device)
+ name = "bscan_spi_{}".format(target)
try:
- platform.build(top, build_name=name, build_dir=dir)
+ platform.build(top, build_name=name)
except Exception as e:
print(("ERROR: xilinx_bscan_spi build failed "
- "for {}: {}").format(device, e))
+ "for {}: {}").format(target, e))
if errors:
raise
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 7f5b72e0..431f11cb 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -4913,16 +4913,13 @@ functionality is available through the @command{flash write_bank},
@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.
-@item @var{dr_length} ... is the length of the DR register. This will be 1 for
-@file{xilinx_bscan_spi.py} bitstreams and most other cases.
@end itemize
@example
target create $_TARGETNAME testee -chain-position $_CHIPNAME.fpga
set _XILINX_USER1 0x02
-set _DR_LENGTH 1
flash bank $_FLASHNAME spi 0x0 0 0 0 \
- $_TARGETNAME $_XILINX_USER1 $_DR_LENGTH
+ $_TARGETNAME $_XILINX_USER1
@end example
@end deffn
diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c
index a995fc75..a05ff378 100644
--- a/src/flash/nor/jtagspi.c
+++ b/src/flash/nor/jtagspi.c
@@ -32,14 +32,13 @@ struct jtagspi_flash_bank {
const struct flash_device *dev;
int probed;
uint32_t ir;
- uint32_t dr_len;
};
FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
{
struct jtagspi_flash_bank *info;
- if (CMD_ARGC < 8)
+ if (CMD_ARGC < 7)
return ERROR_COMMAND_SYNTAX_ERROR;
info = malloc(sizeof(struct jtagspi_flash_bank));
@@ -52,7 +51,6 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
info->tap = NULL;
info->probed = 0;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->dr_len);
return ERROR_OK;
}
@@ -63,9 +61,6 @@ static void jtagspi_set_ir(struct flash_bank *bank)
struct scan_field field;
uint8_t buf[4];
- if (buf_get_u32(info->tap->cur_instr, 0, info->tap->ir_length) == info->ir)
- return;
-
LOG_DEBUG("loading jtagspi ir");
buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
field.num_bits = info->tap->ir_length;
@@ -84,28 +79,53 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
uint32_t *addr, uint8_t *data, int len)
{
struct jtagspi_flash_bank *info = bank->driver_priv;
- struct scan_field fields[3];
- uint8_t cmd_buf[4];
+ struct scan_field fields[6];
+ uint8_t marker = 1;
+ uint8_t xfer_bits_buf[4];
+ uint8_t addr_buf[3];
uint8_t *data_buf;
+ uint32_t xfer_bits;
int is_read, lenb, n;
/* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */
+ is_read = (len < 0);
+ if (is_read)
+ len = -len;
+
n = 0;
+
+ fields[n].num_bits = 1;
+ fields[n].out_value = &marker;
+ fields[n].in_value = NULL;
+ n++;
+
+ xfer_bits = 8 + len - 1;
+ /* cmd + read/write - 1 due to the counter implementation */
+ if (addr)
+ xfer_bits += 24;
+ h_u32_to_be(xfer_bits_buf, xfer_bits);
+ flip_u8(xfer_bits_buf, xfer_bits_buf, 4);
+ fields[n].num_bits = 32;
+ fields[n].out_value = xfer_bits_buf;
+ fields[n].in_value = NULL;
+ n++;
+
+ cmd = flip_u32(cmd, 8);
fields[n].num_bits = 8;
- cmd_buf[0] = cmd;
- if (addr) {
- h_u24_to_be(cmd_buf + 1, *addr);
- fields[n].num_bits += 24;
- }
- flip_u8(cmd_buf, cmd_buf, 4);
- fields[n].out_value = cmd_buf;
+ fields[n].out_value = &cmd;
fields[n].in_value = NULL;
n++;
- is_read = (len < 0);
- if (is_read)
- len = -len;
+ if (addr) {
+ h_u24_to_be(addr_buf, *addr);
+ flip_u8(addr_buf, addr_buf, 3);
+ fields[n].num_bits = 24;
+ fields[n].out_value = addr_buf;
+ fields[n].in_value = NULL;
+ n++;
+ }
+
lenb = DIV_ROUND_UP(len, 8);
data_buf = malloc(lenb);
if (lenb > 0) {
@@ -114,10 +134,11 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
return ERROR_FAIL;
}
if (is_read) {
- fields[n].num_bits = info->dr_len;
+ fields[n].num_bits = jtag_tap_count_enabled();
fields[n].out_value = NULL;
fields[n].in_value = NULL;
n++;
+
fields[n].out_value = NULL;
fields[n].in_value = data_buf;
} else {
@@ -130,6 +151,7 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
}
jtagspi_set_ir(bank);
+ /* passing from an IR scan to SHIFT-DR clears BYPASS registers */
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
jtag_execute_queue();
diff --git a/tcl/cpld/jtagspi.cfg b/tcl/cpld/jtagspi.cfg
index 60c3cb10..e720c395 100644
--- a/tcl/cpld/jtagspi.cfg
+++ b/tcl/cpld/jtagspi.cfg
@@ -6,12 +6,6 @@ if { [info exists JTAGSPI_IR] } {
set _JTAGSPI_IR $_USER1
}
-if { [info exists DR_LENGTH] } {
- set _DR_LENGTH $DR_LENGTH
-} else {
- set _DR_LENGTH 1
-}
-
if { [info exists TARGETNAME] } {
set _TARGETNAME $TARGETNAME
} else {
@@ -25,7 +19,7 @@ if { [info exists FLASHNAME] } {
}
target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
-flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR $_DR_LENGTH
+flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR
proc jtagspi_init {chain_id proxy_bit} {
# load proxy bitstream $proxy_bit and probe spi flash