On 7/31/2026 10:03 PM, Ralph Siemsen wrote:
> Prevent random memory writes from corrupting flash memory.
> 
> When using the Direct Access Controller (DAC), the QSPI flash appears as
> a memory-mapped device. A stray write within the DAC region can corrupt
> flash contents.
>

my suggestion will be check first, why stray write are happening

> To prevent this, enable the hardware write protection feature. Due to
> known errata [1] of the QSPI controller, the entire address range is
> protected, and only gets unlocked during intentional QSPI writes.
> 



> [1] https://www.renesas.com/en/document/tcu/qspi-contoller-issue
> 
> Signed-off-by: Ralph Siemsen <[email protected]>
> ---
>  drivers/spi/Kconfig            | 11 +++++++++++
>  drivers/spi/cadence_qspi.h     |  6 ++++++
>  drivers/spi/cadence_qspi_apb.c | 27 +++++++++++++++++++++++++++
>  3 files changed, 44 insertions(+)
> 
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index 007ad5e7733..19f8d48507b 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -168,6 +168,17 @@ config CADENCE_QSPI
>         used to access the SPI NOR flash on platforms embedding this
>         Cadence IP core.
>  
> +config CADENCE_QSPI_WRITE_PROTECT
> +     bool "Cadence QSPI write protection"
> +     depends on CADENCE_QSPI
> +     help
> +       Enable hardware write protection in the QSPI controller. Helps avoid
> +       flash corruption due to stray writes. The direct access region is kept
> +       locked by default, and only gets unlocked during "sf write".
> +
> +       This is similar to SYS_FLASH_PROTECTION however blocking is done by
> +       the controller, rather than by the flash device.
> +
>  config HAS_CQSPI_REF_CLK
>       bool "Cadence QSPI static reference clock"
>       depends on CADENCE_QSPI
> diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
> index 1e9081c2d17..6b3ed46977a 100644
> --- a/drivers/spi/cadence_qspi.h
> +++ b/drivers/spi/cadence_qspi.h
> @@ -119,6 +119,12 @@
>  #define CQSPI_REG_IRQSTATUS                     0x40
>  #define CQSPI_REG_IRQMASK                       0x44
>  
> +#define CQSPI_REG_LOWER_WRITE_PROTECT           0x50
> +#define CQSPI_REG_UPPER_WRITE_PROTECT           0x54
> +
> +#define CQSPI_REG_WRITE_PROTECT_CTRL            0x58
> +#define CQSPI_REG_WRPROT_ENABLE                 BIT(1)
> +
>  #define CQSPI_REG_INDIRECTRD                    0x60
>  #define CQSPI_REG_INDIRECTRD_START              BIT(0)
>  #define CQSPI_REG_INDIRECTRD_CANCEL             BIT(1)
> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> index 0d4bc685f5d..353b57a46af 100644
> --- a/drivers/spi/cadence_qspi_apb.c
> +++ b/drivers/spi/cadence_qspi_apb.c
> @@ -325,6 +325,17 @@ void cadence_qspi_apb_delay(void *reg_base,
>       cadence_qspi_apb_controller_enable(reg_base);
>  }
>  
> +static void cadence_qspi_apb_write_protect_enable(void *reg_base)
> +{
> +     writel(CQSPI_REG_WRPROT_ENABLE,
> +            reg_base + CQSPI_REG_WRITE_PROTECT_CTRL);
> +}
> +

I expect compilation warning on platform, which does not define
CONFIG_CADENCE_QSPI_WRITE_PROTECT

> +static void cadence_qspi_apb_write_protect_disable(void *reg_base)
> +{
> +     writel(0, reg_base + CQSPI_REG_WRITE_PROTECT_CTRL);
> +}
> +
>  void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv)
>  {
>       unsigned reg;
> @@ -346,6 +357,18 @@ void cadence_qspi_apb_controller_init(struct 
> cadence_spi_priv *priv)
>       /* Indirect mode configurations */
>       writel(priv->fifo_depth / 2, priv->regbase + CQSPI_REG_SRAMPARTITION);
>  
> +     if (IS_ENABLED(CONFIG_CADENCE_QSPI_WRITE_PROTECT)) {
> +             /*
> +              * Enable AHB write protection, to reduce the chance of 
> corrupting
> +              * flash memory due to a stray write within the DAC region.
> +              * Protect the entire address range, regardless of the flash 
> size.
> +              * During "sf write" the protection will be temporarily 
> disabled.
> +              */
> +             writel(0, priv->regbase + CQSPI_REG_LOWER_WRITE_PROTECT);
> +             writel(~0, priv->regbase + CQSPI_REG_UPPER_WRITE_PROTECT);
> +             cadence_qspi_apb_write_protect_enable(priv->regbase);
> +     }
> +
>       /* Disable all interrupts */
>       writel(0, priv->regbase + CQSPI_REG_IRQMASK);
>  
> @@ -955,7 +978,11 @@ int cadence_qspi_apb_write_execute(struct 
> cadence_spi_priv *priv,
>        */
>       cadence_qspi_apb_enable_linear_mode(true);
>       if (!priv->dtr && priv->use_dac_mode && (to + len < priv->ahbsize)) {
> +             if (IS_ENABLED(CONFIG_CADENCE_QSPI_WRITE_PROTECT))
> +                     cadence_qspi_apb_write_protect_disable(priv->regbase);
>               memcpy_toio(priv->ahbbase + to, buf, len);
> +             if (IS_ENABLED(CONFIG_CADENCE_QSPI_WRITE_PROTECT))
> +                     cadence_qspi_apb_write_protect_enable(priv->regbase);
>               if (!cadence_qspi_wait_idle(priv->regbase))
>                       return -EIO;
>               return 0;
> 

Reply via email to