diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 700fb6bdf4b8..3e906dce5311 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -1820,6 +1820,26 @@ static int rockchip_drm_gem_dmabuf_end_cpu_access(struct dma_buf *dma_buf, return rockchip_gem_prime_end_cpu_access(obj, dir); } +static int rockchip_drm_gem_begin_cpu_access_partial( + struct dma_buf *dma_buf, + enum dma_data_direction dir, + unsigned int offset, unsigned int len) +{ + struct drm_gem_object *obj = dma_buf->priv; + + return rockchip_gem_prime_begin_cpu_access_partial(obj, dir, offset, len); +} + +static int rockchip_drm_gem_end_cpu_access_partial( + struct dma_buf *dma_buf, + enum dma_data_direction dir, + unsigned int offset, unsigned int len) +{ + struct drm_gem_object *obj = dma_buf->priv; + + return rockchip_gem_prime_end_cpu_access_partial(obj, dir, offset, len); +} + static const struct dma_buf_ops rockchip_drm_gem_prime_dmabuf_ops = { .attach = drm_gem_map_attach, .detach = drm_gem_map_detach, @@ -1833,6 +1853,8 @@ static const struct dma_buf_ops rockchip_drm_gem_prime_dmabuf_ops = { .vunmap = drm_gem_dmabuf_vunmap, .begin_cpu_access = rockchip_drm_gem_dmabuf_begin_cpu_access, .end_cpu_access = rockchip_drm_gem_dmabuf_end_cpu_access, + .begin_cpu_access_partial = rockchip_drm_gem_begin_cpu_access_partial, + .end_cpu_access_partial = rockchip_drm_gem_end_cpu_access_partial, }; #ifdef CONFIG_ARCH_ROCKCHIP diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c index 55001f42a72d..ef49d5e46736 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c @@ -1027,3 +1027,95 @@ int rockchip_gem_prime_end_cpu_access(struct drm_gem_object *obj, rk_obj->sgt->nents, dir); return 0; } + +static int rockchip_gem_prime_sgl_sync_range(struct device *dev, + struct scatterlist *sgl, unsigned int nents, + unsigned int offset, unsigned int length, + enum dma_data_direction dir, bool for_cpu) +{ + int i; + struct scatterlist *sg; + unsigned int len = 0; + dma_addr_t sg_dma_addr; + + for_each_sg(sgl, sg, nents, i) { + if (sg_dma_len(sg) == 0) + break; + + if (i > 0) { + pr_warn_ratelimited("Partial cmo only supported with 1 segment\n" + "is dma_set_max_seg_size being set on dev:%s\n", + dev_name(dev)); + return -EINVAL; + } + } + + for_each_sg(sgl, sg, nents, i) { + unsigned int sg_offset, sg_left, size = 0; + + if (i == 0) + sg_dma_addr = sg_dma_address(sg); + + len += sg->length; + if (len <= offset) { + sg_dma_addr += sg->length; + continue; + } + + sg_left = len - offset; + sg_offset = sg->length - sg_left; + + size = (length < sg_left) ? length : sg_left; + if (for_cpu) + dma_sync_single_range_for_cpu(dev, sg_dma_addr, + sg_offset, size, dir); + else + dma_sync_single_range_for_device(dev, sg_dma_addr, + sg_offset, size, dir); + + offset += size; + length -= size; + sg_dma_addr += sg->length; + + if (length == 0) + break; + } + + return 0; +} + +int rockchip_gem_prime_begin_cpu_access_partial(struct drm_gem_object *obj, + enum dma_data_direction dir, + unsigned int offset, + unsigned int len) +{ + struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); + struct drm_device *drm = obj->dev; + + if (!rk_obj->sgt) + return 0; + + rockchip_gem_prime_sgl_sync_range(drm->dev, rk_obj->sgt->sgl, + rk_obj->sgt->nents, + offset, len, dir, true); + + return 0; +} + +int rockchip_gem_prime_end_cpu_access_partial(struct drm_gem_object *obj, + enum dma_data_direction dir, + unsigned int offset, + unsigned int len) +{ + struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); + struct drm_device *drm = obj->dev; + + if (!rk_obj->sgt) + return 0; + + rockchip_gem_prime_sgl_sync_range(drm->dev, rk_obj->sgt->sgl, + rk_obj->sgt->nents, + offset, len, dir, false); + + return 0; +} diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h index 9b3b01ede8ec..2b299b848465 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h @@ -91,4 +91,15 @@ int rockchip_gem_prime_begin_cpu_access(struct drm_gem_object *obj, int rockchip_gem_prime_end_cpu_access(struct drm_gem_object *obj, enum dma_data_direction dir); + +int rockchip_gem_prime_begin_cpu_access_partial(struct drm_gem_object *obj, + enum dma_data_direction dir, + unsigned int offset, + unsigned int len); + +int rockchip_gem_prime_end_cpu_access_partial(struct drm_gem_object *obj, + enum dma_data_direction dir, + unsigned int offset, + unsigned int len); + #endif /* _ROCKCHIP_DRM_GEM_H */