]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: cadence-qspi: Add support for the Renesas RZ/N1 controller
authorMiquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
Thu, 5 Feb 2026 18:09:50 +0000 (19:09 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 5 Feb 2026 18:25:28 +0000 (18:25 +0000)
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 <wsa+renesas@sang-engineering.com>
Signed-off-by: Miquel Raynal (Schneider Electric) <miquel.raynal@bootlin.com>
Link: https://patch.msgid.link/20260205-schneider-6-19-rc1-qspi-v5-3-843632b3c674@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-cadence-quadspi.c

index f14a746cba2d773adcfb83c000a7d8ea06a2c2f7..649ff55333f05062bc6b8e81d75e07f695e89834 100644 (file)
@@ -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 */ }
 };