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] 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 */ } }; -- 2.47.3