From 36ea4109ba79b5c98aa08e7a5e307e4b0b961955 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 10 Jun 2025 18:08:53 +0800 Subject: [PATCH] media: rockchip: vicap: support reserved mem attach dma_buf with iommu Change-Id: Ibd8d54ddda18d2cd5ac7d3d38808fd52a0048f43 Signed-off-by: Zefa Chen --- drivers/media/platform/rockchip/cif/capture.c | 1 + drivers/media/platform/rockchip/cif/common.c | 65 ++++++++++++++++--- drivers/media/platform/rockchip/cif/common.h | 1 + drivers/media/platform/rockchip/cif/hw.h | 2 + .../media/platform/rockchip/cif/subdev-itf.c | 5 +- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index dd4cf893139e..ca3db74adb8e 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -6171,6 +6171,7 @@ void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) if (buf->dbufs.is_init) v4l2_subdev_call(sd, core, ioctl, RKISP_VICAP_CMD_RX_BUFFER_FREE, &buf->dbufs); + rkcif_free_reserved_mem_buf(dev, buf); memset(buf, 0, sizeof(*buf)); buf->dummy.is_free = true; } diff --git a/drivers/media/platform/rockchip/cif/common.c b/drivers/media/platform/rockchip/cif/common.c index 9f5cdb3e037d..61ec92440b8b 100644 --- a/drivers/media/platform/rockchip/cif/common.c +++ b/drivers/media/platform/rockchip/cif/common.c @@ -343,17 +343,42 @@ int rkcif_alloc_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffe { struct rkcif_dummy_buffer *dummy = &buf->dummy; u32 reserved_mem = 0; + struct dma_buf_attachment *dba; + struct sg_table *sgt; + dma_addr_t dma; + int ret = 0; + u32 dma_addr = 0; if (dev->pre_buf_num) reserved_mem = SHARED_MEM_RESERVED_HEAD_SIZE; - dummy->dma_addr = reserved_mem + dev->resmem_pa + dummy->size * buf->buf_idx; - if (dummy->dma_addr + dummy->size > dev->resmem_pa + dev->resmem_size) + dma_addr = reserved_mem + dev->resmem_pa + dummy->size * buf->buf_idx; + if (dma_addr + dummy->size > dev->resmem_pa + dev->resmem_size) return -EINVAL; - buf->dbufs.dma = dummy->dma_addr; + buf->dbufs.dma = dma_addr; buf->dbufs.is_resmem = true; - buf->shmem.shm_start = dummy->dma_addr; + buf->shmem.shm_start = dma_addr; buf->shmem.shm_size = dummy->size; dummy->dbuf = rkcif_shm_alloc(&buf->shmem); + buf->dbufs.dbuf = dummy->dbuf; + if (dev->hw_dev->iommu_en) { + dba = dma_buf_attach(dummy->dbuf, dev->hw_dev->dev); + if (IS_ERR(dba)) { + ret = PTR_ERR(dba); + goto err_alloc; + } + dummy->dba = dba; + sgt = dma_buf_map_attachment(dba, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto err_alloc; + } + dummy->sgt = sgt; + dma = sg_dma_address(sgt->sgl); + get_dma_buf(dummy->dbuf); + dummy->dma_addr = dma; + } else { + dummy->dma_addr = dma_addr; + } if (dummy->is_need_vaddr) { struct iosys_map map; @@ -361,6 +386,11 @@ int rkcif_alloc_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffe dummy->vaddr = map.vaddr; } return 0; +err_alloc: + v4l2_info(&dev->v4l2_dev, + "can't match dma_buf 0x%x with iommu\n", + (u32)dummy->dma_addr); + return ret; } void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf) @@ -396,13 +426,30 @@ void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffe if (buf->dbufs.is_init) v4l2_subdev_call(sd, core, ioctl, RKISP_VICAP_CMD_RX_BUFFER_FREE, &buf->dbufs); + if (dev->hw_dev->iommu_en) { + if (dummy->dba) { + if (dummy->sgt) { + dma_buf_unmap_attachment(dummy->dba, dummy->sgt, + DMA_BIDIRECTIONAL); + dummy->sgt = NULL; + } + dma_buf_detach(dummy->dbuf, dummy->dba); + dma_buf_put(dummy->dbuf); + dummy->dba = NULL; + } + } if (dummy->is_need_vaddr) dummy->dbuf->ops->vunmap(dummy->dbuf, NULL); -#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP - free_reserved_area(phys_to_virt(buf->shmem.shm_start), - phys_to_virt(buf->shmem.shm_start + buf->shmem.shm_size), - -1, "rkisp_thunderboot"); -#endif + dma_buf_put(dummy->dbuf); buf->dummy.is_free = true; } +void rkcif_free_reserved_mem(u32 start, u32 size) +{ +#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP + free_reserved_area(phys_to_virt(start), + phys_to_virt(start + size), + -1, "rkisp_thunderboot"); +#endif +} + diff --git a/drivers/media/platform/rockchip/cif/common.h b/drivers/media/platform/rockchip/cif/common.h index 7bdfe4f40223..8745df4508f8 100644 --- a/drivers/media/platform/rockchip/cif/common.h +++ b/drivers/media/platform/rockchip/cif/common.h @@ -25,6 +25,7 @@ void rkcif_free_common_dummy_buf(struct rkcif_device *dev, struct rkcif_dummy_bu int rkcif_alloc_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf); void rkcif_free_reserved_mem_buf(struct rkcif_device *dev, struct rkcif_rx_buffer *buf); +void rkcif_free_reserved_mem(u32 start, u32 size); #endif /* _RKCIF_COMMON_H */ diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index 537dc154b329..c0ecbf2ab78c 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -81,6 +81,8 @@ struct rkcif_dummy_buffer { struct vb2_queue vb2_queue; struct list_head list; struct dma_buf *dbuf; + struct dma_buf_attachment *dba; + struct sg_table *sgt; dma_addr_t dma_addr; struct page **pages; void *mem_priv; diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 26a6423d88f2..d47d38be3b5f 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -98,6 +98,7 @@ static void sditf_buffree_work(struct work_struct *work) if (rx_buf) { list_del(&rx_buf->list_free); rkcif_free_reserved_mem_buf(priv->cif_dev, rx_buf); + rkcif_free_reserved_mem(rx_buf->shmem.shm_start, rx_buf->shmem.shm_size); memset(rx_buf, 0, sizeof(*rx_buf)); rx_buf->dummy.is_free = true; } @@ -1444,7 +1445,7 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, if (cif_dev->is_thunderboot || cif_dev->is_rtt_suspend || cif_dev->is_aov_reserved) - dma_sync_single_for_device(cif_dev->dev, + dma_sync_single_for_device(cif_dev->hw_dev->dev, rx_buf->dummy.dma_addr + rx_buf->dummy.size - stream->pixm.plane_fmt[0].bytesperline * 3, stream->pixm.plane_fmt[0].bytesperline * 3, @@ -1453,6 +1454,7 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, cif_dev->hw_dev->mem_ops->prepare(rx_buf->dummy.mem_priv); } } + spin_unlock_irqrestore(&stream->vbq_lock, flags); if (dbufs->is_switch && dbufs->type == BUF_SHORT) { if (stream->is_in_vblank || !stream->dma_en) { @@ -1465,7 +1467,6 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, v4l2_dbg(3, rkcif_debug, &cif_dev->v4l2_dev, "switch to online mode\n"); } - spin_unlock_irqrestore(&stream->vbq_lock, flags); spin_lock_irqsave(&stream->cifdev->stream_spinlock, flags); stream->is_finish_single_cap = true;