This is an automated email from Gerrit.

"Gaetan Perrot <[email protected]>" just uploaded a new patch set 
to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9023

-- gerrit

commit 2ffee023a13e5680148e701f134e0a2eb18566d2
Author: Gaetan Perrot <[email protected]>
Date:   Thu Jun 26 16:05:39 2025 +0900

    flash: scqspi: Add support for read in SC-QSPI driver
    
    This commit adds the read operation to the SC-QSPI
    driver for the SC-OBC Module A1 using the Quad I/O
    Read (QREAD) command.
    
    The read implementation uses the `0xEC` opcode,
    which enables fast quad read access to the
    `S25FL256L` NOR flash devices through the custom
    QSPI controller.
    
    The command supports 4-byte addressing and
    delivers high-speed read throughput suitable for
    application-level data access.
    
    This feature is required for enabling flash
    verification, logging, and loading data from
    non-volatile storage during runtime.
    
    Change-Id: Ia8d58a0014e8198ebd703501a796e34713c5d00c
    Signed-off-by: Gaetan Perrot <[email protected]>

diff --git a/src/flash/nor/scqspi.c b/src/flash/nor/scqspi.c
index 1dee168a12..a5109e19f2 100644
--- a/src/flash/nor/scqspi.c
+++ b/src/flash/nor/scqspi.c
@@ -60,6 +60,7 @@
 #define SCQSPI_ERASE_BLOCK_WAIT_MS   (800U)
 #define SCQSPI_ERASE_SECTOR_WAIT_MS  (10U)
 #define SCQSPI_PAGE_BUFFER_BYTE      (256U)
+#define SCQSPI_DUMMY_CYCLE_COUNT     (4U)
 #define SCQSPI_REG_READ_RETRY(count) (count)
 #define SCQSPI_CRC32_INIT            (0xFFFFFFFF)
 #define SCQSPI_CRC32_FINAL(crc)      (~(crc))
@@ -719,6 +720,163 @@ end:
        return ret;
 }
 
+static int read_data_from_flash(struct target *target, const uint8_t 
*read_data, uint32_t read_size)
+{
+       int ret;
+       uint32_t bytes_transferred = 0;
+
+       LOG_DEBUG("Read %u bytes from QSPI flash", read_size);
+
+       while (bytes_transferred < read_size) {
+               uint32_t chunk = MIN(SCQSPI_RX_FIFO_MAX_BYTE, read_size - 
bytes_transferred);
+
+               for (uint32_t byte_idx = 0; byte_idx < chunk; byte_idx++) {
+                       ret = target_write_u32(target, 
SCOBCA1_FPGA_NORFLASH_QSPI_RDR, 0x00);
+                       if (ret != ERROR_OK) {
+                               LOG_ERROR("Failed to request RX data at index 
%u",
+                                       bytes_transferred + byte_idx);
+                               goto end;
+                       }
+               }
+
+               for (uint32_t byte_idx = 0; byte_idx < chunk; byte_idx++) {
+                       uint8_t byte;
+                       ret = target_read_u8(target, 
SCOBCA1_FPGA_NORFLASH_QSPI_RDR, &byte);
+                       if (ret != ERROR_OK) {
+                               LOG_ERROR("Failed to read RX data at index %u",
+                                       bytes_transferred + byte_idx);
+                               goto end;
+                       }
+                       ((uint8_t *)read_data)[bytes_transferred + byte_idx] = 
byte;
+               }
+
+               bytes_transferred += chunk;
+       }
+
+end:
+       return ret;
+}
+
+static int send_dummy_cycle(struct target *target, uint8_t dummy_count)
+{
+       uint32_t discard;
+       int ret;
+
+       LOG_DEBUG("Send dummy cycle %d byte", dummy_count);
+       for (int i = 0; i < dummy_count; i++) {
+               ret = target_write_u32(target, SCOBCA1_FPGA_NORFLASH_QSPI_RDR, 
0x00);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("Failed to request RX data");
+                       goto end;
+               }
+       }
+
+       if (!is_qspi_idle(target)) {
+               ret = ERROR_FLASH_BUSY;
+               goto end;
+       }
+
+       LOG_DEBUG("Discard dummy data");
+       for (int i = 0; i < dummy_count; i++) {
+               ret = target_read_u32(target, SCOBCA1_FPGA_NORFLASH_QSPI_RDR, 
&discard);
+               if (ret != ERROR_OK)
+                       goto end;
+       }
+
+end:
+       return ret;
+}
+
+static int scqspi_nor_quad_read(struct flash_bank *bank, const uint8_t 
*buffer, uint32_t offset,
+       uint32_t count)
+{
+       struct scqspi_flash_bank *scqspi_info = bank->driver_priv;
+       struct target *target = bank->target;
+       uint32_t mem_addr = scqspi_info->flash_addr + offset;
+       /*
+        * Workaround: scqspi_info->dev.qread_cmd is set to 0x00 by default,
+        * but for our NOR flash (S25FL256L), the correct Quad Read command is 
0xEC.
+        * This is based on the datasheet.
+        * Reason for the mismatch is unclear, so we override it manually here.
+        */
+       uint32_t qread_cmd = 0xEC;
+       int ret;
+
+       LOG_DEBUG("Read %d bytes from 0x%08x", count, mem_addr);
+
+       ret = activate_spi_ss(target, scqspi_info->spi_ss);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to activate SPI SS : %d", ret);
+               goto end;
+       }
+
+       LOG_DEBUG("Send Quad I/O Read instruction : 0x%08x", qread_cmd);
+       ret = target_write_u32(target, SCOBCA1_FPGA_NORFLASH_QSPI_TDR, 
qread_cmd);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to send `Quad I/O Read (4byte)` instruction");
+               goto inactivate_ss;
+       }
+
+       if (!is_qspi_idle(target)) {
+               ret = ERROR_FLASH_BUSY;
+               goto inactivate_ss;
+       }
+
+       ret = activate_spi_ss(target, SCQSPI_SPI_MODE_QUAD + 
scqspi_info->spi_ss);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to activate SPI SS : %d", ret);
+               goto inactivate_ss;
+       }
+
+       LOG_DEBUG("Send Memory Address (4byte)");
+       ret = write_mem_addr_to_flash(target, mem_addr);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to write memory address to flash");
+               goto inactivate_ss;
+       }
+
+       LOG_DEBUG("Send Mode (0x00)");
+       target_write_u32(target, SCOBCA1_FPGA_NORFLASH_QSPI_TDR, 0x00);
+
+       LOG_DEBUG("Send Dummy Cycle");
+       ret = send_dummy_cycle(target, SCQSPI_DUMMY_CYCLE_COUNT);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed send dummy cycle to flash");
+               goto inactivate_ss;
+       }
+
+       if (!is_qspi_idle(target)) {
+               ret = ERROR_FLASH_BUSY;
+               goto inactivate_ss;
+       }
+
+       ret = read_data_from_flash(target, buffer, count);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read data to flash : %d", ret);
+               goto inactivate_ss;
+       }
+
+       if (!is_qspi_idle(target)) {
+               ret = ERROR_FLASH_BUSY;
+               goto inactivate_ss;
+       }
+
+inactivate_ss:
+       ret = inactivate_spi_ss(target);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to inactivate SPI SS : %d", ret);
+               goto end;
+       }
+
+       if (!is_qspi_control_done(target)) {
+               LOG_ERROR("Confirm SPI Control is Done failed");
+               ret = ERROR_FAIL;
+       }
+
+end:
+       return ret;
+}
+
 /* -------------------------------------------------------------------------
  * Command handler functions
  * -------------------------------------------------------------------------*/
@@ -863,8 +1021,37 @@ end:
 
 static int scqspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t 
offset, uint32_t count)
 {
-       LOG_DEBUG("%s", __func__);
-       return ERROR_OK;
+       int ret;
+       struct target *target = bank->target;
+       struct scqspi_flash_bank *scqspi_info = bank->driver_priv;
+
+       LOG_DEBUG("%s: offset=0x%08x count=0x%08x (base: 0x%08x)", __func__, 
offset, count,
+               scqspi_info->flash_addr);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               ret = ERROR_TARGET_NOT_HALTED;
+               goto end;
+       }
+
+       if (!(scqspi_info->probed)) {
+               LOG_ERROR("Flash bank not probed");
+               ret = ERROR_FLASH_BANK_NOT_PROBED;
+               goto end;
+       }
+
+       if (offset + count > bank->size) {
+               LOG_ERROR("Flash access out of range: offset=%u, count=%u, 
bank_size=%u", offset,
+                       count, bank->size);
+               return ERROR_FLASH_DST_OUT_OF_BANK;
+       }
+
+       ret = scqspi_nor_quad_read(bank, buffer, offset, count);
+       if (ret != ERROR_OK)
+               LOG_ERROR("Failed to read data on flash : %d", ret);
+
+end:
+       return ret;
 }
 
 static int scqspi_probe(struct flash_bank *bank)

-- 

Reply via email to