[PATCH v5] mtd: sunxi-nand: enable mdma support for allwinner a23
Boris Brezillon
boris.brezillon at collabora.com
Thu Oct 8 11:36:06 EDT 2020
Hello Manuel,
The subject prefix should be "mtd: rawnand: sunxi:" not "mtd:
sunxi-nand:"
On Thu, 8 Oct 2020 16:58:47 +0200 (CEST)
Manuel Dipolt <mdipolt at robart.cc> wrote:
> This patch enables nand mdma mode for the Allwinner socs A23/A33/H3
^NAND MDMA (Master DMA)
And you need a period at the of your sentence.
>
> Signed-off-by: Manuel Dipolt <manuel.dipolt at robart.cc>
> ---
> drivers/mtd/nand/raw/sunxi_nand.c | 156 +++++++++++++++++++-----------
> 1 file changed, 101 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
> index 2a7ca3072f35..8403785e85e1 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;
> };
> @@ -346,7 +347,7 @@ static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
> static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
> int chunksize, int nchunks,
> enum dma_data_direction ddir,
> - struct scatterlist *sg)
> + struct scatterlist *sg, dma_addr_t *mem_addr)
You don't need to pass the mem_addr, it will be extracted from the sg
list.
> {
> struct dma_async_tx_descriptor *dmad;
> enum dma_transfer_direction tdir;
> @@ -358,29 +359,46 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
> else
> tdir = DMA_MEM_TO_DEV;
>
> - sg_init_one(sg, buf, nchunks * chunksize);
> - ret = dma_map_sg(nfc->dev, sg, 1, ddir);
> - if (!ret)
> - return -ENOMEM;
> + if (nfc->caps->has_mdma) {
> + *mem_addr = dma_map_single(nfc->dev, (void *)buf, nchunks * chunksize, tdir);
> + ret = dma_mapping_error(nfc->dev, *mem_addr);
You can use sg_init_one() here as well.
> + if (ret) {
> + dev_err(nfc->dev, "DMA mapping error\n");
> + return ret;
> + }
> + } else {
> + sg_init_one(sg, buf, nchunks * chunksize);
> + ret = dma_map_sg(nfc->dev, sg, 1, ddir);
> + 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;
> + 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(*mem_addr, nfc->regs + NFC_REG_MDMA_ADDR);
^ sg_dma_address(sg)
> + } 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;
>
> @@ -395,11 +413,24 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
>
> static void sunxi_nfc_dma_op_cleanup(struct sunxi_nfc *nfc,
> enum dma_data_direction ddir,
> - struct scatterlist *sg)
> + struct scatterlist *sg, dma_addr_t mem_addr, size_t size)
> {
> - dma_unmap_sg(nfc->dev, sg, 1, ddir);
> - writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
> - nfc->regs + NFC_REG_CTL);
> + enum dma_transfer_direction tdir;
> +
> + if (ddir == DMA_FROM_DEVICE)
> + tdir = DMA_DEV_TO_MEM;
> + else
> + tdir = DMA_MEM_TO_DEV;
> +
> + if (nfc->caps->has_mdma) {
> + dma_unmap_single(nfc->dev, mem_addr, size, tdir);
> + writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
> + nfc->regs + NFC_REG_CTL);
> + } else {
> + dma_unmap_sg(nfc->dev, sg, 1, ddir);
> + writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
> + nfc->regs + NFC_REG_CTL);
> + }
> }
As I said in my previous review, if you get rid of the mem_addr
argument, you shouldn't need any changes to this function. Have you
tried using sg_dma_address()?
Regards,
Boris
More information about the linux-mtd
mailing list