summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVenkatesh Yadav Abbarapu <venkatesh.abbarapu@amd.com>2025-07-02 11:09:53 +0530
committerMichal Simek <michal.simek@amd.com>2025-07-08 15:01:25 +0200
commit6b772a0bcc1a3b03b6cfce30864a22149b613036 (patch)
tree2e05dd43a781ae7af6a566cf0202947d1cb295c4
parentbfa3f147e1b5df74db8cdffbef5a276d2c2daec3 (diff)
cadence_qspi: fix odd byte read issue in STIG mode
In DDR mode, even bytes are read using DMA, while the remaining odd bytes are read using STIG mode. However, the data is not correctly transferred into the flash read data lower register because the supplementary byte of the STIG opcode is not being written to the opcode extension register, resulting in incorrect data being read. To resolve this issue, when using STIG transactions, the corresponding supplementary byte of any STIG opcode must be defined in the Opcode Extension Register (Lower). Issue has been observed on the Macronix MX66UM2G45G flashes. Signed-off-by: Prasad Kummari <prasad.kummari@amd.com> Signed-off-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@amd.com> Link: https://lore.kernel.org/r/20250702053953.640046-1-venkatesh.abbarapu@amd.com Signed-off-by: Michal Simek <michal.simek@amd.com>
-rw-r--r--drivers/spi/cadence_ospi_versal.c12
-rw-r--r--drivers/spi/cadence_qspi.h4
-rw-r--r--drivers/spi/cadence_qspi_apb.c6
3 files changed, 17 insertions, 5 deletions
diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c
index fbeb0c6a85c..6dc6fbe5a5b 100644
--- a/drivers/spi/cadence_ospi_versal.c
+++ b/drivers/spi/cadence_ospi_versal.c
@@ -20,7 +20,7 @@
int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
const struct spi_mem_op *op)
{
- u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data;
+ u32 reg, ret, rx_rem, n_rx, bytes_to_dma, data, status;
u8 opcode, addr_bytes, *rxbuf, dummy_cycles;
n_rx = op->data.nbytes;
@@ -87,6 +87,16 @@ int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv,
CQSPI_REG_SIZE_ADDRESS_MASK;
opcode = CMD_4BYTE_FAST_READ;
+
+ /* Set up command opcode extension. */
+ status = readl(priv->regbase + CQSPI_REG_CONFIG);
+ if (status & CQSPI_REG_CONFIG_DTR_PROTO) {
+ ret = cadence_qspi_setup_opcode_ext(priv, op,
+ CQSPI_REG_OP_EXT_STIG_LSB);
+ if (ret)
+ return ret;
+ }
+
dummy_cycles = 8;
writel((dummy_cycles << CQSPI_REG_RD_INSTR_DUMMY_LSB) | opcode,
priv->regbase + CQSPI_REG_RD_INSTR);
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 80510f2542b..879e7f8dbfb 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -320,5 +320,7 @@ int cadence_qspi_flash_reset(struct udevice *dev);
ofnode cadence_qspi_get_subnode(struct udevice *dev);
void cadence_qspi_apb_enable_linear_mode(bool enable);
int cadence_device_reset(struct udevice *dev);
-
+int cadence_qspi_setup_opcode_ext(struct cadence_spi_priv *priv,
+ const struct spi_mem_op *op,
+ unsigned int shift);
#endif /* __CADENCE_QSPI_H__ */
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index ebfcae9a5b3..6f89d3add5d 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -384,9 +384,9 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg)
return 0;
}
-static int cadence_qspi_setup_opcode_ext(struct cadence_spi_priv *priv,
- const struct spi_mem_op *op,
- unsigned int shift)
+int cadence_qspi_setup_opcode_ext(struct cadence_spi_priv *priv,
+ const struct spi_mem_op *op,
+ unsigned int shift)
{
unsigned int reg;
u8 ext;