summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-02-05 23:13:44 +0000
committerMark Brown <broonie@kernel.org>2026-02-05 23:13:44 +0000
commitbe8d4567609d417a5ecc8d67db441c0445722f54 (patch)
tree68747175b2d965bf41406c39469db56321c95c02 /drivers
parent6516169fa7f6110ce42a5958c921255f2d0968bc (diff)
parenta40236feb62ccbf2b36d288550a483122b3205e5 (diff)
spi: cadence-qspi: Add Renesas RZ/N1 support
Merge series from "Miquel Raynal (Schneider Electric)" <miquel.raynal@bootlin.com>: This series adds support for the QSPI controller available on Renesas RZ/N1S and RZ/N1D SoC. It has been tested with a custom board (see last SPI patch for details), but has been tested by Wolfram (thank you!) on the DB board. Link: https://lore.kernel.org/linux-devicetree/20260116114852.52948-2-wsa+renesas@sang-engineering.com/ Adding support for this SoC required a few adaptations to the Cadence QSPI driver which have already been merged (except one regarding clocks handling). This series contains the remaining patches, the ones actually adding support for the RZ/N1 flavour.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/spi-cadence-quadspi.c168
1 files changed, 71 insertions, 97 deletions
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 2d287950d44c..649ff55333f0 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;
@@ -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;
@@ -123,8 +124,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 */
@@ -1339,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);
}
@@ -1514,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;
/*
@@ -1540,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;
@@ -1593,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))
@@ -1668,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.
@@ -1771,51 +1780,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 +1788,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 +1799,13 @@ 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;
+ if (of_device_is_compatible(pdev->dev.of_node, "renesas,rzn1-qspi"))
+ cqspi->is_rzn1 = 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 +1822,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 +1861,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 +1872,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,8 +1899,13 @@ 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);
- host->max_speed_hz = cqspi->master_ref_clk_hz;
+ cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clks[CLK_QSPI_REF].clk);
+ 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;
@@ -1958,12 +1930,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;
@@ -2004,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");
@@ -2029,11 +1995,8 @@ release_dma_chan:
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 +2025,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 +2043,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 +2138,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 = {
@@ -2186,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",
@@ -2227,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 */ }
};