linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7] mtd: rawnand: sunxi: Add MDMA support
@ 2020-10-12 15:41 Manuel Dipolt
  2020-10-28 13:42 ` Miquel Raynal
  2020-10-28 14:35 ` Boris Brezillon
  0 siblings, 2 replies; 3+ messages in thread
From: Manuel Dipolt @ 2020-10-12 15:41 UTC (permalink / raw)
  To: linux-mtd; +Cc: Roland Ruckerbauer, Boris Brezillon, maxime, miquel raynal

This patch enables NAND MDMA (MBUS DMA) mode for 
the Allwinner SoCs A23/A33/H3. 

The DMA transfer method gets sets now to MBUS DMA as default for
the sun8i-a23-nand-controller (till now DMA transfer was executed
via the shared DMA engine).

The main advantage is more bandwidth for the users of the shared DMA
engine and also that the MBUS DMA setup requires less configuration
effort. For example you don't need to define a dedicated DMA channel
in the device-tree any more.


Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Manuel Dipolt <manuel.dipolt@robart.cc>
---
 drivers/mtd/nand/raw/sunxi_nand.c | 118 +++++++++++++++++++-----------
 1 file changed, 75 insertions(+), 43 deletions(-)

diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 2a7ca3072f35..21c4ae93075a 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -51,6 +51,7 @@
 #define NFC_REG_USER_DATA(x)	(0x0050 + ((x) * 4))
 #define NFC_REG_SPARE_AREA	0x00A0
 #define NFC_REG_PAT_ID		0x00A4
+#define NFC_REG_MDMA_ADDR	0x00C0
 #define NFC_REG_MDMA_CNT	0x00C4
 #define NFC_RAM0_BASE		0x0400
 #define NFC_RAM1_BASE		0x0800
@@ -207,13 +208,13 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
  * NAND Controller capabilities structure: stores NAND controller capabilities
  * for distinction between compatible strings.
  *
- * @extra_mbus_conf:	Contrary to A10, A10s and A13, accessing internal RAM
+ * @has_mdma:		Use mbus dma mode, otherwise general dma
  *			through MBUS on A23/A33 needs extra configuration.
  * @reg_io_data:	I/O data register
  * @dma_maxburst:	DMA maxburst
  */
 struct sunxi_nfc_caps {
-	bool extra_mbus_conf;
+	bool has_mdma;
 	unsigned int reg_io_data;
 	unsigned int dma_maxburst;
 };
@@ -363,24 +364,34 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
 	if (!ret)
 		return -ENOMEM;
 
-	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
-	if (!dmad) {
-		ret = -EINVAL;
-		goto err_unmap_buf;
+	if (!nfc->caps->has_mdma) {
+		dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
+		if (!dmad) {
+			ret = -EINVAL;
+			goto err_unmap_buf;
+		}
 	}
 
 	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
 	       nfc->regs + NFC_REG_CTL);
 	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
 	writel(chunksize, nfc->regs + NFC_REG_CNT);
-	if (nfc->caps->extra_mbus_conf)
+
+	if (nfc->caps->has_mdma) {
+		writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_DMA_TYPE_NORMAL,
+		       nfc->regs + NFC_REG_CTL);
 		writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT);
+		writel(sg_dma_address(sg), nfc->regs + NFC_REG_MDMA_ADDR);
+	} else {
+		writel(readl(nfc->regs + NFC_REG_CTL) | NFC_DMA_TYPE_NORMAL,
+		       nfc->regs + NFC_REG_CTL);
 
-	dmat = dmaengine_submit(dmad);
+		dmat = dmaengine_submit(dmad);
 
-	ret = dma_submit_error(dmat);
-	if (ret)
-		goto err_clr_dma_flag;
+		ret = dma_submit_error(dmat);
+		if (ret)
+			goto err_clr_dma_flag;
+	}
 
 	return 0;
 
@@ -911,7 +922,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
 	unsigned int max_bitflips = 0;
 	int ret, i, raw_mode = 0;
 	struct scatterlist sg;
-	u32 status;
+	u32 status, wait;
 
 	ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
 	if (ret)
@@ -929,13 +940,18 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
 	writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
 	       NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
 
-	dma_async_issue_pending(nfc->dmac);
+	wait = NFC_CMD_INT_FLAG;
+
+	if (nfc->caps->has_mdma)
+		wait |= NFC_DMA_INT_FLAG;
+	else
+		dma_async_issue_pending(nfc->dmac);
 
 	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
 	       nfc->regs + NFC_REG_CMD);
 
-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
-	if (ret)
+	ret = sunxi_nfc_wait_events(nfc, wait, false, 0);
+	if (ret && !nfc->caps->has_mdma)
 		dmaengine_terminate_all(nfc->dmac);
 
 	sunxi_nfc_randomizer_disable(nand);
@@ -1276,6 +1292,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
 	struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
 	struct nand_ecc_ctrl *ecc = &nand->ecc;
 	struct scatterlist sg;
+	u32 wait;
 	int ret, i;
 
 	sunxi_nfc_select_chip(nand, nand->cur_cs);
@@ -1304,14 +1321,19 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
 	writel((NAND_CMD_RNDIN << 8) | NAND_CMD_PAGEPROG,
 	       nfc->regs + NFC_REG_WCMD_SET);
 
-	dma_async_issue_pending(nfc->dmac);
+	wait = NFC_CMD_INT_FLAG;
+
+	if (nfc->caps->has_mdma)
+		wait |= NFC_DMA_INT_FLAG;
+	else
+		dma_async_issue_pending(nfc->dmac);
 
 	writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD |
 	       NFC_DATA_TRANS | NFC_ACCESS_DIR,
 	       nfc->regs + NFC_REG_CMD);
 
-	ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0);
-	if (ret)
+	ret = sunxi_nfc_wait_events(nfc, wait, false, 0);
+	if (ret && !nfc->caps->has_mdma)
 		dmaengine_terminate_all(nfc->dmac);
 
 	sunxi_nfc_randomizer_disable(nand);
@@ -1695,7 +1717,7 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
 	mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
 	ecc->priv = data;
 
-	if (nfc->dmac) {
+	if (nfc->dmac || nfc->caps->has_mdma) {
 		ecc->read_page = sunxi_nfc_hw_ecc_read_page_dma;
 		ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage_dma;
 		ecc->write_page = sunxi_nfc_hw_ecc_write_page_dma;
@@ -2058,6 +2080,36 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc)
 	}
 }
 
+static int sunxi_nfc_dma_init(struct sunxi_nfc *nfc, struct resource *r)
+{
+	int ret;
+
+	if (nfc->caps->has_mdma)
+		return 0;
+
+	nfc->dmac = dma_request_chan(nfc->dev, "rxtx");
+	if (IS_ERR(nfc->dmac)) {
+		ret = PTR_ERR(nfc->dmac);
+		if (ret == -EPROBE_DEFER)
+			return ret;
+
+		/* Ignore errors to fall back to PIO mode */
+		dev_warn(nfc->dev, "failed to request rxtx DMA channel: %d\n", ret);
+		nfc->dmac = NULL;
+	} else {
+		struct dma_slave_config dmac_cfg = { };
+
+		dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data;
+		dmac_cfg.dst_addr = dmac_cfg.src_addr;
+		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
+		dmac_cfg.src_maxburst = nfc->caps->dma_maxburst;
+		dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst;
+		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
+	}
+	return 0;
+}
+
 static int sunxi_nfc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -2132,30 +2184,10 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
 	if (ret)
 		goto out_ahb_reset_reassert;
 
-	nfc->dmac = dma_request_chan(dev, "rxtx");
-	if (IS_ERR(nfc->dmac)) {
-		ret = PTR_ERR(nfc->dmac);
-		if (ret == -EPROBE_DEFER)
-			goto out_ahb_reset_reassert;
-
-		/* Ignore errors to fall back to PIO mode */
-		dev_warn(dev, "failed to request rxtx DMA channel: %d\n", ret);
-		nfc->dmac = NULL;
-	} else {
-		struct dma_slave_config dmac_cfg = { };
+	ret = sunxi_nfc_dma_init(nfc, r);
 
-		dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data;
-		dmac_cfg.dst_addr = dmac_cfg.src_addr;
-		dmac_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-		dmac_cfg.dst_addr_width = dmac_cfg.src_addr_width;
-		dmac_cfg.src_maxburst = nfc->caps->dma_maxburst;
-		dmac_cfg.dst_maxburst = nfc->caps->dma_maxburst;
-		dmaengine_slave_config(nfc->dmac, &dmac_cfg);
-
-		if (nfc->caps->extra_mbus_conf)
-			writel(readl(nfc->regs + NFC_REG_CTL) |
-			       NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL);
-	}
+	if (ret)
+		goto out_ahb_reset_reassert;
 
 	platform_set_drvdata(pdev, nfc);
 
@@ -2202,7 +2234,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
 };
 
 static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
-	.extra_mbus_conf = true,
+	.has_mdma = true,
 	.reg_io_data = NFC_REG_A23_IO_DATA,
 	.dma_maxburst = 8,
 };
-- 
2.20.1




______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v7] mtd: rawnand: sunxi: Add MDMA support
  2020-10-12 15:41 [PATCH v7] mtd: rawnand: sunxi: Add MDMA support Manuel Dipolt
@ 2020-10-28 13:42 ` Miquel Raynal
  2020-10-28 14:35 ` Boris Brezillon
  1 sibling, 0 replies; 3+ messages in thread
From: Miquel Raynal @ 2020-10-28 13:42 UTC (permalink / raw)
  To: Manuel Dipolt; +Cc: Roland Ruckerbauer, Boris Brezillon, linux-mtd, maxime

Hi Manuel,

Manuel Dipolt <mdipolt@robart.cc> wrote on Mon, 12 Oct 2020 17:41:22
+0200 (CEST):

> This patch enables NAND MDMA (MBUS DMA) mode for 
> the Allwinner SoCs A23/A33/H3. 
> 
> The DMA transfer method gets sets now to MBUS DMA as default for
> the sun8i-a23-nand-controller (till now DMA transfer was executed
> via the shared DMA engine).
> 
> The main advantage is more bandwidth for the users of the shared DMA
> engine and also that the MBUS DMA setup requires less configuration
> effort. For example you don't need to define a dedicated DMA channel
> in the device-tree any more.
> 
> 
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Manuel Dipolt <manuel.dipolt@robart.cc>

I tested your patch, it breaks my CHIP pro (sun5i R8):

[    1.775606] nand: device found, Manufacturer ID: 0x98, Chip ID: 0xd7
[    1.782168] nand: Toshiba TC58TEG5DCLTA00
[    1.786292] nand: 4096 MiB, MLC, erase size: 4096 KiB, page size: 16384, OOB size: 1280
[    1.798037] Scanning device for bad blocks
[    2.808728] sunxi_nand 1c03000.nand-controller: wait interrupt timedout
[    2.983031] random: fast init done
[    3.848719] sunxi_nand 1c03000.nand-controller: wait interrupt timedout
[    4.017501] random: crng init done
[    4.859050] sunxi_nand 1c03000.nand-controller: wait for empty cmd FIFO timedout
[    5.870270] sunxi_nand 1c03000.nand-controller: wait for empty cmd FIFO timedout
[    6.881406] sunxi_nand 1c03000.nand-controller: wait for empty cmd FIFO timedout
[    6.892444] nand_bbt: can't scan flash and build the RAM-based BBT
[    6.902268] sunxi_nand 1c03000.nand-controller: failed to init nand chips
[    6.912925] sunxi_nand: probe of 1c03000.nand-controller failed with error -110

I don't have the time to debug it right now, I'm sorry.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v7] mtd: rawnand: sunxi: Add MDMA support
  2020-10-12 15:41 [PATCH v7] mtd: rawnand: sunxi: Add MDMA support Manuel Dipolt
  2020-10-28 13:42 ` Miquel Raynal
@ 2020-10-28 14:35 ` Boris Brezillon
  1 sibling, 0 replies; 3+ messages in thread
From: Boris Brezillon @ 2020-10-28 14:35 UTC (permalink / raw)
  To: Manuel Dipolt; +Cc: Roland Ruckerbauer, linux-mtd, maxime, miquel raynal

On Mon, 12 Oct 2020 17:41:22 +0200 (CEST)
Manuel Dipolt <mdipolt@robart.cc> wrote:

> @@ -363,24 +364,34 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
>  	if (!ret)
>  		return -ENOMEM;
>  
> -	dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
> -	if (!dmad) {
> -		ret = -EINVAL;
> -		goto err_unmap_buf;
> +	if (!nfc->caps->has_mdma) {
> +		dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
> +		if (!dmad) {
> +			ret = -EINVAL;
> +			goto err_unmap_buf;
> +		}
>  	}
>  
>  	writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
>  	       nfc->regs + NFC_REG_CTL);
>  	writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
>  	writel(chunksize, nfc->regs + NFC_REG_CNT);
> -	if (nfc->caps->extra_mbus_conf)
> +
> +	if (nfc->caps->has_mdma) {
> +		writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_DMA_TYPE_NORMAL,
> +		       nfc->regs + NFC_REG_CTL);
>  		writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT);
> +		writel(sg_dma_address(sg), nfc->regs + NFC_REG_MDMA_ADDR);
> +	} else {
> +		writel(readl(nfc->regs + NFC_REG_CTL) | NFC_DMA_TYPE_NORMAL,
> +		       nfc->regs + NFC_REG_CTL);

You might want to try dropping this writel (looks like it was only done
when extra_mbus_conf was set).

>  
> -	dmat = dmaengine_submit(dmad);
> +		dmat = dmaengine_submit(dmad);
>  
> -	ret = dma_submit_error(dmat);
> -	if (ret)
> -		goto err_clr_dma_flag;
> +		ret = dma_submit_error(dmat);
> +		if (ret)
> +			goto err_clr_dma_flag;
> +	}
>  
>  	return 0;
>  

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-10-28 14:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-12 15:41 [PATCH v7] mtd: rawnand: sunxi: Add MDMA support Manuel Dipolt
2020-10-28 13:42 ` Miquel Raynal
2020-10-28 14:35 ` Boris Brezillon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).