mtd: sunxi-nand: add dma support for allwinner h3
PATCH 1/1 mtd: sunxi-nand: add dma support for allwinner h3
The Allwinner H3 soc is using different dma mode,
see old sunxi drivers https://github.com/allwinner-zh/linux-3.4-sunxi/tree/master/modules/nand
Added support for it and a compatible option sun8i-h3-nand-controller, which using sunxi_nfc_h3_caps with a new dma_option field, which is set to 0 for the H3.
--- drivers/mtd/nand/raw/sunxi_nand.c | 193 +++++++++++++++++++++--------- 1 file changed, 137 insertions(+), 56 deletions(-)
drivers/mtd/nand/raw/sunxi_nand.c +137 -56
@@ -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,12 +208,14 @@ 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. * +* @dma_mode: use different dma method, required for chips like H3 * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM * through MBUS on A23/A33 needs extra configuration. * @reg_io_data: I/O data register * @dma_maxburst: DMA maxburst */ struct sunxi_nfc_caps { +unsigned int dma_mode;bool extra_mbus_conf;unsigned int reg_io_data;unsigned int dma_maxburst;
@@ -263,9 +266,12 @@ static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)if (!(ien & st))return IRQ_NONE ; -if ((ien & st) == ien) +if ((ien & st) ==NFC_CMD_INT_ENABLE )complete (&nfc->complete); +if ((ien & st) ==NFC_DMA_INT_ENABLE ) +complete (&nfc->complete); +writel (st &NFC_INT_MASK , nfc->regs +NFC_REG_ST );writel (~st & ien &NFC_INT_MASK , nfc->regs +NFC_REG_INT );
@@ -912,15 +918,31 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufint ret, i, raw_mode =0 ;struct scatterlist sg;u32 status; - +int chunksize; +__u32 mem_addr; + ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, -DMA_FROM_DEVICE , &sg); -if (ret) -return ret; +if (nfc->caps->dma_mode ==1 ) { + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, +DMA_FROM_DEVICE , &sg); +if (ret) +return ret; + }else { + chunksize = ecc->size; + mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_DEV_TO_MEM ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error\n" ); + } + +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT ); + }sunxi_nfc_hw_ecc_enable (nand);sunxi_nfc_randomizer_config (nand, page, false);
@@ -929,19 +951,32 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufwritel ((NAND_CMD_RNDOUTSTART <<16 ) | (NAND_CMD_RNDOUT <<8 ) |NAND_CMD_READSTART , nfc->regs +NFC_REG_RCMD_SET ); -dma_async_issue_pending (nfc->dmac); +if (nfc->caps->dma_mode ==1 ) { +dma_async_issue_pending (nfc->dmac); -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); +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) -dmaengine_terminate_all (nfc->dmac); + ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); + +if (ret) +dmaengine_terminate_all (nfc->dmac); + }else { +writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , + nfc->regs +NFC_REG_CMD ); + + ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); + }sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); +if (nfc->caps->dma_mode ==1 ) { +sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); + }else { +dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_DEV_TO_MEM ); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); + }if (ret)return ret;
@@ -1128,7 +1163,7 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf, int oob_required, int page) { int ret; - +sunxi_nfc_select_chip (nand, nand->cur_cs);nand_read_page_op (nand, page,0 ,NULL ,0 );
@@ -1276,19 +1311,35 @@ 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; -int ret, i; - +int ret, i, nchunks, chunksize; +__u32 mem_addr; +sunxi_nfc_select_chip (nand, nand->cur_cs); ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, -DMA_TO_DEVICE , &sg); -if (ret) - goto pio_fallback; +if (nfc->caps->dma_mode ==1 ) { + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, +DMA_TO_DEVICE , &sg); +if (ret) + goto pio_fallback; + }else { + chunksize = ecc->size; + nchunks = ecc->steps; + mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_MEM_TO_DEV ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error\n" ); + } +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT ); + } +for (i =0 ; i < ecc->steps; i++) {const u8 *oob = nand->oob_poi + (i * (ecc->bytes +4 ));
@@ -1304,20 +1355,33 @@ 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); +if (nfc->caps->dma_mode ==1 ) { +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 ); -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD | + ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); +if (ret) +dmaengine_terminate_all (nfc->dmac); + }else { +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) -dmaengine_terminate_all (nfc->dmac); + ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); + }sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); +if (nfc->caps->dma_mode ==1 ) { +sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); + }else { +dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_MEM_TO_DEV ); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); + }if (ret)return ret;
@@ -1695,7 +1759,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->dma_mode ==0 ) { 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;
@@ -2132,38 +2196,43 @@ 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 ; +if (nfc->caps->dma_mode ==0 ) { +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL ); + 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); - -if (nfc->caps->extra_mbus_conf) -writel (readl (nfc->regs +NFC_REG_CTL ) | -NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL ); + 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 = { }; + + 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 ); + } } + +platform_set_drvdata (pdev, nfc); -platform_set_drvdata (pdev, nfc); - - ret =sunxi_nand_chips_init (dev, nfc); -if (ret) { -dev_err (dev,"failed to init nand chips\n" ); - goto out_release_dmac; - } + ret =sunxi_nand_chips_init (dev, nfc); +if (ret) { +dev_err (dev,"failed to init nand chips\n" ); + goto out_release_dmac; + }return 0 ;
@@ -2197,16 +2266,24 @@ static int sunxi_nfc_remove(struct platform_device *pdev) }static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { + .dma_mode =1 , .reg_io_data =NFC_REG_A10_IO_DATA , .dma_maxburst =4 , };static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { + .dma_mode =1 , .extra_mbus_conf = true, .reg_io_data =NFC_REG_A23_IO_DATA , .dma_maxburst =8 , }; +static const struct sunxi_nfc_caps sunxi_nfc_h3_caps = { + .dma_mode =0 , + .reg_io_data =NFC_REG_A23_IO_DATA , + .dma_maxburst =8 , +}; +static const struct of_device_id sunxi_nfc_ids[] = { { .compatible ="allwinner,sun4i-a10-nand" ,
@@ -2216,6 +2293,10 @@ static const struct of_device_id sunxi_nfc_ids[] = { .compatible = "allwinner,sun8i-a23-nand-controller", .data = &sunxi_nfc_a23_caps, }, + { + .compatible = "allwinner,sun8i-h3-nand-controller", + .data = &sunxi_nfc_h3_caps, + }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, sunxi_nfc_ids);
Signature · 5 lines
2.20.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/
Miquel Raynal
maintainerHi Manuel,
Manuel Dipolt <[email protected]> wrote on Mon, 5 Oct 2020 14:20:19 +0200 (CEST):
Quoted 8 lines
The Allwinner H3 soc is using different dma mode,
see old sunxi drivers https://github.com/allwinner-zh/linux-3.4-sunxi/tree/master/modules/nandAdded support for it and a compatible option sun8i-h3-nand-controller, which using
sunxi_nfc_h3_capswith a newdma_optionfield, which is set to 0 for the H3.
There are a few obvious style issues in your patch, can you please run
$ scripts/checkpatch.pl --strict
and address all the reported errors in a v2?
Thanks!
Miquèl
Quoted 1 line
Signed-off-by Manuel Dipolt <[email protected]>
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
Re: [PATCH v2] mtd: sunxi-nand: add dma support for allwinner h3 - corrected obvious style issues
hi Miquèl,
sorry for the style issues, patched now
yours,
Manuel
--- drivers/mtd/nand/raw/sunxi_nand.c | 73 ++++++++++++++++--------------- 1 file changed, 37 insertions(+), 36 deletions(-)
drivers/mtd/nand/raw/sunxi_nand.c +37 -36
@@ -61,7 +61,7 @@#define NFC_RESET BIT(1)#define NFC_BUS_WIDTH_MSK BIT(2)#define NFC_BUS_WIDTH_8 (0 << 2) -#define NFC_BUS_WIDTH_16 (1 << 2) +#define NFC_BUS_WIDTH_16 BIT(2)#define NFC_RB_SEL_MSK BIT(3)#define NFC_RB_SEL (x) ((x) << 3)#define NFC_CE_SEL_MSK GENMASK(26, 24)
@@ -119,7 +119,7 @@#define NFC_SEND_CMD4 BIT(29)#define NFC_CMD_TYPE_MSK GENMASK(31, 30)#define NFC_NORMAL_OP (0 << 30) -#define NFC_ECC_OP (1 << 30) +#define NFC_ECC_OP BIT(30)#define NFC_PAGE_OP (2U << 30)/* define bit use in NFC_RCMD_SET */
@@ -266,11 +266,11 @@ static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)if (!(ien & st))return IRQ_NONE ; -if ((ien & st) ==NFC_CMD_INT_ENABLE ) +if ((ien & st) ==NFC_CMD_INT_ENABLE )complete (&nfc->complete);if ((ien & st) ==NFC_DMA_INT_ENABLE ) -complete (&nfc->complete); +complete (&nfc->complete);writel (st &NFC_INT_MASK , nfc->regs +NFC_REG_ST );writel (~st & ien &NFC_INT_MASK , nfc->regs +NFC_REG_INT );
@@ -295,7 +295,7 @@ static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events,writel (events, nfc->regs +NFC_REG_INT ); ret =wait_for_completion_timeout (&nfc->complete, -msecs_to_jiffies (timeout_ms)); +msecs_to_jiffies (timeout_ms));if (!ret) ret = -ETIMEDOUT ;else
@@ -662,7 +662,7 @@ static void sunxi_nfc_randomize_bbm(struct nand_chip *nand, int page, u8 *bbm) }static void sunxi_nfc_randomizer_write_buf (struct nand_chip *nand, -const uint8_t *buf,int len, +const u8 *buf,int len,bool ecc,int page) {sunxi_nfc_randomizer_config (nand, page, ecc);
@@ -920,22 +920,23 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufu32 status;int chunksize;__u32 mem_addr; - + ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret;if (nfc->caps->dma_mode ==1 ) { ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, -DMA_FROM_DEVICE , &sg); +DMA_FROM_DEVICE , &sg);if (ret)return ret; }else { - chunksize = ecc->size; - mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_DEV_TO_MEM ); -if (dma_mapping_error (nfc->dev, mem_addr)) { + chunksize = ecc->size; + mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize, +DMA_DEV_TO_MEM ); + +if (dma_mapping_error (nfc->dev, mem_addr))dev_err (nfc->dev,"DMA mapping error\n" ); - }writel (readl (nfc->regs +NFC_REG_CTL ) |NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL );writel (nchunks, nfc->regs +NFC_REG_SECTOR_NUM );
@@ -955,7 +956,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufdma_async_issue_pending (nfc->dmac);writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); + nfc->regs +NFC_REG_CMD ); ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 );
@@ -963,7 +964,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufdmaengine_terminate_all (nfc->dmac); }else {writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); + nfc->regs +NFC_REG_CMD ); ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); }
@@ -1163,7 +1164,7 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf, int oob_required, int page) { int ret; - +sunxi_nfc_select_chip (nand, nand->cur_cs);nand_read_page_op (nand, page,0 ,NULL ,0 );
@@ -1234,7 +1235,7 @@ static int sunxi_nfc_hw_ecc_read_subpage_dma(struct nand_chip *nand, }static int sunxi_nfc_hw_ecc_write_page (struct nand_chip *nand, -const uint8_t *buf,int oob_required, +const u8 *buf,int oob_required,int page) {struct mtd_info *mtd =nand_to_mtd (nand);
@@ -1313,7 +1314,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,struct scatterlist sg;int ret, i, nchunks, chunksize;__u32 mem_addr; - +sunxi_nfc_select_chip (nand, nand->cur_cs); ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);
@@ -1322,15 +1323,16 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,if (nfc->caps->dma_mode ==1 ) { ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, -DMA_TO_DEVICE , &sg); +DMA_TO_DEVICE , &sg);if (ret) goto pio_fallback; }else { chunksize = ecc->size; nchunks = ecc->steps; mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_MEM_TO_DEV ); -if (dma_mapping_error (nfc->dev, mem_addr)) { -dev_err (nfc->dev,"DMA mapping error\n" ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error, fallback to pio...\n" ); + goto pio_fallback; }writel (readl (nfc->regs +NFC_REG_CTL ) |NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL );
@@ -1339,7 +1341,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR );writel (chunksize, nfc->regs +NFC_REG_CNT ); } - +for (i =0 ; i < ecc->steps; i++) {const u8 *oob = nand->oob_poi + (i * (ecc->bytes +4 ));
@@ -1423,7 +1425,7 @@ static const s32 tWB_lut[] = {6, 12, 16, 20};static const s32 tRHW_lut[] = {4 ,8 ,12 ,20 };static int _sunxi_nand_lookup_timing (const s32 *lut,int lut_size,u32 duration, -u32 clk_period) +u32 clk_period) {u32 clk_cycles =DIV_ROUND_UP (duration, clk_period);int i;
@@ -2013,10 +2015,8 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, sunxi_nand =devm_kzalloc (dev,struct_size (sunxi_nand, sels, nsels),GFP_KERNEL ); -if (!sunxi_nand) { -dev_err (dev,"could not allocate chip\n" ); +if (!sunxi_nand)return -ENOMEM ; - } sunxi_nand->nsels = nsels;
@@ -2196,9 +2196,10 @@ static int sunxi_nfc_probe(struct platform_device *pdev)if (ret) goto out_ahb_reset_reassert; -if (nfc->caps->dma_mode ==0 ) { -writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL ); - nfc->dmac =NULL ; +if (nfc->caps->dma_mode ==0 ) { +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , + nfc->regs +NFC_REG_CTL ); + nfc->dmac =NULL ; }else { nfc->dmac =dma_request_chan (dev,"rxtx" );if (IS_ERR (nfc->dmac)) {
@@ -2225,14 +2226,14 @@ static int sunxi_nfc_probe(struct platform_device *pdev) NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL); } } - -platform_set_drvdata (pdev, nfc); - - ret =sunxi_nand_chips_init (dev, nfc); -if (ret) { -dev_err (dev,"failed to init nand chips\n" ); - goto out_release_dmac; - } + +platform_set_drvdata (pdev, nfc); + + ret =sunxi_nand_chips_init (dev, nfc); +if (ret) { +dev_err (dev,"failed to init nand chips\n" ); + goto out_release_dmac; + }return 0 ;
Signature · 6 lines
2.20.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/
Quoted 5 lines · On Mon, 5 Oct 2020 14:20:19 +0200 (CEST) Manuel Dipolt <[email protected]>…
The Allwinner H3 soc is using different dma mode,
see old sunxi drivers https://github.com/allwinner-zh/linux-3.4-sunxi/tree/master/modules/nandAdded support for it and a compatible option sun8i-h3-nand-controller, which using
sunxi_nfc_h3_capswith a newdma_optionfield, which is set to 0 for the H3.
Just a drive-by review.
Quoted 22 lines
Signed-off-by Manuel Dipolt <[email protected]>--- drivers/mtd/nand/raw/sunxi_nand.c | 193 +++++++++++++++++++++--------- 1 file changed, 137 insertions(+), 56 deletions(-)drivers/mtd/nand/raw/sunxi_nand.c +1
-0@@ -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,12 +208,14 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)* NAND Controller capabilities structure: stores NAND controller capabilities
drivers/mtd/nand/raw/sunxi_nand.c static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) · line 218
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-0* for distinction between compatible strings. * +* @dma_mode: use different dma method, required for chips like H3 * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM * through MBUS on A23/A33 needs extra configuration. * @reg_io_data: I/O data register * @dma_maxburst: DMA maxburst */ struct sunxi_nfc_caps { +unsigned int dma_mode;
Maybe:
bool has_mdma;
Quoted 4 lines
drivers/mtd/nand/raw/sunxi_nand.c +0
-0bool extra_mbus_conf;unsigned int reg_io_data;unsigned int dma_maxburst;
drivers/mtd/nand/raw/sunxi_nand.c static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id) · line 274
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +4
-1@@ -263,9 +266,12 @@ static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)if (!(ien & st))return IRQ_NONE ; -if ((ien & st) == ien) +if ((ien & st) ==NFC_CMD_INT_ENABLE )complete (&nfc->complete); +if ((ien & st) ==NFC_DMA_INT_ENABLE ) +complete (&nfc->complete); +
If you need to wait on the DMA event, pass the flag to sunxi_nfc_wait_events().
Quoted 26 lines
drivers/mtd/nand/raw/sunxi_nand.c +10
-5writel (st &NFC_INT_MASK , nfc->regs +NFC_REG_ST );writel (~st & ien &NFC_INT_MASK , nfc->regs +NFC_REG_INT );@@ -912,15 +918,31 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufint ret, i, raw_mode =0 ;struct scatterlist sg;u32 status; - +int chunksize; +__u32 mem_addr; + ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, -DMA_FROM_DEVICE , &sg); -if (ret) -return ret; +if (nfc->caps->dma_mode ==1 ) { + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, +DMA_FROM_DEVICE , &sg); +if (ret) +return ret; + }else { + chunksize = ecc->size;
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf · line 944
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +10
-0+ mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_DEV_TO_MEM ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error\n" ); + } + +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT );
This could probably go in an sunxi_nfc_mdma_op_prepare() helper.
Quoted 20 lines
drivers/mtd/nand/raw/sunxi_nand.c +5
-6+ }sunxi_nfc_hw_ecc_enable (nand);sunxi_nfc_randomizer_config (nand, page, false);@@ -929,19 +951,32 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufwritel ((NAND_CMD_RNDOUTSTART <<16 ) | (NAND_CMD_RNDOUT <<8 ) |NAND_CMD_READSTART , nfc->regs +NFC_REG_RCMD_SET ); -dma_async_issue_pending (nfc->dmac); +if (nfc->caps->dma_mode ==1 ) { +dma_async_issue_pending (nfc->dmac); -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); +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) -dmaengine_terminate_all (nfc->dmac);
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf · line 969
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +10
-0+ ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); + +if (ret) +dmaengine_terminate_all (nfc->dmac); + }else { +writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , + nfc->regs +NFC_REG_CMD ); + + ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); + }
How about:
u32 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_DMA_INT_FLAG, false, 0); if (ret && !nfc->caps->has_mdma) dmaengine_terminate_all(nfc->dmac);
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf · line 978
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +5
-1sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); +if (nfc->caps->dma_mode ==1 ) { +sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); + }else { +dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_DEV_TO_MEM ); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL );
I'd suggest moving that to an sunxi_nfc_mdma_op_cleanup() helper. BTW, why do you need to reset the RAM method here?
Quoted 109 lines
drivers/mtd/nand/raw/sunxi_nand.c +44
-15+ }if (ret)return ret;@@ -1128,7 +1163,7 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf, int oob_required, int page) { int ret; - +sunxi_nfc_select_chip (nand, nand->cur_cs);nand_read_page_op (nand, page,0 ,NULL ,0 );@@ -1276,19 +1311,35 @@ 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; -int ret, i; - +int ret, i, nchunks, chunksize; +__u32 mem_addr; +sunxi_nfc_select_chip (nand, nand->cur_cs); ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, -DMA_TO_DEVICE , &sg); -if (ret) - goto pio_fallback; +if (nfc->caps->dma_mode ==1 ) { + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, +DMA_TO_DEVICE , &sg); +if (ret) + goto pio_fallback; + }else { + chunksize = ecc->size; + nchunks = ecc->steps; + mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_MEM_TO_DEV ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error\n" ); + } +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT ); + } +for (i =0 ; i < ecc->steps; i++) {const u8 *oob = nand->oob_poi + (i * (ecc->bytes +4 ));@@ -1304,20 +1355,33 @@ 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); +if (nfc->caps->dma_mode ==1 ) { +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 ); -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD | + ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); +if (ret) +dmaengine_terminate_all (nfc->dmac); + }else { +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) -dmaengine_terminate_all (nfc->dmac); + ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); + }sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); +if (nfc->caps->dma_mode ==1 ) { +sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); + }else { +dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_MEM_TO_DEV ); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); + }if (ret)return ret;@@ -1695,7 +1759,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->dma_mode ==0 ) { 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;@@ -2132,38 +2196,43 @@ static int sunxi_nfc_probe(struct platform_device *pdev)if (ret) goto out_ahb_reset_reassert; - nfc->dmac =dma_request_chan (dev,"rxtx" );
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_probe(struct platform_device *pdev) · line 2200
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-8-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 ; +if (nfc->caps->dma_mode ==0 ) { +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL );
This shouldn't be done in the probe helper.
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_probe(struct platform_device *pdev) · line 2201
Quoted 1 line
drivers/mtd/nand/raw/sunxi_nand.c +1
-0+ nfc->dmac =NULL ;
No need to set that field to NULL, the nfc object is allocated with kzalloc().
Quoted 28 lines
drivers/mtd/nand/raw/sunxi_nand.c +14
-13}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); - -if (nfc->caps->extra_mbus_conf) -writel (readl (nfc->regs +NFC_REG_CTL ) | -NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL ); + 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 = { }; + + dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data; + dmac_cfg.dst_addr = dmac_cfg.src_addr;
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_probe(struct platform_device *pdev) · line 2226
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +10
-0+ 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 ); + }
Can you move that to a sunxi_nfc_dma_init() helper?
Quoted 20 lines
drivers/mtd/nand/raw/sunxi_nand.c +7
-7} + +platform_set_drvdata (pdev, nfc); -platform_set_drvdata (pdev, nfc); - - ret =sunxi_nand_chips_init (dev, nfc); -if (ret) { -dev_err (dev,"failed to init nand chips\n" ); - goto out_release_dmac; - } + ret =sunxi_nand_chips_init (dev, nfc); +if (ret) { +dev_err (dev,"failed to init nand chips\n" ); + goto out_release_dmac; + }return 0 ;
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_remove(struct platform_device *pdev) · line 2275
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-0@@ -2197,16 +2266,24 @@ static int sunxi_nfc_remove(struct platform_device *pdev) }static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { + .dma_mode =1 , .reg_io_data =NFC_REG_A10_IO_DATA , .dma_maxburst =4 , };static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { + .dma_mode =1 ,
I think the A23 also has an MDMA block.
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_remove(struct platform_device *pdev) · line 2284
Quoted 9 lines
drivers/mtd/nand/raw/sunxi_nand.c +4
-0.extra_mbus_conf = true, .reg_io_data = NFC_REG_A23_IO_DATA, .dma_maxburst = 8, }; +static const struct sunxi_nfc_caps sunxi_nfc_h3_caps = { + .dma_mode =0 , + .reg_io_data =NFC_REG_A23_IO_DATA , + .dma_maxburst =8 ,
You don't need to set that field if you use the MDMA.
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-0+}; +static const struct of_device_id sunxi_nfc_ids[] = { { .compatible ="allwinner,sun4i-a10-nand" ,
drivers/mtd/nand/raw/sunxi_nand.c static const struct of_device_id sunxi_nfc_ids[] = { · line 2302
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +4
-0@@ -2216,6 +2293,10 @@ static const struct of_device_id sunxi_nfc_ids[] = { .compatible = "allwinner,sun8i-a23-nand-controller", .data = &sunxi_nfc_a23_caps, }, + { + .compatible = "allwinner,sun8i-h3-nand-controller", + .data = &sunxi_nfc_h3_caps, + }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, sunxi_nfc_ids);
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
Re: [PATCH v3] mtd: sunxi-nand: add dma support for allwinner h3 - review changes
hi Boris,
thanks for the fast review,
applied the suggested changes and answered your question, please take a look if its okay
yours,
Manuel
Quoted 53 lines
----- Original Message -----
From: "Boris Brezillon" <[email protected]>
To: "Manuel Dipolt" <[email protected]>
Cc: "linux-mtd" <[email protected]>, "miquel raynal" <[email protected]>, "bbrezillon" <[email protected]>, "maxime" <[email protected]>, "Roland Ruckerbauer" <[email protected]>
Sent: Monday, October 5, 2020 3:09:12 PM
Subject: Re: [PATCH -next] mtd: sunxi-nand: add dma support for allwinner h3Quoted 5 lines · On Mon, 5 Oct 2020 14:20:19 +0200 (CEST) Manuel Dipolt <[email protected]>…
The Allwinner H3 soc is using different dma mode,
see old sunxi drivers https://github.com/allwinner-zh/linux-3.4-sunxi/tree/master/modules/nandAdded support for it and a compatible option sun8i-h3-nand-controller, which using
sunxi_nfc_h3_capswith a newdma_optionfield, which is set to 0 for the H3.Just a drive-by review.
Quoted 22 lines
Signed-off-by Manuel Dipolt <[email protected]>--- drivers/mtd/nand/raw/sunxi_nand.c | 193 +++++++++++++++++++++--------- 1 file changed, 137 insertions(+), 56 deletions(-)drivers/mtd/nand/raw/sunxi_nand.c +1
-0@@ -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,12 +208,14 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)* NAND Controller capabilities structure: stores NAND controller capabilities drivers/mtd/nand/raw/sunxi_nand.c static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) · line 218
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-0* for distinction between compatible strings. * +* @dma_mode: use different dma method, required for chips like H3 * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM * through MBUS on A23/A33 needs extra configuration. * @reg_io_data: I/O data register * @dma_maxburst: DMA maxburst */ struct sunxi_nfc_caps { +unsigned int dma_mode;Maybe:
Quoted 1 line
bool has_mdma;
renamed
Quoted 12 lines
Quoted 12 lines
drivers/mtd/nand/raw/sunxi_nand.c +1
-1bool extra_mbus_conf;unsigned int reg_io_data;unsigned int dma_maxburst;@@ -263,9 +266,12 @@ static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)if (!(ien & st))return IRQ_NONE ; -if ((ien & st) == ien) +if ((ien & st) ==NFC_CMD_INT_ENABLE )complete (&nfc->complete);
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id) · line 274
Quoted 3 lines
drivers/mtd/nand/raw/sunxi_nand.c +3
-0+if ((ien & st) ==NFC_DMA_INT_ENABLE ) +complete (&nfc->complete); +If you need to wait on the DMA event, pass the flag to
sunxi_nfc_wait_events().
reverted back to if ((ien & st) == ien)
Quoted 31 lines
Quoted 31 lines
drivers/mtd/nand/raw/sunxi_nand.c +14
-5writel (st &NFC_INT_MASK , nfc->regs +NFC_REG_ST );writel (~st & ien &NFC_INT_MASK , nfc->regs +NFC_REG_INT );@@ -912,15 +918,31 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufint ret, i, raw_mode =0 ;struct scatterlist sg;u32 status; - +int chunksize; +__u32 mem_addr; + ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, -DMA_FROM_DEVICE , &sg); -if (ret) -return ret; +if (nfc->caps->dma_mode ==1 ) { + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks, +DMA_FROM_DEVICE , &sg); +if (ret) +return ret; + }else { + chunksize = ecc->size; + mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_DEV_TO_MEM ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error\n" ); + }
Quoted 9 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf · line 944
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c +6
-0+ +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT );This could probably go in an
sunxi_nfc_mdma_op_prepare()helper.
created
Quoted 33 lines
Quoted 20 lines
drivers/mtd/nand/raw/sunxi_nand.c +5
-6+ }sunxi_nfc_hw_ecc_enable (nand);sunxi_nfc_randomizer_config (nand, page, false);@@ -929,19 +951,32 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufwritel ((NAND_CMD_RNDOUTSTART <<16 ) | (NAND_CMD_RNDOUT <<8 ) |NAND_CMD_READSTART , nfc->regs +NFC_REG_RCMD_SET ); -dma_async_issue_pending (nfc->dmac); +if (nfc->caps->dma_mode ==1 ) { +dma_async_issue_pending (nfc->dmac); -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); +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) -dmaengine_terminate_all (nfc->dmac);drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf · line 969
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +10
-0+ ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); + +if (ret) +dmaengine_terminate_all (nfc->dmac); + }else { +writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , + nfc->regs +NFC_REG_CMD ); + + ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); + }How about:
Quoted 14 lines
u32 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_DMA_INT_FLAG, false, 0); if (ret && !nfc->caps->has_mdma) dmaengine_terminate_all(nfc->dmac);
changed to:
u32 wait_event_flags = NFC_CMD_INT_FLAG;
if (nfc->caps->has_mdma)
wait_event_flags = 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, wait_event_flags, false, 0); if (ret && !nfc->caps->has_mdma)
dmaengine_terminate_all(nfc->dmac);
Quoted 5 lines
Quoted 5 lines
drivers/mtd/nand/raw/sunxi_nand.c +0
-0sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand);
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf · line 977
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c +5
-1-sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); +if (nfc->caps->dma_mode ==1 ) { +sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); + }else { +dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_DEV_TO_MEM ); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL );I'd suggest moving that to an
sunxi_nfc_mdma_op_cleanup()helper. BTW, why do you need to reset the RAM method here?
created sunxi_nfc_mdma_op_cleanup,
reset of RAM method is required cause OOB part of driver does not support dma yet
Quoted 108 lines
Quoted 108 lines
drivers/mtd/nand/raw/sunxi_nand.c +44
-14+ }if (ret)return ret;@@ -1128,7 +1163,7 @@ static int sunxi_nfc_hw_ecc_read_page_dma(struct nand_chip *nand, u8 *buf, int oob_required, int page) { int ret; - +sunxi_nfc_select_chip (nand, nand->cur_cs);nand_read_page_op (nand, page,0 ,NULL ,0 );@@ -1276,19 +1311,35 @@ 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; -int ret, i; - +int ret, i, nchunks, chunksize; +__u32 mem_addr; +sunxi_nfc_select_chip (nand, nand->cur_cs); ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, -DMA_TO_DEVICE , &sg); -if (ret) - goto pio_fallback; +if (nfc->caps->dma_mode ==1 ) { + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, +DMA_TO_DEVICE , &sg); +if (ret) + goto pio_fallback; + }else { + chunksize = ecc->size; + nchunks = ecc->steps; + mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_MEM_TO_DEV ); +if (dma_mapping_error (nfc->dev, mem_addr)) { +dev_err (nfc->dev,"DMA mapping error\n" ); + } +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT ); + } +for (i =0 ; i < ecc->steps; i++) {const u8 *oob = nand->oob_poi + (i * (ecc->bytes +4 ));@@ -1304,20 +1355,33 @@ 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); +if (nfc->caps->dma_mode ==1 ) { +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 ); -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD | + ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); +if (ret) +dmaengine_terminate_all (nfc->dmac); + }else { +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) -dmaengine_terminate_all (nfc->dmac); + ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); + }sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); +if (nfc->caps->dma_mode ==1 ) { +sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); + }else { +dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_MEM_TO_DEV ); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); + }if (ret)return ret;@@ -1695,7 +1759,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->dma_mode ==0 ) { 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;@@ -2132,38 +2196,43 @@ static int sunxi_nfc_probe(struct platform_device *pdev)if (ret) goto out_ahb_reset_reassert;
Quoted 13 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_probe(struct platform_device *pdev) · line 2200
Quoted 11 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-9- 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 ; +if (nfc->caps->dma_mode ==0 ) { +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL );This shouldn't be done in the probe helper.
moved to sunxi_nfc_dma_init, or shouldn't it not called on probing?
Quoted 5 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_probe(struct platform_device *pdev) · line 2201
Quoted 2 lines
drivers/mtd/nand/raw/sunxi_nand.c +1
-0+ nfc->dmac =NULL ;No need to set that field to NULL, the nfc object is allocated with
kzalloc().
removed
Quoted 33 lines
Quoted 33 lines
drivers/mtd/nand/raw/sunxi_nand.c +18
-13}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); - -if (nfc->caps->extra_mbus_conf) -writel (readl (nfc->regs +NFC_REG_CTL ) | -NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL ); + 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 = { }; + + 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;
Quoted 8 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_probe(struct platform_device *pdev) · line 2226
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c +6
-0+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 ); + }Can you move that to a
sunxi_nfc_dma_init()helper?
moved to sunxi_nfc_dma_init
Quoted 29 lines
Quoted 29 lines
drivers/mtd/nand/raw/sunxi_nand.c +8
-7} + +platform_set_drvdata (pdev, nfc); -platform_set_drvdata (pdev, nfc); - - ret =sunxi_nand_chips_init (dev, nfc); -if (ret) { -dev_err (dev,"failed to init nand chips\n" ); - goto out_release_dmac; - } + ret =sunxi_nand_chips_init (dev, nfc); +if (ret) { +dev_err (dev,"failed to init nand chips\n" ); + goto out_release_dmac; + }return 0 ;@@ -2197,16 +2266,24 @@ static int sunxi_nfc_remove(struct platform_device *pdev) }static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { + .dma_mode =1 , .reg_io_data =NFC_REG_A10_IO_DATA , .dma_maxburst =4 , };
Quoted 4 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_remove(struct platform_device *pdev) · line 2275
Quoted 2 lines
drivers/mtd/nand/raw/sunxi_nand.c +1
-0static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { + .dma_mode =1 ,I think the A23 also has an MDMA block.
I have only a H3 and A33 board for testing,
A33 nandump with sun8i-a23-nand-controller 14.112s A33 nandump with sun8i-h3-nand-controller 12.975s
it worked also for A33, haven't enough trust yet to enable it without more testing on other hardware
Quoted 6 lines
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c +0
-0.extra_mbus_conf = true, .reg_io_data = NFC_REG_A23_IO_DATA, .dma_maxburst = 8, };
Quoted 6 lines
drivers/mtd/nand/raw/sunxi_nand.c static int sunxi_nfc_remove(struct platform_device *pdev) · line 2284
Quoted 4 lines
drivers/mtd/nand/raw/sunxi_nand.c +4
-0+static const struct sunxi_nfc_caps sunxi_nfc_h3_caps = { + .dma_mode =0 , + .reg_io_data =NFC_REG_A23_IO_DATA , + .dma_maxburst =8 ,You don't need to set that field if you use the MDMA.
removed
Quoted 17 lines
Quoted 7 lines
drivers/mtd/nand/raw/sunxi_nand.c +2
-0+}; +static const struct of_device_id sunxi_nfc_ids[] = { { .compatible ="allwinner,sun4i-a10-nand" ,drivers/mtd/nand/raw/sunxi_nand.c static const struct of_device_id sunxi_nfc_ids[] = { · line 2302
Quoted 10 lines
drivers/mtd/nand/raw/sunxi_nand.c +4
-0@@ -2216,6 +2293,10 @@ static const struct of_device_id sunxi_nfc_ids[] = { .compatible = "allwinner,sun8i-a23-nand-controller", .data = &sunxi_nfc_a23_caps, }, + { + .compatible = "allwinner,sun8i-h3-nand-controller", + .data = &sunxi_nfc_h3_caps, + }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, sunxi_nfc_ids);
yours,
Manuel
--- drivers/mtd/nand/raw/sunxi_nand.c | 248 ++++++++++++++++-------------- 1 file changed, 132 insertions(+), 116 deletions(-)
drivers/mtd/nand/raw/sunxi_nand.c +132 -116
@@ -208,14 +208,14 @@ 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. * -* @dma_mode: use different dma method, required for chips like H3 +* @has_mdma: use mbus dma mode, otherwise general dma * @extra_mbus_conf: Contrary to A10, A10s and A13, accessing internal RAM * through MBUS on A23/A33 needs extra configuration. * @reg_io_data: I/O data register * @dma_maxburst: DMA maxburst */ struct sunxi_nfc_caps { -unsigned int dma_mode; +bool has_mdma;bool extra_mbus_conf;unsigned int reg_io_data;unsigned int dma_maxburst;
@@ -266,10 +266,7 @@ static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)if (!(ien & st))return IRQ_NONE ; -if ((ien & st) ==NFC_CMD_INT_ENABLE ) -complete (&nfc->complete); - -if ((ien & st) ==NFC_DMA_INT_ENABLE ) +if ((ien & st) == ien)complete (&nfc->complete);writel (st &NFC_INT_MASK , nfc->regs +NFC_REG_ST );
@@ -399,6 +396,35 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,return ret; } +static int sunxi_nfc_mdma_op_prepare (struct sunxi_nfc *nfc,const void *buf, +int chunksize,int nchunks, +enum dma_data_direction ddir, +__u32 *mem_addr) +{ +enum dma_transfer_direction tdir; +int ret; + +if (ddir ==DMA_FROM_DEVICE ) + tdir =DMA_DEV_TO_MEM ; +else + tdir =DMA_MEM_TO_DEV ; + + *mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize, tdir); + ret =dma_mapping_error (nfc->dev, *mem_addr); +if (ret) { +dev_err (nfc->dev,"DMA mapping error\n" ); +return ret; + } + +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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); +writel (*mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); +writel (chunksize, nfc->regs +NFC_REG_CNT ); + +return 0 ; +} +static void sunxi_nfc_dma_op_cleanup (struct sunxi_nfc *nfc,enum dma_data_direction ddir,struct scatterlist *sg)
@@ -408,6 +434,21 @@ static void sunxi_nfc_dma_op_cleanup(struct sunxi_nfc *nfc, nfc->regs + NFC_REG_CTL); } +static void sunxi_nfc_mdma_op_cleanup (struct sunxi_nfc *nfc, +enum dma_data_direction ddir, +__u32 *mem_addr,size_t size) +{ +enum dma_transfer_direction tdir; + +if (ddir ==DMA_FROM_DEVICE ) + tdir =DMA_DEV_TO_MEM ; +else + tdir =DMA_MEM_TO_DEV ; + +dma_unmap_single (nfc->dev, *mem_addr, size, tdir); +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); +} +static void sunxi_nfc_select_chip (struct nand_chip *nand,unsigned int cs) {struct mtd_info *mtd =nand_to_mtd (nand);
@@ -917,33 +958,22 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufunsigned int max_bitflips =0 ;int ret, i, raw_mode =0 ;struct scatterlist sg; -u32 status; -int chunksize; +u32 status, wait_event_flags;__u32 mem_addr; ret =sunxi_nfc_wait_cmd_fifo_empty (nfc);if (ret)return ret; -if (nfc->caps->dma_mode ==1 ) { +if (nfc->caps->has_mdma) + ret =sunxi_nfc_mdma_op_prepare (nfc, buf, ecc->size, nchunks, +DMA_FROM_DEVICE , &mem_addr); +else ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, nchunks,DMA_FROM_DEVICE , &sg); -if (ret) -return ret; - }else { - chunksize = ecc->size; - mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize, -DMA_DEV_TO_MEM ); - -if (dma_mapping_error (nfc->dev, mem_addr)) -dev_err (nfc->dev,"DMA mapping error\n" ); -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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); -writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); -writel (chunksize, nfc->regs +NFC_REG_CNT ); - } +if (ret) +return ret;sunxi_nfc_hw_ecc_enable (nand);sunxi_nfc_randomizer_config (nand, page, false);
@@ -952,32 +982,27 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *bufwritel ((NAND_CMD_RNDOUTSTART <<16 ) | (NAND_CMD_RNDOUT <<8 ) |NAND_CMD_READSTART , nfc->regs +NFC_REG_RCMD_SET ); -if (nfc->caps->dma_mode ==1 ) { -dma_async_issue_pending (nfc->dmac); - -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); + wait_event_flags =NFC_CMD_INT_FLAG ; - ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); +if (nfc->caps->has_mdma) + wait_event_flags =NFC_DMA_INT_FLAG ; +else +dma_async_issue_pending (nfc->dmac); -if (ret) -dmaengine_terminate_all (nfc->dmac); - }else { -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , - nfc->regs +NFC_REG_CMD ); +writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD |NFC_DATA_TRANS , + nfc->regs +NFC_REG_CMD ); - ret =sunxi_nfc_wait_events (nfc,NFC_DMA_INT_FLAG , false,0 ); - } + ret =sunxi_nfc_wait_events (nfc, wait_event_flags, false,0 ); +if (ret && !nfc->caps->has_mdma) +dmaengine_terminate_all (nfc->dmac);sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -if (nfc->caps->dma_mode ==1 ) { +if (nfc->caps->has_mdma) +sunxi_nfc_mdma_op_cleanup (nfc,DMA_FROM_DEVICE , &mem_addr, nchunks * ecc->size); +else sunxi_nfc_dma_op_cleanup (nfc,DMA_FROM_DEVICE , &sg); - }else { -dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_DEV_TO_MEM ); -writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); - }if (ret)return ret;
@@ -1312,7 +1337,8 @@ 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; -int ret, i, nchunks, chunksize; +int ret, i; +u32 wait_event_flags;__u32 mem_addr;sunxi_nfc_select_chip (nand, nand->cur_cs);
@@ -1321,26 +1347,14 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,if (ret)return ret; -if (nfc->caps->dma_mode ==1 ) { - ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps, -DMA_TO_DEVICE , &sg); -if (ret) - goto pio_fallback; - }else { - chunksize = ecc->size; - nchunks = ecc->steps; - mem_addr = (__u32 )dma_map_single (nfc->dev, (void *)buf, nchunks * chunksize,DMA_MEM_TO_DEV ); -if (dma_mapping_error (nfc->dev, mem_addr)) { -dev_err (nfc->dev,"DMA mapping error, fallback to pio...\n" ); - goto pio_fallback; - } +if (nfc->caps->has_mdma) + ret =sunxi_nfc_mdma_op_prepare (nfc, buf, ecc->size, ecc->steps, +DMA_TO_DEVICE , &mem_addr); +else + ret =sunxi_nfc_dma_op_prepare (nfc, buf, ecc->size, ecc->steps,DMA_TO_DEVICE , &sg); -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 * nchunks, nfc->regs +NFC_REG_MDMA_CNT ); -writel (mem_addr, nfc->regs +NFC_REG_MDMA_ADDR ); -writel (chunksize, nfc->regs +NFC_REG_CNT ); - } +if (ret) +return ret;for (i =0 ; i < ecc->steps; i++) {const u8 *oob = nand->oob_poi + (i * (ecc->bytes +4 ));
@@ -1357,33 +1371,28 @@ 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 ); -if (nfc->caps->dma_mode ==1 ) { -dma_async_issue_pending (nfc->dmac); + wait_event_flags =NFC_CMD_INT_FLAG ; -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD | -NFC_DATA_TRANS |NFC_ACCESS_DIR , - nfc->regs +NFC_REG_CMD ); +if (nfc->caps->has_mdma) + wait_event_flags =NFC_DMA_INT_FLAG ; +else +dma_async_issue_pending (nfc->dmac); - ret =sunxi_nfc_wait_events (nfc,NFC_CMD_INT_FLAG , false,0 ); -if (ret) -dmaengine_terminate_all (nfc->dmac); - }else { -writel (NFC_PAGE_OP |NFC_DATA_SWAP_METHOD | -NFC_DATA_TRANS |NFC_ACCESS_DIR , - nfc->regs +NFC_REG_CMD ); +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_DMA_INT_FLAG , false,0 ); - } + ret =sunxi_nfc_wait_events (nfc, wait_event_flags, false,0 ); +if (ret && !nfc->caps->has_mdma) +dmaengine_terminate_all (nfc->dmac);sunxi_nfc_randomizer_disable (nand);sunxi_nfc_hw_ecc_disable (nand); -if (nfc->caps->dma_mode ==1 ) { +if (nfc->caps->has_mdma) +sunxi_nfc_mdma_op_cleanup (nfc,DMA_TO_DEVICE , &mem_addr, ecc->size * ecc->steps); +else sunxi_nfc_dma_op_cleanup (nfc,DMA_TO_DEVICE , &sg); - }else { -dma_unmap_single (nfc->dev, mem_addr, nchunks * chunksize,DMA_MEM_TO_DEV ); -writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_RAM_METHOD , nfc->regs +NFC_REG_CTL ); - }if (ret)return ret;
@@ -1761,7 +1770,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 || nfc->caps->dma_mode ==0 ) { +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;
@@ -2122,6 +2131,41 @@ 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) { +writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , + nfc->regs +NFC_REG_CTL ); + }else { + nfc->dmac =dma_request_chan (nfc->dev,"rxtx" ); +if (IS_ERR (nfc->dmac)) { + ret =PTR_ERR (nfc->dmac); +if (ret) +return ret; + +/* Ignore errors to fall back to PIO mode */ +dev_warn (nfc->dev,"failed to request rxtx DMA channel: %d\n" , ret); + }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); + +if (nfc->caps->extra_mbus_conf) +writel (readl (nfc->regs +NFC_REG_CTL ) | +NFC_DMA_TYPE_NORMAL , nfc->regs +NFC_REG_CTL ); + } + } +return 0 ; +} +static int sunxi_nfc_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -2196,36 +2240,10 @@ static int sunxi_nfc_probe(struct platform_device *pdev)if (ret) goto out_ahb_reset_reassert; -if (nfc->caps->dma_mode ==0 ) { -writel (readl (nfc->regs +NFC_REG_CTL ) & ~NFC_DMA_TYPE_NORMAL , - nfc->regs +NFC_REG_CTL ); - nfc->dmac =NULL ; - }else { - 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);
@@ -2267,22 +2285,20 @@ static int sunxi_nfc_remove(struct platform_device *pdev) }static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { - .dma_mode =1 , + .has_mdma = false, .reg_io_data =NFC_REG_A10_IO_DATA , .dma_maxburst =4 , };static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = { - .dma_mode =1 , + .has_mdma = false, .extra_mbus_conf = true, .reg_io_data =NFC_REG_A23_IO_DATA , .dma_maxburst =8 , };static const struct sunxi_nfc_caps sunxi_nfc_h3_caps = { - .dma_mode =0 , - .reg_io_data =NFC_REG_A23_IO_DATA , - .dma_maxburst =8 , + .has_mdma = true, };static const struct of_device_id sunxi_nfc_ids[] = {
Signature · 12 lines
2.20.1 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/
Re: [PATCH v3] mtd: sunxi-nand: add dma support for allwinner h3 - review changes
Quoted 5 lines · On Tue, 6 Oct 2020 19:20:08 +0200 (CEST) Manuel Dipolt <[email protected]>…
hi Boris,
thanks for the fast review,
applied the suggested changes and answered your question, please take a look if its okay
Please submit a new patch with a proper commit message instead of replying to the existing thread and pasting the new version at the end.
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
Re: [PATCH v3] mtd: sunxi-nand: add dma support for allwinner h3 - review changes
Will post it again as V4 where V1-V3 are together
----- Original Message -----
From: "Boris Brezillon" <[email protected]>
To: "Manuel Dipolt" <[email protected]>
Cc: "linux-mtd" <[email protected]>, "Roland Ruckerbauer" <[email protected]>, "miquel raynal" <[email protected]>, "maxime" <[email protected]>, "bbrezillon" <[email protected]>
Sent: Wednesday, October 7, 2020 3:02:58 PM
Subject: Re: [PATCH v3] mtd: sunxi-nand: add dma support for allwinner h3 - review changes
Quoted 5 lines · On Tue, 6 Oct 2020 19:20:08 +0200 (CEST) Manuel Dipolt <[email protected]>…
hi Boris,
thanks for the fast review,
applied the suggested changes and answered your question, please take a look if its okay
Please submit a new patch with a proper commit message instead of replying to the existing thread and pasting the new version at the end.
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
PATCH v3 1/1 mtd: sunxi-nand: add dma support for allwinner h3 - review changes
Will post it again as V4 where V1-V3 are together
----- Original Message -----
From: "Boris Brezillon" <[email protected]>
To: "Manuel Dipolt" <[email protected]>
Cc: "linux-mtd" <[email protected]>, "Roland Ruckerbauer" <[email protected]>, "miquel raynal" <[email protected]>, "maxime" <[email protected]>, "bbrezillon" <[email protected]>
Sent: Wednesday, October 7, 2020 3:02:58 PM
Subject: Re: [PATCH v3] mtd: sunxi-nand: add dma support for allwinner h3 - review changes
Quoted 5 lines · On Tue, 6 Oct 2020 19:20:08 +0200 (CEST) Manuel Dipolt <[email protected]>…
hi Boris,
thanks for the fast review,
applied the suggested changes and answered your question, please take a look if its okay
Please submit a new patch with a proper commit message instead of replying to the existing thread and pasting the new version at the end.
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/