From 796f35c684c51b7242f3bcc8302a89ec8b7f8b61 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:03 +0800 Subject: [PATCH 01/10] drm/exynos: Internalize exynos_drm_gem_free_object() exynos_drm_gem_free_object() is only provided as a callback for GEM objects. It does not need to be exposed to the rest of the driver. Move it above where it is used and internalize it to just the GEM functions. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 10 +++++----- drivers/gpu/drm/exynos/exynos_drm_gem.h | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 69ef6cda1ce9..59fd736a1fb9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -133,6 +133,11 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) kfree(exynos_gem); } +static void exynos_drm_gem_free_object(struct drm_gem_object *obj) +{ + exynos_drm_gem_destroy(to_exynos_gem(obj)); +} + static const struct vm_operations_struct exynos_drm_gem_vm_ops = { .open = drm_gem_vm_open, .close = drm_gem_vm_close, @@ -318,11 +323,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, return 0; } -void exynos_drm_gem_free_object(struct drm_gem_object *obj) -{ - exynos_drm_gem_destroy(to_exynos_gem(obj)); -} - int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 79d7e1a87419..8b5bd20ae8c1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -88,9 +88,6 @@ static inline void exynos_drm_gem_put(struct exynos_drm_gem *exynos_gem) int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* free gem object. */ -void exynos_drm_gem_free_object(struct drm_gem_object *obj); - /* create memory region for drm framebuffer. */ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, From e457a1a9585b941e2aa771142b63c951f6a3d54e Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:04 +0800 Subject: [PATCH 02/10] drm/exynos: Use DRM core dedicated DMA device tracking facility The exynos driver tracks a dedicated DMA device in its private data. The DRM core already has facilities to do this, and it is integrated into DRM PRIME imports and GEM DMA helpers. Convert the exynos driver to use the core's dedicated DMA device tracking facility. Also get rid of exynos_drm_gem_prime_import() as it is identical to drm_gem_prime_import() after the conversion. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dma.c | 11 +++++----- drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 8 -------- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 11 +++++----- drivers/gpu/drm/exynos/exynos_drm_gem.c | 27 ++++++++++--------------- drivers/gpu/drm/exynos/exynos_drm_gem.h | 2 -- 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c b/drivers/gpu/drm/exynos/exynos_drm_dma.c index 6a6761935224..bde2b86a7a7d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dma.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -45,7 +46,7 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev, struct exynos_drm_private *priv = drm_dev->dev_private; int ret = 0; - if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) { + if (get_dma_ops(drm_dev_dma_dev(drm_dev)) != get_dma_ops(subdrv_dev)) { DRM_DEV_ERROR(subdrv_dev, "Device %s lacks support for IOMMU\n", dev_name(subdrv_dev)); return -EINVAL; @@ -97,8 +98,8 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev, { struct exynos_drm_private *priv = drm->dev_private; - if (!priv->dma_dev) { - priv->dma_dev = dev; + if (drm_dev_dma_dev(drm) == drm->dev) { + drm_dev_set_dma_dev(drm, dev); DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n", dev_name(dev)); } @@ -113,7 +114,7 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev, mapping = arm_iommu_create_mapping(dev, EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE); else if (IS_ENABLED(CONFIG_IOMMU_DMA)) - mapping = iommu_get_domain_for_dev(priv->dma_dev); + mapping = iommu_get_domain_for_dev(dev); if (!mapping) return -ENODEV; @@ -139,5 +140,5 @@ void exynos_drm_cleanup_dma(struct drm_device *drm) arm_iommu_release_mapping(priv->mapping); priv->mapping = NULL; - priv->dma_dev = NULL; + drm_dev_set_dma_dev(drm, NULL); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 2101a74dc1ed..9ee30086879f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -109,7 +109,6 @@ static const struct drm_driver exynos_drm_driver = { .open = exynos_drm_open, .postclose = exynos_drm_postclose, .dumb_create = exynos_drm_gem_dumb_create, - .gem_prime_import = exynos_drm_gem_prime_import, .gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table, EXYNOS_DRM_FBDEV_DRIVER_OPS, .ioctls = exynos_ioctls, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 06c29ff2aac0..1ab7195d09ae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -198,7 +198,6 @@ struct drm_exynos_file_private { */ struct exynos_drm_private { struct device *g2d_dev; - struct device *dma_dev; struct device *vidi_dev; void *mapping; @@ -208,13 +207,6 @@ struct exynos_drm_private { wait_queue_head_t wait; }; -static inline struct device *to_dma_dev(struct drm_device *dev) -{ - struct exynos_drm_private *priv = dev->dev_private; - - return priv->dma_dev; -} - static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) { struct exynos_drm_private *priv = drm_dev->dev_private; diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 348603262af0..85a3a247dfca 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -278,7 +279,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE; - g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev), + g2d->cmdlist_pool_virt = dma_alloc_attrs(drm_dev_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, &g2d->cmdlist_pool, GFP_KERNEL, g2d->cmdlist_dma_attrs); @@ -311,7 +312,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d) return 0; err: - dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, + dma_free_attrs(drm_dev_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); return ret; @@ -322,7 +323,7 @@ static void g2d_fini_cmdlist(struct g2d_data *g2d) kfree(g2d->cmdlist_node); if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) { - dma_free_attrs(to_dma_dev(g2d->drm_dev), + dma_free_attrs(drm_dev_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt, g2d->cmdlist_pool, g2d->cmdlist_dma_attrs); @@ -397,7 +398,7 @@ static void g2d_userptr_put_dma_addr(struct g2d_data *g2d, return; out: - dma_unmap_sgtable(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt, + dma_unmap_sgtable(drm_dev_dma_dev(g2d->drm_dev), g2d_userptr->sgt, DMA_BIDIRECTIONAL, 0); unpin_user_pages_dirty_lock(g2d_userptr->pages, g2d_userptr->npages, @@ -506,7 +507,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d, g2d_userptr->sgt = sgt; - ret = dma_map_sgtable(to_dma_dev(g2d->drm_dev), sgt, + ret = dma_map_sgtable(drm_dev_dma_dev(g2d->drm_dev), sgt, DMA_BIDIRECTIONAL, 0); if (ret) { DRM_DEV_ERROR(g2d->dev, "failed to map sgt with dma region.\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 59fd736a1fb9..9ec76163609f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) unsigned long attr = 0; if (exynos_gem->dma_addr) { - DRM_DEV_DEBUG_KMS(to_dma_dev(dev), "already allocated.\n"); + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(dev), "already allocated.\n"); return 0; } @@ -54,18 +55,18 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) attr |= DMA_ATTR_NO_KERNEL_MAPPING; exynos_gem->dma_attrs = attr; - exynos_gem->cookie = dma_alloc_attrs(to_dma_dev(dev), exynos_gem->size, + exynos_gem->cookie = dma_alloc_attrs(drm_dev_dma_dev(dev), exynos_gem->size, &exynos_gem->dma_addr, GFP_KERNEL, exynos_gem->dma_attrs); if (!exynos_gem->cookie) { - DRM_DEV_ERROR(to_dma_dev(dev), "failed to allocate buffer.\n"); + DRM_DEV_ERROR(drm_dev_dma_dev(dev), "failed to allocate buffer.\n"); return -ENOMEM; } if (kvmap) exynos_gem->kvaddr = exynos_gem->cookie; - DRM_DEV_DEBUG_KMS(to_dma_dev(dev), "dma_addr(0x%lx), size(0x%lx)\n", + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(dev), "dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)exynos_gem->dma_addr, exynos_gem->size); return 0; } @@ -82,7 +83,7 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)exynos_gem->dma_addr, exynos_gem->size); - dma_free_attrs(to_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, + dma_free_attrs(drm_dev_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, (dma_addr_t)exynos_gem->dma_addr, exynos_gem->dma_attrs); } @@ -101,7 +102,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj, if (ret) return ret; - DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "gem handle = 0x%x\n", *handle); + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(obj->dev), "gem handle = 0x%x\n", *handle); /* drop reference from allocate - handle holds it now. */ drm_gem_object_put(obj); @@ -113,7 +114,7 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem) { struct drm_gem_object *obj = &exynos_gem->base; - DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "handle count = %d\n", + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(obj->dev), "handle count = %d\n", obj->handle_count); /* @@ -289,7 +290,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, if (vm_size > exynos_gem->size) return -EINVAL; - ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, exynos_gem->cookie, + ret = dma_mmap_attrs(drm_dev_dma_dev(drm_dev), vma, exynos_gem->cookie, exynos_gem->dma_addr, exynos_gem->size, exynos_gem->dma_attrs); if (ret < 0) { @@ -372,7 +373,7 @@ static int exynos_drm_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); - DRM_DEV_DEBUG_KMS(to_dma_dev(obj->dev), "flags = 0x%x\n", + DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(obj->dev), "flags = 0x%x\n", exynos_gem->flags); /* non-cachable as default. */ @@ -398,12 +399,6 @@ static int exynos_drm_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct } /* low-level interface prime helpers */ -struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf) -{ - return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev)); -} - struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) { struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj); @@ -415,7 +410,7 @@ struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) if (!sgt) return ERR_PTR(-ENOMEM); - ret = dma_get_sgtable_attrs(to_dma_dev(drm_dev), sgt, exynos_gem->cookie, + ret = dma_get_sgtable_attrs(drm_dev_dma_dev(drm_dev), sgt, exynos_gem->cookie, exynos_gem->dma_addr, exynos_gem->size, exynos_gem->dma_attrs); if (ret) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 8b5bd20ae8c1..b6785f1136ab 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -94,8 +94,6 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args); /* low-level interface prime helpers */ -struct drm_gem_object *exynos_drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf); struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj); struct drm_gem_object * exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, From 11e898373fba6b1d27b15ab4beff592701a57293 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:05 +0800 Subject: [PATCH 03/10] drm/exynos: Drop exynos_drm_gem.size field A size field is already included in the base GEM object, and is initialized through drm_gem_object_init() with the same value. Drop the field in the subclass to save some space. More changes to make exynos_drm_gem a subclass of drm_gem_dma_object will follow. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_gem.c | 17 ++++++++--------- drivers/gpu/drm/exynos/exynos_drm_gem.h | 3 --- drivers/gpu/drm/exynos/exynos_drm_ipp.c | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index ab0e0c74ec47..125b87adfdc4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -119,7 +119,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, goto err; } - if (size > exynos_gem[i]->size) { + if (size > exynos_gem[i]->base.size) { i++; ret = -EINVAL; goto err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 85a3a247dfca..e92a4d872c41 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -720,7 +720,7 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d, } if (!g2d_check_buf_desc_is_valid(g2d, buf_desc, - reg_type, exynos_gem->size)) { + reg_type, exynos_gem->base.size)) { exynos_drm_gem_put(exynos_gem); ret = -EFAULT; goto err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 9ec76163609f..d9d42809a1a9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -55,7 +55,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) attr |= DMA_ATTR_NO_KERNEL_MAPPING; exynos_gem->dma_attrs = attr; - exynos_gem->cookie = dma_alloc_attrs(drm_dev_dma_dev(dev), exynos_gem->size, + exynos_gem->cookie = dma_alloc_attrs(drm_dev_dma_dev(dev), exynos_gem->base.size, &exynos_gem->dma_addr, GFP_KERNEL, exynos_gem->dma_attrs); if (!exynos_gem->cookie) { @@ -67,7 +67,7 @@ static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem, bool kvmap) exynos_gem->kvaddr = exynos_gem->cookie; DRM_DEV_DEBUG_KMS(drm_dev_dma_dev(dev), "dma_addr(0x%lx), size(0x%lx)\n", - (unsigned long)exynos_gem->dma_addr, exynos_gem->size); + (unsigned long)exynos_gem->dma_addr, exynos_gem->base.size); return 0; } @@ -81,9 +81,9 @@ static void exynos_drm_free_buf(struct exynos_drm_gem *exynos_gem) } DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr(0x%lx), size(0x%lx)\n", - (unsigned long)exynos_gem->dma_addr, exynos_gem->size); + (unsigned long)exynos_gem->dma_addr, exynos_gem->base.size); - dma_free_attrs(drm_dev_dma_dev(dev), exynos_gem->size, exynos_gem->cookie, + dma_free_attrs(drm_dev_dma_dev(dev), exynos_gem->base.size, exynos_gem->cookie, (dma_addr_t)exynos_gem->dma_addr, exynos_gem->dma_attrs); } @@ -162,7 +162,6 @@ static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev, if (!exynos_gem) return ERR_PTR(-ENOMEM); - exynos_gem->size = size; obj = &exynos_gem->base; obj->funcs = &exynos_drm_gem_object_funcs; @@ -287,11 +286,11 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem, vm_size = vma->vm_end - vma->vm_start; /* check if user-requested size is valid. */ - if (vm_size > exynos_gem->size) + if (vm_size > exynos_gem->base.size) return -EINVAL; ret = dma_mmap_attrs(drm_dev_dma_dev(drm_dev), vma, exynos_gem->cookie, - exynos_gem->dma_addr, exynos_gem->size, + exynos_gem->dma_addr, exynos_gem->base.size, exynos_gem->dma_attrs); if (ret < 0) { DRM_ERROR("failed to mmap.\n"); @@ -317,7 +316,7 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, exynos_gem = to_exynos_gem(obj); args->flags = exynos_gem->flags; - args->size = exynos_gem->size; + args->size = obj->size; drm_gem_object_put(obj); @@ -411,7 +410,7 @@ struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) return ERR_PTR(-ENOMEM); ret = dma_get_sgtable_attrs(drm_dev_dma_dev(drm_dev), sgt, exynos_gem->cookie, - exynos_gem->dma_addr, exynos_gem->size, + exynos_gem->dma_addr, obj->size, exynos_gem->dma_attrs); if (ret) { DRM_ERROR("failed to get sgtable, %d\n", ret); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index b6785f1136ab..3ff9fa9955ea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -22,8 +22,6 @@ * - a new handle to this gem object would be created * by drm_gem_handle_create(). * @flags: indicate memory type to allocated buffer and cache attruibute. - * @size: size requested from user, in bytes and this size is aligned - * in page unit. * @cookie: cookie returned by dma_alloc_attrs * @kvaddr: kernel virtual address to allocated memory region (for fbdev) * @dma_addr: bus address(accessed by dma) to allocated memory region. @@ -38,7 +36,6 @@ struct exynos_drm_gem { struct drm_gem_object base; unsigned int flags; - unsigned long size; void *cookie; void *kvaddr; dma_addr_t dma_addr; diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index ee3d61345a66..43bc4f63bb84 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -364,7 +364,7 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf, } buf->exynos_gem[i] = gem; - if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) { + if (size + buf->buf.offset[i] > buf->exynos_gem[i]->base.size) { i++; ret = -EINVAL; goto gem_free; From 0867757f1eec0a246c70b2407a1bbed949170821 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:43:06 +0800 Subject: [PATCH 04/10] drm/exynos: Drop MAX_FB_BUFFER in favor of DRM_FORMAT_MAX_PLANES MAX_FB_BUFFER refers to the maximum number of buffer planes for a framebuffer. This is the same as DRM_FORMAT_MAX_PLANES, which denotes the maximum number of planes. Signed-off-by: Chen-Yu Tsai Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - drivers/gpu/drm/exynos/exynos_drm_fb.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_ipp.h | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 1ab7195d09ae..b126cd129944 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -19,7 +19,6 @@ #define MAX_CRTC 3 #define MAX_PLANE 5 -#define MAX_FB_BUFFER 4 #define DEFAULT_WIN 0 diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 125b87adfdc4..93f387b12126 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -99,7 +99,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *mode_cmd) { - struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; + struct exynos_drm_gem *exynos_gem[DRM_FORMAT_MAX_PLANES]; struct drm_framebuffer *fb; int i; int ret; @@ -145,7 +145,7 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index) { struct exynos_drm_gem *exynos_gem; - if (WARN_ON_ONCE(index >= MAX_FB_BUFFER)) + if (WARN_ON_ONCE(index >= DRM_FORMAT_MAX_PLANES)) return 0; exynos_gem = to_exynos_gem(fb->obj[index]); diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h index 67a0805ee009..2842c8af0b7c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.h @@ -70,9 +70,9 @@ struct exynos_drm_ipp_buffer { struct drm_exynos_ipp_task_buffer buf; struct drm_exynos_ipp_task_rect rect; - struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; + struct exynos_drm_gem *exynos_gem[DRM_FORMAT_MAX_PLANES]; const struct drm_format_info *format; - dma_addr_t dma_addr[MAX_FB_BUFFER]; + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; }; /** From 5633d4402ce140bbc6f5e3f7f75f9f7fc0cd6923 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 26 Mar 2026 17:30:38 +0800 Subject: [PATCH 05/10] drm/exynos/dma: Drop iommu_dma_init_domain() stub Commit 1feda5eb77fc ("drm/exynos: Use selected dma_dev default iommu domain instead of a fake one") removed the code around creating a custom IOMMU domain, but forgot to remove the stub. Remove the iommu_dma_init_domain() stub as the function is no longer referenced, and was also made private to the IOMMU DMA code. Signed-off-by: Chen-Yu Tsai Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dma.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dma.c b/drivers/gpu/drm/exynos/exynos_drm_dma.c index bde2b86a7a7d..734741c80cbe 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dma.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dma.c @@ -24,10 +24,6 @@ #define to_dma_iommu_mapping(dev) NULL #endif -#if !defined(CONFIG_IOMMU_DMA) -#define iommu_dma_init_domain(...) ({ -EINVAL; }) -#endif - #define EXYNOS_DEV_ADDR_START 0x20000000 #define EXYNOS_DEV_ADDR_SIZE 0x40000000 From 760bbc58c2c833dec0ee38dd959f4f2f4084fc57 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 11 May 2026 13:54:31 +0200 Subject: [PATCH 06/10] drm/exynos: fbdev: Remove offset into screen_buffer The screen_buffer field in struct fb_info contains the kernel address of the first byte of framebuffer memory. Do not add the display offset. This offset only describes scrolling during scanout. Signed-off-by: Thomas Zimmermann Fixes: 19c8b8343d9c ("drm/exynos: fixed overlay data updating.") Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae Cc: dri-devel@lists.freedesktop.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Cc: # v3.2+ --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 637927818dfe..d283ded266d5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -61,17 +61,13 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, struct fb_info *fbi = helper->info; struct drm_framebuffer *fb = helper->fb; unsigned int size = fb->width * fb->height * fb->format->cpp[0]; - unsigned long offset; fbi->fbops = &exynos_drm_fb_ops; drm_fb_helper_fill_info(fbi, helper, sizes); - offset = fbi->var.xoffset * fb->format->cpp[0]; - offset += fbi->var.yoffset * fb->pitches[0]; - fbi->flags |= FBINFO_VIRTFB; - fbi->screen_buffer = exynos_gem->kvaddr + offset; + fbi->screen_buffer = exynos_gem->kvaddr; fbi->screen_size = size; fbi->fix.smem_len = size; From b4edfb1b4689f3b336f9feb26dec9213917aac18 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 11 May 2026 13:54:32 +0200 Subject: [PATCH 07/10] drm/exynos: fbdev: Inline exynos_drm_fbdev_update() Inline exynos_drm_fbdev_update() into its only caller. Prepares the code for using DRM client buffers. Signed-off-by: Thomas Zimmermann Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 35 ++++++----------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index d283ded266d5..1c564edd497e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -54,26 +54,6 @@ static const struct fb_ops exynos_drm_fb_ops = { .fb_destroy = exynos_drm_fb_destroy, }; -static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes, - struct exynos_drm_gem *exynos_gem) -{ - struct fb_info *fbi = helper->info; - struct drm_framebuffer *fb = helper->fb; - unsigned int size = fb->width * fb->height * fb->format->cpp[0]; - - fbi->fbops = &exynos_drm_fb_ops; - - drm_fb_helper_fill_info(fbi, helper, sizes); - - fbi->flags |= FBINFO_VIRTFB; - fbi->screen_buffer = exynos_gem->kvaddr; - fbi->screen_size = size; - fbi->fix.smem_len = size; - - return 0; -} - static const struct drm_fb_helper_funcs exynos_drm_fbdev_helper_funcs = { }; @@ -82,6 +62,7 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, { struct exynos_drm_gem *exynos_gem; struct drm_device *dev = helper->dev; + struct fb_info *info = helper->info; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; unsigned long size; int ret; @@ -115,15 +96,17 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, } helper->funcs = &exynos_drm_fbdev_helper_funcs; - ret = exynos_drm_fbdev_update(helper, sizes, exynos_gem); - if (ret < 0) - goto err_destroy_framebuffer; + info->fbops = &exynos_drm_fb_ops; + + drm_fb_helper_fill_info(info, helper, sizes); + + info->flags |= FBINFO_VIRTFB; + info->screen_buffer = exynos_gem->kvaddr; + info->screen_size = size; + info->fix.smem_len = size; return 0; -err_destroy_framebuffer: - drm_framebuffer_cleanup(helper->fb); - helper->fb = NULL; err_destroy_gem: exynos_drm_gem_destroy(exynos_gem); return ret; From 7878a215fdd5c2805535077327aada200c7054d3 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 11 May 2026 13:54:33 +0200 Subject: [PATCH 08/10] drm/exynos: fbdev: Calculate buffer geometry with format helpers Replace the geometry and size calculation in exynos' fbdev emulation with DRM format helpers. This consists of a 4CC lookup from the fbdev parameters, format lookup, pitch calculation and size calculation. Then allocate the GEM buffer object for the framebuffer memory from the calculated size. Mmap provides the allocated buffer to user space, so align the buffer size to PAGE_SIZE. Initialize the fields screen_size and fix.smem_len in struct fb_info from the size of the allocated buffer object. This is the real size and can differ from the requested size. v3: - add more error checks to geometry calculations Signed-off-by: Thomas Zimmermann Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 45 +++++++++++++++-------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 1c564edd497e..9163efd676dd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -60,11 +60,14 @@ static const struct drm_fb_helper_funcs exynos_drm_fbdev_helper_funcs = { int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct exynos_drm_gem *exynos_gem; struct drm_device *dev = helper->dev; struct fb_info *info = helper->info; + u32 fourcc, pitch; + u64 size; + const struct drm_format_info *format; + struct exynos_drm_gem *exynos_gem; + struct drm_gem_object *obj; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; - unsigned long size; int ret; DRM_DEV_DEBUG_KMS(dev->dev, @@ -72,23 +75,33 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, sizes->surface_width, sizes->surface_height, sizes->surface_bpp); - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + if (fourcc == DRM_FORMAT_INVALID) + return -EINVAL; + format = drm_get_format_info(dev, fourcc, DRM_FORMAT_MOD_LINEAR); + if (!format) + return -EINVAL; + pitch = drm_format_info_min_pitch(format, 0, sizes->surface_width); + if (!pitch) + return -EINVAL; + if (check_mul_overflow(pitch, sizes->surface_height, &size)) + return -EINVAL; + size = ALIGN(size, PAGE_SIZE); + if (size < PAGE_SIZE) + return -EINVAL; exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_WC, size, true); if (IS_ERR(exynos_gem)) return PTR_ERR(exynos_gem); + obj = &exynos_gem->base; - helper->fb = - exynos_drm_framebuffer_init(dev, - drm_get_format_info(dev, mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd, &exynos_gem, 1); + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + mode_cmd.pixel_format = fourcc; + mode_cmd.pitches[0] = pitch; + mode_cmd.modifier[0] = DRM_FORMAT_MOD_LINEAR; + + helper->fb = exynos_drm_framebuffer_init(dev, format, &mode_cmd, &exynos_gem, 1); if (IS_ERR(helper->fb)) { DRM_DEV_ERROR(dev->dev, "failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); @@ -102,8 +115,8 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, info->flags |= FBINFO_VIRTFB; info->screen_buffer = exynos_gem->kvaddr; - info->screen_size = size; - info->fix.smem_len = size; + info->screen_size = obj->size; + info->fix.smem_len = obj->size; return 0; From 65b6a41252e8fce8204da5546f04c7fbdabb51a4 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 11 May 2026 13:54:34 +0200 Subject: [PATCH 09/10] drm/exynos: fbdev: Use a DRM client buffer Replace the internal DRM framebuffer with a DRM client buffer. The client buffer allocates the DRM framebuffer on a file and also uses GEM object handles via the regular ADDFB2 interfaces. Using client-buffer interfaces unifies framebuffer allocation for DRM clients in user space and exynos' internal fbdev emulation. It also simplifies the clean-up side of the fbdev emulation. Signed-off-by: Thomas Zimmermann Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 44 ++++++++++++++--------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 9163efd676dd..121c342dd14a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -36,12 +36,10 @@ static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) static void exynos_drm_fb_destroy(struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_framebuffer *fb = fb_helper->fb; drm_fb_helper_fini(fb_helper); - drm_framebuffer_remove(fb); - + drm_client_buffer_delete(fb_helper->buffer); drm_client_release(&fb_helper->client); } @@ -60,14 +58,17 @@ static const struct drm_fb_helper_funcs exynos_drm_fbdev_helper_funcs = { int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct drm_device *dev = helper->dev; + struct drm_client_dev *client = &helper->client; + struct drm_device *dev = client->dev; + struct drm_file *file = client->file; struct fb_info *info = helper->info; u32 fourcc, pitch; u64 size; const struct drm_format_info *format; struct exynos_drm_gem *exynos_gem; struct drm_gem_object *obj; - struct drm_mode_fb_cmd2 mode_cmd = { 0 }; + struct drm_client_buffer *buffer; + u32 handle; int ret; DRM_DEV_DEBUG_KMS(dev->dev, @@ -95,19 +96,20 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, return PTR_ERR(exynos_gem); obj = &exynos_gem->base; - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pixel_format = fourcc; - mode_cmd.pitches[0] = pitch; - mode_cmd.modifier[0] = DRM_FORMAT_MOD_LINEAR; + ret = drm_gem_handle_create(file, obj, &handle); + if (ret) + goto err_drm_gem_object_put; - helper->fb = exynos_drm_framebuffer_init(dev, format, &mode_cmd, &exynos_gem, 1); - if (IS_ERR(helper->fb)) { - DRM_DEV_ERROR(dev->dev, "failed to create drm framebuffer.\n"); - ret = PTR_ERR(helper->fb); - goto err_destroy_gem; + buffer = drm_client_buffer_create(client, sizes->surface_width, sizes->surface_height, + fourcc, handle, pitch); + if (IS_ERR(buffer)) { + ret = PTR_ERR(buffer); + goto err_drm_gem_handle_delete; } + helper->funcs = &exynos_drm_fbdev_helper_funcs; + helper->buffer = buffer; + helper->fb = buffer->fb; info->fbops = &exynos_drm_fb_ops; @@ -118,9 +120,17 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, info->screen_size = obj->size; info->fix.smem_len = obj->size; + /* The handle is only needed for creating the framebuffer. */ + drm_gem_handle_delete(file, handle); + + /* The framebuffer still holds a reference on the GEM object. */ + drm_gem_object_put(obj); + return 0; -err_destroy_gem: - exynos_drm_gem_destroy(exynos_gem); +err_drm_gem_handle_delete: + drm_gem_handle_delete(file, handle); +err_drm_gem_object_put: + drm_gem_object_put(obj); return ret; } From b9bb45aeaf028450c753782280922d31120b342a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 11 May 2026 13:54:35 +0200 Subject: [PATCH 10/10] drm/exynos: Make exynos_drm_framebuffer_init() an internal interface The only caller of exynos_drm_framebuffer_init() is the helper exynos_user_fb_create() from the same source file. Declare the former as static. Tidy up the header's include statements. v2: - clean up the includes in the header file (Chen-Yu) Signed-off-by: Thomas Zimmermann Tested-by: Marek Szyprowski Acked-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 3 ++- drivers/gpu/drm/exynos/exynos_drm_fb.h | 10 +++------- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 93f387b12126..4cff2b2b630f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -22,6 +22,7 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_fbdev.h" +#include "exynos_drm_gem.h" static int check_fb_gem_memory_type(struct drm_device *drm_dev, struct exynos_drm_gem *exynos_gem) @@ -55,7 +56,7 @@ static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = { .create_handle = drm_gem_fb_create_handle, }; -struct drm_framebuffer * +static struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *mode_cmd, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index fdc6cb40cc9c..74300ad9bb51 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -10,14 +10,10 @@ #ifndef _EXYNOS_DRM_FB_H_ #define _EXYNOS_DRM_FB_H_ -#include "exynos_drm_gem.h" +#include -struct drm_framebuffer * -exynos_drm_framebuffer_init(struct drm_device *dev, - const struct drm_format_info *info, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct exynos_drm_gem **exynos_gem, - int count); +struct drm_device; +struct drm_framebuffer; dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 121c342dd14a..8641c9e84d4c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -22,6 +22,7 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_fbdev.h" +#include "exynos_drm_gem.h" #define MAX_CONNECTOR 4