From 2b97f5cd1a956a9ac948ec57775600158988dadd Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Thu, 5 Feb 2026 19:09:48 +0100 Subject: [PATCH 1/3] spi: dt-bindings: cdns,qspi-nor: Add Renesas RZ/N1D400 to the list Add support for the Renesas RZ/N1D400 QSPI controller. This SoC is identified in the bindings with its other name: r9a06g032. It is part of the RZ/N1 family, which contains a "D" and a "S" variant. IPs in this SoC are typically described using 2 compatibles: the SoC specific compatible and the family compatible. The original Cadence IP compatible is dropped because it is unusable on its own. Indirect accesses are not supported by this flavour of the Cadence IP, which means several properties have no meaning in the scope of the Renesas compatible. Let's make sure they are no longer expected nor mandatory. Tested-by: Wolfram Sang Reviewed-by: Rob Herring (Arm) Signed-off-by: Miquel Raynal (Schneider Electric) Link: https://patch.msgid.link/20260205-schneider-6-19-rc1-qspi-v5-1-843632b3c674@bootlin.com Signed-off-by: Mark Brown --- .../bindings/spi/cdns,qspi-nor.yaml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml index 0d47bd94d67e..891f578b5ac4 100644 --- a/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +++ b/Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml @@ -61,6 +61,20 @@ allOf: cdns,fifo-depth: enum: [ 128, 256 ] default: 128 + - if: + properties: + compatible: + contains: + const: renesas,rzn1-qspi + then: + properties: + cdns,trigger-address: false + cdns,fifo-depth: false + cdns,fifo-width: false + else: + required: + - cdns,trigger-address + - cdns,fifo-depth properties: compatible: @@ -80,6 +94,9 @@ properties: # controllers are meant to be used with flashes of all kinds, # ie. also NAND flashes, not only NOR flashes. - const: cdns,qspi-nor + - items: + - const: renesas,r9a06g032-qspi + - const: renesas,rzn1-qspi - const: cdns,qspi-nor deprecated: true @@ -163,8 +180,6 @@ required: - reg - interrupts - clocks - - cdns,fifo-width - - cdns,trigger-address - '#address-cells' - '#size-cells' From 324ecc7788c2e21d0d9197a8c015ff75382122d9 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Thu, 5 Feb 2026 19:09:49 +0100 Subject: [PATCH 2/3] spi: cadence-qspi: Kill cqspi_jh7110_clk_init This controller can be fed by either a main "ref" clock, or three clocks ("ref" again, "ahb", "apb"). In practice, it is likely that all controllers have the same inputs, but a single clock feeds the three interfaces (ref is used for controlling the external interface, ahb/apb the internal ones). Handling these clocks is in no way SoC specific, only the number of expected clocks may change. Plus, we will soon be adding another controller requiring an AHB and an APB clock as well, so it is time to align the whole clock handling. Furthermore, the use of the cqspi_jh7110_clk_init() helper, which specifically grabs and enables the "ahb" and "apb" clocks, is a bit convoluted: - only the JH7110 compatible provides the ->jh7110_clk_init() callback, - in the probe, if the above callback is set in the driver data, the driver does not call the callback (!) but instead calls the helper directly (?), - in the helper, the is_jh7110 boolean is set. This logic does not make sense. Instead: - in the probe, set the is_jh7110 boolean based on the compatible, - collect all available clocks with the "bulk" helper, - enable the extra clocks if they are available, - kill the SoC specific cqspi_jh7110_clk_init() helper. This also allows to group the clock handling instead of depending on the driver data pointer, which further simplifies the error path and the remove callback. Tested-by: Wolfram Sang Signed-off-by: Miquel Raynal (Schneider Electric) Link: https://patch.msgid.link/20260205-schneider-6-19-rc1-qspi-v5-2-843632b3c674@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 112 ++++++++---------------------- 1 file changed, 29 insertions(+), 83 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 2d287950d44c..f14a746cba2d 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -57,7 +57,8 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_DEVICE_CS_CNT_MAX); #define CQSPI_OP_WIDTH(part) ((part).nbytes ? ilog2((part).buswidth) : 0) enum { - CLK_QSPI_APB = 0, + CLK_QSPI_REF = 0, + CLK_QSPI_APB, CLK_QSPI_AHB, CLK_QSPI_NUM, }; @@ -78,8 +79,7 @@ struct cqspi_flash_pdata { struct cqspi_st { struct platform_device *pdev; struct spi_controller *host; - struct clk *clk; - struct clk *clks[CLK_QSPI_NUM]; + struct clk_bulk_data clks[CLK_QSPI_NUM]; unsigned int sclk; void __iomem *iobase; @@ -123,8 +123,6 @@ struct cqspi_driver_platdata { int (*indirect_read_dma)(struct cqspi_flash_pdata *f_pdata, u_char *rxbuf, loff_t from_addr, size_t n_rx); u32 (*get_dma_status)(struct cqspi_st *cqspi); - int (*jh7110_clk_init)(struct platform_device *pdev, - struct cqspi_st *cqspi); }; /* Operation timeout value */ @@ -1771,51 +1769,6 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) return 0; } -static int cqspi_jh7110_clk_init(struct platform_device *pdev, struct cqspi_st *cqspi) -{ - static struct clk_bulk_data qspiclk[] = { - { .id = "apb" }, - { .id = "ahb" }, - }; - - int ret = 0; - - ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(qspiclk), qspiclk); - if (ret) { - dev_err(&pdev->dev, "%s: failed to get qspi clocks\n", __func__); - return ret; - } - - cqspi->clks[CLK_QSPI_APB] = qspiclk[0].clk; - cqspi->clks[CLK_QSPI_AHB] = qspiclk[1].clk; - - ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_APB]); - if (ret) { - dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_APB\n", __func__); - return ret; - } - - ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_AHB]); - if (ret) { - dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_AHB\n", __func__); - goto disable_apb_clk; - } - - cqspi->is_jh7110 = true; - - return 0; - -disable_apb_clk: - clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]); - - return ret; -} - -static void cqspi_jh7110_disable_clk(struct platform_device *pdev, struct cqspi_st *cqspi) -{ - clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]); - clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]); -} static int cqspi_probe(struct platform_device *pdev) { const struct cqspi_driver_platdata *ddata; @@ -1824,8 +1777,7 @@ static int cqspi_probe(struct platform_device *pdev) struct spi_controller *host; struct resource *res_ahb; struct cqspi_st *cqspi; - int ret; - int irq; + int ret, irq; host = devm_spi_alloc_host(&pdev->dev, sizeof(*cqspi)); if (!host) @@ -1836,10 +1788,11 @@ static int cqspi_probe(struct platform_device *pdev) host->mem_caps = &cqspi_mem_caps; cqspi = spi_controller_get_devdata(host); + if (of_device_is_compatible(pdev->dev.of_node, "starfive,jh7110-qspi")) + cqspi->is_jh7110 = true; cqspi->pdev = pdev; cqspi->host = host; - cqspi->is_jh7110 = false; cqspi->ddata = ddata = of_device_get_match_data(dev); platform_set_drvdata(pdev, cqspi); @@ -1856,12 +1809,14 @@ static int cqspi_probe(struct platform_device *pdev) return ret; } - /* Obtain QSPI clock. */ - cqspi->clk = devm_clk_get(dev, NULL); - if (IS_ERR(cqspi->clk)) { - dev_err(dev, "Cannot claim QSPI clock.\n"); - ret = PTR_ERR(cqspi->clk); - return ret; + /* Obtain QSPI clocks. */ + ret = devm_clk_bulk_get_optional(dev, CLK_QSPI_NUM, cqspi->clks); + if (ret) + return dev_err_probe(dev, ret, "Failed to get clocks\n"); + + if (!cqspi->clks[CLK_QSPI_REF].clk) { + dev_err(dev, "Cannot claim mandatory QSPI ref clock.\n"); + return -ENODEV; } /* Obtain and remap controller address. */ @@ -1893,10 +1848,9 @@ static int cqspi_probe(struct platform_device *pdev) if (ret) return ret; - - ret = clk_prepare_enable(cqspi->clk); + ret = clk_bulk_prepare_enable(CLK_QSPI_NUM, cqspi->clks); if (ret) { - dev_err(dev, "Cannot enable QSPI clock.\n"); + dev_err(dev, "Cannot enable QSPI clocks.\n"); goto disable_rpm; } @@ -1905,22 +1859,22 @@ static int cqspi_probe(struct platform_device *pdev) if (IS_ERR(rstc)) { ret = PTR_ERR(rstc); dev_err(dev, "Cannot get QSPI reset.\n"); - goto disable_clk; + goto disable_clks; } rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp"); if (IS_ERR(rstc_ocp)) { ret = PTR_ERR(rstc_ocp); dev_err(dev, "Cannot get QSPI OCP reset.\n"); - goto disable_clk; + goto disable_clks; } - if (of_device_is_compatible(pdev->dev.of_node, "starfive,jh7110-qspi")) { + if (cqspi->is_jh7110) { rstc_ref = devm_reset_control_get_optional_exclusive(dev, "rstc_ref"); if (IS_ERR(rstc_ref)) { ret = PTR_ERR(rstc_ref); dev_err(dev, "Cannot get QSPI REF reset.\n"); - goto disable_clk; + goto disable_clks; } reset_control_assert(rstc_ref); reset_control_deassert(rstc_ref); @@ -1932,7 +1886,7 @@ static int cqspi_probe(struct platform_device *pdev) reset_control_assert(rstc_ocp); reset_control_deassert(rstc_ocp); - cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); + cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clks[CLK_QSPI_REF].clk); host->max_speed_hz = cqspi->master_ref_clk_hz; /* write completion is supported by default */ @@ -1958,12 +1912,6 @@ static int cqspi_probe(struct platform_device *pdev) cqspi->slow_sram = true; if (ddata->quirks & CQSPI_NEEDS_APB_AHB_HAZARD_WAR) cqspi->apb_ahb_hazard = true; - - if (ddata->jh7110_clk_init) { - ret = cqspi_jh7110_clk_init(pdev, cqspi); - if (ret) - goto disable_clk; - } if (ddata->quirks & CQSPI_DISABLE_STIG_MODE) cqspi->disable_stig_mode = true; @@ -2029,11 +1977,8 @@ static int cqspi_probe(struct platform_device *pdev) disable_controller: cqspi_controller_enable(cqspi, 0); disable_clks: - if (cqspi->is_jh7110) - cqspi_jh7110_disable_clk(pdev, cqspi); -disable_clk: if (pm_runtime_get_sync(&pdev->dev) >= 0) - clk_disable_unprepare(cqspi->clk); + clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); disable_rpm: if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) pm_runtime_disable(dev); @@ -2062,14 +2007,12 @@ static void cqspi_remove(struct platform_device *pdev) cqspi_controller_enable(cqspi, 0); - if (cqspi->is_jh7110) - cqspi_jh7110_disable_clk(pdev, cqspi); if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) ret = pm_runtime_get_sync(&pdev->dev); if (ret >= 0) - clk_disable(cqspi->clk); + clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { pm_runtime_put_sync(&pdev->dev); @@ -2082,15 +2025,19 @@ static int cqspi_runtime_suspend(struct device *dev) struct cqspi_st *cqspi = dev_get_drvdata(dev); cqspi_controller_enable(cqspi, 0); - clk_disable_unprepare(cqspi->clk); + clk_bulk_disable_unprepare(CLK_QSPI_NUM, cqspi->clks); return 0; } static int cqspi_runtime_resume(struct device *dev) { struct cqspi_st *cqspi = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(CLK_QSPI_NUM, cqspi->clks); + if (ret) + return ret; - clk_prepare_enable(cqspi->clk); cqspi_wait_idle(cqspi); cqspi_controller_enable(cqspi, 0); cqspi_controller_init(cqspi); @@ -2173,7 +2120,6 @@ static const struct cqspi_driver_platdata versal2_ospi = { static const struct cqspi_driver_platdata jh7110_qspi = { .quirks = CQSPI_DISABLE_DAC_MODE, - .jh7110_clk_init = cqspi_jh7110_clk_init, }; static const struct cqspi_driver_platdata pensando_cdns_qspi = { From a40236feb62ccbf2b36d288550a483122b3205e5 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Thu, 5 Feb 2026 19:09:50 +0100 Subject: [PATCH 3/3] spi: cadence-qspi: Add support for the Renesas RZ/N1 controller Renesas RZ/N1 QSPI controllers embed a modified version of the Cadence IP with the following settings: - a limited bus clock range - no DTR support - no DMA - no useful interrupt flag - only direct accesses (no INDAC mode) - write protection The controller has been tested by running the SPI NOR check list with a custom RZ/N1D400 based board mounted with a Spansion s25fl128s1 quad SPI. Tested-by: Wolfram Sang Signed-off-by: Miquel Raynal (Schneider Electric) Link: https://patch.msgid.link/20260205-schneider-6-19-rc1-qspi-v5-3-843632b3c674@bootlin.com Signed-off-by: Mark Brown --- drivers/spi/spi-cadence-quadspi.c | 56 +++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index f14a746cba2d..649ff55333f0 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -110,6 +110,7 @@ struct cqspi_st { bool apb_ahb_hazard; bool is_jh7110; /* Flag for StarFive JH7110 SoC */ + bool is_rzn1; /* Flag for Renesas RZ/N1 SoC */ bool disable_stig_mode; refcount_t refcount; refcount_t inflight_ops; @@ -1337,8 +1338,9 @@ static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata, * mode. So, we can not use direct mode when in DTR mode for writing * data. */ - if (!op->cmd.dtr && cqspi->use_direct_mode && - cqspi->use_direct_mode_wr && ((to + len) <= cqspi->ahb_size)) { + if ((!op->cmd.dtr && cqspi->use_direct_mode && + cqspi->use_direct_mode_wr && ((to + len) <= cqspi->ahb_size)) || + (cqspi->ddata && cqspi->ddata->quirks & CQSPI_NO_INDIRECT_MODE)) { memcpy_toio(cqspi->ahb_base + to, buf, len); return cqspi_wait_idle(cqspi); } @@ -1512,6 +1514,7 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) static bool cqspi_supports_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) { + struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller); bool all_true, all_false; /* @@ -1538,6 +1541,9 @@ static bool cqspi_supports_mem_op(struct spi_mem *mem, /* A single opcode is supported, it will be repeated */ if ((op->cmd.opcode >> 8) != (op->cmd.opcode & 0xFF)) return false; + + if (cqspi->is_rzn1) + return false; } else if (!all_false) { /* Mixed DTR modes are not supported. */ return false; @@ -1591,18 +1597,20 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi) cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs"); - if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { - /* Zero signals FIFO depth should be runtime detected. */ - cqspi->fifo_depth = 0; - } + if (!(cqspi->ddata && cqspi->ddata->quirks & CQSPI_NO_INDIRECT_MODE)) { + if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { + /* Zero signals FIFO depth should be runtime detected. */ + cqspi->fifo_depth = 0; + } - if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) - cqspi->fifo_width = 4; + if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) + cqspi->fifo_width = 4; - if (of_property_read_u32(np, "cdns,trigger-address", - &cqspi->trigger_address)) { - dev_err(dev, "couldn't determine trigger-address\n"); - return -ENXIO; + if (of_property_read_u32(np, "cdns,trigger-address", + &cqspi->trigger_address)) { + dev_err(dev, "couldn't determine trigger-address\n"); + return -ENXIO; + } } if (of_property_read_u32(np, "num-cs", &cqspi->num_chipselect)) @@ -1666,6 +1674,9 @@ static void cqspi_controller_detect_fifo_depth(struct cqspi_st *cqspi) struct device *dev = &cqspi->pdev->dev; u32 reg, fifo_depth; + if (cqspi->ddata && cqspi->ddata->quirks & CQSPI_NO_INDIRECT_MODE) + return; + /* * Bits N-1:0 are writable while bits 31:N are read as zero, with 2^N * the FIFO depth. @@ -1790,6 +1801,8 @@ static int cqspi_probe(struct platform_device *pdev) cqspi = spi_controller_get_devdata(host); if (of_device_is_compatible(pdev->dev.of_node, "starfive,jh7110-qspi")) cqspi->is_jh7110 = true; + if (of_device_is_compatible(pdev->dev.of_node, "renesas,rzn1-qspi")) + cqspi->is_rzn1 = true; cqspi->pdev = pdev; cqspi->host = host; @@ -1887,7 +1900,12 @@ static int cqspi_probe(struct platform_device *pdev) reset_control_deassert(rstc_ocp); cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clks[CLK_QSPI_REF].clk); - host->max_speed_hz = cqspi->master_ref_clk_hz; + if (!cqspi->is_rzn1) { + host->max_speed_hz = cqspi->master_ref_clk_hz; + } else { + host->max_speed_hz = cqspi->master_ref_clk_hz / 2; + host->min_speed_hz = cqspi->master_ref_clk_hz / 32; + } /* write completion is supported by default */ cqspi->wr_completion = true; @@ -1952,7 +1970,7 @@ static int cqspi_probe(struct platform_device *pdev) if (ddata && (ddata->quirks & CQSPI_SUPPORT_DEVICE_RESET)) cqspi_device_reset(cqspi); - if (cqspi->use_direct_mode) { + if (cqspi->use_direct_mode && !cqspi->is_rzn1) { ret = cqspi_request_mmap_dma(cqspi); if (ret == -EPROBE_DEFER) { dev_err_probe(&pdev->dev, ret, "Failed to request mmap DMA\n"); @@ -2132,6 +2150,12 @@ static const struct cqspi_driver_platdata mobileye_eyeq5_ospi = { CQSPI_RD_NO_IRQ, }; +static const struct cqspi_driver_platdata renesas_rzn1_qspi = { + .hwcaps_mask = CQSPI_SUPPORTS_QUAD, + .quirks = CQSPI_NO_SUPPORT_WR_COMPLETION | CQSPI_RD_NO_IRQ | + CQSPI_HAS_WR_PROTECT | CQSPI_NO_INDIRECT_MODE, +}; + static const struct of_device_id cqspi_dt_ids[] = { { .compatible = "cdns,qspi-nor", @@ -2173,6 +2197,10 @@ static const struct of_device_id cqspi_dt_ids[] = { .compatible = "amd,versal2-ospi", .data = &versal2_ospi, }, + { + .compatible = "renesas,rzn1-qspi", + .data = &renesas_rzn1_qspi, + }, { /* end of table */ } };