From ba40db36971a59f197b41219e8ffc6ce9998df82 Mon Sep 17 00:00:00 2001 From: Honglei Huang Date: Tue, 30 Jun 2026 18:21:23 +0800 Subject: [PATCH 01/61] drm/gpusvm: split MM state flags out of drm_gpusvm_pages_flags drm_gpusvm_pages_flags currently mixes two status: - MM / virtual-address state: whether the range has been (partially) unmapped by the Linux MM, these follow the lifetime of the VMA and are a single per VA range fact. - Device mapping state: has_devmem_pages and has_dma_mapping, which describe the current page mapping status held by device itself. Keeping both on the pages object blurs the semantics of the abstraction of pages and VA range. So move the MM state flags onto the range, and keep drm_gpusvm_pages_flags strictly for mapping state. - Introduce drm_gpusvm_range_flags { migrate_devmem, unmapped, partial_unmap } on drm_gpusvm_range. - Shrink drm_gpusvm_pages_flags to just has_devmem_pages and has_dma_mapping. Side effect: drivers now need to check the unmap flags in the driver itself to avoid handling the unmapped pages. Mirror that bit onto drm_gpusvm_pages so the framework can still short circuit drm_gpusvm_get_pages() under the notifier lock, and make drm_gpusvm_range_set_unmapped() propagate it to the backing pages. This follows Matt's review fixup for the v0 series; see the Link below. Like drm_gpusvm_pages_flags, drm_gpusvm_range_flags unions its bits with a u16 __flags member. Build the new value in a local copy and publish it with a single WRITE_ONCE() on __flags, and have the lockless readers use READ_ONCE(), so concurrent bitfield access stays data-race free and KCSAN quiet. Suggested-by: Matthew Brost Reviewed-by: Matthew Brost Link: https://gitlab.freedesktop.org/mbrost/xe-kernel-driver-svn-perf-6-15-2025/-/commit/623f6a50c037d9e44f6c9fbe6859a0ba7ad50177 Signed-off-by: Honglei Huang Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260630102127.392396-2-honghuan@amd.com --- drivers/gpu/drm/drm_gpusvm.c | 26 +++++++++++++++++++++++--- drivers/gpu/drm/xe/xe_svm.c | 22 +++++++++++++++++----- include/drm/drm_gpusvm.h | 30 +++++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 958cb605aedd..abdfdaaf5e23 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -641,7 +641,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm, range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1; INIT_LIST_HEAD(&range->entry); range->pages.notifier_seq = LONG_MAX; - range->pages.flags.migrate_devmem = migrate_devmem ? 1 : 0; + range->flags.migrate_devmem = migrate_devmem ? 1 : 0; return range; } @@ -1784,20 +1784,40 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_has_mapping); /** * drm_gpusvm_range_set_unmapped() - Mark a GPU SVM range as unmapped * @range: Pointer to the GPU SVM range structure. + * @pages: Pointer to the GPU SVM pages structure(s). + * @pages_count: Number of GPU SVM pages structure(s) passed in. * @mmu_range: Pointer to the MMU notifier range structure. * * This function marks a GPU SVM range as unmapped and sets the partial_unmap flag * if the range partially falls within the provided MMU notifier range. */ void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range, + struct drm_gpusvm_pages *pages, + unsigned int pages_count, const struct mmu_notifier_range *mmu_range) { + struct drm_gpusvm_range_flags range_flags = { + .__flags = range->flags.__flags, + }; + unsigned int i; + lockdep_assert_held_write(&range->gpusvm->notifier_lock); - range->pages.flags.unmapped = true; + range_flags.unmapped = true; + for (i = 0; i < pages_count; ++i) { + struct drm_gpusvm_pages_flags flags = { + .__flags = pages[i].flags.__flags, + }; + + flags.unmapped = true; + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + WRITE_ONCE(pages[i].flags.__flags, flags.__flags); + } if (drm_gpusvm_range_start(range) < mmu_range->start || drm_gpusvm_range_end(range) > mmu_range->end) - range->pages.flags.partial_unmap = true; + range_flags.partial_unmap = true; + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + WRITE_ONCE(range->flags.__flags, range_flags.__flags); } EXPORT_SYMBOL_GPL(drm_gpusvm_range_set_unmapped); diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index e0f0c23d172d..28a5d95945c3 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -134,7 +134,8 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, struct xe_svm_range *range, range_debug(range, "GARBAGE COLLECTOR ADD"); - drm_gpusvm_range_set_unmapped(&range->base, mmu_range); + drm_gpusvm_range_set_unmapped(&range->base, &range->base.pages, 1, + mmu_range); spin_lock(&vm->svm.garbage_collector.lock); if (list_empty(&range->garbage_collector_link)) @@ -166,7 +167,7 @@ xe_svm_range_notifier_event_begin(struct xe_vm *vm, struct drm_gpusvm_range *r, range_debug(range, "NOTIFIER"); /* Skip if already unmapped or if no binding exist */ - if (range->base.pages.flags.unmapped || !range->tile_present) + if (range->base.flags.unmapped || !range->tile_present) return 0; range_debug(range, "NOTIFIER - EXECUTE"); @@ -1135,8 +1136,12 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm { struct xe_vm *vm = range_to_vm(&range->base); u64 range_size = xe_svm_range_size(range); + struct drm_gpusvm_range_flags flags = { + /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */ + .__flags = READ_ONCE(range->base.flags.__flags), + }; - if (!range->base.pages.flags.migrate_devmem || !dpagemap) + if (!flags.migrate_devmem || !dpagemap) return false; xe_assert(vm->xe, IS_DGFX(vm->xe)); @@ -1220,6 +1225,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma, struct xe_validation_ctx vctx; struct drm_exec exec; struct xe_svm_range *range; + struct drm_gpusvm_range_flags range_flags; struct dma_fence *fence; struct drm_pagemap *dpagemap; struct xe_tile *tile = gt_to_tile(gt); @@ -1248,7 +1254,9 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma, xe_svm_range_fault_count_stats_incr(gt, range); - if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) + /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */ + range_flags.__flags = READ_ONCE(range->base.flags.__flags); + if (ctx.devmem_only && !range_flags.migrate_devmem) return -EACCES; if (xe_svm_range_is_valid(range, tile, ctx.devmem_only, dpagemap)) { @@ -1620,8 +1628,12 @@ int xe_svm_alloc_vram(struct xe_svm_range *range, const struct drm_gpusvm_ctx *c struct xe_device *xe = vm->xe; int err, retries = 1; bool write_locked = false; + struct drm_gpusvm_range_flags flags = { + /* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */ + .__flags = READ_ONCE(range->base.flags.__flags), + }; - xe_assert(range_to_vm(&range->base)->xe, range->base.pages.flags.migrate_devmem); + xe_assert(range_to_vm(&range->base)->xe, flags.migrate_devmem); range_debug(range, "ALLOCATE VRAM"); migration_state = drm_gpusvm_scan_mm(&range->base, diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index 8a4d7134a9a7..251a7266a73f 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -109,9 +109,7 @@ struct drm_gpusvm_notifier { /** * struct drm_gpusvm_pages_flags - Structure representing a GPU SVM pages flags * - * @migrate_devmem: Flag indicating whether the pages can be migrated to device memory * @unmapped: Flag indicating if the pages has been unmapped - * @partial_unmap: Flag indicating if the pages has been partially unmapped * @has_devmem_pages: Flag indicating if the pages has devmem pages * @has_dma_mapping: Flag indicating if the pages has a DMA mapping * @__flags: Flags for pages in u16 form (used for READ_ONCE) @@ -119,11 +117,8 @@ struct drm_gpusvm_notifier { struct drm_gpusvm_pages_flags { union { struct { - /* All flags below must be set upon creation */ - u16 migrate_devmem : 1; /* All flags below must be set / cleared under notifier lock */ u16 unmapped : 1; - u16 partial_unmap : 1; u16 has_devmem_pages : 1; u16 has_dma_mapping : 1; }; @@ -151,6 +146,27 @@ struct drm_gpusvm_pages { struct drm_gpusvm_pages_flags flags; }; +/** + * struct drm_gpusvm_range_flags - Range-level GPU SVM flags + * + * @migrate_devmem: Flag indicating whether the range can be migrated to device memory + * @unmapped: Flag indicating if the range has been unmapped + * @partial_unmap: Flag indicating if the range has been partially unmapped + * @__flags: All flags in u16 form (used for READ_ONCE) + */ +struct drm_gpusvm_range_flags { + union { + struct { + /* All flags below must be set upon creation */ + u16 migrate_devmem : 1; + /* All flags below must be set / cleared under notifier lock */ + u16 unmapped : 1; + u16 partial_unmap : 1; + }; + u16 __flags; + }; +}; + /** * struct drm_gpusvm_range - Structure representing a GPU SVM range * @@ -160,6 +176,7 @@ struct drm_gpusvm_pages { * @itree: Interval tree node for the range (inserted in GPU SVM notifier) * @entry: List entry to fast interval tree traversal * @pages: The pages for this range. + * @flags: Flags for range see &struct drm_gpusvm_range_flags * * This structure represents a GPU SVM range used for tracking memory ranges * mapped in a DRM device. @@ -171,6 +188,7 @@ struct drm_gpusvm_range { struct interval_tree_node itree; struct list_head entry; struct drm_gpusvm_pages pages; + struct drm_gpusvm_range_flags flags; }; /** @@ -310,6 +328,8 @@ drm_gpusvm_range_find(struct drm_gpusvm_notifier *notifier, unsigned long start, unsigned long end); void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range, + struct drm_gpusvm_pages *pages, + unsigned int pages_count, const struct mmu_notifier_range *mmu_range); int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, From 1d0c4c15c2a62fc15bf69b9e72c30461b2e9346f Mon Sep 17 00:00:00 2001 From: Honglei Huang Date: Tue, 30 Jun 2026 18:21:24 +0800 Subject: [PATCH 02/61] drm/gpusvm: embed struct drm_device into drm_gpusvm_pages drm_gpusvm_pages is the layer that actually represents physical pages/mappings it owns the dma_addr array, the dma_iova_state... With the previous patch, so drm_gpusvm_pages is now strictly about physical pages and their DMA view. Since now the drm_gpusvm_pages instance is inherently bound to one specific drm_device, make that ownership explicit by giving drm_gpusvm_pages its own drm_device handle, and drive all DMA through it instead of through the gpusvm: - Add drm to struct drm_gpusvm_pages and route all DMA in drm_gpusvm_get_pages() / __drm_gpusvm_unmap_pages() through svm_pages->drm instead of gpusvm->drm. - Bind svm_pages->drm where the pages object is initialised (drm_gpusvm_range_alloc() and the xe userptr setup) and require it to be set on entry to drm_gpusvm_get_pages(); the dma device is immutable for the lifetime of the pages instance. A later patch introduces drm_gpusvm_init_pages() to centralise this. Suggested-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: Honglei Huang Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260630102127.392396-3-honghuan@amd.com --- drivers/gpu/drm/drm_gpusvm.c | 30 ++++++++++++++++++++---------- drivers/gpu/drm/xe/xe_userptr.c | 2 ++ include/drm/drm_gpusvm.h | 2 ++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index abdfdaaf5e23..604554e40f62 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -641,6 +641,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm, range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1; INIT_LIST_HEAD(&range->entry); range->pages.notifier_seq = LONG_MAX; + range->pages.drm = gpusvm->drm; range->flags.migrate_devmem = migrate_devmem ? 1 : 0; return range; @@ -1135,11 +1136,16 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, unsigned long npages) { struct drm_pagemap *dpagemap = svm_pages->dpagemap; - struct device *dev = gpusvm->drm->dev; + struct device *dev; unsigned long i, j; lockdep_assert_held(&gpusvm->notifier_lock); + if (!svm_pages->drm) + return; + + dev = svm_pages->drm->dev; + if (svm_pages->flags.has_dma_mapping) { struct drm_gpusvm_pages_flags flags = { .__flags = svm_pages->flags.__flags, @@ -1421,6 +1427,9 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, DMA_BIDIRECTIONAL; struct dma_iova_state *state = &svm_pages->state; + if (!svm_pages->drm) + return -EINVAL; + retry: if (time_after(jiffies, timeout)) return -EBUSY; @@ -1520,7 +1529,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, pagemap = page_pgmap(page); dpagemap = drm_pagemap_page_to_dpagemap(page); - if (drm_WARN_ON(gpusvm->drm, !dpagemap)) { + if (drm_WARN_ON(svm_pages->drm, !dpagemap)) { /* * Raced. This is not supposed to happen * since hmm_range_fault() should've migrated @@ -1532,10 +1541,10 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, } svm_pages->dma_addr[j] = dpagemap->ops->device_map(dpagemap, - gpusvm->drm->dev, + svm_pages->drm->dev, page, order, dma_dir); - if (dma_mapping_error(gpusvm->drm->dev, + if (dma_mapping_error(svm_pages->drm->dev, svm_pages->dma_addr[j].addr)) { err = -EFAULT; goto err_unmap; @@ -1555,11 +1564,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, } if (!i) - dma_iova_try_alloc(gpusvm->drm->dev, state, + dma_iova_try_alloc(svm_pages->drm->dev, state, 0, npages * PAGE_SIZE); if (dma_use_iova(state)) { - err = dma_iova_link(gpusvm->drm->dev, state, + err = dma_iova_link(svm_pages->drm->dev, state, hmm_pfn_to_phys(pfns[i]), svm_pages->state_offset, PAGE_SIZE << order, @@ -1570,11 +1579,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, addr = state->addr + svm_pages->state_offset; svm_pages->state_offset += PAGE_SIZE << order; } else { - addr = dma_map_page(gpusvm->drm->dev, + addr = dma_map_page(svm_pages->drm->dev, page, 0, PAGE_SIZE << order, dma_dir); - if (dma_mapping_error(gpusvm->drm->dev, addr)) { + if (dma_mapping_error(svm_pages->drm->dev, addr)) { err = -EFAULT; goto err_unmap; } @@ -1590,7 +1599,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, } if (dma_use_iova(state)) { - err = dma_iova_sync(gpusvm->drm->dev, state, 0, + err = dma_iova_sync(svm_pages->drm->dev, state, 0, svm_pages->state_offset); if (err) goto err_unmap; @@ -1640,7 +1649,8 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range, const struct drm_gpusvm_ctx *ctx) { - return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm, + return drm_gpusvm_get_pages(gpusvm, &range->pages, + gpusvm->mm, &range->notifier->notifier, drm_gpusvm_range_start(range), drm_gpusvm_range_end(range), ctx); diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index 1d2ab678faf5..d409c82104f4 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -390,6 +390,7 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start, unsigned long range) { struct xe_userptr *userptr = &uvma->userptr; + struct xe_vm *vm = xe_vma_vm(&uvma->vma); int err; INIT_LIST_HEAD(&userptr->invalidate_link); @@ -402,6 +403,7 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start, return err; userptr->pages.notifier_seq = LONG_MAX; + userptr->pages.drm = &vm->xe->drm; return 0; } diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index 251a7266a73f..842353afb27b 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -129,6 +129,7 @@ struct drm_gpusvm_pages_flags { /** * struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages * + * @drm: The DRM device that owns the dma mappings * @dma_addr: Device address array * @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping. * Note this is assuming only one drm_pagemap per range is allowed. @@ -138,6 +139,7 @@ struct drm_gpusvm_pages_flags { * @flags: Flags for the range; see &struct drm_gpusvm_pages_flags */ struct drm_gpusvm_pages { + struct drm_device *drm; struct drm_pagemap_addr *dma_addr; struct drm_pagemap *dpagemap; struct dma_iova_state state; From 24c339202c0bc83e9e9e945eeee618ececc6a88b Mon Sep 17 00:00:00 2001 From: Honglei Huang Date: Tue, 30 Jun 2026 18:21:25 +0800 Subject: [PATCH 03/61] drm/xe: have xe_svm_range embed one drm_gpusvm_pages With drm_gpusvm_pages now self contained, make xe stop relying on the drm_gpusvm_range pages and take responsibility for the page lifecycle on the driver side. Driver side (xe): - Embed struct drm_gpusvm_pages in xe_svm_range and route all xe accesses through it instead of range->base.pages. - Initialise the embedded pages via drm_gpusvm_init_pages(), which binds the owning &xe->drm up front, and take over the page lifecycle: xe_svm_range_get_pages() calls drm_gpusvm_get_pages() directly; the notifier event_end and xe_svm_range_free() paths drive unmap/free on the embedded pages object. - Convert the open-coded userptr pages init in xe_userptr_setup() to the same drm_gpusvm_init_pages() helper. - Switch xe_svm_range_pages_valid() to drm_gpusvm_pages_valid(). Framework side (drm_gpusvm): - Add a small inline drm_gpusvm_init_pages() helper that records the owning drm_device and initialises the per-pages state, giving drivers a single hook to extend. - Export drm_gpusvm_pages_valid() to let driver owned pages can query mapping state without going through a range. - Lifecycle change: drm_gpusvm_range_remove() no longer *triggers* unmap/free of the embedded pages. The unmap/free logic itself stays in the framework -- drm_gpusvm_free_pages() still performs the DMA unmap (as an idempotent backstop) and frees the dma_addr array -- but the driver now owns *when* it runs, since the driver owns the drm_gpusvm_pages object. Side effect / contract: a driver that owns a drm_gpusvm_pages is now responsible for its lifecycle: drm_gpusvm_init_pages() before first use, and drm_gpusvm_free_pages() when the owner goes away. Xe does the latter from its ops->range_free callback, which the framework invokes once the range refcount drops to zero in drm_gpusvm_range_remove(). The timely DMA unmap for the IOMMU security model still happens in the notifier invalidate path via drm_gpusvm_unmap_pages(); the unmap inside drm_gpusvm_free_pages() is only a backstop for pages that were never invalidated. Suggested-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: Honglei Huang Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260630102127.392396-4-honghuan@amd.com --- drivers/gpu/drm/drm_gpusvm.c | 16 ++++++++----- drivers/gpu/drm/xe/xe_pt.c | 2 +- drivers/gpu/drm/xe/xe_svm.c | 42 ++++++++++++++++++++++++++------- drivers/gpu/drm/xe/xe_svm.h | 12 ++++++---- drivers/gpu/drm/xe/xe_userptr.c | 5 ++-- include/drm/drm_gpusvm.h | 20 ++++++++++++++++ 6 files changed, 74 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index 604554e40f62..b0e9a2db1080 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -1228,12 +1228,17 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages); * This function removes the specified GPU SVM range and also removes the parent * GPU SVM notifier if no more ranges remain in the notifier. The caller must * hold a lock to protect range and notifier removal. + * + * This function does not unmap or free the drm_gpusvm_pages, the driver owns + * that lifecycle. The caller must DMA unmap the range's pages before calling + * this function, so a range is never removed from the MMU interval tree while + * still DMA mapped. Typically the driver calls drm_gpusvm_unmap_pages() first. + * And the range_free callback's drm_gpusvm_free_pages() is a final fallback safe + * net. */ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) { - unsigned long npages = npages_in_range(drm_gpusvm_range_start(range), - drm_gpusvm_range_end(range)); struct drm_gpusvm_notifier *notifier; drm_gpusvm_driver_lock_held(gpusvm); @@ -1245,8 +1250,6 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm, return; drm_gpusvm_notifier_lock(gpusvm); - __drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages); - __drm_gpusvm_free_pages(gpusvm, &range->pages); __drm_gpusvm_range_remove(notifier, range); drm_gpusvm_notifier_unlock(gpusvm); @@ -1325,13 +1328,14 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put); * * Return: True if GPU SVM range has valid pages, False otherwise */ -static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_pages *svm_pages) +bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages) { lockdep_assert_held(&gpusvm->notifier_lock); return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping; } +EXPORT_SYMBOL_GPL(drm_gpusvm_pages_valid); /** * drm_gpusvm_range_pages_valid() - GPU SVM range pages valid diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 5fdad444009f..c48ddc888cb0 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -760,7 +760,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, return -EAGAIN; } if (xe_svm_range_has_dma_mapping(range)) { - xe_res_first_dma(range->base.pages.dma_addr, 0, + xe_res_first_dma(range->pages.dma_addr, 0, xe_svm_range_size(range), &curs); xe_svm_range_debug(range, "BIND PREPARE - MIXED"); diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 28a5d95945c3..8b48a942f3e6 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -66,7 +66,7 @@ static bool xe_svm_range_in_vram(struct xe_svm_range *range) struct drm_gpusvm_pages_flags flags = { /* Pairs with WRITE_ONCE in drm_gpusvm.c */ - .__flags = READ_ONCE(range->base.pages.flags.__flags), + .__flags = READ_ONCE(range->pages.flags.__flags), }; return flags.has_devmem_pages; @@ -96,7 +96,7 @@ static struct xe_vm *range_to_vm(struct drm_gpusvm_range *r) (r__)->base.gpusvm, \ xe_svm_range_in_vram((r__)) ? 1 : 0, \ xe_svm_range_has_vram_binding((r__)) ? 1 : 0, \ - (r__)->base.pages.notifier_seq, \ + (r__)->pages.notifier_seq, \ xe_svm_range_start((r__)), xe_svm_range_end((r__)), \ xe_svm_range_size((r__))) @@ -115,6 +115,7 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm) return NULL; INIT_LIST_HEAD(&range->garbage_collector_link); + drm_gpusvm_init_pages(&range->pages, &gpusvm_to_vm(gpusvm)->xe->drm); xe_vm_get(gpusvm_to_vm(gpusvm)); return &range->base; @@ -122,8 +123,10 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm) static void xe_svm_range_free(struct drm_gpusvm_range *range) { + drm_gpusvm_free_pages(range->gpusvm, &(to_xe_range(range)->pages), + drm_gpusvm_range_size(range) >> PAGE_SHIFT); xe_vm_put(range_to_vm(range)); - kfree(range); + kfree(to_xe_range(range)); } static void @@ -134,7 +137,7 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, struct xe_svm_range *range, range_debug(range, "GARBAGE COLLECTOR ADD"); - drm_gpusvm_range_set_unmapped(&range->base, &range->base.pages, 1, + drm_gpusvm_range_set_unmapped(&range->base, &range->pages, 1, mmu_range); spin_lock(&vm->svm.garbage_collector.lock); @@ -209,7 +212,8 @@ xe_svm_range_notifier_event_end(struct xe_vm *vm, struct drm_gpusvm_range *r, xe_svm_assert_in_notifier(vm); - drm_gpusvm_range_unmap_pages(&vm->svm.gpusvm, r, &ctx); + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &(to_xe_range(r)->pages), + drm_gpusvm_range_size(r) >> PAGE_SHIFT, &ctx); if (!xe_vm_is_closed(vm) && mmu_range->event == MMU_NOTIFY_UNMAP) xe_svm_garbage_collector_add_range(vm, to_xe_range(r), mmu_range); @@ -300,6 +304,7 @@ static void xe_svm_invalidate(struct drm_gpusvm *gpusvm, static int __xe_svm_garbage_collector(struct xe_vm *vm, struct xe_svm_range *range) { + struct drm_gpusvm_ctx ctx = { .in_notifier = false, }; struct dma_fence *fence; range_debug(range, "GARBAGE COLLECTOR"); @@ -311,6 +316,10 @@ static int __xe_svm_garbage_collector(struct xe_vm *vm, return PTR_ERR(fence); dma_fence_put(fence); + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &range->pages, + drm_gpusvm_range_size(&range->base) >> PAGE_SHIFT, + &ctx); + drm_gpusvm_range_remove(&vm->svm.gpusvm, &range->base); return 0; @@ -945,15 +954,28 @@ void xe_svm_close(struct xe_vm *vm) */ void xe_svm_fini(struct xe_vm *vm) { + struct drm_gpusvm_notifier *notifier, *next; + struct drm_gpusvm_ctx ctx = { .in_notifier = false, }; + xe_assert(vm->xe, xe_vm_is_closed(vm)); + drm_gpusvm_for_each_notifier_safe(notifier, next, &vm->svm.gpusvm, 0, LONG_MAX) { + struct drm_gpusvm_range *range, *__next; + + drm_gpusvm_for_each_range_safe(range, __next, notifier, 0, LONG_MAX) + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, + &(to_xe_range(range)->pages), + drm_gpusvm_range_size(range) >> PAGE_SHIFT, + &ctx); + } + drm_gpusvm_fini(&vm->svm.gpusvm); } static bool xe_svm_range_has_pagemap_locked(const struct xe_svm_range *range, const struct drm_pagemap *dpagemap) { - return range->base.pages.dpagemap == dpagemap; + return range->pages.dpagemap == dpagemap; } static bool xe_svm_range_has_pagemap(struct xe_svm_range *range, @@ -1018,7 +1040,7 @@ bool xe_svm_range_validate(struct xe_vm *vm, if (dpagemap) ret = ret && xe_svm_range_has_pagemap_locked(range, dpagemap); else - ret = ret && !range->base.pages.dpagemap; + ret = ret && !range->pages.dpagemap; xe_svm_notifier_unlock(vm); @@ -1513,7 +1535,11 @@ int xe_svm_range_get_pages(struct xe_vm *vm, struct xe_svm_range *range, { int err = 0; - err = drm_gpusvm_range_get_pages(&vm->svm.gpusvm, &range->base, ctx); + err = drm_gpusvm_get_pages(&vm->svm.gpusvm, &range->pages, + vm->svm.gpusvm.mm, + &range->base.notifier->notifier, + drm_gpusvm_range_start(&range->base), + drm_gpusvm_range_end(&range->base), ctx); if (err == -EOPNOTSUPP) { range_debug(range, "PAGE FAULT - EVICT PAGES"); drm_gpusvm_range_evict(&vm->svm.gpusvm, &range->base); diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h index 3ca46a6f98c7..c8f4a7ba0f4f 100644 --- a/drivers/gpu/drm/xe/xe_svm.h +++ b/drivers/gpu/drm/xe/xe_svm.h @@ -31,6 +31,8 @@ struct xe_vram_region; struct xe_svm_range { /** @base: base drm_gpusvm_range */ struct drm_gpusvm_range base; + /** @pages: Page/DMA mapping state for this range (single drm_device). */ + struct drm_gpusvm_pages pages; /** * @garbage_collector_link: Link into VM's garbage collect SVM range * list. Protected by VM's garbage collect lock. @@ -74,7 +76,7 @@ struct xe_pagemap { */ static inline bool xe_svm_range_pages_valid(struct xe_svm_range *range) { - return drm_gpusvm_range_pages_valid(range->base.gpusvm, &range->base); + return drm_gpusvm_pages_valid(range->base.gpusvm, &range->pages); } int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr); @@ -132,7 +134,7 @@ void *xe_svm_private_page_owner(struct xe_vm *vm, bool force_smem); static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range) { lockdep_assert_held(&range->base.gpusvm->notifier_lock); - return range->base.pages.flags.has_dma_mapping; + return range->pages.flags.has_dma_mapping; } /** @@ -210,10 +212,10 @@ struct xe_vram_region; struct xe_svm_range { struct { struct interval_tree_node itree; - struct { - const struct drm_pagemap_addr *dma_addr; - } pages; } base; + struct { + const struct drm_pagemap_addr *dma_addr; + } pages; u32 tile_present; u32 tile_invalidated; }; diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index d409c82104f4..8b2d461ea0b2 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -396,15 +396,14 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start, INIT_LIST_HEAD(&userptr->invalidate_link); INIT_LIST_HEAD(&userptr->repin_link); + drm_gpusvm_init_pages(&userptr->pages, &vm->xe->drm); + err = mmu_interval_notifier_insert(&userptr->notifier, current->mm, start, range, &vma_userptr_notifier_ops); if (err) return err; - userptr->pages.notifier_seq = LONG_MAX; - userptr->pages.drm = &vm->xe->drm; - return 0; } diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index 842353afb27b..3f38283111cc 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -310,6 +310,9 @@ void drm_gpusvm_range_put(struct drm_gpusvm_range *range); bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range); +bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, + struct drm_gpusvm_pages *svm_pages); + int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range, const struct drm_gpusvm_ctx *ctx); @@ -350,6 +353,23 @@ void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm, struct drm_gpusvm_pages *svm_pages, unsigned long npages); +/** + * drm_gpusvm_init_pages() - Initialize a freshly allocated drm_gpusvm_pages + * @svm_pages: Pointer to the drm_gpusvm_pages to initialize. + * @drm: The DRM device that will own DMA mappings for this pages object. + * + * Drivers that embed one or more drm_gpusvm_pages in their own range + * structure must call this once on each pages instance after allocation, + * before the first drm_gpusvm_get_pages() / unmap / free. + */ +static inline void drm_gpusvm_init_pages(struct drm_gpusvm_pages *svm_pages, + struct drm_device *drm) +{ + memset(svm_pages, 0, sizeof(*svm_pages)); + svm_pages->drm = drm; + svm_pages->notifier_seq = LONG_MAX; +} + /** * enum drm_gpusvm_scan_result - Scan result from the drm_gpusvm_scan_mm() function. * @DRM_GPUSVM_SCAN_UNPOPULATED: At least one page was not present or inaccessible. From e19d32c2b32dbb3b15e761cfd9dd35c38ec2c911 Mon Sep 17 00:00:00 2001 From: Honglei Huang Date: Tue, 30 Jun 2026 18:21:26 +0800 Subject: [PATCH 04/61] drm/gpusvm: move struct drm_gpusvm_pages out of struct drm_gpusvm_range Since the pages the physical pages and MM VA range has been abstractly separated. Unbinding a single form of physical page from the MM VA range, brings flexibility to the drm gpu SVM framework, transfer the way of management of MM and device physical pages to the driver layer. framework's range embedded pages object and its range level wrappers have no users left. Remove the following: - Drop pages in drm_gpusvm_range. - Drop drm_gpusvm_range_pages_valid(), drm_gpusvm_range_get_pages() and drm_gpusvm_range_unmap_pages(); drivers should use the drm_gpusvm_pages helpers (drm_gpusvm_pages_valid, drm_gpusvm_get_pages, drm_gpusvm_unmap_pages) directly on a pages object they own. - Drop the notifier_seq seeding in drm_gpusvm_range_alloc(); drivers initialise notifier_seq on their own pages object. Update the DOC: overview to match the new model: document struct drm_gpusvm_pages and the driver owned 1:1 / N:1 layouts, and rewrite the usage examples to operate on a driver embedded pages object by the drm_gpusvm_pages helpers instead of the removed range level wrappers. Suggested-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: Honglei Huang Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260630102127.392396-5-honghuan@amd.com --- drivers/gpu/drm/drm_gpusvm.c | 169 +++++++++++++++++++---------------- include/drm/drm_gpusvm.h | 13 --- 2 files changed, 90 insertions(+), 92 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index b0e9a2db1080..e0fd0b2fcc5e 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -48,6 +48,47 @@ * event. As mentioned above, ranges are tracked in a notifier's Red-Black * tree. * + * - Pages: + * struct drm_gpusvm_pages holds the DMA mapping state for a range of + * CPU virtual addresses: the DMA mapped device addresses, + * the device private pagemap, the IOVA state, the per mapping + * notifier sequence number, and the drm_device that owns the DMA + * mappings. + * A driver embeds one or more struct drm_gpusvm_pages alongside its + * struct drm_gpusvm_range, choosing one of two layouts: + * + * 1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest + * layout; to mirror a VA range on several devices a driver uses a + * separate range (and notifier) per device, so the HMM fault is taken + * once per device. + * + * N:1 - one drm_gpusvm_pages per drm_device, all sharing one range and + * notifier; only the per-device DMA mapping differs. The instances must + * sit in contiguous memory so a single drm_gpusvm_range_set_unmapped() + * can mark them all. A driver can keep one instance inline for the single + * device case and switch to a heap array only when more devices join, + * e.g.: + * + * .. code-block:: c + * + * struct driver_range { + * struct drm_gpusvm_range base; + * unsigned int num_pages; // 1: inline_pages, >1: pages[] + * union { + * struct drm_gpusvm_pages inline_pages; + * struct drm_gpusvm_pages *pages; + * }; + * }; + * + * In the N:1 case the driver allocates the pages array with a zeroing + * allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with + * drm_gpusvm_init_pages(), and frees each entry with + * drm_gpusvm_free_pages() plus the array itself, from its range free + * callback. Each drm_gpusvm_pages is mapped independently by their own + * drm_device. + * Each drm_gpusvm_pages must be zero-initialised and initialised with + * drm_gpusvm_init_pages(), called once per entry. + * * - Operations: * Define the interface for driver-specific GPU SVM operations such as * range allocation, notifier allocation, and invalidations. @@ -92,7 +133,7 @@ * range RB tree and list, as well as the range's DMA mappings and sequence * number. GPU SVM manages all necessary locking and unlocking operations, * except for the recheck range's pages being valid - * (drm_gpusvm_range_pages_valid) when the driver is committing GPU bindings. + * (drm_gpusvm_pages_valid) when the driver is committing GPU bindings. * This lock corresponds to the ``driver->update`` lock mentioned in * Documentation/mm/hmm.rst. Future revisions may transition from a GPU SVM * global lock to a per-notifier lock if finer-grained locking is deemed @@ -140,15 +181,20 @@ * * .. code-block:: c * - * int driver_bind_range(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range) + * struct driver_range { + * struct drm_gpusvm_range base; + * struct drm_gpusvm_pages pages; + * }; + * + * int driver_bind_range(struct drm_gpusvm *gpusvm, struct driver_range *drange) * { * int err = 0; * - * driver_alloc_and_setup_memory_for_bind(gpusvm, range); + * driver_alloc_and_setup_memory_for_bind(gpusvm, drange); * * drm_gpusvm_notifier_lock(gpusvm); - * if (drm_gpusvm_range_pages_valid(range)) - * driver_commit_bind(gpusvm, range); + * if (drm_gpusvm_pages_valid(gpusvm, &drange->pages)) + * driver_commit_bind(gpusvm, drange); * else * err = -EAGAIN; * drm_gpusvm_notifier_unlock(gpusvm); @@ -160,6 +206,8 @@ * unsigned long gpuva_start, unsigned long gpuva_end) * { * struct drm_gpusvm_ctx ctx = {}; + * struct driver_range *drange; + * struct drm_gpusvm_range *range; * int err; * * driver_svm_lock(); @@ -174,6 +222,7 @@ * err = PTR_ERR(range); * goto unlock; * } + * drange = container_of(range, struct driver_range, base); * * if (driver_migration_policy(range)) { * err = drm_pagemap_populate_mm(driver_choose_drm_pagemap(), @@ -183,7 +232,10 @@ * goto retry; * } * - * err = drm_gpusvm_range_get_pages(gpusvm, range, &ctx); + * err = drm_gpusvm_get_pages(gpusvm, &drange->pages, + * gpusvm->mm, &range->notifier->notifier, + * drm_gpusvm_range_start(range), + * drm_gpusvm_range_end(range), &ctx); * if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM) { // CPU mappings changed * if (err == -EOPNOTSUPP) * drm_gpusvm_range_evict(gpusvm, range); @@ -192,7 +244,7 @@ * goto unlock; * } * - * err = driver_bind_range(gpusvm, range); + * err = driver_bind_range(gpusvm, drange); * if (err == -EAGAIN) // CPU mappings changed * goto retry * @@ -205,6 +257,21 @@ * * .. code-block:: c * + * // The driver owns the drm_gpusvm_pages lifecycle. ops->range_free is + * // the final fallback: drm_gpusvm_free_pages() unmaps any + * // lingering DMA mapping and a no-op if already unmapped and frees the + * // dma_addr array. The normal flow is to DMA unmap before + * // drm_gpusvm_range_remove() (before the range leaves the tree). + * void driver_range_free(struct drm_gpusvm_range *range) + * { + * struct driver_range *drange = + * container_of(range, struct driver_range, base); + * + * drm_gpusvm_free_pages(range->gpusvm, &drange->pages, + * drm_gpusvm_range_size(range) >> PAGE_SHIFT); + * kfree(drange); + * } + * * void __driver_garbage_collector(struct drm_gpusvm *gpusvm, * struct drm_gpusvm_range *range) * { @@ -215,6 +282,14 @@ * drm_gpusvm_range_evict(gpusvm, range); * * driver_unbind_range(range); + * // The pages must be DMA unmapped before drm_gpusvm_range_remove() + * // , so a range is never off the MMU interval tree while still DMA + * // mapped as the original drmsvm design flow. Otherwise a concurrent CPU + * // munmap's notifier could miss this range and free pages still mapped + * // for device DMA. This is the normal unmap point. + * drm_gpusvm_unmap_pages(gpusvm, &drange->pages, + * drm_gpusvm_range_size(range) >> PAGE_SHIFT, + * &(struct drm_gpusvm_ctx){ .in_notifier = false }); * drm_gpusvm_range_remove(gpusvm, range); * } * @@ -236,17 +311,22 @@ * { * struct drm_gpusvm_ctx ctx = { .in_notifier = true, }; * struct drm_gpusvm_range *range = NULL; + * struct driver_range *drange; * * driver_invalidate_device_pages(gpusvm, mmu_range->start, mmu_range->end); * * drm_gpusvm_for_each_range(range, notifier, mmu_range->start, * mmu_range->end) { - * drm_gpusvm_range_unmap_pages(gpusvm, range, &ctx); + * drange = container_of(range, struct driver_range, base); + * + * drm_gpusvm_unmap_pages(gpusvm, &drange->pages, + * drm_gpusvm_range_size(range) >> PAGE_SHIFT, + * &ctx); * * if (mmu_range->event != MMU_NOTIFY_UNMAP) * continue; * - * drm_gpusvm_range_set_unmapped(range, mmu_range); + * drm_gpusvm_range_set_unmapped(range, &drange->pages, 1, mmu_range); * driver_garbage_collector_add(gpusvm, range); * } * } @@ -640,8 +720,6 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm, range->itree.start = ALIGN_DOWN(fault_addr, chunk_size); range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1; INIT_LIST_HEAD(&range->entry); - range->pages.notifier_seq = LONG_MAX; - range->pages.drm = gpusvm->drm; range->flags.migrate_devmem = migrate_devmem ? 1 : 0; return range; @@ -930,7 +1008,7 @@ drm_gpusvm_range_chunk_size(struct drm_gpusvm *gpusvm, * mallocs 16k but the CPU VMA is ~128k which results in 64k SVM * ranges. When migrating the SVM ranges, some processes fail in * drm_pagemap_migrate_to_devmem with 'migrate.cpages != npages' - * and then upon drm_gpusvm_range_get_pages device pages from + * and then upon drm_gpusvm_get_pages device pages from * other processes are collected + faulted in which creates all * sorts of problems. Unsure exactly how this happening, also * problem goes away if 'xe_exec_system_allocator --r @@ -1337,27 +1415,6 @@ bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, } EXPORT_SYMBOL_GPL(drm_gpusvm_pages_valid); -/** - * drm_gpusvm_range_pages_valid() - GPU SVM range pages valid - * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure - * - * This function determines if a GPU SVM range pages are valid. Expected be - * called holding gpusvm->notifier_lock and as the last step before committing a - * GPU binding. This is akin to a notifier seqno check in the HMM documentation - * but due to wider notifiers (i.e., notifiers which span multiple ranges) this - * function is required for finer grained checking (i.e., per range) if pages - * are valid. - * - * Return: True if GPU SVM range has valid pages, False otherwise - */ -bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range) -{ - return drm_gpusvm_pages_valid(gpusvm, &range->pages); -} -EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid); - /** * drm_gpusvm_pages_valid_unlocked() - GPU SVM pages valid unlocked * @gpusvm: Pointer to the GPU SVM structure @@ -1638,29 +1695,6 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, } EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages); -/** - * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range - * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure - * @ctx: GPU SVM context - * - * This function gets pages for a GPU SVM range and ensures they are mapped for - * DMA access. - * - * Return: 0 on success, negative error code on failure. - */ -int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx) -{ - return drm_gpusvm_get_pages(gpusvm, &range->pages, - gpusvm->mm, - &range->notifier->notifier, - drm_gpusvm_range_start(range), - drm_gpusvm_range_end(range), ctx); -} -EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages); - /** * drm_gpusvm_unmap_pages() - Unmap GPU svm pages * @gpusvm: Pointer to the GPU SVM structure @@ -1691,29 +1725,6 @@ void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm, } EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages); -/** - * drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range - * @gpusvm: Pointer to the GPU SVM structure - * @range: Pointer to the GPU SVM range structure - * @ctx: GPU SVM context - * - * This function unmaps pages associated with a GPU SVM range. If @in_notifier - * is set, it is assumed that gpusvm->notifier_lock is held in write mode; if it - * is clear, it acquires gpusvm->notifier_lock in read mode. Must be called on - * each GPU SVM range attached to notifier in gpusvm->ops->invalidate for IOMMU - * security model. - */ -void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx) -{ - unsigned long npages = npages_in_range(drm_gpusvm_range_start(range), - drm_gpusvm_range_end(range)); - - return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx); -} -EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages); - /** * drm_gpusvm_range_evict() - Evict GPU SVM range * @gpusvm: Pointer to the GPU SVM structure diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index 3f38283111cc..2862104aa1b2 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -177,7 +177,6 @@ struct drm_gpusvm_range_flags { * @refcount: Reference count for the range * @itree: Interval tree node for the range (inserted in GPU SVM notifier) * @entry: List entry to fast interval tree traversal - * @pages: The pages for this range. * @flags: Flags for range see &struct drm_gpusvm_range_flags * * This structure represents a GPU SVM range used for tracking memory ranges @@ -189,7 +188,6 @@ struct drm_gpusvm_range { struct kref refcount; struct interval_tree_node itree; struct list_head entry; - struct drm_gpusvm_pages pages; struct drm_gpusvm_range_flags flags; }; @@ -307,20 +305,9 @@ drm_gpusvm_range_get(struct drm_gpusvm_range *range); void drm_gpusvm_range_put(struct drm_gpusvm_range *range); -bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range); - bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm, struct drm_gpusvm_pages *svm_pages); -int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx); - -void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm, - struct drm_gpusvm_range *range, - const struct drm_gpusvm_ctx *ctx); - bool drm_gpusvm_has_mapping(struct drm_gpusvm *gpusvm, unsigned long start, unsigned long end); From 808db118eb2b93727f4a8f300480e7c7ff4046fe Mon Sep 17 00:00:00 2001 From: Honglei Huang Date: Tue, 30 Jun 2026 18:21:27 +0800 Subject: [PATCH 05/61] drm/gpusvm: let the drm_gpusvm core context purely MM level The core mechanism of drm_gpusvm is HMM, which is fundamentally an MM side subsystem. A drm_device, enters the picture on the device side at DMA mapping / GPU bind. So move struct drm_device from struct drm_gpusvm in drm_gpusvm. Let drm_gpusvm keep its core neutral and leave device side decisions to the driver. Make drm_gpusvm a pure MM level object. - Move the drm_device from struct drm_gpusvm. drm_device now stored in drm_gpusvm_pages. - Drop the drm parameter from drm_gpusvm_init() - Update the xe call sites in xe_svm_init() and other callers. drm_device does not disappear from the framework, it is relocated onto each drm_gpusvm_pages where DMA actually happens. Suggested-by: Matthew Brost Reviewed-by: Matthew Brost Signed-off-by: Honglei Huang Signed-off-by: Matthew Brost Link: https://patch.msgid.link/20260630102127.392396-6-honghuan@amd.com --- drivers/gpu/drm/drm_gpusvm.c | 8 ++++---- drivers/gpu/drm/xe/xe_svm.c | 4 ++-- drivers/gpu/drm/xe/xe_svm.h | 2 +- include/drm/drm_gpusvm.h | 4 +--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c index e0fd0b2fcc5e..fcfe635bc195 100644 --- a/drivers/gpu/drm/drm_gpusvm.c +++ b/drivers/gpu/drm/drm_gpusvm.c @@ -439,7 +439,6 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * drm_gpusvm_init() - Initialize the GPU SVM. * @gpusvm: Pointer to the GPU SVM structure. * @name: Name of the GPU SVM. - * @drm: Pointer to the DRM device structure. * @mm: Pointer to the mm_struct for the address space. * @mm_start: Start address of GPU SVM. * @mm_range: Range of the GPU SVM. @@ -453,7 +452,9 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * This function initializes the GPU SVM. * * Note: If only using the simple drm_gpusvm_pages API (get/unmap/free), - * then only @gpusvm, @name, and @drm are expected. However, the same base + * then only @gpusvm and @name are expected. The @drm drm_device for dma + * mappings is bound per-pages via drm_gpusvm_init_pages() before the first + * drm_gpusvm_get_pages() call. However, the same base * @gpusvm can also be used with both modes together in which case the full * setup is needed, where the core drm_gpusvm_pages API will simply never use * the other fields. @@ -461,7 +462,7 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = { * Return: 0 on success, a negative error code on failure. */ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, - const char *name, struct drm_device *drm, + const char *name, struct mm_struct *mm, unsigned long mm_start, unsigned long mm_range, unsigned long notifier_size, @@ -479,7 +480,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm, } gpusvm->name = name; - gpusvm->drm = drm; gpusvm->mm = mm; gpusvm->mm_start = mm_start; gpusvm->mm_range = mm_range; diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 8b48a942f3e6..b228a737cfd6 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -911,7 +911,7 @@ int xe_svm_init(struct xe_vm *vm) return err; } - err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm, + err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", current->mm, 0, vm->size, xe_modparam.svm_notifier_size * SZ_1M, &gpusvm_ops, fault_chunk_sizes, @@ -925,7 +925,7 @@ int xe_svm_init(struct xe_vm *vm) } } else { err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", - &vm->xe->drm, NULL, 0, 0, 0, NULL, + NULL, 0, 0, 0, NULL, NULL, 0); } diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h index c8f4a7ba0f4f..a921556d3466 100644 --- a/drivers/gpu/drm/xe/xe_svm.h +++ b/drivers/gpu/drm/xe/xe_svm.h @@ -235,7 +235,7 @@ static inline int xe_svm_init(struct xe_vm *vm) { #if IS_ENABLED(CONFIG_DRM_GPUSVM) - return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm, + return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", NULL, 0, 0, 0, NULL, NULL, 0); #else return 0; diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h index 2862104aa1b2..b7d987bf76aa 100644 --- a/include/drm/drm_gpusvm.h +++ b/include/drm/drm_gpusvm.h @@ -195,7 +195,6 @@ struct drm_gpusvm_range { * struct drm_gpusvm - GPU SVM structure * * @name: Name of the GPU SVM - * @drm: Pointer to the DRM device structure * @mm: Pointer to the mm_struct for the address space * @mm_start: Start address of GPU SVM * @mm_range: Range of the GPU SVM @@ -219,7 +218,6 @@ struct drm_gpusvm_range { */ struct drm_gpusvm { const char *name; - struct drm_device *drm; struct mm_struct *mm; unsigned long mm_start; unsigned long mm_range; @@ -271,7 +269,7 @@ struct drm_gpusvm_ctx { }; int drm_gpusvm_init(struct drm_gpusvm *gpusvm, - const char *name, struct drm_device *drm, + const char *name, struct mm_struct *mm, unsigned long mm_start, unsigned long mm_range, unsigned long notifier_size, From 104c00917264c5b9571072471e3a8689cd1a2c4d Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Thu, 2 Jul 2026 15:37:38 +0100 Subject: [PATCH 06/61] drm/panthor: Remove redundant drm_sched_job_cleanup() from the .free_job callback After calling drm_sched_job_cleanup(), the free job callback releases its reference to the job, where the act of dropping the last reference will also call the drm_sched_job_cleanup() helper. We can therefore remove the redundant call from the .free_job callback. But we have to leave the "if (job->base.s_fence)" guard in job_release(), since that one not only handles the above described double cleanup, but also deals with all job cleanup paths which happen before the point the job was armed. Signed-off-by: Tvrtko Ursulin Cc: Boris Brezillon Cc: Liviu Dudau Cc: Steven Price Reviewed-by: Steven Price Signed-off-by: Tvrtko Ursulin Link: https://lore.kernel.org/r/20260702143745.79293-2-tvrtko.ursulin@igalia.com [tursulin: fixup commit text s/it's/its/] --- drivers/gpu/drm/panthor/panthor_sched.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 298b046c95ed..5832dccfc093 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3446,7 +3446,6 @@ queue_timedout_job(struct drm_sched_job *sched_job) static void queue_free_job(struct drm_sched_job *sched_job) { - drm_sched_job_cleanup(sched_job); panthor_job_put(sched_job); } From c03adcddd5413e829e9cf63e8a7074a4c3d19d12 Mon Sep 17 00:00:00 2001 From: Diogo Silva Date: Tue, 7 Jul 2026 18:14:55 +0200 Subject: [PATCH 07/61] drm/qxl: remove dependency on DRM simple helpers Simple KMS helper are deprecated since they only add an intermediate layer between drivers and the atomic modesetting. This patch removes the drm_simple_encoder_init() helper usage in the qxl display driver by open coding it and using the encoder atomic helpers directly. This is a step to eventually get rid of this simple KMS helper, once all drivers that use it have been converted. Signed-off-by: Diogo Silva Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20260707-qxl-simple-v2-1-08d21bc74a41@gmail.com --- drivers/gpu/drm/qxl/qxl_display.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index a026bd35ef48..7f4178800afd 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -31,12 +31,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -1095,6 +1095,10 @@ static const struct drm_connector_helper_funcs qxl_connector_helper_funcs = { .best_encoder = qxl_best_encoder, }; +static const struct drm_encoder_funcs qxl_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static enum drm_connector_status qxl_conn_detect( struct drm_connector *connector, bool force) @@ -1169,10 +1173,10 @@ static int qdev_output_init(struct drm_device *dev, int num_output) drm_connector_init(dev, &qxl_output->base, &qxl_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); - ret = drm_simple_encoder_init(dev, &qxl_output->enc, - DRM_MODE_ENCODER_VIRTUAL); + ret = drm_encoder_init(dev, &qxl_output->enc, &qxl_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) { - drm_err(dev, "drm_simple_encoder_init() failed, error %d\n", + drm_err(dev, "drm_encoder_init() failed, error %d\n", ret); goto err_drm_connector_cleanup; } From a9f950adfe2147318d75e7a6eab5e814851802ac Mon Sep 17 00:00:00 2001 From: Laxman Acharya Padhya Date: Sat, 4 Jul 2026 12:51:48 +0545 Subject: [PATCH 08/61] drm/panel: samsung-s6d16d0: Power off on prepare failure If enabling tearing mode or exiting sleep mode fails after the regulator is enabled, s6d16d0_prepare() returns without asserting reset or disabling the supply. Since the DRM panel core leaves the panel unprepared, a later unprepare call skips the driver callback and the supply remains enabled. Assert reset and disable the supply before returning the DSI command error. Fixes: ac1d6d74884e ("drm/panel: Add driver for Samsung S6D16D0 panel") Assisted-by: Codex:gpt-5 Signed-off-by: Laxman Acharya Padhya Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260704070648.35249-1-acharyalaxman8848@gmail.com --- drivers/gpu/drm/panel/panel-samsung-s6d16d0.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index 1b14aa4efe35..54a65abf7e89 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -88,16 +88,22 @@ static int s6d16d0_prepare(struct drm_panel *panel) MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret) { dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret); - return ret; + goto err_power_off; } /* Exit sleep mode and power on */ ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret) { dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret); - return ret; + goto err_power_off; } return 0; + +err_power_off: + gpiod_set_value_cansleep(s6->reset_gpio, 1); + regulator_disable(s6->supply); + + return ret; } static int s6d16d0_enable(struct drm_panel *panel) From a284476db2653ae893f46cbea408eb412db54eb0 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 23 Jun 2026 11:46:17 +0100 Subject: [PATCH 09/61] drm/panfrost: include panfrost_drv.h for panfrost_transparent_hugepage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The panfrost_transparent_hugepage variable is declared in panfrost_drv.h but the panfrost_drv.c does not incldue this header. Fix the following sparse warning by including panfrost_drv.h : drivers/gpu/drm/panfrost/panfrost_drv.c:958:6: warning: symbol 'panfrost_transparent_hugepage' was not declared. Should it be static? Signed-off-by: Ben Dooks Reviewed-by: Steven Price Reviewed-by: Adrián Larumbe Reviewed-by: Boris Brezillon Link: https://patch.msgid.link/20260623104617.768289-1-ben.dooks@codethink.co.uk Signed-off-by: Adrián Larumbe --- drivers/gpu/drm/panfrost/panfrost_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 784e36d72c2b..36cc2e67a308 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -21,6 +21,7 @@ #include #include "panfrost_device.h" +#include "panfrost_drv.h" #include "panfrost_gem.h" #include "panfrost_mmu.h" #include "panfrost_job.h" From 34e27b90552acf21bd73aac395667c8aae6da480 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Jul 2026 13:05:20 +1000 Subject: [PATCH 10/61] nouveau/instmem: use iomapping interface for instmem handling This avoids constant need to ioremap when instobjs move at least on 64-bit systems. This create the io mapping on first use, because creating it at init time causes a resource mapping error, because nouveau hasn't kicked simpledrm off the hardware yet, but ioremap_wc the whole BAR causes an overlap with BOOTFB/simpledrm. I think the resource system could do better here, but it's easier to just delay creating the mapping until first use. Signed-off-by: Dave Airlie Link: https://patch.msgid.link/20260706030520.857104-1-airlied@gmail.com Signed-off-by: Danilo Krummrich --- .../nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c | 1 + .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 39 ++++++++++++++----- .../drm/nouveau/nvkm/subdev/instmem/priv.h | 1 + 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c index 700cea5def35..f128330f30d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c @@ -297,6 +297,7 @@ r535_fbsr = { static void * r535_instmem_dtor(struct nvkm_instmem *imem) { + nv50_instmem_dtor(imem); kfree(imem->func); return imem; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 6fbaa1e5876d..f4489efc94a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -30,10 +30,14 @@ #include #include +#include + struct nv50_instmem { struct nvkm_instmem base; u64 addr; + struct io_mapping iomap; + /* Mappings that can be evicted when BAR2 space has been exhausted. */ struct list_head lru; }; @@ -124,7 +128,6 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm) struct nv50_instobj *eobj; struct nvkm_memory *memory = &iobj->base.memory; struct nvkm_subdev *subdev = &imem->base.subdev; - struct nvkm_device *device = subdev->device; struct nvkm_vma *bar = NULL, *ebar; u64 size = nvkm_memory_size(memory); void *emap; @@ -155,7 +158,7 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm) mutex_unlock(&imem->base.mutex); if (!eobj) break; - iounmap(emap); + io_mapping_unmap(emap); nvkm_vmm_put(vmm, &ebar); } @@ -172,8 +175,7 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm) /* Make the mapping visible to the host. */ iobj->bar = bar; - iobj->map = ioremap_wc(device->func->resource_addr(device, NVKM_BAR2_INST) + - (u32)iobj->bar->addr, size); + iobj->map = io_mapping_map_wc(&imem->iomap, (u32)iobj->bar->addr, size); if (!iobj->map) { nvkm_warn(subdev, "PRAMIN ioremap failed\n"); nvkm_vmm_put(vmm, &iobj->bar); @@ -188,6 +190,16 @@ nv50_instobj_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm, return nvkm_memory_map(memory, offset, vmm, vma, argv, argc); } +static bool +check_io_mapping(struct nv50_instmem *imem) +{ + struct nvkm_device *device = imem->base.subdev.device; + + return io_mapping_init_wc(&imem->iomap, + device->func->resource_addr(device, NVKM_BAR2_INST), + device->func->resource_size(device, NVKM_BAR2_INST)) != NULL; +} + static void nv50_instobj_release(struct nvkm_memory *memory) { @@ -239,7 +251,7 @@ nv50_instobj_acquire(struct nvkm_memory *memory) /* Attempt to get a direct CPU mapping of the object. */ if ((vmm = nvkm_bar_bar2_vmm(imem->subdev.device))) { - if (!iobj->map) + if (!iobj->map && iobj->imem->iomap.size) nv50_instobj_kmap(iobj, vmm); map = iobj->map; } @@ -277,7 +289,12 @@ nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vmm *vmm) iobj->lru.next = NULL; } - nv50_instobj_kmap(iobj, vmm); + /* + * boot is only called on BAR2, if we can't remap the complete + * BAR it's unlikely things are functioning well. + */ + if (check_io_mapping(iobj->imem)) + nv50_instobj_kmap(iobj, vmm); nvkm_instmem_boot(imem); mutex_unlock(&imem->mutex); } @@ -330,7 +347,7 @@ nv50_instobj_dtor(struct nvkm_memory *memory) if (map) { struct nvkm_vmm *vmm = nvkm_bar_bar2_vmm(imem->subdev.device); - iounmap(map); + io_mapping_unmap(map); if (likely(vmm)) /* Can be NULL during BAR destructor. */ nvkm_vmm_put(vmm, &bar); } @@ -406,10 +423,14 @@ nv50_instmem_fini(struct nvkm_instmem *base) nv50_instmem(base)->addr = ~0ULL; } -static void * +void * nv50_instmem_dtor(struct nvkm_instmem *base) { - return nv50_instmem(base); + struct nv50_instmem *imem = nv50_instmem(base); + + if (imem->iomap.size) + io_mapping_fini(&imem->iomap); + return imem; } static const struct nvkm_instmem_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index 87bbdd786eaa..b423f01f5fcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -26,6 +26,7 @@ int nv50_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, struct nvkm_memory **); int nv50_instobj_wrap(struct nvkm_instmem *, struct nvkm_memory *vram, struct nvkm_memory **bar2); +void *nv50_instmem_dtor(struct nvkm_instmem *base); void nvkm_instmem_ctor(const struct nvkm_instmem_func *, struct nvkm_device *, enum nvkm_subdev_type, int, struct nvkm_instmem *); From 5958ff1a715dd885210ce7208f1aa1fa930e8671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Antinori?= Date: Mon, 6 Jul 2026 19:43:35 -0300 Subject: [PATCH 11/61] drm/panel: novatek-nt37801: Use mipi_dsi_*_multi() functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace mipi_dsi_* functions with their non-deprecated mipi_dsi_*_multi counterparts. This change reduces error-checking boilerplate and improves readability. Signed-off-by: Nicolás Antinori Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patch.msgid.link/20260706224414.1015766-1-nico.antinori.7@gmail.com --- drivers/gpu/drm/panel/panel-novatek-nt37801.c | 106 ++++++++---------- 1 file changed, 46 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c index 861e999250f9..5e46c4c6d771 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -51,61 +51,56 @@ static void novatek_nt37801_reset(struct novatek_nt37801 *ctx) mipi_dsi_dcs_write_seq_multi((dsi_ctx), NT37801_DCS_SWITCH_PAGE, \ 0x55, 0xaa, 0x52, 0x08, (page)) -static int novatek_nt37801_on(struct novatek_nt37801 *ctx) +static void novatek_nt37801_on(struct mipi_dsi_multi_context *dsi_ctx) { - struct mipi_dsi_device *dsi = ctx->dsi; - struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; + dsi_ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; - dsi->mode_flags |= MIPI_DSI_MODE_LPM; - - novatek_nt37801_switch_page(&dsi_ctx, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x10); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1b); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x55); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x18); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x19); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0f); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0x00); - mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x059f); - mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0c7f); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03, 0x03); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, + novatek_nt37801_switch_page(dsi_ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x02); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf5, 0x10); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x1b); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf4, 0x55); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x18); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf8, 0x19); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x0f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfc, 0x00); + mipi_dsi_dcs_set_column_address_multi(dsi_ctx, 0x0000, 0x059f); + mipi_dsi_dcs_set_page_address_multi(dsi_ctx, 0x0000, 0x0c7f); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x90, 0x03, 0x03); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x91, 0x89, 0x28, 0x00, 0x28, 0xc2, 0x00, 0x02, 0x68, 0x04, 0x6c, 0x00, 0x0a, 0x02, 0x77, 0x01, 0xe9, 0x10, 0xf0); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x23); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb, + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x23); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb, 0x00, 0x01, 0x00, 0x11, 0x33, 0x33, 0x33, 0x55, 0x57, 0xd0, 0x00, 0x00, 0x44, 0x56, 0x77, 0x78, 0x9a, 0xbc, 0xdd, 0xf0); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x06); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0xdc); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00); - mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x06); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf3, 0xdc); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00); + mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x51, 0x07, 0xff, 0x07, 0xff, 0x0f, 0xff); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9c, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_MEMORY_START); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5a, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5f, 0x00); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x9c, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_MEMORY_START); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x2f, 0x00); - novatek_nt37801_switch_page(&dsi_ctx, 0x01); - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03); - mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); - mipi_dsi_msleep(&dsi_ctx, 120); - mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); - mipi_dsi_msleep(&dsi_ctx, 20); - - return dsi_ctx.accum_err; + novatek_nt37801_switch_page(dsi_ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03); + mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 120); + mipi_dsi_dcs_set_display_on_multi(dsi_ctx); + mipi_dsi_msleep(dsi_ctx, 20); } static int novatek_nt37801_off(struct novatek_nt37801 *ctx) @@ -127,7 +122,8 @@ static int novatek_nt37801_off(struct novatek_nt37801 *ctx) static int novatek_nt37801_prepare(struct drm_panel *panel) { struct novatek_nt37801 *ctx = to_novatek_nt37801(panel); - struct device *dev = &ctx->dsi->dev; + struct mipi_dsi_device *dsi = ctx->dsi; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; struct drm_dsc_picture_parameter_set pps; int ret; @@ -137,22 +133,12 @@ static int novatek_nt37801_prepare(struct drm_panel *panel) return ret; novatek_nt37801_reset(ctx); - - ret = novatek_nt37801_on(ctx); - if (ret < 0) - goto err; - + novatek_nt37801_on(&dsi_ctx); drm_dsc_pps_payload_pack(&pps, &ctx->dsc); - - ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); - if (ret < 0) { - dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); - goto err; - } - - ret = mipi_dsi_compression_mode(ctx->dsi, true); - if (ret < 0) { - dev_err(dev, "failed to enable compression mode: %d\n", ret); + mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps); + mipi_dsi_compression_mode_multi(&dsi_ctx, true); + if (dsi_ctx.accum_err) { + ret = dsi_ctx.accum_err; goto err; } From e73e34a4a4c2a9d4359202a2ed02f4930684dd01 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 1 Jul 2026 19:19:38 +0200 Subject: [PATCH 12/61] drm: of: fix wording in comment Fix a comment according to English grammar. Link: https://lore.kernel.org/all/DI9ZFQUNMSBU.214AU8467OK76@bootlin.com/ Suggested-by: Laurent Pinchart Reviewed-by: Louis Chauvet Link: https://patch.msgid.link/20260701-drm-fix-graph-wording-v1-1-295605c5777b@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/drm_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 96eef327bf7e..1f4cff6bb4a7 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -297,7 +297,7 @@ int drm_of_find_panel_or_bridge(const struct device_node *np, /* * of_graph_get_remote_node() produces a noisy error message if port * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph presents in the + * so at first we silently check whether a graph is present in the * device-tree node. */ if (!of_graph_is_present(np)) From 7a8ece0e0d7006164c2ba51f2726964cc1818117 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 1 Jul 2026 19:19:39 +0200 Subject: [PATCH 13/61] drm/bridge: samsung-dsim: fix wording in comment Fix a comment according to English grammar. Link: https://lore.kernel.org/all/DI9ZFQUNMSBU.214AU8467OK76@bootlin.com/ Suggested-by: Laurent Pinchart Reviewed-by: Louis Chauvet Link: https://patch.msgid.link/20260701-drm-fix-graph-wording-v1-2-295605c5777b@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/samsung-dsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 5788066d479e..25ab475309e8 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1919,7 +1919,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host, /* * of_graph_get_remote_node() produces a noisy error message if port * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph presents in the + * so at first we silently check whether a graph is present in the * device-tree node. */ if (!of_graph_is_present(np)) From e8113d658235369fb31584c58538a5d2bc6fe867 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 1 Jul 2026 19:19:40 +0200 Subject: [PATCH 14/61] drm/bridge: fix wording in comment Fix a comment according to English grammar. Reviewed-by: Louis Chauvet Link: https://patch.msgid.link/20260701-drm-fix-graph-wording-v1-3-295605c5777b@bootlin.com Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/drm_bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 6ead9b75ae3d..38afa3bc2b7c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1717,7 +1717,7 @@ struct drm_bridge *of_drm_get_bridge_by_endpoint(const struct device_node *np, /* * of_graph_get_remote_node() produces a noisy error message if port * node isn't found and the absence of the port is a legit case here, - * so at first we silently check whether graph is present in the + * so at first we silently check whether a graph is present in the * device-tree node. */ if (!of_graph_is_present(np)) From 12f5090aaa3cc82ce2d8ca0d7bb2b86817587ace Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Tue, 30 Jun 2026 17:34:04 +0200 Subject: [PATCH 15/61] drm/bridge: rename drm_for_each_bridge_in_chain_scoped() to drm_for_each_bridge_in_chain() drm_for_each_bridge_in_chain_scoped() was added in commit e46efc6a7d28 ("drm/bridge: add drm_for_each_bridge_in_chain_scoped()") to provide a safer alternative to drm_for_each_bridge_in_chain(). Following commits converted all users to the _scoped variant. Finally commit 2f08387a444c ("drm/bridge: remove drm_for_each_bridge_in_chain()") removed the old drm_for_each_bridge_in_chain() macro. It's time to rename drm_for_each_bridge_in_chain_scoped() back to the original name. Reviewed-by: Louis Chauvet Link: https://patch.msgid.link/20260630-drm-bridge-alloc-getput-for_each_bridge-2-v2-1-e0a1094cd1eb@bootlin.com Signed-off-by: Luca Ceresoli --- .clang-format | 2 +- drivers/gpu/drm/display/drm_bridge_connector.c | 4 ++-- drivers/gpu/drm/drm_atomic.c | 2 +- drivers/gpu/drm/drm_bridge.c | 2 +- drivers/gpu/drm/tests/drm_bridge_test.c | 2 +- include/drm/drm_bridge.h | 11 +++++------ 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.clang-format b/.clang-format index 6a3de86ab27a..5ef5743b77c9 100644 --- a/.clang-format +++ b/.clang-format @@ -167,7 +167,7 @@ ForEachMacros: - 'drm_connector_for_each_possible_encoder' - 'drm_exec_for_each_locked_object' - 'drm_exec_for_each_locked_object_reverse' - - 'drm_for_each_bridge_in_chain_scoped' + - 'drm_for_each_bridge_in_chain' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' - 'drm_for_each_crtc_reverse' diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index 92f8a2d7aab4..8b54069fa53a 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -147,7 +147,7 @@ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector, to_drm_bridge_connector(connector); /* Notify all bridges in the pipeline of hotplug events. */ - drm_for_each_bridge_in_chain_scoped(bridge_connector->encoder, bridge) { + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) { if (bridge->funcs->hpd_notify) bridge->funcs->hpd_notify(bridge, connector, status); } @@ -854,7 +854,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, * detection are available, we don't support hotplug detection at all. */ connector_type = DRM_MODE_CONNECTOR_Unknown; - drm_for_each_bridge_in_chain_scoped(encoder, bridge) { + drm_for_each_bridge_in_chain(encoder, bridge) { if (!bridge->interlace_allowed) connector->interlace_allowed = false; if (!bridge->ycbcr_420_allowed) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 735ab7badc2e..e5c8ef06caed 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1554,7 +1554,7 @@ drm_atomic_add_encoder_bridges(struct drm_atomic_commit *state, "Adding all bridges for [encoder:%d:%s] to %p\n", encoder->base.id, encoder->name, state); - drm_for_each_bridge_in_chain_scoped(encoder, bridge) { + drm_for_each_bridge_in_chain(encoder, bridge) { /* Skip bridges that don't implement the atomic state hooks. */ if (!bridge->funcs->atomic_duplicate_state) continue; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 38afa3bc2b7c..07914b91a76c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1817,7 +1817,7 @@ static int encoder_bridges_show(struct seq_file *m, void *data) struct drm_printer p = drm_seq_file_printer(m); unsigned int idx = 0; - drm_for_each_bridge_in_chain_scoped(encoder, bridge) + drm_for_each_bridge_in_chain(encoder, bridge) drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true); return 0; diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c index 10a32620e962..430d9bc67a10 100644 --- a/drivers/gpu/drm/tests/drm_bridge_test.c +++ b/drivers/gpu/drm/tests/drm_bridge_test.c @@ -1071,7 +1071,7 @@ static void drm_test_bridge_chain_verify_fmt(struct kunit *test, struct drm_bridge_state *bstate; unsigned int i = 0; - drm_for_each_bridge_in_chain_scoped(&priv->encoder, bridge) { + drm_for_each_bridge_in_chain(&priv->encoder, bridge) { KUNIT_ASSERT_LT(test, i, num_expected); bstate = drm_bridge_get_current_state(bridge); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 18f3db367dc1..0fadc39dfc12 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -1474,9 +1474,9 @@ static inline struct drm_bridge *__drm_for_each_bridge_in_chain_next(struct drm_ DEFINE_FREE(__drm_for_each_bridge_in_chain_cleanup, struct drm_bridge *, if (_T) { mutex_unlock(&_T->encoder->bridge_chain_mutex); drm_bridge_put(_T); }) -/* Internal to drm_for_each_bridge_in_chain_scoped() */ +/* Internal to drm_for_each_bridge_in_chain() */ static inline struct drm_bridge * -__drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder) +__drm_for_each_bridge_in_chain_start(struct drm_encoder *encoder) { mutex_lock(&encoder->bridge_chain_mutex); @@ -1489,8 +1489,7 @@ __drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder) } /** - * drm_for_each_bridge_in_chain_scoped - iterate over all bridges attached - * to an encoder + * drm_for_each_bridge_in_chain - iterate over all bridges attached to an encoder * @encoder: the encoder to iterate bridges on * @bridge: a bridge pointer updated to point to the current bridge at each * iteration @@ -1500,9 +1499,9 @@ __drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder) * Automatically gets/puts the bridge reference while iterating and locks * the encoder chain mutex to prevent chain modifications while iterating. */ -#define drm_for_each_bridge_in_chain_scoped(encoder, bridge) \ +#define drm_for_each_bridge_in_chain(encoder, bridge) \ for (struct drm_bridge *bridge __free(__drm_for_each_bridge_in_chain_cleanup) = \ - __drm_for_each_bridge_in_chain_scoped_start((encoder)); \ + __drm_for_each_bridge_in_chain_start((encoder)); \ bridge; \ bridge = __drm_for_each_bridge_in_chain_next(bridge)) \ From 511ee3e5f7e4e82b6a5a0f9aa16895ab9a96fd08 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Tue, 2 Jun 2026 20:36:48 +0200 Subject: [PATCH 16/61] drm/bridge: sii9234: fix some typos in comments and messages Fix spelling and formatting so that the code is easier to follow, and so that it is more searchable. Reviewed-by: Dmitry Baryshkov Signed-off-by: Henrik Grimler Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260602-exynos4-sii9234-driver-v4-1-9b2fc38e104a@grimler.se Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/sii9234.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index bb1bed03eb5b..930117bbba87 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -339,7 +339,7 @@ static int sii9234_cbus_reset(struct sii9234 *ctx) return sii9234_clear_error(ctx); } -/* Require to chek mhl imformation of samsung in cbus_init_register */ +/* Require to check mhl information of samsung in cbus_init_register */ static int sii9234_cbus_init(struct sii9234 *ctx) { cbus_writeb(ctx, 0x07, 0xF2); @@ -614,7 +614,7 @@ static void sii9234_cable_out(struct sii9234 *ctx) disable_irq(to_i2c_client(ctx->dev)->irq); tpi_writeb(ctx, TPI_DPD_REG, 0); - /* Turn on&off hpd festure for only QCT HDMI */ + /* Turn on&off hpd feature for only QCT HDMI */ sii9234_hw_off(ctx); ctx->state = ST_OFF; @@ -708,7 +708,7 @@ static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx) { int value; - /* Work_around code to handle wrong interrupt */ + /* Workaround code to handle wrong interrupt */ if (ctx->state != ST_RGND_1K) { dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n"); return ST_FAILURE; @@ -723,9 +723,9 @@ static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx) } dev_dbg(ctx->dev, "RSEN lost\n"); /* - * Once RSEN loss is confirmed,we need to check - * based on cable status and chip power status,whether - * it is SINK Loss(HDMI cable not connected, TV Off) + * Once RSEN loss is confirmed, we need to check + * based on cable status and chip power status, whether + * it is SINK Loss (HDMI cable not connected, TV Off) * or MHL cable disconnection * TODO: Define the below mhl_disconnection() */ @@ -820,7 +820,7 @@ static int sii9234_init_resources(struct sii9234 *ctx, int ret; if (!ctx->dev->of_node) { - dev_err(ctx->dev, "not DT device\n"); + dev_err(ctx->dev, "no DT device\n"); return -ENODEV; } From a3bbe1f4877d372da713b79764787e01306b12aa Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Tue, 2 Jun 2026 20:36:49 +0200 Subject: [PATCH 17/61] drm/bridge: sii9234: use dev_err_probe where applicable In case of error during resource acquisition the driver should print an error message only if it is not deferred probe. Use dev_err_probe helper to handle this, which will also record defer probe reason for debugging. Reviewed-by: Dmitry Baryshkov Signed-off-by: Henrik Grimler Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260602-exynos4-sii9234-driver-v4-2-9b2fc38e104a@grimler.se Signed-off-by: Luca Ceresoli --- drivers/gpu/drm/bridge/sii9234.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index 930117bbba87..e43248e515b3 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -825,21 +825,17 @@ static int sii9234_init_resources(struct sii9234 *ctx, } ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->gpio_reset)) { - dev_err(ctx->dev, "failed to get reset gpio from DT\n"); - return PTR_ERR(ctx->gpio_reset); - } + if (IS_ERR(ctx->gpio_reset)) + return dev_err_probe(ctx->dev, PTR_ERR(ctx->gpio_reset), + "failed to get reset gpio from DT\n"); ctx->supplies[0].supply = "avcc12"; ctx->supplies[1].supply = "avcc33"; ctx->supplies[2].supply = "iovcc18"; ctx->supplies[3].supply = "cvcc12"; ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(ctx->dev, "regulator_bulk failed\n"); - return ret; - } + if (ret) + return dev_err_probe(ctx->dev, ret, "regulator_bulk failed\n"); ctx->client[I2C_MHL] = client; @@ -911,10 +907,9 @@ static int sii9234_probe(struct i2c_client *client) sii9234_irq_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "sii9234", ctx); - if (ret < 0) { - dev_err(dev, "failed to install IRQ handler\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to install IRQ handler\n"); ret = sii9234_init_resources(ctx, client); if (ret < 0) From 9813e158d13d51d20d9257879bf79da7abcc9107 Mon Sep 17 00:00:00 2001 From: Leandro Ribeiro Date: Tue, 26 May 2026 15:16:59 -0300 Subject: [PATCH 18/61] drm/drm_blend: allow blend mode property without PREMULTI Some hardware only supports the COVERAGE blend mode and lacks PREMULTI support entirely. DRM currently requires that PREMULTI is present when creating a blend mode property, which prevents such drivers from being properly upstreamed. Remove this restriction and allow drivers to create a blend mode property without PREMULTI, enabling support for hardware that implements only COVERAGE blend mode. This does not introduce a regression, as no existing upstream drivers expose only COVERAGE. However, userspace that wants to support such kind of hardware in the future will have to check the supported blend modes instead of assuming PREMULTI is always supported. Signed-off-by: Leandro Ribeiro Acked-by: Pekka Paalanen Reviewed-by: Daniel Stone Link: https://patch.msgid.link/20260526181700.25310-2-leandro.ribeiro@collabora.com Signed-off-by: Daniel Stone --- drivers/gpu/drm/drm_blend.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 2f0d1ba285be..d17ae964fb21 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -563,10 +563,10 @@ EXPORT_SYMBOL(drm_atomic_normalize_zpos); /** * drm_plane_create_blend_mode_property - create a new blend mode property * @plane: drm plane - * @supported_modes: bitmask of supported modes, must include - * BIT(DRM_MODE_BLEND_PREMULTI). Current DRM assumption is - * that alpha is premultiplied, and old userspace can break if - * the property defaults to anything else. + * @supported_modes: bitmask of supported modes. When + * BIT(DRM_MODE_BLEND_PREMULTI) is included, it will be used + * as the default. Otherwise, the default will fallback to one + * of the supported modes. * * This creates a new property describing the blend mode. * @@ -599,13 +599,14 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, { DRM_MODE_BLEND_PREMULTI, "Pre-multiplied" }, { DRM_MODE_BLEND_COVERAGE, "Coverage" }, }; + unsigned int default_mode; unsigned int valid_mode_mask = BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) | BIT(DRM_MODE_BLEND_COVERAGE); int i; if (WARN_ON((supported_modes & ~valid_mode_mask) || - ((supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) == 0))) + (supported_modes == 0))) return -EINVAL; prop = drm_property_create(dev, DRM_MODE_PROP_ENUM, @@ -630,7 +631,14 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, } } - drm_object_attach_property(&plane->base, prop, DRM_MODE_BLEND_PREMULTI); + if (supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) + default_mode = DRM_MODE_BLEND_PREMULTI; + else if (supported_modes & BIT(DRM_MODE_BLEND_COVERAGE)) + default_mode = DRM_MODE_BLEND_COVERAGE; + else + default_mode = DRM_MODE_BLEND_PIXEL_NONE; + + drm_object_attach_property(&plane->base, prop, default_mode); plane->blend_mode_property = prop; return 0; From 860e748bddcc9291cbdd23e801640aeeba30cc44 Mon Sep 17 00:00:00 2001 From: Leandro Ribeiro Date: Tue, 26 May 2026 15:17:00 -0300 Subject: [PATCH 19/61] drm: ensure blend mode supported if pixel format with alpha exposed Before "drm/drm_blend: allow blend mode property without PREMULTI", userspace would have to assume that only PREMULTI was supported by drivers that didn't expose the blend mode property. But now userspace shouldn't rely on that, as they can't count with drivers always supporting PREMULTI. Warn if a driver exposes pixel formats with alpha but doesn't expose the blend mode property. This way userspace doesn't have to guess. Drivers triggering this warning must be fixed. Signed-off-by: Leandro Ribeiro Acked-by: Pekka Paalanen Reviewed-by: Daniel Stone Link: https://patch.msgid.link/20260526181700.25310-3-leandro.ribeiro@collabora.com Signed-off-by: Daniel Stone --- drivers/gpu/drm/drm_mode_config.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index f432f485a914..3bcc7bf0900c 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -857,6 +857,25 @@ static void validate_encoder_possible_crtcs(struct drm_encoder *encoder) encoder->possible_crtcs, crtc_mask); } +static void validate_blend_mode_for_alpha_formats(struct drm_plane *plane) +{ + const struct drm_format_info *fmt; + u32 i; + + /* blend mode property supported, no need to check anything */ + if (plane->blend_mode_property) + return; + + for (i = 0; i < plane->format_count; i++) { + fmt = drm_format_info(plane->format_types[i]); + if (fmt->has_alpha) { + WARN(1, "[PLANE:%d:%s] pixel format with alpha exposed but blend mode not setup", + plane->base.id, plane->name); + break; + } + } +} + void drm_mode_config_validate(struct drm_device *dev) { struct drm_encoder *encoder; @@ -915,6 +934,8 @@ void drm_mode_config_validate(struct drm_device *dev) drm_for_each_plane(plane, dev) { if (plane->type == DRM_PLANE_TYPE_PRIMARY) num_primary++; + + validate_blend_mode_for_alpha_formats(plane); } WARN(num_primary != dev->mode_config.num_crtc, From d91748f683693be386fa127b7ec25d2a366b88b9 Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 8 Jul 2026 11:56:44 +0200 Subject: [PATCH 20/61] drm/imx: Switch to irq_domain_create_linear() irq_domain_add_linear() is going away as being obsolete now. Switch to the preferred irq_domain_create_linear(). That differs in the first parameter: It takes more generic struct fwnode_handle instead of struct device_node. Therefore, of_fwnode_handle() is added around the parameter. Note some of the users can likely use dev->fwnode directly instead of indirect of_fwnode_handle(dev->of_node). But dev->fwnode is not guaranteed to be set for all, so this has to be investigated on case to case basis (by people who can actually test with the HW). [ Liu Ying: Fix a complaint from 'checkpatch.pl --strict'. ] Signed-off-by: Jiri Slaby (SUSE) Cc: Thomas Gleixner Cc: Liu Ying Acked-by: Liu Ying Link: https://patch.msgid.link/20260708095645.385291-1-jirislaby@kernel.org Signed-off-by: Liu Ying --- drivers/gpu/drm/imx/dc/dc-ic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/imx/dc/dc-ic.c b/drivers/gpu/drm/imx/dc/dc-ic.c index a270ae4030cd..4f3b1553cbba 100644 --- a/drivers/gpu/drm/imx/dc/dc-ic.c +++ b/drivers/gpu/drm/imx/dc/dc-ic.c @@ -174,8 +174,8 @@ static int dc_ic_probe(struct platform_device *pdev) regmap_write(data->regs, USERINTERRUPTMASK(i), 0xffffffff); } - data->domain = irq_domain_add_linear(dev->of_node, IRQ_COUNT, - &irq_generic_chip_ops, data); + data->domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), IRQ_COUNT, + &irq_generic_chip_ops, data); if (!data->domain) { dev_err(dev, "failed to create IRQ domain\n"); pm_runtime_put(dev); From 68952f1b00736f91867939f50d7b78c08126caad Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 8 Jul 2026 11:56:45 +0200 Subject: [PATCH 21/61] drm/imx: include dc-drv.h to avoid sparse warning sparse (build with C=1) warns: drivers/gpu/drm/imx/dc/dc-ic.c:273:24: warning: symbol 'dc_ic_driver' was not declared. Should it be static? And it is right. Include dc-drv.h which declares the struct. This ensures the types of both match. Signed-off-by: Jiri Slaby (SUSE) Cc: Liu Ying Reviewed-by: Liu Ying Link: https://patch.msgid.link/20260708095645.385291-2-jirislaby@kernel.org Signed-off-by: Liu Ying --- drivers/gpu/drm/imx/dc/dc-ic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/imx/dc/dc-ic.c b/drivers/gpu/drm/imx/dc/dc-ic.c index 4f3b1553cbba..fa87bf1f4508 100644 --- a/drivers/gpu/drm/imx/dc/dc-ic.c +++ b/drivers/gpu/drm/imx/dc/dc-ic.c @@ -14,6 +14,8 @@ #include #include +#include "dc-drv.h" + #define USERINTERRUPTMASK(n) (0x8 + 4 * (n)) #define INTERRUPTENABLE(n) (0x10 + 4 * (n)) #define INTERRUPTPRESET(n) (0x18 + 4 * (n)) From a3910673fec99f335285810df584f722f26f70b0 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:08 +0200 Subject: [PATCH 22/61] drm/adp: mipi: Add atomic bridge state handlers The mipi bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Joshua Peisach Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-1-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/adp/adp-mipi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/adp/adp-mipi.c b/drivers/gpu/drm/adp/adp-mipi.c index cba7d32150a9..232bb9539423 100644 --- a/drivers/gpu/drm/adp/adp-mipi.c +++ b/drivers/gpu/drm/adp/adp-mipi.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -222,6 +223,9 @@ static int adp_dsi_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs adp_dsi_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = adp_dsi_bridge_attach, }; From ae2c6b34a2b0cbb36d1bf841ceae4866cac87d7b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:09 +0200 Subject: [PATCH 23/61] drm/bridge: analogix-anx6345: Switch to atomic bridge callbacks The analogix-anx6345 bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-2-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c index f3fe47b12edc..eba5c6dcb5ad 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c @@ -566,7 +566,8 @@ anx6345_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void anx6345_bridge_disable(struct drm_bridge *bridge) +static void anx6345_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx6345 *anx6345 = bridge_to_anx6345(bridge); @@ -580,7 +581,8 @@ static void anx6345_bridge_disable(struct drm_bridge *bridge) anx6345_poweroff(anx6345); } -static void anx6345_bridge_enable(struct drm_bridge *bridge) +static void anx6345_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx6345 *anx6345 = bridge_to_anx6345(bridge); int err; @@ -600,11 +602,14 @@ static void anx6345_bridge_enable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs anx6345_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = anx6345_bridge_attach, .detach = anx6345_bridge_detach, .mode_valid = anx6345_bridge_mode_valid, - .disable = anx6345_bridge_disable, - .enable = anx6345_bridge_enable, + .atomic_disable = anx6345_bridge_disable, + .atomic_enable = anx6345_bridge_enable, }; static void unregister_i2c_dummy_clients(struct anx6345 *anx6345) From e25f2a1d6e69135d17ef421843cbb5d82b114db3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:10 +0200 Subject: [PATCH 24/61] drm/bridge: analogix-anx78xx: Switch to atomic bridge callbacks The analogix-anx78xx bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-3-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c index ba0fc149a9e7..32186efa6f50 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c @@ -937,7 +937,8 @@ anx78xx_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void anx78xx_bridge_disable(struct drm_bridge *bridge) +static void anx78xx_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); @@ -975,7 +976,8 @@ static void anx78xx_bridge_mode_set(struct drm_bridge *bridge, mutex_unlock(&anx78xx->lock); } -static void anx78xx_bridge_enable(struct drm_bridge *bridge) +static void anx78xx_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); int err; @@ -992,12 +994,15 @@ static void anx78xx_bridge_enable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs anx78xx_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = anx78xx_bridge_attach, .detach = anx78xx_bridge_detach, .mode_valid = anx78xx_bridge_mode_valid, - .disable = anx78xx_bridge_disable, + .atomic_disable = anx78xx_bridge_disable, .mode_set = anx78xx_bridge_mode_set, - .enable = anx78xx_bridge_enable, + .atomic_enable = anx78xx_bridge_enable, }; static irqreturn_t anx78xx_hpd_threaded_handler(int irq, void *data) From 0dcfc4c7f7a42170b0c3a952f0f56904258a724f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:11 +0200 Subject: [PATCH 25/61] drm/bridge: aux-bridge: Add atomic bridge state handlers The aux-bridge bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-4-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/aux-bridge.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c index 1ed21a8713bf..169939d23310 100644 --- a/drivers/gpu/drm/bridge/aux-bridge.c +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -104,6 +105,9 @@ static int drm_aux_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs drm_aux_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = drm_aux_bridge_attach, }; From dc015b8b282136771c42170ec7f541cd1e22efc8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:12 +0200 Subject: [PATCH 26/61] drm/bridge: aux-hpd-bridge: Add atomic bridge state handlers The aux-hpd-bridge bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-5-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/aux-hpd-bridge.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c index f02a38a2638a..a2e525aa5788 100644 --- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -165,6 +166,9 @@ static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs drm_aux_hpd_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = drm_aux_hpd_bridge_attach, }; From 94775f06ea3c66a9023b2db4bd8211fc36301239 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:13 +0200 Subject: [PATCH 27/61] drm/bridge: chrontel-ch7033: Switch to atomic bridge callbacks The chrontel-ch7033 bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-6-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/chrontel-ch7033.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index a237c65ebd69..92d464727e41 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -330,7 +330,8 @@ static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void ch7033_bridge_disable(struct drm_bridge *bridge) +static void ch7033_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); @@ -338,7 +339,8 @@ static void ch7033_bridge_disable(struct drm_bridge *bridge) regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00); } -static void ch7033_bridge_enable(struct drm_bridge *bridge) +static void ch7033_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge); @@ -514,11 +516,14 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ch7033_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = ch7033_bridge_attach, .detach = ch7033_bridge_detach, .mode_valid = ch7033_bridge_mode_valid, - .disable = ch7033_bridge_disable, - .enable = ch7033_bridge_enable, + .atomic_disable = ch7033_bridge_disable, + .atomic_enable = ch7033_bridge_enable, .mode_set = ch7033_bridge_mode_set, }; From 43b4eda100a44e0ee2c146466f41d4806215ab3a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:14 +0200 Subject: [PATCH 28/61] drm/bridge: cros-ec-anx7688: Add atomic bridge state handlers The cros-ec-anx7688 bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-7-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/cros-ec-anx7688.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/cros-ec-anx7688.c b/drivers/gpu/drm/bridge/cros-ec-anx7688.c index a35dae9b56e2..da16c793e3ba 100644 --- a/drivers/gpu/drm/bridge/cros-ec-anx7688.c +++ b/drivers/gpu/drm/bridge/cros-ec-anx7688.c @@ -5,6 +5,7 @@ * Copyright 2020 Google LLC */ +#include #include #include #include @@ -92,6 +93,9 @@ static bool cros_ec_anx7688_bridge_mode_fixup(struct drm_bridge *bridge, } static const struct drm_bridge_funcs cros_ec_anx7688_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .mode_fixup = cros_ec_anx7688_bridge_mode_fixup, }; From 3c8c30fcd10425014bdcbafc5d75eaa6799da3f5 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:15 +0200 Subject: [PATCH 29/61] drm/bridge: lontium-lt8713sx: Add atomic bridge state handlers The lontium-lt8713sx bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-8-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt8713sx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt8713sx.c b/drivers/gpu/drm/bridge/lontium-lt8713sx.c index cee485adf5e5..4a6420b876da 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8713sx.c +++ b/drivers/gpu/drm/bridge/lontium-lt8713sx.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -508,6 +509,9 @@ static const struct attribute_group *lt8713sx_attr_groups[] = { }; static const struct drm_bridge_funcs lt8713sx_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = lt8713sx_bridge_attach, }; From b68169fc055dd26d58f8856fbf0c737af0504ce6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:16 +0200 Subject: [PATCH 30/61] drm/bridge: lontium-lt8912b: Switch to atomic bridge callbacks The lontium-lt8912b bridge uses the legacy non-atomic enable bridge callback. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Acked-by: Francesco Dolcini Tested-by: Francesco Dolcini # Verdin AM62 Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-9-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt8912b.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 729b12b67470..df5d07e7644c 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -457,7 +457,8 @@ static void lt8912_bridge_mode_set(struct drm_bridge *bridge, drm_display_mode_to_videomode(adj, <->mode); } -static void lt8912_bridge_enable(struct drm_bridge *bridge) +static void lt8912_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct lt8912 *lt = bridge_to_lt8912(bridge); @@ -634,11 +635,14 @@ static const struct drm_edid *lt8912_bridge_edid_read(struct drm_bridge *bridge, } static const struct drm_bridge_funcs lt8912_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = lt8912_bridge_attach, .detach = lt8912_bridge_detach, .mode_valid = lt8912_bridge_mode_valid, .mode_set = lt8912_bridge_mode_set, - .enable = lt8912_bridge_enable, + .atomic_enable = lt8912_bridge_enable, .detect = lt8912_bridge_detect, .edid_read = lt8912_bridge_edid_read, }; From 59a6bf37641e072d6289903bc0fdf1e042aede7b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:17 +0200 Subject: [PATCH 31/61] drm/bridge: lontium-lt9611uxc: Add atomic bridge state handlers The lontium-lt9611uxc bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-10-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 9427cc2358ae..6625ba23761c 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -465,6 +465,9 @@ static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge, } static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = lt9611uxc_bridge_attach, .mode_valid = lt9611uxc_bridge_mode_valid, .mode_set = lt9611uxc_bridge_mode_set, From c47ab48c139e8b0bd8c81639c88128a1ffb6a2d4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:18 +0200 Subject: [PATCH 32/61] drm/bridge: lvds-codec: Switch to atomic bridge callbacks The lvds-codec bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Laurent Pinchart Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-11-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/lvds-codec.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c index d1135dc3b99f..a82ea0c944eb 100644 --- a/drivers/gpu/drm/bridge/lvds-codec.c +++ b/drivers/gpu/drm/bridge/lvds-codec.c @@ -43,7 +43,8 @@ static int lvds_codec_attach(struct drm_bridge *bridge, bridge, flags); } -static void lvds_codec_enable(struct drm_bridge *bridge) +static void lvds_codec_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct lvds_codec *lvds_codec = to_lvds_codec(bridge); int ret; @@ -59,7 +60,8 @@ static void lvds_codec_enable(struct drm_bridge *bridge) gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0); } -static void lvds_codec_disable(struct drm_bridge *bridge) +static void lvds_codec_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct lvds_codec *lvds_codec = to_lvds_codec(bridge); int ret; @@ -100,8 +102,8 @@ lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge, static const struct drm_bridge_funcs funcs = { .attach = lvds_codec_attach, - .enable = lvds_codec_enable, - .disable = lvds_codec_disable, + .atomic_enable = lvds_codec_enable, + .atomic_disable = lvds_codec_disable, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_create_state = drm_atomic_helper_bridge_create_state, From 2ee765ca19e7e09ddd65770c26ef31d9e070fbfd Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:19 +0200 Subject: [PATCH 33/61] drm/bridge: megachips-stdpxxxx-ge-b850v3-fw: Add atomic bridge state handlers The megachips-stdpxxxx-ge-b850v3-fw bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Ian Ray Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-12-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 2d02cc69f237..25ff0a0acc93 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -214,6 +214,9 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = ge_b850v3_lvds_attach, .detect = ge_b850v3_lvds_bridge_detect, .edid_read = ge_b850v3_lvds_edid_read, From f9ac341cf57aeb75af0791de8b33c88ce8766185 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:20 +0200 Subject: [PATCH 34/61] drm/bridge: microchip-lvds: Add atomic bridge state handlers The microchip-lvds bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Manikandan Muralidharan Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-13-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/microchip-lvds.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c index 5fb8633f43c5..dd4ffc9f4df3 100644 --- a/drivers/gpu/drm/bridge/microchip-lvds.c +++ b/drivers/gpu/drm/bridge/microchip-lvds.c @@ -167,6 +167,9 @@ static void mchp_lvds_atomic_disable(struct drm_bridge *bridge, } static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = mchp_lvds_attach, .atomic_enable = mchp_lvds_atomic_enable, .atomic_disable = mchp_lvds_atomic_disable, From b50791afed41825ec6839889756aa39f500b45ef Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:21 +0200 Subject: [PATCH 35/61] drm/bridge: nxp-ptn3460: Switch to atomic bridge callbacks The nxp-ptn3460 bridge uses the legacy non-atomic pre_enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-14-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/nxp-ptn3460.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 7acb11f16dc1..a9b4ac2defc9 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -111,7 +111,8 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) return 0; } -static void ptn3460_pre_enable(struct drm_bridge *bridge) +static void ptn3460_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); int ret; @@ -139,7 +140,8 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) ptn_bridge->enabled = true; } -static void ptn3460_disable(struct drm_bridge *bridge) +static void ptn3460_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); @@ -163,7 +165,7 @@ static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge, int ret; power_off = !ptn_bridge->enabled; - ptn3460_pre_enable(&ptn_bridge->bridge); + ptn3460_pre_enable(&ptn_bridge->bridge, NULL); edid = kmalloc(EDID_LENGTH, GFP_KERNEL); if (!edid) { @@ -182,7 +184,7 @@ static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge, out: if (power_off) - ptn3460_disable(&ptn_bridge->bridge); + ptn3460_disable(&ptn_bridge->bridge, NULL); return drm_edid; } @@ -248,8 +250,11 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ptn3460_bridge_funcs = { - .pre_enable = ptn3460_pre_enable, - .disable = ptn3460_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = ptn3460_pre_enable, + .atomic_disable = ptn3460_disable, .attach = ptn3460_bridge_attach, .edid_read = ptn3460_edid_read, }; From 92a31e7cd5961a6f91b7b14e4c28e3bbb262b368 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:22 +0200 Subject: [PATCH 36/61] drm/bridge: of-display-mode-bridge: Add atomic bridge state handlers The of-display-mode-bridge bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-15-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/of-display-mode-bridge.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/of-display-mode-bridge.c b/drivers/gpu/drm/bridge/of-display-mode-bridge.c index e66dae168fd0..af3e727e91c9 100644 --- a/drivers/gpu/drm/bridge/of-display-mode-bridge.c +++ b/drivers/gpu/drm/bridge/of-display-mode-bridge.c @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -52,6 +53,9 @@ static int of_display_mode_bridge_get_modes(struct drm_bridge *bridge, } static const struct drm_bridge_funcs of_display_mode_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = of_display_mode_bridge_attach, .get_modes = of_display_mode_bridge_get_modes, }; From a1289e41ed6317650f60f2e8b3c1271ea13ba611 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:23 +0200 Subject: [PATCH 37/61] drm/bridge: parade-ps8622: Switch to atomic bridge callbacks The parade-ps8622 bridge uses the legacy non-atomic pre_enable, disable and post_disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-16-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/parade-ps8622.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index f879a1df077d..33844db753aa 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -336,7 +336,8 @@ static const struct backlight_ops ps8622_backlight_ops = { .update_status = ps8622_backlight_update, }; -static void ps8622_pre_enable(struct drm_bridge *bridge) +static void ps8622_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); int ret; @@ -381,13 +382,15 @@ static void ps8622_pre_enable(struct drm_bridge *bridge) ps8622->enabled = true; } -static void ps8622_disable(struct drm_bridge *bridge) +static void ps8622_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { /* Delay after panel is disabled */ msleep(PS8622_PWMO_END_T12_MS); } -static void ps8622_post_disable(struct drm_bridge *bridge) +static void ps8622_post_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); @@ -428,9 +431,12 @@ static int ps8622_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs ps8622_bridge_funcs = { - .pre_enable = ps8622_pre_enable, - .disable = ps8622_disable, - .post_disable = ps8622_post_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_pre_enable = ps8622_pre_enable, + .atomic_disable = ps8622_disable, + .atomic_post_disable = ps8622_post_disable, .attach = ps8622_attach, }; From 9acab3cbecf5d736287e754b17ea80988b4ecec4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:24 +0200 Subject: [PATCH 38/61] drm/bridge: sii9234: Add atomic bridge state handlers The sii9234 bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-17-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/sii9234.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c index e43248e515b3..be67642ab7d3 100644 --- a/drivers/gpu/drm/bridge/sii9234.c +++ b/drivers/gpu/drm/bridge/sii9234.c @@ -13,6 +13,7 @@ * Dharam Kumar */ #include +#include #include #include #include @@ -874,6 +875,9 @@ static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge, } static const struct drm_bridge_funcs sii9234_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .mode_valid = sii9234_mode_valid, }; From 22275d9f584c26a018167830a29a23adfebe2b75 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:25 +0200 Subject: [PATCH 39/61] drm/bridge: sil-sii8620: Add atomic bridge state handlers The sil-sii8620 bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-18-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/sil-sii8620.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 982306eb4f0a..22c81b38b41e 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -2280,6 +2281,9 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge, } static const struct drm_bridge_funcs sii8620_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = sii8620_attach, .detach = sii8620_detach, .mode_fixup = sii8620_mode_fixup, From 0a01de65a741da622e06dd3c31289ce1053b1a77 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:26 +0200 Subject: [PATCH 40/61] drm/bridge: simple-bridge: Switch to atomic bridge callbacks The simple-bridge bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-19-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/simple-bridge.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index cc13c98f9be6..3fba7002322e 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -132,7 +132,8 @@ static int simple_bridge_attach(struct drm_bridge *bridge, return 0; } -static void simple_bridge_enable(struct drm_bridge *bridge) +static void simple_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); int ret; @@ -146,7 +147,8 @@ static void simple_bridge_enable(struct drm_bridge *bridge) gpiod_set_value_cansleep(sbridge->enable, 1); } -static void simple_bridge_disable(struct drm_bridge *bridge) +static void simple_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); @@ -157,9 +159,12 @@ static void simple_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs simple_bridge_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = simple_bridge_attach, - .enable = simple_bridge_enable, - .disable = simple_bridge_disable, + .atomic_enable = simple_bridge_enable, + .atomic_disable = simple_bridge_disable, }; static int simple_bridge_probe(struct platform_device *pdev) From f27a178ddc9963c5c6c0dd239940c358eabdf08d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:27 +0200 Subject: [PATCH 41/61] drm/bridge: tc358764: Switch to atomic bridge callbacks The tc358764 bridge uses the legacy non-atomic pre_enable and post_disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-20-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/tc358764.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 12b43245bb8f..f55a56cbd88f 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -266,7 +266,8 @@ static void tc358764_reset(struct tc358764 *ctx) usleep_range(1000, 2000); } -static void tc358764_post_disable(struct drm_bridge *bridge) +static void tc358764_post_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tc358764 *ctx = bridge_to_tc358764(bridge); int ret; @@ -278,7 +279,8 @@ static void tc358764_post_disable(struct drm_bridge *bridge) dev_err(ctx->dev, "error disabling regulators (%d)\n", ret); } -static void tc358764_pre_enable(struct drm_bridge *bridge) +static void tc358764_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tc358764 *ctx = bridge_to_tc358764(bridge); int ret; @@ -303,8 +305,11 @@ static int tc358764_attach(struct drm_bridge *bridge, } static const struct drm_bridge_funcs tc358764_bridge_funcs = { - .post_disable = tc358764_post_disable, - .pre_enable = tc358764_pre_enable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_post_disable = tc358764_post_disable, + .atomic_pre_enable = tc358764_pre_enable, .attach = tc358764_attach, }; From ad0e737d5ce4b0218fcacd3b19a4794ed4324673 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:28 +0200 Subject: [PATCH 42/61] drm/bridge: tda998x: Switch to atomic bridge callbacks The tda998x bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-21-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/tda998x_drv.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c index 6c427bc75896..16c745591175 100644 --- a/drivers/gpu/drm/bridge/tda998x_drv.c +++ b/drivers/gpu/drm/bridge/tda998x_drv.c @@ -1410,7 +1410,8 @@ static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void tda998x_bridge_enable(struct drm_bridge *bridge) +static void tda998x_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); @@ -1428,7 +1429,8 @@ static void tda998x_bridge_enable(struct drm_bridge *bridge) } } -static void tda998x_bridge_disable(struct drm_bridge *bridge) +static void tda998x_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); @@ -1745,12 +1747,15 @@ static void tda998x_bridge_hpd_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs tda998x_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = tda998x_bridge_attach, .detach = tda998x_bridge_detach, .mode_valid = tda998x_bridge_mode_valid, - .disable = tda998x_bridge_disable, + .atomic_disable = tda998x_bridge_disable, .mode_set = tda998x_bridge_mode_set, - .enable = tda998x_bridge_enable, + .atomic_enable = tda998x_bridge_enable, .edid_read = tda998x_bridge_edid_read, .detect = tda998x_bridge_detect, .hpd_enable = tda998x_bridge_hpd_enable, From d2281093ace59d5a9293f9a0cef979c596e2d5ec Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:29 +0200 Subject: [PATCH 43/61] drm/bridge: ti-tfp410: Switch to atomic bridge callbacks The ti-tfp410 bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on is_bridge @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Laurent Pinchart Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-22-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-tfp410.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index 6f06f7b4e992..f0a14f52aaac 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -174,14 +174,16 @@ static void tfp410_detach(struct drm_bridge *bridge) } } -static void tfp410_enable(struct drm_bridge *bridge) +static void tfp410_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tfp410 *dvi = drm_bridge_to_tfp410(bridge); gpiod_set_value_cansleep(dvi->powerdown, 0); } -static void tfp410_disable(struct drm_bridge *bridge) +static void tfp410_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct tfp410 *dvi = drm_bridge_to_tfp410(bridge); @@ -242,8 +244,8 @@ static int tfp410_atomic_check(struct drm_bridge *bridge, static const struct drm_bridge_funcs tfp410_bridge_funcs = { .attach = tfp410_attach, .detach = tfp410_detach, - .enable = tfp410_enable, - .disable = tfp410_disable, + .atomic_enable = tfp410_enable, + .atomic_disable = tfp410_disable, .mode_valid = tfp410_mode_valid, .atomic_create_state = drm_atomic_helper_bridge_create_state, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, From cf083a5e46143566f8a923da29010870aa675ca1 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:30 +0200 Subject: [PATCH 44/61] drm/bridge: ti-tpd12s015: Add atomic bridge state handlers The ti-tpd12s015 bridge doesn't implement any enable or disable callbacks, but is still missing the atomic state handlers. In order to remove the legacy bridge callback support from the DRM bridge core, add them. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-23-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/ti-tpd12s015.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c index 136e47ad1a10..e7b172ab7f55 100644 --- a/drivers/gpu/drm/bridge/ti-tpd12s015.c +++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c @@ -19,6 +19,7 @@ #include #include +#include #include struct tpd12s015_device { @@ -96,6 +97,9 @@ static void tpd12s015_hpd_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs tpd12s015_bridge_funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = tpd12s015_attach, .detach = tpd12s015_detach, .detect = tpd12s015_bridge_detect, From 1e503f172cf98b5628c5a4130a23afca86ed3f9e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:31 +0200 Subject: [PATCH 45/61] drm/bridge: thc63lvd1024: Switch to atomic bridge callbacks The thc63lvd1024 bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-24-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/thc63lvd1024.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c index c804222846c3..679b424ba0c3 100644 --- a/drivers/gpu/drm/bridge/thc63lvd1024.c +++ b/drivers/gpu/drm/bridge/thc63lvd1024.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -81,7 +82,8 @@ static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void thc63_enable(struct drm_bridge *bridge) +static void thc63_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct thc63_dev *thc63 = to_thc63(bridge); int ret; @@ -97,7 +99,8 @@ static void thc63_enable(struct drm_bridge *bridge) gpiod_set_value(thc63->oe, 1); } -static void thc63_disable(struct drm_bridge *bridge) +static void thc63_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct thc63_dev *thc63 = to_thc63(bridge); int ret; @@ -112,10 +115,13 @@ static void thc63_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs thc63_bridge_func = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .attach = thc63_attach, .mode_valid = thc63_mode_valid, - .enable = thc63_enable, - .disable = thc63_disable, + .atomic_enable = thc63_enable, + .atomic_disable = thc63_disable, }; static int thc63_parse_dt(struct thc63_dev *thc63) From cc83959891cbb437dd8e1309c7d0bca287634bfa Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:32 +0200 Subject: [PATCH 46/61] drm/bridge: waveshare-dsi: Switch to atomic bridge callbacks The waveshare-dsi bridge uses the legacy non-atomic enable and disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-25-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/bridge/waveshare-dsi.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c index ded57f298d64..9c9825c9b7c5 100644 --- a/drivers/gpu/drm/bridge/waveshare-dsi.c +++ b/drivers/gpu/drm/bridge/waveshare-dsi.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -92,7 +93,8 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge, &ws->bridge, flags); } -static void ws_bridge_bridge_enable(struct drm_bridge *bridge) +static void ws_bridge_bridge_enable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ws_bridge *ws = bridge_to_ws_bridge(bridge); @@ -100,7 +102,8 @@ static void ws_bridge_bridge_enable(struct drm_bridge *bridge) backlight_enable(ws->backlight); } -static void ws_bridge_bridge_disable(struct drm_bridge *bridge) +static void ws_bridge_bridge_disable(struct drm_bridge *bridge, + struct drm_atomic_commit *commit) { struct ws_bridge *ws = bridge_to_ws_bridge(bridge); @@ -109,8 +112,11 @@ static void ws_bridge_bridge_disable(struct drm_bridge *bridge) } static const struct drm_bridge_funcs ws_bridge_bridge_funcs = { - .enable = ws_bridge_bridge_enable, - .disable = ws_bridge_bridge_disable, + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_enable = ws_bridge_bridge_enable, + .atomic_disable = ws_bridge_bridge_disable, .attach = ws_bridge_bridge_attach, }; From d1fd3717bb135f972099df881d2921b0d452e5b4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 7 Jul 2026 17:11:33 +0200 Subject: [PATCH 47/61] drm/exynos: mic: Switch to atomic bridge callbacks The mic bridge uses the legacy non-atomic pre_enable and post_disable bridge callbacks. In order to remove the legacy bridge callback support from the DRM bridge core, switch to their atomic counterparts and add the bridge atomic state handlers. Generated by the following Coccinelle script: @ is_bridge @ identifier funcs; @@ struct drm_bridge_funcs funcs = { ..., }; @ has_create_state depends on is_bridge @ identifier funcs, f; @@ struct drm_bridge_funcs funcs = { ..., .atomic_create_state = f, ..., }; @ update_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { + .atomic_create_state = drm_atomic_helper_bridge_create_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ..., }; @ update_pre_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .pre_enable = f, + .atomic_pre_enable = f, ..., }; @ update_pre_enable_impl depends on update_pre_enable_struct @ identifier update_pre_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_enable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .enable = f, + .atomic_enable = f, ..., }; @ update_enable_impl depends on update_enable_struct @ identifier update_enable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .disable = f, + .atomic_disable = f, ..., }; @ update_disable_impl depends on update_disable_struct @ identifier update_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } @ update_post_disable_struct depends on (is_bridge && !has_create_state) @ identifier is_bridge.funcs; identifier f; @@ struct drm_bridge_funcs funcs = { ..., - .post_disable = f, + .atomic_post_disable = f, ..., }; @ update_post_disable_impl depends on update_post_disable_struct @ identifier update_post_disable_struct.f; identifier b; @@ -void f(struct drm_bridge *b) +void f(struct drm_bridge *b, struct drm_atomic_commit *commit) { ... } Reviewed-by: Luca Ceresoli Link: https://patch.msgid.link/20260707-drm-all-atomic-bridges-v2-26-21d03cbca446@kernel.org Signed-off-by: Maxime Ripard --- drivers/gpu/drm/exynos/exynos_drm_mic.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index e68c954ec3e6..3069f958137f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -21,6 +21,7 @@ #include