diff options
Diffstat (limited to 'drivers/mtd/nand/raw/cadence-nand-controller.c')
| -rw-r--r-- | drivers/mtd/nand/raw/cadence-nand-controller.c | 44 | 
1 files changed, 33 insertions, 11 deletions
| diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 8d1d710e439d..6667eea95597 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -471,6 +471,8 @@ struct cdns_nand_ctrl {  	struct {  		void __iomem *virt;  		dma_addr_t dma; +		dma_addr_t iova_dma; +		u32 size;  	} io;  	int irq; @@ -1835,11 +1837,11 @@ static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,  	}  	if (dir == DMA_FROM_DEVICE) { -		src_dma = cdns_ctrl->io.dma; +		src_dma = cdns_ctrl->io.iova_dma;  		dst_dma = buf_dma;  	} else {  		src_dma = buf_dma; -		dst_dma = cdns_ctrl->io.dma; +		dst_dma = cdns_ctrl->io.iova_dma;  	}  	tx = dmaengine_prep_dma_memcpy(cdns_ctrl->dmac, dst_dma, src_dma, len, @@ -1861,12 +1863,12 @@ static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,  	dma_async_issue_pending(cdns_ctrl->dmac);  	wait_for_completion(&finished); -	dma_unmap_single(cdns_ctrl->dev, buf_dma, len, dir); +	dma_unmap_single(dma_dev->dev, buf_dma, len, dir);  	return 0;  err_unmap: -	dma_unmap_single(cdns_ctrl->dev, buf_dma, len, dir); +	dma_unmap_single(dma_dev->dev, buf_dma, len, dir);  err:  	dev_dbg(cdns_ctrl->dev, "Fall back to CPU I/O\n"); @@ -2869,6 +2871,7 @@ cadence_nand_irq_cleanup(int irqnum, struct cdns_nand_ctrl *cdns_ctrl)  static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)  {  	dma_cap_mask_t mask; +	struct dma_device *dma_dev = cdns_ctrl->dmac->device;  	int ret;  	cdns_ctrl->cdma_desc = dma_alloc_coherent(cdns_ctrl->dev, @@ -2904,15 +2907,24 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)  	dma_cap_set(DMA_MEMCPY, mask);  	if (cdns_ctrl->caps1->has_dma) { -		cdns_ctrl->dmac = dma_request_channel(mask, NULL, NULL); -		if (!cdns_ctrl->dmac) { -			dev_err(cdns_ctrl->dev, -				"Unable to get a DMA channel\n"); -			ret = -EBUSY; +		cdns_ctrl->dmac = dma_request_chan_by_mask(&mask); +		if (IS_ERR(cdns_ctrl->dmac)) { +			ret = dev_err_probe(cdns_ctrl->dev, PTR_ERR(cdns_ctrl->dmac), +					    "%d: Failed to get a DMA channel\n", ret);  			goto disable_irq;  		}  	} +	cdns_ctrl->io.iova_dma = dma_map_resource(dma_dev->dev, cdns_ctrl->io.dma, +						  cdns_ctrl->io.size, +						  DMA_BIDIRECTIONAL, 0); + +	ret = dma_mapping_error(dma_dev->dev, cdns_ctrl->io.iova_dma); +	if (ret) { +		dev_err(cdns_ctrl->dev, "Failed to map I/O resource to DMA\n"); +		goto dma_release_chnl; +	} +  	nand_controller_init(&cdns_ctrl->controller);  	INIT_LIST_HEAD(&cdns_ctrl->chips); @@ -2923,18 +2935,22 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)  	if (ret) {  		dev_err(cdns_ctrl->dev, "Failed to register MTD: %d\n",  			ret); -		goto dma_release_chnl; +		goto unmap_dma_resource;  	}  	kfree(cdns_ctrl->buf);  	cdns_ctrl->buf = kzalloc(cdns_ctrl->buf_size, GFP_KERNEL);  	if (!cdns_ctrl->buf) {  		ret = -ENOMEM; -		goto dma_release_chnl; +		goto unmap_dma_resource;  	}  	return 0; +unmap_dma_resource: +	dma_unmap_resource(dma_dev->dev, cdns_ctrl->io.iova_dma, +			   cdns_ctrl->io.size, DMA_BIDIRECTIONAL, 0); +  dma_release_chnl:  	if (cdns_ctrl->dmac)  		dma_release_channel(cdns_ctrl->dmac); @@ -2956,6 +2972,10 @@ free_buf_desc:  static void cadence_nand_remove(struct cdns_nand_ctrl *cdns_ctrl)  {  	cadence_nand_chips_cleanup(cdns_ctrl); +	if (cdns_ctrl->dmac) +		dma_unmap_resource(cdns_ctrl->dmac->device->dev, +				   cdns_ctrl->io.iova_dma, cdns_ctrl->io.size, +				   DMA_BIDIRECTIONAL, 0);  	cadence_nand_irq_cleanup(cdns_ctrl->irq, cdns_ctrl);  	kfree(cdns_ctrl->buf);  	dma_free_coherent(cdns_ctrl->dev, sizeof(struct cadence_nand_cdma_desc), @@ -3020,7 +3040,9 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev)  	cdns_ctrl->io.virt = devm_platform_get_and_ioremap_resource(ofdev, 1, &res);  	if (IS_ERR(cdns_ctrl->io.virt))  		return PTR_ERR(cdns_ctrl->io.virt); +  	cdns_ctrl->io.dma = res->start; +	cdns_ctrl->io.size = resource_size(res);  	dt->clk = devm_clk_get(cdns_ctrl->dev, "nf_clk");  	if (IS_ERR(dt->clk)) | 
