All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] spi: cadence_qspi: clock enable, compatible, write protect
@ 2026-08-14 18:28 Ralph Siemsen
  2026-08-14 18:28 ` [PATCH v2 1/3] spi: cadence_qspi: enable all clocks Ralph Siemsen
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Ralph Siemsen @ 2026-08-14 18:28 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard, Ralph Siemsen

1) enable the clock(s) before accessing the QSPI registers
2) add RZ/N1 specific compatible string
3) add an option to enable hardware write protection
   (TBD: maybe drop this change)

Both have been split from "Renesas RZ/N1 additional drivers" series.

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
Ralph Siemsen (3):
      spi: cadence_qspi: enable all clocks
      spi: cadence_qspi: add RZ/N1 compatible
      spi: cadence_qspi: Use APB write protection

 drivers/spi/Kconfig            | 11 +++++++++++
 drivers/spi/cadence_qspi.c     | 13 ++++++++++---
 drivers/spi/cadence_qspi.h     |  6 ++++++
 drivers/spi/cadence_qspi_apb.c | 23 +++++++++++++++++++++++
 4 files changed, 50 insertions(+), 3 deletions(-)
---
base-commit: 36c377b9859ffb53eb1e39ea31e8d96d1e0fe1e5
change-id: 20260811-rzn1-2026-10-spi-cec7e474ed54

Best regards,
--  
Ralph Siemsen <ralph.siemsen@linaro.org>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/3] spi: cadence_qspi: enable all clocks
  2026-08-14 18:28 [PATCH v2 0/3] spi: cadence_qspi: clock enable, compatible, write protect Ralph Siemsen
@ 2026-08-14 18:28 ` Ralph Siemsen
  2026-08-14 22:03   ` Marek Vasut via U-Boot
  2026-08-14 18:28 ` [PATCH v2 2/3] spi: cadence_qspi: add RZ/N1 compatible Ralph Siemsen
  2026-08-14 18:28 ` [PATCH v2 3/3] spi: cadence_qspi: Use APB write protection Ralph Siemsen
  2 siblings, 1 reply; 7+ messages in thread
From: Ralph Siemsen @ 2026-08-14 18:28 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard, Ralph Siemsen

On certain devices (such as Renesas RZ/N1) it is necessary to
enable the clock(s) before accessing the QSPI controller registers.

As there can be multiple clocks, use clk_get_bulk() to obtain clock(s)
and clk_enable_bulk() to turn them on. Warn if clk_enable_bulk() fails,
but keep going so as not to break existing users.

As before, it is assumed that the first clock is the reference clock,
so the order in the devicetree matters.

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
Changes in v2:
- patch was split from the series "Renesas RZ/N1 additional drivers"
  https://lore.kernel.org/u-boot/20260731-rzn1-2026-07-v1-2-af2ce80db9d8@linaro.org/
- move clock enable before clk_get_rate()
- handle multiple clocks using clk_get_bulk() and clk_enable_bulk()
---
 drivers/spi/cadence_qspi.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 984d4a39ded..0f70493dea4 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -208,7 +208,7 @@ static int cadence_spi_probe(struct udevice *bus)
 {
 	struct cadence_spi_plat *plat = dev_get_plat(bus);
 	struct cadence_spi_priv *priv = dev_get_priv(bus);
-	struct clk clk;
+	struct clk_bulk clks;
 	int ret;
 
 	priv->regbase		= plat->regbase;
@@ -240,7 +240,7 @@ static int cadence_spi_probe(struct udevice *bus)
 				  ZYNQMP_PM_REQUEST_ACK_NO, 0, 0, NULL);
 
 	if (priv->ref_clk_hz == 0) {
-		ret = clk_get_by_index(bus, 0, &clk);
+		ret = clk_get_bulk(bus, &clks);
 		if (ret) {
 #ifdef CONFIG_HAS_CQSPI_REF_CLK
 			priv->ref_clk_hz = CONFIG_CQSPI_REF_CLK;
@@ -250,7 +250,11 @@ static int cadence_spi_probe(struct udevice *bus)
 			return ret;
 #endif
 		} else {
-			priv->ref_clk_hz = clk_get_rate(&clk);
+			ret = clk_enable_bulk(&clks);
+			if (ret)
+				dev_warn(bus, "failed clk_enable_bulk\n");
+
+			priv->ref_clk_hz = clk_get_rate(&clks.clks[0]);
 			if (IS_ERR_VALUE(priv->ref_clk_hz))
 				return priv->ref_clk_hz;
 		}

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/3] spi: cadence_qspi: add RZ/N1 compatible
  2026-08-14 18:28 [PATCH v2 0/3] spi: cadence_qspi: clock enable, compatible, write protect Ralph Siemsen
  2026-08-14 18:28 ` [PATCH v2 1/3] spi: cadence_qspi: enable all clocks Ralph Siemsen
@ 2026-08-14 18:28 ` Ralph Siemsen
  2026-08-14 18:28 ` [PATCH v2 3/3] spi: cadence_qspi: Use APB write protection Ralph Siemsen
  2 siblings, 0 replies; 7+ messages in thread
From: Ralph Siemsen @ 2026-08-14 18:28 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard, Ralph Siemsen

The Renesas RZ/N1 contains a QSPI controller based on Cadence IP.
Add its compatible string as per linux commit
2b97f5cd1a95 ("spi: dt-bindings: cdns,qspi-nor: Add Renesas
RZ/N1D400 to the list")

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
 drivers/spi/cadence_qspi.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 0f70493dea4..12ac64c9e08 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -505,6 +505,9 @@ static const struct udevice_id cadence_spi_ids[] = {
 		.compatible = "xlnx,versal-ospi-1.0",
 		.data = (ulong)&cdns_xilinx_qspi,
 	},
+	{
+		.compatible = "renesas,rzn1-qspi",
+	},
 	{ }
 };
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 3/3] spi: cadence_qspi: Use APB write protection
  2026-08-14 18:28 [PATCH v2 0/3] spi: cadence_qspi: clock enable, compatible, write protect Ralph Siemsen
  2026-08-14 18:28 ` [PATCH v2 1/3] spi: cadence_qspi: enable all clocks Ralph Siemsen
  2026-08-14 18:28 ` [PATCH v2 2/3] spi: cadence_qspi: add RZ/N1 compatible Ralph Siemsen
@ 2026-08-14 18:28 ` Ralph Siemsen
  2026-08-14 22:04   ` Marek Vasut via U-Boot
  2 siblings, 1 reply; 7+ messages in thread
From: Ralph Siemsen @ 2026-08-14 18:28 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard, Ralph Siemsen

Add an option to make use of hardware write protection in the QSPI
controller. This helps prevent flash corruption due to stray writes.
No stray writes have been observed, this is defensive code.

When enabled, the controller is configured to block writes to flash. Due
to known errata [1] the full 32-bit address range is protected, even
though the flash occupies only a portion.

The protection gets temporarily lifted while intentionally writing
to flash, for example using "sf write" command.

[1] https://www.renesas.com/en/document/tcu/qspi-contoller-issue

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
Changes in v2:
- patch was split from the series "Renesas RZ/N1 additional drivers"
  https://lore.kernel.org/u-boot/20260731-rzn1-2026-07-v1-3-af2ce80db9d8@linaro.org/
- combine the enable()/disable() into a single function
- move the IS_ENABLED() check inside the function
- reword the commit message
- considering to drop this feature, since Linux disables it
---
 drivers/spi/Kconfig            | 11 +++++++++++
 drivers/spi/cadence_qspi.h     |  6 ++++++
 drivers/spi/cadence_qspi_apb.c | 23 +++++++++++++++++++++++
 3 files changed, 40 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..fc4649916ad 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -325,6 +325,15 @@ void cadence_qspi_apb_delay(void *reg_base,
 	cadence_qspi_apb_controller_enable(reg_base);
 }
 
+static void cadence_qspi_apb_write_protect(void *reg_base, bool enable)
+{
+	if (!IS_ENABLED(CONFIG_CADENCE_QSPI_WRITE_PROTECT))
+		return;
+
+	writel(enable ? CQSPI_REG_WRPROT_ENABLE : 0,
+	       reg_base + CQSPI_REG_WRITE_PROTECT_CTRL);
+}
+
 void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv)
 {
 	unsigned reg;
@@ -346,6 +355,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(priv->regbase, true);
+	}
+
 	/* Disable all interrupts */
 	writel(0, priv->regbase + CQSPI_REG_IRQMASK);
 
@@ -955,7 +976,9 @@ 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)) {
+		cadence_qspi_apb_write_protect(priv->regbase, false);
 		memcpy_toio(priv->ahbbase + to, buf, len);
+		cadence_qspi_apb_write_protect(priv->regbase, true);
 		if (!cadence_qspi_wait_idle(priv->regbase))
 			return -EIO;
 		return 0;

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/3] spi: cadence_qspi: enable all clocks
  2026-08-14 18:28 ` [PATCH v2 1/3] spi: cadence_qspi: enable all clocks Ralph Siemsen
@ 2026-08-14 22:03   ` Marek Vasut via U-Boot
  2026-08-15 14:09     ` Ralph Siemsen
  0 siblings, 1 reply; 7+ messages in thread
From: Marek Vasut via U-Boot @ 2026-08-14 22:03 UTC (permalink / raw)
  To: Ralph Siemsen, u-boot
  Cc: Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard

On 8/14/26 8:28 PM, Ralph Siemsen wrote:

[...]

> @@ -250,7 +250,11 @@ static int cadence_spi_probe(struct udevice *bus)
>   			return ret;
>   #endif
>   		} else {
> -			priv->ref_clk_hz = clk_get_rate(&clk);
> +			ret = clk_enable_bulk(&clks);

Some sort of clk_disable_bulk() seems to be missing.

Fail path which disables the clock seems to be missing too in this function.

> +			if (ret)
> +				dev_warn(bus, "failed clk_enable_bulk\n");
> +
> +			priv->ref_clk_hz = clk_get_rate(&clks.clks[0]);

Can the refclock be second or later (not first) clock in the list of 
multiple clock in DT ? If yes, then the clk_get_rate[0] will return 
bogus rate for another clock.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 3/3] spi: cadence_qspi: Use APB write protection
  2026-08-14 18:28 ` [PATCH v2 3/3] spi: cadence_qspi: Use APB write protection Ralph Siemsen
@ 2026-08-14 22:04   ` Marek Vasut via U-Boot
  0 siblings, 0 replies; 7+ messages in thread
From: Marek Vasut via U-Boot @ 2026-08-14 22:04 UTC (permalink / raw)
  To: Ralph Siemsen, u-boot
  Cc: Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard

On 8/14/26 8:28 PM, Ralph Siemsen wrote:
> Add an option to make use of hardware write protection in the QSPI
> controller. This helps prevent flash corruption due to stray writes.
> No stray writes have been observed, this is defensive code.
> 
> When enabled, the controller is configured to block writes to flash. Due
> to known errata [1] the full 32-bit address range is protected, even
> though the flash occupies only a portion.
> 
> The protection gets temporarily lifted while intentionally writing
> to flash, for example using "sf write" command.
> 
> [1] https://www.renesas.com/en/document/tcu/qspi-contoller-issue
> 
> Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>

Reviewed-by: Marek Vasut <marek.vasut+renesas@mailbox.org>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/3] spi: cadence_qspi: enable all clocks
  2026-08-14 22:03   ` Marek Vasut via U-Boot
@ 2026-08-15 14:09     ` Ralph Siemsen
  0 siblings, 0 replies; 7+ messages in thread
From: Ralph Siemsen @ 2026-08-15 14:09 UTC (permalink / raw)
  To: Marek Vasut
  Cc: u-boot, Tom Rini, Michal Simek, Marek Vasut, Padmarao Begari,
	Anshul Dalal, Neha Malcom Francis, Johan Jonker, Quentin Schulz,
	Patrice Chotard

On Sat, Aug 15, 2026 at 12:03:55AM +0200, Marek Vasut wrote:
>On 8/14/26 8:28 PM, Ralph Siemsen wrote:
>
>[...]
>
>>@@ -250,7 +250,11 @@ static int cadence_spi_probe(struct udevice *bus)
>>  			return ret;
>>  #endif
>>  		} else {
>>-			priv->ref_clk_hz = clk_get_rate(&clk);
>>+			ret = clk_enable_bulk(&clks);
>
>Some sort of clk_disable_bulk() seems to be missing.
>
>Fail path which disables the clock seems to be missing too in this function.

Ack for both.

>>+			if (ret)
>>+				dev_warn(bus, "failed clk_enable_bulk\n");
>>+
>>+			priv->ref_clk_hz = clk_get_rate(&clks.clks[0]);
>
>Can the refclock be second or later (not first) clock in the list of 
>multiple clock in DT ? If yes, then the clk_get_rate[0] will return 
>bogus rate for another clock.

The right solution is to get the clock by name. But once again we have a 
pile of existing boards which may not have the correct name ("ref") in 
their device tree. So I went with the simple option of continuing to 
assume that the first clock is the refclock.

Ralph

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-08-15 14:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 18:28 [PATCH v2 0/3] spi: cadence_qspi: clock enable, compatible, write protect Ralph Siemsen
2026-08-14 18:28 ` [PATCH v2 1/3] spi: cadence_qspi: enable all clocks Ralph Siemsen
2026-08-14 22:03   ` Marek Vasut via U-Boot
2026-08-15 14:09     ` Ralph Siemsen
2026-08-14 18:28 ` [PATCH v2 2/3] spi: cadence_qspi: add RZ/N1 compatible Ralph Siemsen
2026-08-14 18:28 ` [PATCH v2 3/3] spi: cadence_qspi: Use APB write protection Ralph Siemsen
2026-08-14 22:04   ` Marek Vasut via U-Boot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.