This is an automated email from Gerrit.

"Brandon Martin <marti...@mothictech.com>" just uploaded a new patch set to 
Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8933

-- gerrit

commit bdd42ee831329890e3ec2fe60742e992993b2a6c
Author: Brandon Martin <marti...@mothictech.com>
Date:   Mon May 19 06:30:26 2025 -0400

    On-chip algorithm programming for FLEXSPI
    
    This considerably improves programming throughput on the order of 4-5x.
    
    There are currently several IMXRT1020'isms in the algorithm code with
    respect to disabling various watchdogs.  These will need to be factored
    out.
    
    Change-Id: Ibf61dcaad09d9d3dcea1cbfe4e825c67935cdb93
    Signed-off-by: Brandon Martin <marti...@mothictech.com>

diff --git a/contrib/loaders/flash/fsl_flexspi_blockwrite.S 
b/contrib/loaders/flash/fsl_flexspi_blockwrite.S
new file mode 100644
index 0000000000..9619c65b69
--- /dev/null
+++ b/contrib/loaders/flash/fsl_flexspi_blockwrite.S
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2025 by Brandon Martin (Mothic Technologies LLC)        *
+ *   marti...@mothictech.com                                               *
+ ***************************************************************************/
+
+       .text
+       .syntax unified
+       .cpu cortex-m7
+       .thumb
+       .thumb_func
+
+       /*
+        * Params:
+        * r0 = flash destination address [in/out]
+        * r1 = blkcount - 0 indicates success [in/out]
+        * r2 = blksize in 32-bit words (must be <= IP TX FIFO length)
+        * r3 = workarea (streaming FIFO) start address
+        * r4 = workarea (streaming FIFO) end address
+        * r5 = FLEXSPI register base
+        */
+
+#include "../../../src/flash/nor/fsl_flexspi.h"
+
+       .macro  wait_ipcmd
+0:
+       ldr     r7, [r5, #REG_INTR]
+       ands    r6, r7, #INTR_IPCMDERR
+       bne     error
+       ands    r6, r7, #INTR_IPCMDDONE
+       beq     0b
+       .endm
+
+       .macro clear_intr
+       mov     r6, #(INTR_AHBCMDERR | INTR_IPCMDERR | INTR_AHBCMDGE | 
INTR_IPCMDGE | INTR_IPCMDDONE | INTR_IPRXWA | \
+                       INTR_IPTXWE)
+       str     r6, [r5, #REG_INTR]
+       .endm
+
+       .align  4
+
+start:
+       cpsid   i
+       mov     r6, #0
+       ldr     r7, wdog1
+       strh    r6, [r7, #8]
+       mov     r6, #0x0030
+       strh    r6, [r7, #0]
+       ldr     r7, wdog2
+       mov     r6, #0
+       strh    r6, [r7, #8]
+       mov     r6, #0x0030
+       strh    r6, [r7, #0]
+       ldr     r7, rtwdog
+       ldr     r6, [r7]
+       ands    r6, #BIT(7)
+       beq     rtwdog_disabled
+       ldr     r6, rtwdog_unlock
+       str     r6, [r7, #4]
+       mov     r6, #0x00002120
+       str     r6, [r7]
+rtwdog_disabled:
+       ldr     r7, src
+       ldr     r6, src_scr_disable_wdogs
+       str     r6, [r7]
+       mov     r6, #0x1ff
+       str     r6, [r7, #8]
+       ldr     r7, systick
+       mov     r6, #0
+       str     r6, [r7]
+
+next_block:
+       /* Write enable */
+       clear_intr
+       str     r0, [r5, #REG_IPCR0]    /* flash address */
+       mov     r6, #(IPCR1_IDATASZ(0) | IPCR1_ISEQID(LUTNUM_WRITE_ENABLE) | 
IPCR1_ISEQNUM(0))
+       str     r6, [r5, #REG_IPCR1]    /* data length and LUT program info */
+       mov     r6, #IPCMD_TRG
+       str     r6, [r5, #REG_IPCMD]    /* initiate command */
+       wait_ipcmd
+
+       /* Configure the TX FIFO for a block */
+       lsr     r6, r2, #1
+       sub     r6, r6, #1
+       lsl     r6, r6, #2
+       orr     r6, r6, #1
+       str     r6, [r5, #REG_IPTXFCR]
+
+       /* Load TX FIFO with this block's data */
+       mov     r8, #0                  /* block word count [r8] */
+       add     r5, r5, #REG_TFDR
+       ldr     r6, [r3, #4]            /* read rp [r6] */
+wait_fifo:
+       ldr     r7, [r3, #0]            /* read wp [r7] */
+       cmp     r7, #0                  /* abort if wp == 0 */
+       beq     exit
+
+       cmp     r6, r7                  /* wait until rp != wp */
+       beq     wait_fifo
+
+       ldr     r7, [r6]                /* read from rp */
+       str     r7, [r5, r8, lsl #2]    /* store to IP TX FIFO */
+
+       add     r6, #4                  /* rp += 4 */
+       cmp     r6, r4                  /* Wrap? */
+       bcc     no_wrap
+       mov     r6, r3
+       add     r6, r6, #8
+no_wrap:
+       add     r8, r8, #1
+       cmp     r2, r8                  /* need more data for block? */
+       bne     wait_fifo
+
+       /* Entire block written to TX FIFO */
+       str     r6, [r3, #4]            /* Store rp */
+       sub     r5, r5, #REG_TFDR
+
+       /* Send write command + data */
+       clear_intr
+       str     r0, [r5, #REG_IPCR0]    /* flash address */
+       mov     r6, #(IPCR1_ISEQID(LUTNUM_DRV) | IPCR1_ISEQNUM(0))
+       orr     r6, r6, r2, lsl #2
+       str     r6, [r5, #REG_IPCR1]    /* data length and LUT program info */
+       mov     r6, #IPCMD_TRG
+       str     r6, [r5, #REG_IPCMD]    /* initiate command */
+       wait_ipcmd
+
+       /* Read status and wait for completion */
+check_busy:
+       clear_intr
+       mov     r6, #IPRXFCR_RXWMRK(1) | IPRXFCR_CLRIPRXF
+       str     r6, [r5, #REG_IPRXFCR]
+       mov     r6, #0
+       str     r6, [r5, #REG_IPCR0]
+       ldr     r6, wait_busy_ipcr1
+       str     r6, [r5, #REG_IPCR1]
+       mov     r6, #IPCMD_TRG
+       str     r6, [r5, #REG_IPCMD]    /* initiate command */
+
+wait_status:
+       wait_ipcmd
+
+       ldr     r7, [r5, #REG_RFDR]
+       ands    r6, r7, #SPIFLASH_BSY_BIT
+       bne     check_busy
+       ands    r6, r7, #SPIFLASH_WE_BIT
+       bne     error
+
+       /* Block is complete */
+       add     r0, r0, r2, lsl #2      /* flash address += blksize - increment 
after error check since it's output */
+
+       subs    r1, #1                  /* blkcount-- */
+       bne     next_block
+       b       exit
+
+error:
+       mov     r5, #0
+       str     r5, [r3, #4]            /* set rp = 0 on error */
+
+exit:
+       bkpt    #0
+
+wait_busy_ipcr1:
+       .word   (IPCR1_IDATASZ(4) | IPCR1_ISEQID(LUTNUM_READ_STATUS) | 
IPCR1_ISEQNUM(0))
+wdog1:
+       .word   0x400b8000
+wdog2:
+       .word   0x400d0000
+rtwdog:
+       .word   0x400bc000
+rtwdog_unlock:
+       .word   0xd928c520
+systick:
+       .word   0xe000e010
+src:
+       .word   0x400f8000
+src_scr_disable_wdogs:
+       .word   0x504802a0
diff --git a/contrib/loaders/flash/fsl_flexspi_blockwrite.inc 
b/contrib/loaders/flash/fsl_flexspi_blockwrite.inc
new file mode 100644
index 0000000000..31f88a8205
--- /dev/null
+++ b/contrib/loaders/flash/fsl_flexspi_blockwrite.inc
@@ -0,0 +1,23 @@
+/* Autogenerated with ../../../src/helper/bin2char.sh */
+0x72,0xb6,0x4f,0xf0,0x00,0x06,0xdf,0xf8,0x38,0x71,0x3e,0x81,0x4f,0xf0,0x30,0x06,
+0x3e,0x80,0xdf,0xf8,0x30,0x71,0x4f,0xf0,0x00,0x06,0x3e,0x81,0x4f,0xf0,0x30,0x06,
+0x3e,0x80,0x49,0x4f,0x3e,0x68,0x16,0xf0,0x80,0x06,0x04,0xd0,0x47,0x4e,0x7e,0x60,
+0x42,0xf2,0x20,0x16,0x3e,0x60,0x47,0x4f,0x47,0x4e,0x3e,0x60,0x40,0xf2,0xff,0x16,
+0xbe,0x60,0x43,0x4f,0x4f,0xf0,0x00,0x06,0x3e,0x60,0x4f,0xf0,0x7f,0x06,0x6e,0x61,
+0xc5,0xf8,0xa0,0x00,0x4f,0xf4,0x40,0x36,0xc5,0xf8,0xa4,0x60,0x4f,0xf0,0x01,0x06,
+0xc5,0xf8,0xb0,0x60,0x6f,0x69,0x17,0xf0,0x08,0x06,0x63,0xd1,0x17,0xf0,0x01,0x06,
+0xf8,0xd0,0x4f,0xea,0x52,0x06,0xa6,0xf1,0x01,0x06,0x4f,0xea,0x86,0x06,0x46,0xf0,
+0x01,0x06,0xc5,0xf8,0xbc,0x60,0x4f,0xf0,0x00,0x08,0x05,0xf5,0xc0,0x75,0x5e,0x68,
+0x1f,0x68,0x00,0x2f,0x51,0xd0,0xbe,0x42,0xfa,0xd0,0x37,0x68,0x45,0xf8,0x28,0x70,
+0x06,0xf1,0x04,0x06,0xa6,0x42,0x02,0xd3,0x1e,0x46,0x06,0xf1,0x08,0x06,0x08,0xf1,
+0x01,0x08,0x42,0x45,0xec,0xd1,0x5e,0x60,0xa5,0xf5,0xc0,0x75,0x4f,0xf0,0x7f,0x06,
+0x6e,0x61,0xc5,0xf8,0xa0,0x00,0x4f,0xf4,0x20,0x26,0x46,0xea,0x82,0x06,0xc5,0xf8,
+0xa4,0x60,0x4f,0xf0,0x01,0x06,0xc5,0xf8,0xb0,0x60,0x6f,0x69,0x17,0xf0,0x08,0x06,
+0x28,0xd1,0x17,0xf0,0x01,0x06,0xf8,0xd0,0x4f,0xf0,0x7f,0x06,0x6e,0x61,0x4f,0xf0,
+0x05,0x06,0xc5,0xf8,0xb8,0x60,0x4f,0xf0,0x00,0x06,0xc5,0xf8,0xa0,0x60,0x0f,0x4e,
+0xc5,0xf8,0xa4,0x60,0x4f,0xf0,0x01,0x06,0xc5,0xf8,0xb0,0x60,0x6f,0x69,0x17,0xf0,
+0x08,0x06,0x0f,0xd1,0x17,0xf0,0x01,0x06,0xf8,0xd0,0xd5,0xf8,0x00,0x71,0x17,0xf0,
+0x01,0x06,0xe1,0xd1,0x17,0xf0,0x02,0x06,0x04,0xd1,0x00,0xeb,0x82,0x00,0x01,0x39,
+0x8b,0xd1,0x02,0xe0,0x4f,0xf0,0x00,0x05,0x5d,0x60,0x00,0xbe,0x04,0x00,0x01,0x00,
+0x00,0x80,0x0b,0x40,0x00,0x00,0x0d,0x40,0x00,0xc0,0x0b,0x40,0x20,0xc5,0x28,0xd9,
+0x10,0xe0,0x00,0xe0,0x00,0x80,0x0f,0x40,0xa0,0x02,0x48,0x50,
diff --git a/src/flash/nor/fsl_flexspi.c b/src/flash/nor/fsl_flexspi.c
index 06c7ed9aa3..3ee997d505 100644
--- a/src/flash/nor/fsl_flexspi.c
+++ b/src/flash/nor/fsl_flexspi.c
@@ -44,11 +44,15 @@
 #endif
 
 #include "imp.h"
-#include "spi.h"
 
 #include <helper/align.h>
+#include <helper/binarybuffer.h>
 #include <helper/bits.h>
 #include <helper/time_support.h>
+#include <target/algorithm.h>
+#include <target/armv7m.h>
+
+#include "fsl_flexspi.h"
 
 #define TIMEOUT_EXEC_IPCMD                     100
 #define TIMEOUT_RESET                          100
@@ -56,166 +60,6 @@
 #define TIMEOUT_FLASH_ERASE_CHIP       90000
 #define TIMEOUT_FLASH_PROGRAM          250
 
-/* These are the base addresses used on the IMXRT1020 */
-#define FLEXSPI_DEFAULT_IOBASE         0x402A8000
-#define FLEXSPI_LINEAR_AHBASE          0x60000000
-#define FLEXSPI_TX_FIFO_AHBASE         0x7F800000
-#define FLEXSPI_RX_FIFO_AHBASE         0x7FC00000
-
-/* The documentation implies that these may be chip-specific tweakables */
-#define FLEXSPI_AHB_TX_BUFSZ           64
-#define FLEXSPI_AHB_RX_BUFSZ           1024
-#define FLEXSPI_IP_TX_FIFOSZ           128
-#define FLEXSPI_IP_RX_FIFOSZ           128
-
-/* On-chip registers and fields */
-#define REG_MCR0                                       0x00
-#define MCR0_SWRESET                           BIT(0)
-#define MCR0_MDIS                                      BIT(1)
-#define MCR0_ARDFEN                                    BIT(6)
-#define MCR0_ATDFEN                                    BIT(7)
-
-#define REG_AHBCR                                      0x0C
-#define AHBCR_ALIGNMENT(x)                     (((x) & 0x03) << 20)
-#define AHBCR_READSZALIGN                      BIT(10)
-#define AHBCR_READADDROPT                      BIT(6)
-#define AHBCR_PREFETCHEN                       BIT(5)
-#define AHBCR_BUFFERABLEEN                     BIT(4)
-#define AHBCR_CACHABLEEN                       BIT(3)
-#define AHBCR_APAREN                           BIT(0)
-
-#define REG_INTR                                       0x14
-#define INTR_IPCMDDONE                         BIT(0)
-#define INTR_IPCMDGE                           BIT(1)
-#define INTR_AHBCMDGE                          BIT(2)
-#define INTR_IPCMDERR                          BIT(3)
-#define INTR_AHBCMDERR                         BIT(4)
-#define INTR_IPRXWA                                    BIT(5)
-#define INTR_IPTXWE                                    BIT(6)
-#define INTR_SCKSTOPBYRD                       BIT(8)
-#define INTR_SCKSTOPBYWR                       BIT(9)
-#define INTR_AHBBUSTTIMEOUT                    BIT(10)
-#define INTR_SEQTIMEOUT                                BIT(11)
-#define INTR_IPCMDSECUREVIO                    BIT(16)
-
-#define REG_LUTKEY                                     0x18
-#define LUTKEY_MAGIC                           0x5AF05AF0
-
-#define REG_LUTCR                                      0x1C
-#define LUTCR_LOCK                                     BIT(0)
-#define LUTCR_UNLOCK                           BIT(1)
-#define LUTCR_PROTECT                          BIT(2)
-
-#define REG_AHBRXBUF0CR0                       0x20
-#define REG_AHBRXBUF1CR0                       0x24
-#define REG_AHBRXBUF2CR0                       0x28
-#define REG_AHBRXBUF3CR0                       0x2C
-#define AHBRXBUFNCR0_BUFSZ(x)          (((x) & 0xFF) << 0)
-#define AHBRXBUFNCR0_MSTRID(x)         (((x) & 0x0F) << 16)
-#define AHBRXBUFNCR0_PRIORITY(x)       (((x) & 0x03) << 24)
-#define AHBRXBUFNCR0_REGIONEN          BIT(30)
-#define AHBRXBUFNCR0_PREFETCHEN                BIT(31)
-
-#define REG_FLSHA1CR0                          0x60
-#define FLSHNNCR0_FLASHSZ(x)           (((x) & 0x7FFFFF) << 0)
-
-#define REG_FLSHA1CR1                          0x70
-#define FLSHNNCR1_TCSS(x)                      (((x) & 0x1F) << 0)
-#define FLSHNNCR1_TCSH(x)                      (((x) & 0x1F) << 5)
-#define FLSHNNCR1_WA                           BIT(10)
-#define FLSHNNCR1_CAS(x)                       (((x) & 0x0F) << 11)
-#define FLSHNNCR1_CSINTERVALUNIT       BIT(15)
-#define FLSHNNCR1_CSINTERVAL(x)                (((x) & 0xFFFF) << 16)
-
-#define REG_FLSHA1CR2                          0x80
-#define FLSHNNCR2_ARDSEQID(x)          (((x) & 0x0F) << 0)
-#define FLSHNNCR2_ARDSEQNUM(x)         (((x) & 0x07) << 5)
-#define FLSHNNCR2_AWRSEQID(x)          (((x) & 0x0F) << 8)
-#define FLSHNNCR2_AWRSEQNUM(x)         (((x) & 0x07) << 13)
-#define FLSHNNCR2_AWRWAIT(x)           (((x) & 0x0FFF) << 16)
-#define FLSHNNCR2_AWRWAITUNIT(x)       (((x) & 0x07) << 28)
-#define AWRWAITUNIT_2AHB                       0
-#define AWRWAITUNIT_8AHB                       1
-#define AWRWAITUNIT_32AHB                      2
-#define AWRWAITUNIT_128AHB                     3
-#define AWRWAITUNIT_512AHB                     4
-#define AWRWAITUNIT_2048AHB                    5
-#define AWRWAITUNIT_8192AHB                    6
-#define AWRWAITUNIT_32768AHB           7
-#define FLSHNNCR2_CLRINSTRPTR          BIT(31)
-
-#define REG_FLSHCR4                                    0x94
-#define FLSHCR4_WMOPT1                         BIT(0)
-#define FLSHCR4_WMENA                          BIT(2)
-#define FLSHCR4_WMENB                          BIT(3)
-#define FLSHCR4_PAR_WM(x)                      (((x) & 0x03) << 9)
-#define FLSHCR4_PAR_ADDR_ADJ_DIS       BIT(11)
-
-#define REG_IPCR0                                      0xA0
-#define IPCR0_SFAR(x)                          (x)
-
-#define REG_IPCR1                                      0xA4
-#define IPCR1_IDATASZ(x)                       (((x) & 0xFFFF) << 0)
-#define IPCR1_ISEQID(x)                                (((x) & 0x0F) << 16)
-#define IPCR1_ISEQNUM(x)                       (((x) & 0x0F) << 24)
-#define IPCR1_IPAREN                           BIT(31)
-
-#define REG_IPCMD                                      0xB0
-#define IPCMD_TRG                                      BIT(0)
-
-#define REG_IPRXFCR                                    0xB8
-#define IPRXFCR_CLRIPRXF                       BIT(0)
-#define IPRXFCR_RXDMAEN                                BIT(1)
-#define IPRXFCR_RXWMRK(x)                      (((x) & 0x0F) << 2)
-
-#define REG_IPTXFCR                                    0xBC
-#define IPTXFCR_CLRIPTXF                       BIT(0)
-#define IPTXFCR_TXDMAEN                                BIT(1)
-#define IPTXFCR_TXWMRK(x)                      (((x) & 0x0F) << 2)
-
-#define REG_STS1                                       0xE4
-
-#define REG_RFDR                                       0x100
-#define REG_TFDR                                       0x180
-
-#define REG_LUT_BASE                           0x200
-#define REG_LUT(x)                                     (REG_LUT_BASE + (x) * 4)
-
-/*
- * This LUT sequence number is used only during probe to read flash IDs
- *
- * The LUT sequence number 0 is the default for FlexSPI NOR (and NAND?) boot
- */
-#define LUTNUM_AHB_READ                                0
-
-/*
- * The (only) LUT sequence number to be used by the driver after probing
- *
- * Other LUT sequence numbers will not be touched and can be used by
- * application code without impeding operating by the driver without controller
- * re-initialization if some other basic conditions are met.
- *
- * The LUT sequence number 10 is not used by boot procedures nor the Freescale
- * sample code
- */
-#define LUTNUM_DRV                                     10
-
-/* Instruction set for the LUT register (SDR only) */
-#define OPCODE_STOP                                    0
-#define OPCODE_CMD                                     1
-#define OPCODE_RADDR                           2
-#define OPCODE_CADDR                           3
-#define OPCODE_MODE1                           4
-#define OPCODE_MODE2                           5
-#define OPCODE_MODE4                           6
-#define OPCODE_MODE8                           7
-#define OPCODE_WRITE                           8
-#define OPCODE_READ                                    9
-#define OPCODE_LEARN                           10
-#define OPCODE_DATSZ                           11
-#define OPCODE_DUMMY                           12
-#define OPCODE_JMP_ON_CS                       31
-
 /*
  * Macro for constructing the LUT entries with the following
  * register layout:
@@ -289,6 +133,8 @@ static int read_rxfifo(struct flash_bank *bank, uint8_t 
*buf, uint32_t datalen)
        uint32_t nbytes;
        uint8_t bytes[4];
 
+       LOG_DEBUG("want %" PRIx32 "B", datalen);
+
        ret = target_write_u32(target, io_base + REG_IPRXFCR, 
IPRXFCR_RXWMRK(datalen / 8 - 1));
        if (ret != ERROR_OK)
                goto err;
@@ -431,8 +277,8 @@ err:
        return ret;
 }
 
-static int execute_ipcmd_read(struct flash_bank *bank, uint8_t opcode,
-               void *buf, uint32_t datalen)
+static int execute_ipcmd_read_with_lutnum(struct flash_bank *bank, uint8_t 
opcode,
+               void *buf, uint32_t datalen, uint32_t lutnum)
 {
        struct target *target = bank->target;
        struct fsl_flexspi_flash_bank *flexspi_info = bank->driver_priv;
@@ -456,7 +302,7 @@ static int execute_ipcmd_read(struct flash_bank *bank, 
uint8_t opcode,
        lutval[lutidx / 2] |= LUT_DEF(lutidx, OPCODE_STOP, 0, 0);
        lutidx++;
 
-       ret = write_lut_memory(bank, lutval, LUTNUM_DRV);
+       ret = write_lut_memory(bank, lutval, lutnum);
        if (ret != ERROR_OK)
                goto err;
 
@@ -481,7 +327,7 @@ static int execute_ipcmd_read(struct flash_bank *bank, 
uint8_t opcode,
 
        ret = target_write_u32(target,
                                                   io_base + REG_IPCR1,
-                                                  IPCR1_IDATASZ(datalen) | 
IPCR1_ISEQID(LUTNUM_DRV) | IPCR1_ISEQNUM(0));
+                                                  IPCR1_IDATASZ(datalen) | 
IPCR1_ISEQID(lutnum) | IPCR1_ISEQNUM(0));
        if (ret != ERROR_OK)
                goto err;
 
@@ -527,6 +373,12 @@ err:
        return ret;
 }
 
+static int execute_ipcmd_read(struct flash_bank *bank, uint8_t opcode,
+               void *buf, uint32_t datalen)
+{
+       return execute_ipcmd_read_with_lutnum(bank, opcode, buf, datalen, 
LUTNUM_DRV);
+}
+
 static int execute_ipcmd_write(struct flash_bank *bank, uint8_t opcode,
                const void *buf, uint32_t datalen)
 {
@@ -649,7 +501,7 @@ static int read_status_reg(struct flash_bank *bank, uint8_t 
*statusreg)
 
        *statusreg = 0;
 
-       ret = execute_ipcmd_read(bank, SPIFLASH_READ_STATUS, statusreg, 
sizeof(*statusreg));
+       ret = execute_ipcmd_read_with_lutnum(bank, SPIFLASH_READ_STATUS, 
statusreg, sizeof(*statusreg), LUTNUM_READ_STATUS);
        if (ret != ERROR_OK)
                goto err;
 
@@ -665,7 +517,7 @@ static int write_enable(struct flash_bank *bank)
 
        LOG_DEBUG("reached");
 
-       ret = execute_ipcmd_read(bank, SPIFLASH_WRITE_ENABLE, NULL, 0);
+       ret = execute_ipcmd_read_with_lutnum(bank, SPIFLASH_WRITE_ENABLE, NULL, 
0, LUTNUM_WRITE_ENABLE);
        if (ret != ERROR_OK)
                goto err;
 
@@ -700,22 +552,13 @@ static int poll_flash_status(struct flash_bank *bank, 
uint8_t value, uint8_t mas
        return ERROR_TIMEOUT_REACHED;
 }
 
-static int execute_page_program(struct flash_bank *bank, uint8_t opcode,
-               const void *buf, uint32_t flashaddr, uint32_t datalen)
+static int setup_write_lut(struct flash_bank *bank, uint8_t opcode,
+               uint32_t writelen)
 {
-       struct target *target = bank->target;
-       struct fsl_flexspi_flash_bank *flexspi_info = bank->driver_priv;
-       uint32_t io_base = flexspi_info->io_base;
+       LOG_DEBUG("opcode: %02x, writelen: %u", opcode, writelen);
+
        uint32_t lutval[4] = {};
        int lutidx = 0;
-       uint8_t status;
-       int ret;
-
-       LOG_DEBUG("%" PRIu32 "B to 0x%08" PRIx32, datalen, flashaddr);
-
-       ret = write_enable(bank);
-       if (ret != ERROR_OK)
-               goto err;
 
        /* Prepare sequence LUT */
        lutval[lutidx / 2] |= LUT_DEF(lutidx, OPCODE_CMD, lut_pad(1), opcode);
@@ -732,18 +575,36 @@ static int execute_page_program(struct flash_bank *bank, 
uint8_t opcode,
        lutval[lutidx / 2] |= LUT_DEF(lutidx, OPCODE_RADDR, lut_pad(1), 
naddrbytes * 8);
        lutidx++;
 
-       if (datalen > 0) {
-               lutval[lutidx / 2] |= LUT_DEF(lutidx, OPCODE_WRITE, lut_pad(1), 
datalen);
+       if (writelen > 0) {
+               lutval[lutidx / 2] |= LUT_DEF(lutidx, OPCODE_WRITE, lut_pad(1), 
writelen);
                lutidx++;
        }
 
        lutval[lutidx / 2] |= LUT_DEF(lutidx, OPCODE_STOP, 0, 0);
        lutidx++;
 
-       ret = write_lut_memory(bank, lutval, LUTNUM_DRV);
+       return write_lut_memory(bank, lutval, LUTNUM_DRV);
+}
+
+static int program_page(struct flash_bank *bank, uint8_t opcode,
+               const void *buf, uint32_t flashaddr, uint32_t datalen)
+{
+       struct target *target = bank->target;
+       struct fsl_flexspi_flash_bank *flexspi_info = bank->driver_priv;
+       uint32_t io_base = flexspi_info->io_base;
+       uint8_t status;
+       int ret;
+
+       LOG_DEBUG("%" PRIu32 "B to 0x%08" PRIx32, datalen, flashaddr);
+
+       ret = write_enable(bank);
        if (ret != ERROR_OK)
                goto err;
 
+       ret = setup_write_lut(bank, opcode, datalen);
+       if (ret != ERROR_OK)
+               return ret;
+
        /* Clear any stray pending status */
        ret = target_write_u32(target,
                                                   io_base + REG_INTR,
@@ -810,6 +671,122 @@ err:
        return ret;
 }
 
+/* Kinetis Program-LongWord Microcodes */
+static const uint8_t flexspi_flash_blockwrite_algo[] = {
+#include "../../../contrib/loaders/flash/fsl_flexspi_blockwrite.inc"
+};
+
+static int program_block(struct flash_bank *bank, uint8_t opcode,
+               const void *buf, uint32_t flashaddr, uint32_t datalen, uint32_t 
blksize)
+{
+       struct target *target = bank->target;
+       struct fsl_flexspi_flash_bank *flexspi_info = bank->driver_priv;
+       uint32_t progdata_size;
+       struct working_area *algo;
+       struct working_area *progdata;
+       struct reg_param reg_params[6];
+       struct armv7m_algorithm armv7m_info;
+       uint32_t end_address;
+       uint32_t blkcount;
+       int ret;
+       uint8_t statusreg;
+
+       /* Set up driver LUT for block write */
+       ret = setup_write_lut(bank, opcode, blksize);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* Run an extra read status command to ensure LUTNUM_READ_STATUS is set 
up */
+       ret = read_status_reg(bank, &statusreg);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* Likewise for write enable */
+       ret = write_enable(bank);
+       if (ret != ERROR_OK)
+               return ret;
+
+       /* allocate working area with flash programming code */
+       if (target_alloc_working_area(target, 
sizeof(flexspi_flash_blockwrite_algo),
+                       &algo) != ERROR_OK) {
+               LOG_WARNING("no working area available, can't do block memory 
writes");
+               ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto out_noalgo;
+       }
+
+       ret = target_write_buffer(target, algo->address,
+               sizeof(flexspi_flash_blockwrite_algo), 
flexspi_flash_blockwrite_algo);
+       if (ret != ERROR_OK)
+               goto out_noprogdata;
+
+       /* memory buffer, size must be (multiple of blksize) plus 8 */
+       progdata_size = target_get_working_area_avail(target) & 
~(sizeof(uint32_t) - 1);
+       if (progdata_size < (blksize * 2 + 8)) {
+               LOG_WARNING("large enough working area not available for block 
writes");
+               ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto out_noprogdata;
+       }
+
+       /* Anything bigger than 32k seems superfluous */
+       progdata_size = MIN(progdata_size, 32768 + 8);
+
+       /* Ensure it's a multiple of the blksize plus the extra 8 bytes for the 
rp/wp */
+       progdata_size = ALIGN_DOWN(progdata_size, blksize) + 8;
+
+       if (target_alloc_working_area(target, progdata_size, &progdata) != 
ERROR_OK) {
+               LOG_ERROR("allocating working area failed");
+               ret = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               goto out_noprogdata;
+       }
+
+       blkcount = datalen / blksize;
+
+       armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+       armv7m_info.core_mode = ARM_MODE_THREAD;
+
+       init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);         /* 
flash address */
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);            /* 
block count */
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);            /* 
block length */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);            /* 
progdata start */
+       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);            /* 
progdata end */
+       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);            /* 
FLEXSPI base */
+
+       buf_set_u32(reg_params[0].value, 0, 32, flashaddr);
+       buf_set_u32(reg_params[1].value, 0, 32, blkcount);
+       buf_set_u32(reg_params[2].value, 0, 32, blksize / sizeof(uint32_t));
+       buf_set_u32(reg_params[3].value, 0, 32, progdata->address);
+       buf_set_u32(reg_params[4].value, 0, 32,
+                       progdata->address + progdata->size);
+       buf_set_u32(reg_params[5].value, 0, 32, flexspi_info->io_base);
+
+       ret = target_run_flash_async_algorithm(target, buf, blkcount, blksize,
+                                               0, NULL, 
ARRAY_SIZE(reg_params), reg_params,
+                                               progdata->address, 
progdata->size,
+                                               algo->address, 0, &armv7m_info);
+
+       if (ret == ERROR_FLASH_OPERATION_FAILED) {
+               end_address = buf_get_u32(reg_params[0].value, 0, 32);
+
+               LOG_ERROR("Error writing flash at %08" PRIx32, end_address);
+       } else if (ret != ERROR_OK) {
+               LOG_ERROR("Error executing flash block programming algorithm");
+       }
+
+       destroy_reg_param(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+
+       target_free_working_area(target, progdata);
+out_noprogdata:
+       target_free_working_area(target, algo);
+out_noalgo:
+
+       return ret;
+}
+
+
 static int erase_sector(struct flash_bank *bank, unsigned int sector)
 {
        struct target *target = bank->target;
@@ -821,7 +798,7 @@ static int erase_sector(struct flash_bank *bank, unsigned 
int sector)
        uint8_t status;
        int ret;
 
-       LOG_DEBUG("reached");
+       LOG_DEBUG("number %u", sector);
 
        ret = write_enable(bank);
        if (ret != ERROR_OK)
@@ -1305,19 +1282,34 @@ static int fsl_flexspi_write(struct flash_bank *bank, 
const uint8_t *buffer,
         * thereof.
         */
        if (offset % wrsize) {
-               ret = execute_page_program(bank, flexspi_info->dev.pprog_cmd, 
buffer, offset,
+               ret = program_page(bank, flexspi_info->dev.pprog_cmd, buffer, 
offset,
                                offset % flexspi_info->dev.pagesize);
                if (ret != ERROR_OK)
                        goto err;
        }
 
+       /* Attempt to program the entire block using on-chip algorithm */
+       uint32_t blockwrlen = ALIGN_DOWN(count, wrsize);
+       LOG_DEBUG("Block program %" PRIu32 "B at 0x%08" PRIx32, blockwrlen, 
offset);
+       ret = program_block(bank, flexspi_info->dev.pprog_cmd, buffer, offset,
+                       blockwrlen, wrsize);
+       if (ret == ERROR_OK) {
+               count -= blockwrlen;
+               offset += blockwrlen;
+               buffer += blockwrlen;
+       } else {
+               LOG_WARNING("Can't use block program; falling back to page 
program");
+               return ret;
+       }
+
+
        /* Program by page whatever we couldn't program as a block */
        while (count > 0) {
                if (count < wrsize)
                        wrsize = count;
 
-               ret = execute_page_program(bank, flexspi_info->dev.pprog_cmd,
-                               buffer, offset, wrsize);
+               ret = program_page(bank, flexspi_info->dev.pprog_cmd, buffer, 
offset,
+                               wrsize);
                if (ret != ERROR_OK)
                        goto err;
 
diff --git a/src/flash/nor/fsl_flexspi.h b/src/flash/nor/fsl_flexspi.h
new file mode 100644
index 0000000000..c199647276
--- /dev/null
+++ b/src/flash/nor/fsl_flexspi.h
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2022 by Brandon Martin and Mothic Technologies LLC      *
+ *   marti...@mothictech.com                                               *
+ ***************************************************************************/
+
+#include "spi.h"
+
+/* Make the BIT macro available from assembly */
+#ifndef BIT
+# define BIT(x)                                                (1 << (x))
+#endif
+
+/* These are the base addresses used on the IMXRT1020 */
+#define FLEXSPI_DEFAULT_IOBASE         0x402A8000
+#define FLEXSPI_LINEAR_AHBASE          0x60000000
+#define FLEXSPI_TX_FIFO_AHBASE         0x7F800000
+#define FLEXSPI_RX_FIFO_AHBASE         0x7FC00000
+
+/* The documentation implies that these may be chip-specific tweakables */
+#define FLEXSPI_AHB_TX_BUFSZ           64
+#define FLEXSPI_AHB_RX_BUFSZ           1024
+#define FLEXSPI_IP_TX_FIFOSZ           128
+#define FLEXSPI_IP_RX_FIFOSZ           128
+
+/* On-chip registers and fields */
+#define REG_MCR0                                       0x00
+#define MCR0_SWRESET                           BIT(0)
+#define MCR0_MDIS                                      BIT(1)
+#define MCR0_ARDFEN                                    BIT(6)
+#define MCR0_ATDFEN                                    BIT(7)
+
+#define REG_AHBCR                                      0x0C
+#define AHBCR_ALIGNMENT(x)                     (((x) & 0x03) << 20)
+#define AHBCR_READSZALIGN                      BIT(10)
+#define AHBCR_READADDROPT                      BIT(6)
+#define AHBCR_PREFETCHEN                       BIT(5)
+#define AHBCR_BUFFERABLEEN                     BIT(4)
+#define AHBCR_CACHABLEEN                       BIT(3)
+#define AHBCR_APAREN                           BIT(0)
+
+#define REG_INTR                                       0x14
+#define INTR_IPCMDDONE                         BIT(0)
+#define INTR_IPCMDGE                           BIT(1)
+#define INTR_AHBCMDGE                          BIT(2)
+#define INTR_IPCMDERR                          BIT(3)
+#define INTR_AHBCMDERR                         BIT(4)
+#define INTR_IPRXWA                                    BIT(5)
+#define INTR_IPTXWE                                    BIT(6)
+#define INTR_SCKSTOPBYRD                       BIT(8)
+#define INTR_SCKSTOPBYWR                       BIT(9)
+#define INTR_AHBBUSTTIMEOUT                    BIT(10)
+#define INTR_SEQTIMEOUT                                BIT(11)
+#define INTR_IPCMDSECUREVIO                    BIT(16)
+
+#define REG_LUTKEY                                     0x18
+#define LUTKEY_MAGIC                           0x5AF05AF0
+
+#define REG_LUTCR                                      0x1C
+#define LUTCR_LOCK                                     BIT(0)
+#define LUTCR_UNLOCK                           BIT(1)
+#define LUTCR_PROTECT                          BIT(2)
+
+#define REG_AHBRXBUF0CR0                       0x20
+#define REG_AHBRXBUF1CR0                       0x24
+#define REG_AHBRXBUF2CR0                       0x28
+#define REG_AHBRXBUF3CR0                       0x2C
+#define AHBRXBUFNCR0_BUFSZ(x)          (((x) & 0xFF) << 0)
+#define AHBRXBUFNCR0_MSTRID(x)         (((x) & 0x0F) << 16)
+#define AHBRXBUFNCR0_PRIORITY(x)       (((x) & 0x03) << 24)
+#define AHBRXBUFNCR0_REGIONEN          BIT(30)
+#define AHBRXBUFNCR0_PREFETCHEN                BIT(31)
+
+#define REG_FLSHA1CR0                          0x60
+#define FLSHNNCR0_FLASHSZ(x)           (((x) & 0x7FFFFF) << 0)
+
+#define REG_FLSHA1CR1                          0x70
+#define FLSHNNCR1_TCSS(x)                      (((x) & 0x1F) << 0)
+#define FLSHNNCR1_TCSH(x)                      (((x) & 0x1F) << 5)
+#define FLSHNNCR1_WA                           BIT(10)
+#define FLSHNNCR1_CAS(x)                       (((x) & 0x0F) << 11)
+#define FLSHNNCR1_CSINTERVALUNIT       BIT(15)
+#define FLSHNNCR1_CSINTERVAL(x)                (((x) & 0xFFFF) << 16)
+
+#define REG_FLSHA1CR2                          0x80
+#define FLSHNNCR2_ARDSEQID(x)          (((x) & 0x0F) << 0)
+#define FLSHNNCR2_ARDSEQNUM(x)         (((x) & 0x07) << 5)
+#define FLSHNNCR2_AWRSEQID(x)          (((x) & 0x0F) << 8)
+#define FLSHNNCR2_AWRSEQNUM(x)         (((x) & 0x07) << 13)
+#define FLSHNNCR2_AWRWAIT(x)           (((x) & 0x0FFF) << 16)
+#define FLSHNNCR2_AWRWAITUNIT(x)       (((x) & 0x07) << 28)
+#define AWRWAITUNIT_2AHB                       0
+#define AWRWAITUNIT_8AHB                       1
+#define AWRWAITUNIT_32AHB                      2
+#define AWRWAITUNIT_128AHB                     3
+#define AWRWAITUNIT_512AHB                     4
+#define AWRWAITUNIT_2048AHB                    5
+#define AWRWAITUNIT_8192AHB                    6
+#define AWRWAITUNIT_32768AHB           7
+#define FLSHNNCR2_CLRINSTRPTR          BIT(31)
+
+#define REG_FLSHCR4                                    0x94
+#define FLSHCR4_WMOPT1                         BIT(0)
+#define FLSHCR4_WMENA                          BIT(2)
+#define FLSHCR4_WMENB                          BIT(3)
+#define FLSHCR4_PAR_WM(x)                      (((x) & 0x03) << 9)
+#define FLSHCR4_PAR_ADDR_ADJ_DIS       BIT(11)
+
+#define REG_IPCR0                                      0xA0
+#define IPCR0_SFAR(x)                          (x)
+
+#define REG_IPCR1                                      0xA4
+#define IPCR1_IDATASZ(x)                       (((x) & 0xFFFF) << 0)
+#define IPCR1_ISEQID(x)                                (((x) & 0x0F) << 16)
+#define IPCR1_ISEQNUM(x)                       (((x) & 0x0F) << 24)
+#define IPCR1_IPAREN                           BIT(31)
+
+#define REG_IPCMD                                      0xB0
+#define IPCMD_TRG                                      BIT(0)
+
+#define REG_IPRXFCR                                    0xB8
+#define IPRXFCR_CLRIPRXF                       BIT(0)
+#define IPRXFCR_RXDMAEN                                BIT(1)
+#define IPRXFCR_RXWMRK(x)                      (((x) & 0x0F) << 2)
+
+#define REG_IPTXFCR                                    0xBC
+#define IPTXFCR_CLRIPTXF                       BIT(0)
+#define IPTXFCR_TXDMAEN                                BIT(1)
+#define IPTXFCR_TXWMRK(x)                      (((x) & 0x0F) << 2)
+
+#define REG_STS1                                       0xE4
+
+#define REG_RFDR                                       0x100
+#define REG_TFDR                                       0x180
+
+#define REG_LUT_BASE                           0x200
+#define REG_LUT(x)                                     (REG_LUT_BASE + (x) * 4)
+
+/*
+ * This LUT sequence ID is used during probe to read flash IDs and then is
+ * left configured so that the FLEXSPI can provide the usual linear
+ * memory-mapped access to the attached serial flash
+ *
+ * The LUT sequence ID 0 is the default for FlexSPI NOR (and NAND?) boot
+ * and is used by every example from Freescale/NXP that I've ever seen for AHB
+ * reads, though it doesn't strictly have to be.
+ */
+#define LUTNUM_AHB_READ                                0
+
+/*
+ * This LUT sequence ID is used to read flash status since it's a common
+ * thing to have to do interleaved with other actions
+ *
+ * The LUT sequence ID 1 is pretty much universally used for this purpose
+ * throughout Freescale/NXP's example/HAL code, and we at least attempt to use
+ * it in a compatible way.
+ */
+#define LUTNUM_READ_STATUS                     1
+
+/*
+ * This LUT sequence ID is used to perform write enable since it's also a
+ * common thing to have to do interleaved with other actions
+ *
+ * Like with read status, LUT ID 3 seems to be used for this pretty much
+ * everywhere at least for NOR flash.
+ */
+#define LUTNUM_WRITE_ENABLE                    3
+
+/*
+ * The usual LUT sequence ID to be used by the driver after probing for
+ * general activities other than reading status and performing write enable
+ *
+ * Other LUT sequence numbers will not be touched and can be used by
+ * application code without impeding operating by the driver without controller
+ * re-initialization if some other basic conditions are met.
+ *
+ * The LUT sequence number 10 is not used by boot procedures nor the Freescale
+ * sample code
+ */
+#define LUTNUM_DRV                                     10
+
+/* Instruction set for the LUT register (SDR only) */
+#define OPCODE_STOP                                    0
+#define OPCODE_CMD                                     1
+#define OPCODE_RADDR                           2
+#define OPCODE_CADDR                           3
+#define OPCODE_MODE1                           4
+#define OPCODE_MODE2                           5
+#define OPCODE_MODE4                           6
+#define OPCODE_MODE8                           7
+#define OPCODE_WRITE                           8
+#define OPCODE_READ                                    9
+#define OPCODE_LEARN                           10
+#define OPCODE_DATSZ                           11
+#define OPCODE_DUMMY                           12
+#define OPCODE_JMP_ON_CS                       31
+

-- 

Reply via email to