Unverified Commit 65ce1155 authored by Mark Brown's avatar Mark Brown
Browse files

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 in the Cadence
QSPI driver. The bulk of the work is in the few last patches. Everything
else is just misc style fixes and improvements which bothered me while I
was wandering.

In order to support all constraints, I sometimes used a new quirk (for
the write protection feature and the "no indirect mode"), and sometimes
used the compatible directly. The ones I thought might not be RZ/N1
specific have been implemented under the form of a quirk, in order to
ease their reuse. The other adaptations, which I believe are more
Renesas specific, have been handled using the compatible. This is all
very arbitrary, and can be discussed.
parents 7ae4d097 77ee3ba5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ unevaluatedProperties: false

examples:
  - |
    qspi: spi@ff705000 {
    spi@ff705000 {
        compatible = "intel,socfpga-qspi", "cdns,qspi-nor";
        #address-cells = <1>;
        #size-cells = <0>;
+71 −58
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_DEVICE_CS_CNT_MAX);
#define CQSPI_SUPPORT_DEVICE_RESET	BIT(8)
#define CQSPI_DISABLE_STIG_MODE		BIT(9)
#define CQSPI_DISABLE_RUNTIME_PM	BIT(10)
#define CQSPI_NO_INDIRECT_MODE		BIT(11)
#define CQSPI_HAS_WR_PROTECT		BIT(12)

/* Capabilities */
#define CQSPI_SUPPORTS_OCTAL		BIT(0)
@@ -219,6 +221,8 @@ struct cqspi_driver_platdata {
#define CQSPI_REG_IRQSTATUS			0x40
#define CQSPI_REG_IRQMASK			0x44

#define CQSPI_REG_WR_PROT_CTRL			0x58

#define CQSPI_REG_INDIRECTRD			0x60
#define CQSPI_REG_INDIRECTRD_START_MASK		BIT(0)
#define CQSPI_REG_INDIRECTRD_CANCEL_MASK	BIT(1)
@@ -374,17 +378,12 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
	/* Clear interrupt */
	writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS);

	if (cqspi->use_dma_read && ddata && ddata->get_dma_status) {
		if (ddata->get_dma_status(cqspi)) {
			complete(&cqspi->transfer_complete);
			return IRQ_HANDLED;
		}
	}

	else if (!cqspi->slow_sram)
		irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;
	else
	if (cqspi->use_dma_read && ddata && ddata->get_dma_status)
		irq_status = ddata->get_dma_status(cqspi);
	else if (cqspi->slow_sram)
		irq_status &= CQSPI_IRQ_MASK_RD_SLOW_SRAM | CQSPI_IRQ_MASK_WR;
	else
		irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR;

	if (irq_status)
		complete(&cqspi->transfer_complete);
@@ -1263,7 +1262,7 @@ static void cqspi_config_baudrate_div(struct cqspi_st *cqspi)

	reg = readl(reg_base + CQSPI_REG_CONFIG);
	reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB);
	reg |= (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB;
	reg |= div << CQSPI_REG_CONFIG_BAUD_LSB;
	writel(reg, reg_base + CQSPI_REG_CONFIG);
}

@@ -1430,7 +1429,8 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
	if (ret)
		return ret;

	if (cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size))
	if ((cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size)) ||
	    (cqspi->ddata && cqspi->ddata->quirks & CQSPI_NO_INDIRECT_MODE))
		return cqspi_direct_read_execute(f_pdata, buf, from, len);

	if (cqspi->use_dma_read && ddata && ddata->indirect_read_dma &&
@@ -1536,6 +1536,10 @@ static bool cqspi_supports_mem_op(struct spi_mem *mem,
			return false;
		if (op->data.nbytes && op->data.buswidth != 8)
			return false;

		/* A single opcode is supported, it will be repeated */
		if ((op->cmd.opcode >> 8) != (op->cmd.opcode & 0xFF))
			return false;
	} else if (!all_false) {
		/* Mixed DTR modes are not supported. */
		return false;
@@ -1594,10 +1598,8 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi)
		cqspi->fifo_depth = 0;
	}

	if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
		dev_err(dev, "couldn't determine fifo-width\n");
		return -ENXIO;
	}
	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)) {
@@ -1627,9 +1629,9 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
	/* Disable all interrupts. */
	writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);

	if (!(cqspi->ddata && cqspi->ddata->quirks & CQSPI_NO_INDIRECT_MODE)) {
		/* Configure the SRAM split to 1:1 . */
		writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION);

		/* Load indirect trigger address. */
		writel(cqspi->trigger_address,
		       cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER);
@@ -1640,6 +1642,11 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
		/* Program write watermark -- 1/8 of the FIFO. */
		writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
		       cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
	}

	/* Disable write protection at controller level */
	if (cqspi->ddata && cqspi->ddata->quirks & CQSPI_HAS_WR_PROTECT)
		writel(0, cqspi->iobase + CQSPI_REG_WR_PROT_CTRL);

	/* Disable direct access controller */
	if (!cqspi->use_direct_mode) {
@@ -1890,7 +1897,7 @@ static int cqspi_probe(struct platform_device *pdev)
	ret = clk_prepare_enable(cqspi->clk);
	if (ret) {
		dev_err(dev, "Cannot enable QSPI clock.\n");
		goto probe_clk_failed;
		goto disable_rpm;
	}

	/* Obtain QSPI reset control */
@@ -1898,14 +1905,14 @@ 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 probe_reset_failed;
		goto disable_clk;
	}

	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 probe_reset_failed;
		goto disable_clk;
	}

	if (of_device_is_compatible(pdev->dev.of_node, "starfive,jh7110-qspi")) {
@@ -1913,7 +1920,7 @@ static int cqspi_probe(struct platform_device *pdev)
		if (IS_ERR(rstc_ref)) {
			ret = PTR_ERR(rstc_ref);
			dev_err(dev, "Cannot get QSPI REF reset.\n");
			goto probe_reset_failed;
			goto disable_clk;
		}
		reset_control_assert(rstc_ref);
		reset_control_deassert(rstc_ref);
@@ -1955,7 +1962,7 @@ static int cqspi_probe(struct platform_device *pdev)
		if (ddata->jh7110_clk_init) {
			ret = cqspi_jh7110_clk_init(pdev, cqspi);
			if (ret)
				goto probe_reset_failed;
				goto disable_clk;
		}
		if (ddata->quirks & CQSPI_DISABLE_STIG_MODE)
			cqspi->disable_stig_mode = true;
@@ -1963,7 +1970,7 @@ static int cqspi_probe(struct platform_device *pdev)
		if (ddata->quirks & CQSPI_DMA_SET_MASK) {
			ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
			if (ret)
				goto probe_reset_failed;
				goto disable_clks;
		}
	}

@@ -1974,7 +1981,7 @@ static int cqspi_probe(struct platform_device *pdev)
			       pdev->name, cqspi);
	if (ret) {
		dev_err(dev, "Cannot request IRQ.\n");
		goto probe_reset_failed;
		goto disable_clks;
	}

	cqspi_wait_idle(cqspi);
@@ -2001,31 +2008,36 @@ static int cqspi_probe(struct platform_device *pdev)
		ret = cqspi_request_mmap_dma(cqspi);
		if (ret == -EPROBE_DEFER) {
			dev_err_probe(&pdev->dev, ret, "Failed to request mmap DMA\n");
			goto probe_setup_failed;
			goto disable_controller;
		}
	}

	ret = spi_register_controller(host);
	if (ret) {
		dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret);
		goto probe_setup_failed;
		goto release_dma_chan;
	}

	if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
		pm_runtime_put_autosuspend(dev);

	return 0;
probe_setup_failed:
	if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
		pm_runtime_disable(dev);

release_dma_chan:
	if (cqspi->rx_chan)
		dma_release_channel(cqspi->rx_chan);
disable_controller:
	cqspi_controller_enable(cqspi, 0);
probe_reset_failed:
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);
probe_clk_failed:
disable_rpm:
	if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
		pm_runtime_disable(dev);

	return ret;
}

@@ -2034,6 +2046,7 @@ static void cqspi_remove(struct platform_device *pdev)
	const struct cqspi_driver_platdata *ddata;
	struct cqspi_st *cqspi = platform_get_drvdata(pdev);
	struct device *dev = &pdev->dev;
	int ret = 0;

	ddata = of_device_get_match_data(dev);

@@ -2043,18 +2056,21 @@ static void cqspi_remove(struct platform_device *pdev)
		cqspi_wait_idle(cqspi);

	spi_unregister_controller(cqspi->host);
	cqspi_controller_enable(cqspi, 0);

	if (cqspi->rx_chan)
		dma_release_channel(cqspi->rx_chan);

	if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
		if (pm_runtime_get_sync(&pdev->dev) >= 0)
			clk_disable(cqspi->clk);
	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);

	if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
		pm_runtime_put_sync(&pdev->dev);
		pm_runtime_disable(&pdev->dev);
@@ -2134,26 +2150,23 @@ static const struct cqspi_driver_platdata intel_lgm_qspi = {
};

static const struct cqspi_driver_platdata socfpga_qspi = {
	.quirks = CQSPI_DISABLE_DAC_MODE
			| CQSPI_NO_SUPPORT_WR_COMPLETION
			| CQSPI_SLOW_SRAM
			| CQSPI_DISABLE_STIG_MODE
			| CQSPI_DISABLE_RUNTIME_PM,
	.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION |
		  CQSPI_SLOW_SRAM | CQSPI_DISABLE_STIG_MODE |
		  CQSPI_DISABLE_RUNTIME_PM,
};

static const struct cqspi_driver_platdata versal_ospi = {
	.hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
	.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA
			| CQSPI_DMA_SET_MASK,
	.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA |
		  CQSPI_DMA_SET_MASK,
	.indirect_read_dma = cqspi_versal_indirect_read_dma,
	.get_dma_status = cqspi_get_versal_dma_status,
};

static const struct cqspi_driver_platdata versal2_ospi = {
	.hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
	.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA
			| CQSPI_DMA_SET_MASK
			| CQSPI_SUPPORT_DEVICE_RESET,
	.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA |
		  CQSPI_DMA_SET_MASK | CQSPI_SUPPORT_DEVICE_RESET,
	.indirect_read_dma = cqspi_versal_indirect_read_dma,
	.get_dma_status = cqspi_get_versal_dma_status,
};