Linux kernel -stable discussions
 help / color / mirror / Atom feed
* Re: [PATCH] io_uring/io-wq: re-check IO_WQ_BIT_EXIT for each linked work item
From: Jens Axboe @ 2026-05-27 16:03 UTC (permalink / raw)
  To: Runyu Xiao, io-uring; +Cc: linux-kernel, gregkh, jianhao.xu, stable
In-Reply-To: <20260527143726.1272269-1-runyu.xiao@seu.edu.cn>

On 5/27/26 8:37 AM, Runyu Xiao wrote:
> Commit bdf0bf73006e ("io_uring/io-wq: check IO_WQ_BIT_EXIT inside work
> run loop") fixed the obvious case where io_worker_handle_work() took one
> exit-bit snapshot before draining pending work, but the fix stops one
> level too early.
> 
> io_worker_handle_work() now re-checks IO_WQ_BIT_EXIT in its outer work
> run loop, yet it still snapshots that bit once before processing a
> whole dependent linked-work chain. If io_wq_exit_start() sets
> IO_WQ_BIT_EXIT after the first linked item has started, the remaining
> linked items can still reuse stale do_kill = false, skip
> IO_WQ_WORK_CANCEL, and continue running after exit has begun.
> 
> That means the previous fix did not fully eliminate the exit-latency
> problem; it only narrowed it to linked chains. A long or slow linked
> chain can still keep io-wq exit waiting for work that should already
> have been canceled.
> 
> The issue was found on Linux v6.18.21 by our static-analysis tool,
> which flagged linked-work loops that snapshot shared exit state
> outside per-item cancel decisions, and was then confirmed by manual
> auditing of io_worker_handle_work(). It was later reproduced with a
> QEMU no-device validation selftest that preserved the same contract:
> a three-node unbound linked chain, an exit actor setting
> IO_WQ_BIT_EXIT after work1, and slow post-exit linked work. With a
> 3000 ms delay injected into each post-exit item, the buggy path
> spends about 6066 ms after exit running work2/work3, while the fixed
> path cancels both and finishes in about 2 ms.
> 
> Re-check test_bit(IO_WQ_BIT_EXIT, &wq->state) for each iteration of the
> dependent-link loop, right before deciding whether to cancel the
> current work item. That closes the remaining stale-snapshot window and
> prevents linked post-exit work from stretching shutdown latency.

I think this change makes sense to further cut down on the time, but you
need to send it in for the _upstream_ kernel, stable only does backports
of those. Eg if you send this one for current -git and mark it fixing
the correct upstream commit (not the stable one) and add CC stable, then
it'll wind up in stable as well.

-- 
Jens Axboe

^ permalink raw reply

* Re: [PATCH 1/2] btrfs: fix false IO failure after falling back to buffered IO
From: Boris Burkov @ 2026-05-27 16:01 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs, stable
In-Reply-To: <b3393b113c45ac7bd7b2649576b5667395c22a1b.1779846117.git.wqu@suse.com>

On Wed, May 27, 2026 at 02:36:44PM +0930, Qu Wenruo wrote:
> [BUG]
> The test case generic/362 will fail with "nodatasum" mount option (*):
> 
>  MOUNT_OPTIONS -- -o nodatasum /dev/mapper/test-scratch1 /mnt/scratch
> 
>  generic/362  0s ... - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad)
>     --- tests/generic/362.out	2024-08-24 15:31:37.200000000 +0930
>     +++ /home/adam/xfstests/results//generic/362.out.bad	2026-05-27 10:21:17.574771567 +0930
>     @@ -1,2 +1,3 @@
>      QA output created by 362
>     +First write failed: Input/output error
>      Silence is golden
>     ...
> 
> *: If the test case has been executed before with default data checksum,
> the failure will not reproduce. Need the following fix to make it
> reliably reproducible:
> https://lore.kernel.org/linux-btrfs/20260526070055.60193-1-wqu@suse.com/
> 
> [CAUSE]
> Btrfs direct write disable page fault of the input buffer, this is to
> avoid a deadlock specific to btrfs.
> 
> So for the test case generic/362, it uses an anonymous page as input
> buffer. And since the page is not yet faulted in, the direct IO will
> fail with -EFAULT, causing us to go through the following call chain:
> 
>  btrfs_direct_write()

I believe that when direct_write() sees EFAULT from btrfs_dio_write() it
should do the fault and retry, not fallback straight to buffered.

	if (iov_iter_count(from) > 0 && (ret == -EFAULT || ret > 0)) {
		const size_t left = iov_iter_count(from);
		/*
		 * We have more data left to write. Try to fault in as many as
		 * possible of the remainder pages and retry. We do this without
		 * releasing and locking again the inode, to prevent races with
		 * truncate.
		 *
		 * Also, in case the iov refers to pages in the file range of the
		 * file we want to write to (due to a mmap), we could enter an
		 * infinite loop if we retry after faulting the pages in, since
		 * iomap will invalidate any pages in the range early on, before
		 * it tries to fault in the pages of the iov. So we keep track of
		 * how much was left of iov in the previous EFAULT and fallback
		 * to buffered IO in case we haven't made any progress.
		 */
		if (left == prev_left) {
			ret = -ENOTBLK;
		} else {
			fault_in_iov_iter_readable(from, left);
			prev_left = left;
			goto again;
		}
	}

>  |- btrfs_dio_write()
>  |  |- btrfs_dio_iomap_end()
>  |     |- btrfs_finish_ordered_extent(uptodate = false);
>  |        |- can_finish_ordered_extent()
>  |           |- btrfs_mark_ordered_extent_error()
>  |              |- mapping_set_error()
>  |                 Now the address space is marked error.
>  |
>  |- iomap_dio_complete()
>  |  The dio bio is empty, nothing submitted.
>  |
>  |- Fallback to buffered
>  |  And the buffered write finished without error
>  |
>  |- filemap_fdatawait_range()
>     |- filemap_check_errors()
>        The previous error is recorded, thus an error is returned
> 
> However the buffered write is properly submitted and finished, the error
> is from the previous short dio write.
> 
> [FIX]
> When a short dio write happened, we shouldn't mark it as an error, but
> treat it like a truncated write.

I am quite skeptical of this as the proper fix. I looked into this
really thoroughly back in
https://lore.kernel.org/linux-btrfs/20230328051957.1161316-12-hch@lst.de/
and remember concluding it was much better to do the OE split and submit
separate direct writes, and I believe it was more or less working. I am
willing to believe that the mapping_set_error() thing slipped through
the cracks, though, so I apologize if I missed that detail. Has
something changed since then that makes us fall back to buffered on a
write buffer fault? Or am I misunderstanding something about what is
happening in this case?

g/708 is the test case for that particular corruption, FYI.

Thanks for looking into it,
Boris

> 
> Extract a helper, btrfs_mark_ordered_extent_truncated(), and utilize
> that helper to mark the direct IO ordered extent as truncated, so it
> won't cause failure for the later buffered fallback.
> 
> Cc: stable@vger.kernel.org # 6.1+
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>  fs/btrfs/direct-io.c    | 18 +++++++++++++-----
>  fs/btrfs/inode.c        |  6 +-----
>  fs/btrfs/ordered-data.c | 12 ++++++++++++
>  fs/btrfs/ordered-data.h |  2 ++
>  4 files changed, 28 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c
> index 57167d56dc72..598480b77002 100644
> --- a/fs/btrfs/direct-io.c
> +++ b/fs/btrfs/direct-io.c
> @@ -610,6 +610,7 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length,
>  {
>  	struct iomap_iter *iter = container_of(iomap, struct iomap_iter, iomap);
>  	struct btrfs_dio_data *dio_data = iter->private;
> +	struct btrfs_ordered_extent *ordered = dio_data->ordered;
>  	size_t submitted = dio_data->submitted;
>  	const bool write = !!(flags & IOMAP_WRITE);
>  	int ret = 0;
> @@ -624,16 +625,23 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length,
>  	if (submitted < length) {
>  		pos += submitted;
>  		length -= submitted;
> -		if (write)
> -			btrfs_finish_ordered_extent(dio_data->ordered,
> -						    pos, length, false);
> -		else
> +		if (write) {
> +			/*
> +			 * We got a short write, will fallback to buffered IO
> +			 * for the whole range.
> +			 * Set the truncate length to 0, so that no real file
> +			 * extent item will be created.
> +			 */
> +			btrfs_mark_ordered_extent_truncated(ordered, 0);
> +			btrfs_finish_ordered_extent(ordered, pos, length, true);
> +		} else {
>  			btrfs_unlock_dio_extent(&BTRFS_I(inode)->io_tree, pos,
>  						pos + length - 1, NULL);
> +		}
>  		ret = -ENOTBLK;
>  	}
>  	if (write) {
> -		btrfs_put_ordered_extent(dio_data->ordered);
> +		btrfs_put_ordered_extent(ordered);
>  		dio_data->ordered = NULL;
>  	}
>  
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 973a89301baa..2c0131452754 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -7590,11 +7590,7 @@ static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
>  					       EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
>  					       EXTENT_DEFRAG, &cached_state);
>  
> -		spin_lock(&inode->ordered_tree_lock);
> -		set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
> -		ordered->truncated_len = min(ordered->truncated_len,
> -					     cur - ordered->file_offset);
> -		spin_unlock(&inode->ordered_tree_lock);
> +		btrfs_mark_ordered_extent_truncated(ordered, cur - ordered->file_offset);
>  
>  		/*
>  		 * If the ordered extent has finished, we're safe to delete all
> diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
> index f5f77c33cf59..b32d4eabe0ab 100644
> --- a/fs/btrfs/ordered-data.c
> +++ b/fs/btrfs/ordered-data.c
> @@ -358,6 +358,18 @@ void btrfs_mark_ordered_extent_error(struct btrfs_ordered_extent *ordered)
>  		mapping_set_error(ordered->inode->vfs_inode.i_mapping, -EIO);
>  }
>  
> +void btrfs_mark_ordered_extent_truncated(struct btrfs_ordered_extent *ordered,
> +					 u64 truncate_len)
> +{
> +	struct btrfs_inode *inode = ordered->inode;
> +
> +	ASSERT(truncate_len <= ordered->num_bytes);
> +	spin_lock(&inode->ordered_tree_lock);
> +	set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
> +	ordered->truncated_len = min(ordered->truncated_len, truncate_len);
> +	spin_unlock(&inode->ordered_tree_lock);
> +}
> +
>  static void finish_ordered_fn(struct btrfs_work *work)
>  {
>  	struct btrfs_ordered_extent *ordered_extent;
> diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
> index 03e12380a2fd..8d5d5ba1e02f 100644
> --- a/fs/btrfs/ordered-data.h
> +++ b/fs/btrfs/ordered-data.h
> @@ -226,6 +226,8 @@ bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end,
>  struct btrfs_ordered_extent *btrfs_split_ordered_extent(
>  			struct btrfs_ordered_extent *ordered, u64 len);
>  void btrfs_mark_ordered_extent_error(struct btrfs_ordered_extent *ordered);
> +void btrfs_mark_ordered_extent_truncated(struct btrfs_ordered_extent *ordered,
> +					 u64 truncate_len);
>  int __init ordered_data_init(void);
>  void __cold ordered_data_exit(void);
>  
> -- 
> 2.54.0
> 

^ permalink raw reply

* Re: [PATCH 1/1] HID: wacom: Fix OOB write in wacom_hid_set_device_mode()
From: Lee Jones @ 2026-05-27 15:57 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Ping Cheng, Ping Cheng, Jason Gerecke, Jiri Kosina, linux-input,
	linux-kernel, stable
In-Reply-To: <20260521162212.GF3591266@google.com>

On Thu, 21 May 2026, Lee Jones wrote:

> On Thu, 21 May 2026, Benjamin Tissoires wrote:
> 
> > On May 19 2026, Lee Jones wrote:
> > > On Wed, 13 May 2026, Ping Cheng wrote:
> > > 
> > > > On Wed, May 13, 2026 at 1:05 AM Lee Jones <lee@kernel.org> wrote:
> > > > >
> > > > > wacom_hid_set_device_mode() currently assumes that the HID_DG_INPUTMODE
> > > > > usage is always located in the first field (field[0]) of the feature report.
> > > > > However, a device can specify HID_DG_INPUTMODE in a different field.
> > > > >
> > > > > If HID_DG_INPUTMODE is in a field other than the first one and the first
> > > > > field has a report_count smaller than the usage_index of HID_DG_INPUTMODE,
> > > > > this leads to an out-of-bounds write to r->field[0]->value.
> > > > >
> > > > > Fix this by storing the field index of HID_DG_INPUTMODE in 'struct
> > > > > hid_data' during feature mapping.  In wacom_hid_set_device_mode(), use
> > > > > this stored field index to access the correct field and add bounds
> > > > > checks to ensure both the field index and the value index are within
> > > > > valid ranges before writing.
> > > > >
> > > > > Cc: stable@vger.kernel.org
> > > > > Fixes: 5ae6e89f7409 ("HID: wacom: implement the finger part of the HID generic handling")
> > > > > Signed-off-by: Lee Jones <lee@kernel.org>
> > > > 
> > > > Patch looks sensible to me. Thank you for your effort, Lee!
> > > > 
> > > > Tested-by: Ping Cheng <ping.cheng@wacom.com>
> > > > Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
> > > 
> > > Thank you Ping, I appreciate your review.
> > > 
> > > HID folks - any movement on this please?
> > > 
> > 
> > I wanted to apply it today, but the patch conflicts with our current
> > for-7.1/upstream-fixes.
> > 
> > Could you rebase on top of this branch so we can take this without me
> > messing with your patch?
> 
> Sure.  Leave it with me.  Probably be early next week.

Are you sure this conflicted?

I just rebased it onto hid/for-7.1/upstream-fixes without issue.

-- 
Lee Jones

^ permalink raw reply

* Re: [PATCH v3 2/2] x86/tdx: Fix zero-extension for 32-bit port I/O
From: Edgecombe, Rick P @ 2026-05-27 15:45 UTC (permalink / raw)
  To: x86@kernel.org, mingo@redhat.com, kas@kernel.org, tglx@kernel.org,
	bp@alien8.de, dave.hansen@linux.intel.com
  Cc: seanjc@google.com, Huang, Kai, hpa@zytor.com,
	sathyanarayanan.kuppuswamy@linux.intel.com,
	linux-kernel@vger.kernel.org, tsyrulnikov.borys@gmail.com,
	kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	stable@vger.kernel.org
In-Reply-To: <20260527120544.2903923-3-kas@kernel.org>

On Wed, 2026-05-27 at 13:05 +0100, Kiryl Shutsemau (Meta) wrote:
> +	/*
> +	 * IN writes the result into a sub-register of RAX. Only the
> +	 * 32-bit form zero-extends; the smaller forms leave the upper
> +	 * bits untouched:
> +	 *
> +	 *   insn  dest  size  bits written     bits preserved
> +	 *   inb   AL    1     RAX[ 7: 0]       RAX[63: 8]
> +	 *   inw   AX    2     RAX[15: 0]       RAX[63:16]
> +	 *   inl   EAX   4     RAX[63: 0]       (none, zero-extended)

We are working on getting the GHCI spec amended to clarify who is supposed to do
this zero-extending and masking, host or guest. For this and the similar
tdvmcalls. The process involves getting all VMMs in agreement.

Today I think the spec doesn't say to *not* do it, so I think it is reasonable
to merge this, but there is some small risk of complications depending on how
that discussion goes.

> +	 *
> +	 * 'mask' only covers the low 'size' bytes, which is exactly the
> +	 * range affected for size 1 and 2. For size 4 the write also
> +	 * clears RAX[63:32], so widen the clear-mask.
> +	 */


^ permalink raw reply

* Re: [PATCH] nvme: target: rdma: fix ndev refcount leak on queue connect
From: Keith Busch @ 2026-05-27 15:41 UTC (permalink / raw)
  To: Wentao Liang
  Cc: Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni, linux-nvme,
	linux-kernel, stable
In-Reply-To: <20260527084544.864221-1-vulab@iscas.ac.cn>

On Wed, May 27, 2026 at 08:45:44AM +0000, Wentao Liang wrote:
> nvmet_rdma_queue_connect() calls nvmet_rdma_find_get_device() which
> acquires a reference on the returned ndev via kref_get(). On the path
> where the host queue backlog is exceeded and the function returns
> NVME_SC_CONNECT_CTRL_BUSY, reference of ndev is not released, leaking
> the kref.
> 
> Fix this by adding a goto to the existing put_device label before the
> early return.

Thanks, applied to nvme-7.2.

^ permalink raw reply

* Re: [PATCH v3 1/2] x86/tdx: Fix off-by-one in port I/O handling
From: Edgecombe, Rick P @ 2026-05-27 15:38 UTC (permalink / raw)
  To: x86@kernel.org, mingo@redhat.com, kas@kernel.org, tglx@kernel.org,
	bp@alien8.de, dave.hansen@linux.intel.com
  Cc: seanjc@google.com, Huang, Kai, hpa@zytor.com,
	sathyanarayanan.kuppuswamy@linux.intel.com,
	linux-kernel@vger.kernel.org, tsyrulnikov.borys@gmail.com,
	kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	stable@vger.kernel.org
In-Reply-To: <20260527120544.2903923-2-kas@kernel.org>

On Wed, 2026-05-27 at 13:05 +0100, Kiryl Shutsemau (Meta) wrote:
> handle_in() and handle_out() in arch/x86/coco/tdx/tdx.c use:
> 
>     u64 mask = GENMASK(BITS_PER_BYTE * size, 0);
> 
> GENMASK(h, l) includes bit h. For size=1 (INB), this produces
> GENMASK(8, 0) = 0x1FF (9 bits) instead of GENMASK(7, 0) = 0xFF (8
> bits). The mask is one bit too wide for all I/O sizes.
> 
> Fix the mask calculation.
> 
> Fixes: 03149948832a ("x86/tdx: Port I/O: Add runtime hypercalls")
> Reported-by: Borys Tsyrulnikov <tsyrulnikov.borys@gmail.com>
> Link:
> https://lore.kernel.org/all/CAKw_Dz96rfSQc6Rn+9QBcUFHhmkK+9zu+P=bxowfZwxrATCBRg@mail.gmail.com/
> Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> Reviewed-by: Kai Huang <kai.huang@intel.com>
> Reviewed-by: Kuppuswamy Sathyanarayanan
> <sathyanarayanan.kuppuswamy@linux.intel.com>
> Cc: stable@vger.kernel.org

Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>

^ permalink raw reply

* Re: (subset) [PATCH 01/23] mfd: tps6586x: fix OF node refcount
From: Lee Jones @ 2026-05-27 15:36 UTC (permalink / raw)
  To: Lee Jones, Mark Brown, Thierry Reding, Sebastian Hesselbarth,
	Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Srinivas Kandagatla, Greg Kroah-Hartman, Vinod Koul,
	Rafael J. Wysocki, Danilo Krummrich, Rob Herring, Saravana Kannan,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Andi Shyti, Andy Shevchenko,
	Joerg Roedel, Will Deacon, Robin Murphy, Doug Berger,
	Florian Fainelli, Broadcom internal kernel review list,
	Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Matthew Brost, Thomas Hellström, Rodrigo Vivi,
	David Airlie, Simona Vetter, Peter Chen, Paul Cercueil, Bin Liu,
	Philipp Zabel, Maximilian Luz, Hans de Goede, Ilpo Järvinen,
	Krzysztof Kozlowski, Benjamin Herrenschmidt, Bartosz Golaszewski
  Cc: brgl, linux-kernel, netdev, linux-arm-msm, linux-sound,
	driver-core, devicetree, linuxppc-dev, linux-i2c, iommu, linux-pm,
	imx, linux-arm-kernel, intel-xe, dri-devel, linux-usb, linux-mips,
	platform-driver-x86, stable
In-Reply-To: <20260521-pdev-fwnode-ref-v1-1-88c324a1b8d2@oss.qualcomm.com>

On Thu, 21 May 2026 10:36:24 +0200, Bartosz Golaszewski wrote:
> Platform devices created with platform_device_alloc() call
> platform_device_release() when the last reference to the device's
> kobject is dropped. This function calls of_node_put() unconditionally.
> This works fine for devices created with platform_device_register_full()
> but users of the split approach (platform_device_alloc() +
> platform_device_add()) must bump the reference of the of_node they
> assign manually. Add the missing call to of_node_get().
> 
> [...]

Applied, thanks!

[01/23] mfd: tps6586x: fix OF node refcount
        commit: 60a28e85ba5c0707b743857a3304107f2f9d0482

--
Lee Jones [李琼斯]


^ permalink raw reply

* [PATCH V2 4/7] perf/x86/intel/uncore: Defer ADL global PMON enable to enable_box()
From: Zide Chen @ 2026-05-27 15:11 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
	Andi Kleen, Eranian Stephane
  Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen, stable
In-Reply-To: <20260527151154.130505-1-zide.chen@intel.com>

On some Raptor Cove CPUs, enabling uncore PMON globally at driver init
may increase power consumption even when no perf events are in use.

Drop adl_uncore_msr_init_box() and defer programming the global control
register to enable_box(), so it is only set when a box is actually used.

IMC and IMC freerunning counters use a separate control path and are
unaffected.

Cc: stable@vger.kernel.org
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
 arch/x86/events/intel/uncore_snb.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/arch/x86/events/intel/uncore_snb.c b/arch/x86/events/intel/uncore_snb.c
index 3dbc6bacbd9d..edddd4f9ab5f 100644
--- a/arch/x86/events/intel/uncore_snb.c
+++ b/arch/x86/events/intel/uncore_snb.c
@@ -563,12 +563,6 @@ void tgl_uncore_cpu_init(void)
 	skl_uncore_msr_ops.init_box = rkl_uncore_msr_init_box;
 }
 
-static void adl_uncore_msr_init_box(struct intel_uncore_box *box)
-{
-	if (box->pmu->pmu_idx == 0)
-		wrmsrq(ADL_UNC_PERF_GLOBAL_CTL, SNB_UNC_GLOBAL_CTL_EN);
-}
-
 static void adl_uncore_msr_enable_box(struct intel_uncore_box *box)
 {
 	wrmsrq(ADL_UNC_PERF_GLOBAL_CTL, SNB_UNC_GLOBAL_CTL_EN);
@@ -587,7 +581,6 @@ static void adl_uncore_msr_exit_box(struct intel_uncore_box *box)
 }
 
 static struct intel_uncore_ops adl_uncore_msr_ops = {
-	.init_box	= adl_uncore_msr_init_box,
 	.enable_box	= adl_uncore_msr_enable_box,
 	.disable_box	= adl_uncore_msr_disable_box,
 	.exit_box	= adl_uncore_msr_exit_box,
-- 
2.54.0


^ permalink raw reply related

* [PATCH] usb: gadget: composite: fix dead empty check in the USB_DT_OTG handler
From: Maoyi Xie @ 2026-05-27 15:08 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel, Maoyi Xie, stable

The OTG branch of composite_setup() falls back to the first
configuration when none is selected:

	if (cdev->config)
		config = cdev->config;
	else
		config = list_first_entry(&cdev->configs,
					  struct usb_configuration, list);
	if (!config)
		goto done;
	...
	memcpy(req->buf, config->descriptors[0], value);

list_first_entry() never returns NULL. On an empty list it returns
container_of() of the list head. So the "if (!config)" check is dead.

When cdev->configs is empty, config points at the head inside struct
usb_composite_dev. config->descriptors[0] reads whatever sits at that
offset. The memcpy copies up to w_length bytes of it into the response
buffer.

cdev->configs can be empty in two cases. One is a teardown race on
gadget unbind with a control transfer in flight. The other is a driver
that sets is_otg before it adds a config. A reproducer that holds
cdev->configs empty triggers a KASAN fault in this branch.

Use list_first_entry_or_null() so the existing check does its job.

Fixes: 53e6242db8d6 ("usb: gadget: composite: add USB_DT_OTG request handling")
Cc: stable@vger.kernel.org
Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
---
This is the fix for the problem I reported on linux-usb on 2026-05-20 [1].
The full KASAN report and the reproducer are in that message.

[1] https://lore.kernel.org/linux-usb/20260519184106.2356558-1-maoyixie.tju@gmail.com/

 drivers/usb/gadget/composite.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index a902184bdf82..a5e7c6495949 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1863,9 +1863,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 				if (cdev->config)
 					config = cdev->config;
 				else
-					config = list_first_entry(
+					config = list_first_entry_or_null(
 							&cdev->configs,
-						struct usb_configuration, list);
+							struct usb_configuration,
+							list);
 				if (!config)
 					goto done;
 
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH] Input: ims-pcu - fix use-after-free in probe error path
From: Dmitry Torokhov @ 2026-05-27 14:58 UTC (permalink / raw)
  To: Zhian Liang; +Cc: linux-input, linux-kernel, stable
In-Reply-To: <20260525151410.42750-1-liangzhan5dev@gmail.com>

On Mon, May 25, 2026 at 11:14:10PM +0800, Zhian Liang wrote:
> If the driver fails during init (e.g. in ims_pcu_init_application_mode),the error path frees the pcu struct without clearing the interface data.
> 
> If the device is disconnected while in this state, the disconnect handler will retrieve the stale pointer from
> usb_get_intfdata() and trigger a use-after-free

This does not make sense. How will disconnect handler run if probe has
not completed?

> 
> Fix this by setting the interface data to NULL in the probe before freeing the pcu struct.
> 
> Fixes: 628329d52474 ("Input: add IMS Passenger Control Unit driver")
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Zhian Liang <liangzhan5dev@gmail.com>
> ---
>  drivers/input/misc/ims-pcu.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
> index 4c022a36dbe8..fce3232ebf07 100644
> --- a/drivers/input/misc/ims-pcu.c
> +++ b/drivers/input/misc/ims-pcu.c
> @@ -2063,6 +2063,10 @@ static int ims_pcu_probe(struct usb_interface *intf,
>  	ims_pcu_buffers_free(pcu);
>  err_unclaim_intf:
>  	usb_driver_release_interface(&ims_pcu_driver, pcu->data_intf);
> +	goto err_clear_intfdata;
> +err_clear_intfdata:
> +	if (pcu->ctrl_intf)
> +		usb_set_intfdata(pcu->ctrl_intf, NULL);
>  err_free_mem:
>  	kfree(pcu);
>  	return error;

Thanks.

-- 
Dmitry

^ permalink raw reply

* [PATCH v3 01/10] drm/damage-helper: Do not alter damage clips on modeset, but ignore them
From: Thomas Zimmermann @ 2026-05-27 14:46 UTC (permalink / raw)
  To: mripard, maarten.lankhorst, airlied, airlied, simona, admin,
	gargaditya08, paul, jani.nikula, mhklinux, zack.rusin,
	bcm-kernel-feedback-list
  Cc: dri-devel, linux-hyperv, intel-gfx, intel-xe, linux-mips,
	virtualization, Thomas Zimmermann, stable
In-Reply-To: <20260527145113.241595-1-tzimmermann@suse.de>

User space supplies rectangles for damage clipping in a plane property.
For full mode sets, we still require a full plane update. In this case,
leave the information as-is and set the ignore_damage_clips flag instead.
The damage iterator will later ignore any damage information.

Also fixes a bug where ignore_damage_clips was not cleared across plane
duplications.

Leaving the damage information as-is might be helpful to drivers that
benefit from it even on full modesets (e.g., for cache management). It
will also help with consolidating the damage-handling logic.

Also add a new unit test that evaluates the ignore_damage_clips flag. It
sets two damage clips plus the flag and tests if the reported damage
covers the entire framebuffer.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Fixes: 35ed38d58257 ("drm: Allow drivers to indicate the damage helpers to ignore damage clips")
Cc: dri-devel@lists.freedesktop.org
Cc: <stable@vger.kernel.org> # v6.10+
---
 drivers/gpu/drm/drm_atomic_state_helper.c     |  1 +
 drivers/gpu/drm/drm_damage_helper.c           |  6 ++--
 .../gpu/drm/tests/drm_damage_helper_test.c    | 28 +++++++++++++++++++
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index cc70508d4fdb..84d5231ccac1 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -359,6 +359,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
 	state->fence = NULL;
 	state->commit = NULL;
 	state->fb_damage_clips = NULL;
+	state->ignore_damage_clips = false;
 	state->color_mgmt_changed = false;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c
index 74a7f4252ecf..945fac8dc27b 100644
--- a/drivers/gpu/drm/drm_damage_helper.c
+++ b/drivers/gpu/drm/drm_damage_helper.c
@@ -78,10 +78,8 @@ void drm_atomic_helper_check_plane_damage(struct drm_atomic_commit *state,
 		if (WARN_ON(!crtc_state))
 			return;
 
-		if (drm_atomic_crtc_needs_modeset(crtc_state)) {
-			drm_property_blob_put(plane_state->fb_damage_clips);
-			plane_state->fb_damage_clips = NULL;
-		}
+		if (drm_atomic_crtc_needs_modeset(crtc_state))
+			plane_state->ignore_damage_clips = true;
 	}
 }
 EXPORT_SYMBOL(drm_atomic_helper_check_plane_damage);
diff --git a/drivers/gpu/drm/tests/drm_damage_helper_test.c b/drivers/gpu/drm/tests/drm_damage_helper_test.c
index 0df2e1a54b0d..64f038a62ffe 100644
--- a/drivers/gpu/drm/tests/drm_damage_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_damage_helper_test.c
@@ -603,6 +603,33 @@ static void drm_test_damage_iter_damage_not_visible(struct kunit *test)
 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should not return any damage.");
 }
 
+static void drm_test_damage_iter_damage_ignore(struct kunit *test)
+{
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_atomic_helper_damage_iter iter;
+	struct drm_property_blob damage_blob;
+	struct drm_mode_rect damage[2];
+	struct drm_rect clip;
+	u32 num_hits = 0;
+
+	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
+	/* 2 damage clips, but ignore them. */
+	set_damage_clip(&damage[0], 20, 30, 200, 180);
+	set_damage_clip(&damage[1], 240, 200, 280, 250);
+	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
+	set_plane_damage(&mock->state, &damage_blob);
+	mock->state.ignore_damage_clips = true;
+	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
+	drm_atomic_for_each_plane_damage(&iter, &clip) {
+		if (num_hits == 0)
+			check_damage_clip(test, &clip, 0, 0, 1024, 768);
+		num_hits++;
+	}
+
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return full-framebuffer damage.");
+}
+
 static struct kunit_case drm_damage_helper_tests[] = {
 	KUNIT_CASE(drm_test_damage_iter_no_damage),
 	KUNIT_CASE(drm_test_damage_iter_no_damage_fractional_src),
@@ -625,6 +652,7 @@ static struct kunit_case drm_damage_helper_tests[] = {
 	KUNIT_CASE(drm_test_damage_iter_damage_one_outside),
 	KUNIT_CASE(drm_test_damage_iter_damage_src_moved),
 	KUNIT_CASE(drm_test_damage_iter_damage_not_visible),
+	KUNIT_CASE(drm_test_damage_iter_damage_ignore),
 	{ }
 };
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 1/8] drm/amd/display: Add min clock init for DML21 mode programming
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Ovidiu Bunea, Dillon Varone, Alex Hung, Dan Wheeler,
	Alex Deucher, Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Ovidiu Bunea <ovidiu.bunea@amd.com>

[ Upstream commit 23dee18f6503d67b195f1513e404c78653ed0d40 ]

[WHY & HOW]
0 stream cases do not go through any DML validation which leaves DCN
clocks in unoptimized states.

If requesting DML validation or programming with 0 streams, program
DCN clocks to lowest DPM state.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 .../dml2_0/dml21/dml21_translation_helper.c   | 25 +++++++++++++++++++
 .../dml2_0/dml21/dml21_translation_helper.h   |  1 +
 .../display/dc/dml2_0/dml21/dml21_wrapper.c   |  1 +
 3 files changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
index bf5e7f4e0416..5bf3008a71c9 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.c
@@ -927,3 +927,28 @@ void dml21_set_dc_p_state_type(
 	}
 }
 
+void dml21_init_min_clocks_for_dc_state(struct dml2_context *in_ctx, struct dc_state *context)
+{
+	unsigned int lowest_dpm_state_index = 0;
+	struct dc_clocks *min_clocks = &context->bw_ctx.bw.dcn.clk;
+
+	min_clocks->dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->dcfclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dcfclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->dramclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.uclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->fclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.fclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->idle_dramclk_khz = 0;
+	min_clocks->idle_fclk_khz = 0;
+	min_clocks->dcfclk_deep_sleep_khz = 0;
+	min_clocks->fclk_p_state_change_support = true;
+	min_clocks->p_state_change_support = true;
+	min_clocks->dtbclk_en = false;
+	min_clocks->ref_dtbclk_khz = 0;
+	min_clocks->socclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.socclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->subvp_prefetch_dramclk_khz = 0;
+	min_clocks->subvp_prefetch_fclk_khz = 0;
+	min_clocks->phyclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.phyclk.clk_values_khz[lowest_dpm_state_index];
+	min_clocks->stutter_efficiency.base_efficiency = 1;
+	min_clocks->stutter_efficiency.low_power_efficiency = 1;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.h
index 9880d3e0398e..f51d3d8a52c3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_translation_helper.h
@@ -25,4 +25,5 @@ void dml21_map_hw_resources(struct dml2_context *dml_ctx);
 void dml21_get_pipe_mcache_config(struct dc_state *context, struct pipe_ctx *pipe_ctx, struct dml2_per_plane_programming *pln_prog, struct dml2_pipe_configuration_descriptor *mcache_pipe_config);
 void dml21_set_dc_p_state_type(struct pipe_ctx *pipe_ctx, struct dml2_per_stream_programming *stream_programming, bool sub_vp_enabled);
 unsigned int map_plane_to_dml21_display_cfg(const struct dml2_context *dml_ctx, unsigned int stream_id, const struct dc_plane_state *plane, const struct dc_state *context);
+void dml21_init_min_clocks_for_dc_state(struct dml2_context *in_ctx, struct dc_state *context);
 #endif
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
index 798abb2b2e67..96c62bd6a37b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
@@ -215,6 +215,7 @@ static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_s
 		return true;
 
 	if (context->stream_count == 0) {
+		dml21_init_min_clocks_for_dc_state(dml_ctx, context);
 		dml21_build_fams2_programming(in_dc, context, dml_ctx);
 		return true;
 	}
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 0/8] drm/amd: Backport FPU Guard Move from DML to DC
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable; +Cc: amd-gfx, Xi Ruoyao

The change from my commit c97a7dccb3ed ("drm/amd/display/dml2: Guard
dml21_map_dc_state_into_dml_display_cfg with DC_FP_START") was dropped
in the commit e6a8a000cfe6 ("drm/amd/display: Rename dml2 to dml2_0
folder") for some reason I don't know, so on 6.19.y and 7.0.y the
original issue (9070XT fails to work on LoongArch) has regressed.

As I've mentioned in my commit message, it was only an incomplete and
temporary solution.  As the mainline already contains the move of FPU
guard which should ultimately resolve the issue, it seems better to
just backport the final fix instead of adding the temporary ad-hoc
change back.

Tested with 9070XT (where the original issue manifested) and 5500XT.

Ovidiu Bunea (1):
  drm/amd/display: Add min clock init for DML21 mode programming

Rafal Ostrowski (4):
  drm/amd/display: Move FPU Guards From DML To DC - Part 1
  drm/amd/display: Move FPU Guards From DML To DC - Part 2
  drm/amd/display: Move FPU Guards From DML To DC - Part 3
  drm/amd/display: Move dml2_destroy to non-FPU compilation unit

Srinivasan Shanmugam (1):
  drm/amd/display: Fix dc_is_fp_enabled name mismatch

Wayne Lin (1):
  drm/amd/display: Fix fpu guard warning

Xi Ruoyao (1):
  drm/amd/display: Backport dml21 DC_RUN_WITH_PREEMPTION_ENABLED
    addition from DC 3.2.373

 .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c    |   25 +-
 .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.h    |   17 +-
 .../display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c  |    2 -
 .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c  |    2 -
 drivers/gpu/drm/amd/display/dc/core/dc.c      |    5 +-
 .../gpu/drm/amd/display/dc/core/dc_state.c    |   75 +-
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |   15 +-
 .../drm/amd/display/dc/dml/dcn20/dcn20_fpu.c  |    2 +-
 .../drm/amd/display/dc/dml/dcn20/dcn20_fpu.h  |    2 +-
 .../drm/amd/display/dc/dml/dcn31/dcn31_fpu.c  |    6 +-
 .../drm/amd/display/dc/dml/dcn31/dcn31_fpu.h  |    6 +-
 .../gpu/drm/amd/display/dc/dml2_0/Makefile    |   72 +-
 .../dml2_0/dml21/dml21_translation_helper.c   |   25 +
 .../dml2_0/dml21/dml21_translation_helper.h   |    1 +
 .../display/dc/dml2_0/dml21/dml21_wrapper.c   |  391 +--
 .../display/dc/dml2_0/dml21/dml21_wrapper.h   |   30 -
 .../dc/dml2_0/dml21/dml21_wrapper_fpu.c       |  379 +++
 .../dc/dml2_0/dml21/dml21_wrapper_fpu.h       |   60 +
 .../drm/amd/display/dc/dml2_0/dml2_wrapper.c  |   34 +-
 .../amd/display/dc/dml2_0/dml2_wrapper_fpu.c  |   19 +-
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c |    4 +-
 .../dc/resource/dcn21/dcn21_resource.c        |    7 +
 .../dc/resource/dcn31/dcn31_resource.c        |    7 +
 .../dc/resource/dcn315/dcn315_resource.c      |    7 +
 .../dc/resource/dcn316/dcn316_resource.c      |    7 +
 .../dc/resource/dcn35/dcn35_resource.c        |   10 +-
 .../dc/resource/dcn35/dcn35_resource.h        |    1 +
 .../dc/resource/dcn351/dcn351_resource.c      |   10 +-
 .../dc/resource/dcn36/dcn36_resource.c        |    4 +-
 .../dc/resource/dcn401/dcn401_resource.c      |   30 +-
 .../dc/resource/dcn42/dcn42_resource.c        | 2355 +++++++++++++++++
 31 files changed, 3076 insertions(+), 534 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c

-- 
2.54.0


^ permalink raw reply

* [PATCH v7.0.y 8/8] drm/amd/display: Move dml2_destroy to non-FPU compilation unit
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Rafal Ostrowski, Dillon Varone, Chenyu Chen,
	Alex Deucher, Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Rafal Ostrowski <rafal.ostrowski@amd.com>

[ Upstream commit 8bf0cb97edb697dba2515e6452c17c5245111448 ]

On PREEMPT_RT kernels, vfree() can sleep because spin_lock is
converted to rt_mutex. dml2_destroy() calls vfree() while inside
an FPU-guarded region (preempt_count=2), which is illegal.

dml2_wrapper_fpu.c is compiled with CC_FLAGS_FPU which defines
_LINUX_FPU_COMPILATION_UNIT, making DC_RUN_WITH_PREEMPTION_ENABLED()
resolve to a no-op. This prevents the macro from cycling FPU
context off/on around vfree().

Move dml2_destroy() to dml2_wrapper.c (non-FPU compilation unit)
where DC_RUN_WITH_PREEMPTION_ENABLED() properly cycles DC_FP_END/
DC_FP_START around vfree(). This pairs it with dml2_allocate_memory()
which already lives there.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 .../drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c   |  4 ++--
 drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c  | 11 +++++++++++
 .../gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c  | 10 ----------
 3 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
index 7398f8b69adb..8bed59e976d1 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
@@ -58,8 +58,8 @@ bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const s
 
 void dml21_destroy(struct dml2_context *dml2)
 {
-	vfree(dml2->v21.dml_init.dml2_instance);
-	vfree(dml2->v21.mode_programming.programming);
+	DC_RUN_WITH_PREEMPTION_ENABLED(vfree(dml2->v21.dml_init.dml2_instance));
+	DC_RUN_WITH_PREEMPTION_ENABLED(vfree(dml2->v21.mode_programming.programming));
 }
 
 void dml21_copy(struct dml2_context *dst_dml_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
index f4d45875d0be..6e3611a05c83 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
@@ -107,6 +107,17 @@ bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options
 	return true;
 }
 
+void dml2_destroy(struct dml2_context *dml2)
+{
+	if (!dml2)
+		return;
+
+	if (dml2->architecture == dml2_architecture_21)
+		dml21_destroy(dml2);
+
+	DC_RUN_WITH_PREEMPTION_ENABLED(vfree(dml2));
+}
+
 void dml2_reinit(const struct dc *in_dc,
 				 const struct dml2_configuration_options *config,
 				 struct dml2_context **dml2)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c
index 66624cfc27b1..a14e3004a7b7 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c
@@ -548,16 +548,6 @@ void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2)
 	}
 }
 
-void dml2_destroy(struct dml2_context *dml2)
-{
-	if (!dml2)
-		return;
-
-	if (dml2->architecture == dml2_architecture_21)
-		dml21_destroy(dml2);
-	vfree(dml2);
-}
-
 void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2,
 	unsigned int *fclk_change_support, unsigned int *dram_clk_change_support)
 {
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 7/8] drm/amd/display: Fix fpu guard warning
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Wayne Lin, Dillon Varone, Rafal Ostrowski, Chenyu Chen,
	Alex Deucher, Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Wayne Lin <Wayne.Lin@amd.com>

[ Upstream commit 07598c76964a2c73702fa652bcd07ec21088c5ef ]

[Why]
Due to improper fpu guarding, we encounter this warning during boot up:

[   10.027021] WARNING: drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/dc_fpu.c:58 at dc_assert_fp_enabled+0x12/0x20 [amdgpu], CPU#8: (udev-worker)/469
[   10.027644] Modules linked in: binfmt_misc snd_ctl_led nls_iso8859_1 intel_rapl_msr amd_atl intel_rapl_common amdgpu(+) snd_acp_legacy_mach snd_acp_mach snd_soc_nau8821 snd_acp3x_pdm_dma snd_acp3x_rn snd_soc_dmic snd_sof_amd_acp63 snd_sof_amd_vangogh snd_sof_amd_rembrandt snd_sof_amd_renoir snd_sof_amd_acp snd_sof_pci snd_hda_codec_alc269 snd_sof_xtensa_dsp snd_hda_scodec_component snd_hda_codec_realtek_lib snd_sof snd_hda_codec_generic snd_sof_utils snd_pci_ps snd_soc_acpi_amd_match snd_amd_sdw_acpi soundwire_amd snd_hda_codec_atihdmi soundwire_generic_allocation snd_hda_codec_hdmi soundwire_bus snd_soc_sdca edac_mce_amd snd_hda_intel snd_soc_core snd_hda_codec kvm_amd snd_compress snd_hda_core ac97_bus ee1004 amdxcp snd_pcm_dmaengine snd_intel_dspcfg snd_intel_sdw_acpi kvm drm_panel_backlight_quirks snd_rpl_pci_acp6x gpu_sched snd_hwdep snd_acp_pci irqbypass snd_amd_acpi_mach drm_buddy snd_acp_legacy_common snd_seq_midi ghash_clmulni_intel drm_ttm_helper aesni_intel snd_seq_midi_event snd_pci_acp6x joydev rapl
[   10.027750]  snd_pcm snd_rawmidi ttm snd_seq snd_pci_acp5x drm_exec drm_suballoc_helper snd_seq_device wmi_bmof snd_rn_pci_acp3x drm_display_helper snd_timer snd_acp_config cec snd_soc_acpi snd rc_core i2c_piix4 ccp snd_pci_acp3x i2c_smbus soundcore k10temp i2c_algo_bit spi_amd cdc_mbim input_leds cdc_wdm mac_hid sch_fq_codel msr parport_pc ppdev lp parport efi_pstore nfnetlink dmi_sysfs autofs4 cdc_ncm cdc_ether usbnet mii hid_logitech_hidpp hid_logitech_dj hid_generic nvme nvme_core ahci serio_raw nvme_keyring usbhid ucsi_acpi amd_xgbe nvme_auth libahci hkdf typec_ucsi video typec wmi i2c_hid_acpi i2c_hid hid
[   10.027853] CPU: 8 UID: 0 PID: 469 Comm: (udev-worker) Not tainted 6.19.0asdn-260408-asdn #1 PREEMPT(voluntary)
[   10.027858] Hardware name: AMD Crater-RN/Crater-RN, BIOS TCR1004A 03/12/2024
[   10.027861] RIP: 0010:dc_assert_fp_enabled+0x12/0x20 [amdgpu]
[   10.028416] Code: 00 00 00 00 00 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 65 8b 05 39 79 cc c4 85 c0 7e 07 31 c0 e9 9e 75 2a c3 <0f> 0b 31 c0 e9 95 75 2a c3 0f 1f 44 00 00 90 90 90 90 90 90 90 90
[   10.028420] RSP: 0018:ffffcca10188b348 EFLAGS: 00010246
[   10.028425] RAX: 0000000000000000 RBX: ffff88c6077f8000 RCX: 0000000000000000
[   10.028428] RDX: ffff88c607d0e400 RSI: ffffffffc204d860 RDI: ffff88c624c00000
[   10.028430] RBP: ffffcca10188b3e8 R08: ffff88c624c35c88 R09: 0000000000000000
[   10.028433] R10: 0000000000000000 R11: 0000000000000000 R12: ffffcca10188b548
[   10.028435] R13: ffff88c60be5bd00 R14: ffffffffc204d860 R15: ffff88c624c00000
[   10.028438] FS:  00007c80c2432980(0000) GS:ffff88cdc7464000(0000) knlGS:0000000000000000
[   10.028441] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   10.028443] CR2: 00007866ae013da8 CR3: 000000010a511000 CR4: 0000000000350ef0
[   10.028446] Call Trace:
[   10.028449]  <TASK>
[   10.028452]  ? dcn21_update_bw_bounding_box+0x38/0xb30 [amdgpu]
[   10.028991]  ? srso_return_thunk+0x5/0x5f
[   10.029001]  dc_create+0x37c/0x730 [amdgpu]
[   10.029505]  ? srso_return_thunk+0x5/0x5f
[   10.029512]  amdgpu_dm_init+0x374/0x2ff0 [amdgpu]
[   10.030053]  ? srso_return_thunk+0x5/0x5f
[   10.030057]  ? __irq_work_queue_local+0x61/0xe0
[   10.030063]  ? srso_return_thunk+0x5/0x5f
[   10.030067]  ? irq_work_queue+0x2f/0x70
[   10.030071]  ? srso_return_thunk+0x5/0x5f
[   10.030075]  ? __wake_up_klogd+0x75/0xa0
[   10.030081]  ? srso_return_thunk+0x5/0x5f
[   10.030085]  ? vprintk_emit+0x35b/0x3f0
[   10.030102]  dm_hw_init+0x1c/0x110 [amdgpu]
[   10.030625]  amdgpu_device_init+0x23e8/0x3210 [amdgpu]
[   10.031041]  ? pci_read+0x55/0x90
[   10.031047]  ? srso_return_thunk+0x5/0x5f
[   10.031051]  ? pci_read_config_word+0x27/0x50
[   10.031057]  ? srso_return_thunk+0x5/0x5f
[   10.031061]  ? do_pci_enable_device+0x155/0x180
[   10.031068]  amdgpu_driver_load_kms+0x1a/0xd0 [amdgpu]
[   10.031486]  amdgpu_pci_probe+0x28c/0x6f0 [amdgpu]
[   10.031902]  local_pci_probe+0x47/0xb0
[   10.031908]  pci_device_probe+0xf3/0x270
[   10.031914]  really_probe+0xf1/0x410
[   10.031920]  __driver_probe_device+0x8c/0x190
[   10.031924]  driver_probe_device+0x24/0xd0
[   10.031928]  __driver_attach+0x10b/0x240
[   10.031932]  ? __pfx___driver_attach+0x10/0x10
[   10.031936]  bus_for_each_dev+0x8c/0xf0
[   10.031942]  driver_attach+0x1e/0x30
[   10.031947]  bus_add_driver+0x160/0x2a0
[   10.031952]  driver_register+0x5e/0x130
[   10.031957]  ? __pfx_amdgpu_init+0x10/0x10 [amdgpu]
[   10.032361]  __pci_register_driver+0x5e/0x70
[   10.032366]  amdgpu_init+0x5d/0xff0 [amdgpu]
[   10.032768]  ? srso_return_thunk+0x5/0x5f
[   10.032773]  do_one_initcall+0x5d/0x340
[   10.032783]  do_init_module+0x97/0x2c0
[   10.032788]  load_module+0x2b49/0x2c30
[   10.032800]  init_module_from_file+0xf4/0x120
[   10.032804]  ? init_module_from_file+0xf4/0x120
[   10.032813]  idempotent_init_module+0x10f/0x300
[   10.032820]  __x64_sys_finit_module+0x73/0xf0
[   10.032824]  ? srso_return_thunk+0x5/0x5f
[   10.032829]  x64_sys_call+0x1d68/0x26b0
[   10.032834]  do_syscall_64+0x81/0x500
[   10.032839]  ? srso_return_thunk+0x5/0x5f
[   10.032843]  ? do_syscall_64+0x2e5/0x500
[   10.032848]  ? srso_return_thunk+0x5/0x5f
[   10.032852]  ? native_flush_tlb_global+0x95/0xb0
[   10.032860]  ? srso_return_thunk+0x5/0x5f
[   10.032864]  ? __flush_tlb_all+0x13/0x60
[   10.032870]  ? srso_return_thunk+0x5/0x5f
[   10.032874]  ? do_flush_tlb_all+0xe/0x20
[   10.032879]  ? srso_return_thunk+0x5/0x5f
[   10.032882]  ? __flush_smp_call_function_queue+0x9c/0x430
[   10.032888]  ? srso_return_thunk+0x5/0x5f
[   10.032897]  ? irqentry_exit+0xb2/0x740
[   10.032901]  ? srso_return_thunk+0x5/0x5f
[   10.032906]  ? srso_return_thunk+0x5/0x5f
[   10.032911]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[   10.032915] RIP: 0033:0x7c80c1d3490d
[   10.032920] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d3 f4 0f 00 f7 d8 64 89 01 48
[   10.032923] RSP: 002b:00007fff3a12fe28 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[   10.032928] RAX: ffffffffffffffda RBX: 00005c44096804f0 RCX: 00007c80c1d3490d
[   10.032930] RDX: 0000000000000000 RSI: 00005c4409681690 RDI: 000000000000002b
[   10.032933] RBP: 00007fff3a12fec0 R08: 0000000000000000 R09: 00005c4409681790
[   10.032935] R10: 0000000000000000 R11: 0000000000000246 R12: 00005c4409681690
[   10.032937] R13: 0000000000020000 R14: 00005c44094ff7f0 R15: 00005c4409681690
[   10.032945]  </TASK>
[   10.032948] ---[ end trace 0000000000000000 ]---

[How]
Add wrapper function to guard fpu properly for dcn21/dcn31/dcn315/dcn316.

Fixes: 3539437f354b ("drm/amd/display: Move FPU Guards From DML To DC - Part 1")
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Reviewed-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c       | 2 +-
 drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h       | 2 +-
 drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c       | 6 +++---
 drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h       | 6 +++---
 .../gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c | 7 +++++++
 .../gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c | 7 +++++++
 .../drm/amd/display/dc/resource/dcn315/dcn315_resource.c   | 7 +++++++
 .../drm/amd/display/dc/resource/dcn316/dcn316_resource.c   | 7 +++++++
 8 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
index 7aaf13bbd4e4..eb4a76fc60d6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
@@ -2398,7 +2398,7 @@ static struct _vcs_dpi_voltage_scaling_st construct_low_pstate_lvl(struct clk_li
 	return low_pstate_lvl;
 }
 
-void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+void dcn21_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
 {
 	struct _vcs_dpi_voltage_scaling_st *s = dc->scratch.update_bw_bounding_box.clock_limits;
 	struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool);
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
index aed00039ca62..8b2226c5bbbf 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
@@ -78,7 +78,7 @@ int dcn21_populate_dml_pipes_from_context(struct dc *dc,
 					  enum dc_validate_mode validate_mode);
 bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, enum
 				 dc_validate_mode, display_e2e_pipe_params_st *pipes);
-void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn21_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
 
 void dcn21_clk_mgr_set_bw_params_wm_table(struct clk_bw_params *bw_params);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
index 1a28061bb9ff..ad23215da9f8 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
@@ -587,7 +587,7 @@ void dcn31_calculate_wm_and_dlg_fp(
 	context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - total_det;
 }
 
-void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+void dcn31_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
 {
 	struct _vcs_dpi_voltage_scaling_st *s = dc->scratch.update_bw_bounding_box.clock_limits;
 	struct clk_limit_table *clk_table = &bw_params->clk_table;
@@ -665,7 +665,7 @@ void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
 	dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31);
 }
 
-void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+void dcn315_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
 {
 	struct clk_limit_table *clk_table = &bw_params->clk_table;
 	int i, max_dispclk_mhz = 0, max_dppclk_mhz = 0;
@@ -726,7 +726,7 @@ void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
 	dml_init_instance(&dc->dml, &dcn3_15_soc, &dcn3_15_ip, DML_PROJECT_DCN315);
 }
 
-void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+void dcn316_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
 {
 	struct _vcs_dpi_voltage_scaling_st *s = dc->scratch.update_bw_bounding_box.clock_limits;
 	struct clk_limit_table *clk_table = &bw_params->clk_table;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
index dfcc5d50071e..0b7fcbbfd17b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
@@ -44,9 +44,9 @@ void dcn31_calculate_wm_and_dlg_fp(
 		int pipe_cnt,
 		int vlevel);
 
-void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
-void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
-void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn31_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn315_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn316_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
 int dcn_get_max_non_odm_pix_rate_100hz(struct _vcs_dpi_soc_bounding_box_st *soc);
 int dcn_get_approx_det_segs_required_for_pstate(
 		struct _vcs_dpi_soc_bounding_box_st *soc,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
index 4333baac96ad..ec88630ae806 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c
@@ -1387,6 +1387,13 @@ static enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *pla
 	return dcn20_patch_unknown_plane_state(plane_state);
 }
 
+static void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn21_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
+
 static const struct resource_funcs dcn21_res_pool_funcs = {
 	.destroy = dcn21_destroy_resource_pool,
 	.link_enc_create = dcn21_link_encoder_create,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
index 4e9c041c707a..96b1ff262d15 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c
@@ -1856,6 +1856,13 @@ static struct dc_cap_funcs cap_funcs = {
 	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
 };
 
+static void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn31_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
+
 static struct resource_funcs dcn31_res_pool_funcs = {
 	.destroy = dcn31_destroy_resource_pool,
 	.link_enc_create = dcn31_link_encoder_create,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
index 131a6cd4c735..e1d703ce81d6 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c
@@ -1850,6 +1850,13 @@ static struct dc_cap_funcs cap_funcs = {
 	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
 };
 
+static void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn315_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
+
 static struct resource_funcs dcn315_res_pool_funcs = {
 	.destroy = dcn315_destroy_resource_pool,
 	.link_enc_create = dcn31_link_encoder_create,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
index c8c0ce6efcfd..682606563e5d 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c
@@ -1726,6 +1726,13 @@ static struct dc_cap_funcs cap_funcs = {
 	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
 };
 
+static void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn316_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
+
 static struct resource_funcs dcn316_res_pool_funcs = {
 	.destroy = dcn316_destroy_resource_pool,
 	.link_enc_create = dcn31_link_encoder_create,
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 6/8] drm/amd/display: Fix dc_is_fp_enabled name mismatch
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Srinivasan Shanmugam, Roman Li, Alex Hung, Tom Chung,
	Dillon Varone, Rafal Ostrowski, Aurabindo Pillai, Alex Deucher,
	Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>

[ Upstream commit 57ce498faa1e4d358bf44b5df575874c22922786 ]

Fix incorrect function name in comment to match dc_is_fp_enabled.

This function checks if FPU is currently active by reading a counter.
The FPU helpers manage safe usage of FPU in the kernel by tracking when
it starts and stops, avoiding misuse or crashes.

Fixes: 3539437f354b ("drm/amd/display: Move FPU Guards From DML To DC - Part 1")
Cc: Roman Li <roman.li@amd.com>
Cc: Alex Hung <alex.hung@amd.com>
Cc: Tom Chung <chiahsuan.chung@amd.com>
Cc: Dillon Varone <dillon.varone@amd.com>
Cc: Rafal Ostrowski <rafal.ostrowski@amd.com>
Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index 8ba9b4f56f87..172999cc84e5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -59,7 +59,7 @@ inline void dc_assert_fp_enabled(void)
 }
 
 /**
- * dc_assert_fp_enabled - Check if FPU protection is enabled
+ * dc_is_fp_enabled - Check if FPU protection is enabled
  *
  * This function tells if the code is already under FPU protection or not. A
  * function that works as an API for a set of FPU operations can use this
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 5/8] drm/amd/display: Move FPU Guards From DML To DC - Part 3
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Rafal Ostrowski, Dillon Varone, Alex Hung, Alex Deucher,
	Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Rafal Ostrowski <rafal.ostrowski@amd.com>

[ Upstream commit 32c1c35b6d8bd8b7ea9ab3d1454b56b605f17dd1 ]

[Why]
FPU guards (DC_FP_START/DC_FP_END) are required to wrap around code that
can manipulates floats. To do this properly, the FPU guards must be used
in a file that is not compiled as a FPU unit. If the guards are used in
a file that is a FPU unit, other sections in the file that aren't guarded
may be end up being compiled to use FPU operations.

[How]
Added DC_FP_START and DC_FP_END to DC functions that call DML functions
using FPU.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 drivers/gpu/drm/amd/display/dc/dml2_0/Makefile              | 1 +
 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c | 1 +
 .../gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c | 4 +---
 .../gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h | 2 +-
 drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c        | 6 +++++-
 5 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
index a094cfa78260..145ff97ed560 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
@@ -85,6 +85,7 @@ AMD_DAL_DML2 = $(addprefix $(AMDDALPATH)/dc/dml2_0/,$(DML2))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_DML2)
 
+
 DML21 := src/dml2_top/dml2_top_interfaces.o
 DML21 += src/dml2_top/dml2_top_soc15.o
 DML21 += src/dml2_core/dml2_core_dcn4.o
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
index 1a98578f223c..7398f8b69adb 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
@@ -38,6 +38,7 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
 	(*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config;
 
 	DC_RUN_WITH_PREEMPTION_ENABLED((*dml_ctx)->v21.mode_programming.programming = vzalloc(sizeof(struct dml2_display_cfg_programming)));
+
 	if (!((*dml_ctx)->v21.mode_programming.programming))
 		return false;
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
index d5885bbd14c4..f3abfdbe6805 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: MIT
 //
-// Copyright 2024 Advanced Micro Devices, Inc.
+// Copyright 2026 Advanced Micro Devices, Inc.
 
 #include "dml2_internal_types.h"
 #include "dml_top.h"
@@ -377,5 +377,3 @@ void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context
 		}
 	}
 }
-
-
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h
index 2972c6eed21a..e5d9a456645f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: MIT
 //
-// Copyright 2024 Advanced Micro Devices, Inc.
+// Copyright 2026 Advanced Micro Devices, Inc.
 
 #ifndef _DML21_WRAPPER_FPU_H_
 #define _DML21_WRAPPER_FPU_H_
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
index 9215e38343ba..f4d45875d0be 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
@@ -13,6 +13,10 @@
 
 #include "dc_fpu.h"
 
+#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif // !DC_RUN_WITH_PREEMPTION_ENABLED
+
 struct dml2_context *dml2_allocate_memory(void)
 {
 	struct dml2_context *dml2;
@@ -20,7 +24,6 @@ struct dml2_context *dml2_allocate_memory(void)
 	DC_RUN_WITH_PREEMPTION_ENABLED(dml2 = vzalloc(sizeof(struct dml2_context)));
 	return dml2;
 }
-
 bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2,
 	enum dc_validate_mode validate_mode)
 {
@@ -84,6 +87,7 @@ static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_op
 	initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc);
 
 	initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states);
+
 }
 
 bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 4/8] drm/amd/display: Move FPU Guards From DML To DC - Part 2
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Rafal Ostrowski, Dillon Varone, Alex Hung, Chuanyu Tseng,
	Alex Deucher, Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Rafal Ostrowski <rafal.ostrowski@amd.com>

[ Upstream commit 4bb2f0721ed8a2a70f864b9358bd6cd4d92199b3 ]

[Why]
FPU guards (DC_FP_START/DC_FP_END) are required to wrap around code that
can manipulates floats. To do this properly, the FPU guards must be used
in a file that is not compiled as a FPU unit. If the guards are used in
a file that is a FPU unit, other sections in the file that aren't guarded
may be end up being compiled to use FPU operations.

[How]
Removed DC_FP_START and DC_FP_END.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chuanyu Tseng <Chuanyu.Tseng@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
[ Ignore dcn42 which is not supported by 7.0.y. ]
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 .../gpu/drm/amd/display/dc/dml2_0/Makefile    |  73 +---
 .../display/dc/dml2_0/dml21/dml21_wrapper.c   | 379 +----------------
 .../display/dc/dml2_0/dml21/dml21_wrapper.h   |  30 --
 .../dc/dml2_0/dml21/dml21_wrapper_fpu.c       | 381 ++++++++++++++++++
 .../dc/dml2_0/dml21/dml21_wrapper_fpu.h       |  60 +++
 .../drm/amd/display/dc/dml2_0/dml2_wrapper.c  |  21 +-
 .../amd/display/dc/dml2_0/dml2_wrapper_fpu.c  |   9 +-
 7 files changed, 484 insertions(+), 469 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
index 30cfc0848792..a094cfa78260 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
@@ -53,25 +53,29 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/src/inc
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/inc
 subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/
 
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_ccflags) $(frame_warn_flag)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_util.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper_fpu.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_utils.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_policy.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_translation_helper.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_mall_phantom.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml_display_rq_dlg_calc.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_dc_resource_mgmt.o := $(dml2_ccflags)
+# Add FPU flags to all dml2 files by default, remove NO_FPU flags.
+# FPU flags step 1: Find all .c files in dal/dc/dml2_0 and it's subfolders
+DML2_ABS_PATH := $(FULL_AMD_DISPLAY_PATH)/dc/dml2_0
+DML2_C_FILES := $(shell find $(DML2_ABS_PATH) -name '*.c' -type f)
+
+# FPU flags step 2: Convert to .o and make paths relative to $(AMDDALPATH)/dc/dml2_0/
+DML2_RELATIVE_O_FILES := $(patsubst $(DML2_ABS_PATH)/%,dc/dml2_0/%,$(patsubst %.c,%.o,$(DML2_C_FILES)))
 
+# FPU flags step 3: Apply FPU flags to all .o files from dal/dc/dml2_0 and it's subfolders
+$(foreach obj,$(DML2_RELATIVE_O_FILES),$(eval CFLAGS_$(AMDDALPATH)/$(obj) := $(dml2_ccflags)))
+$(foreach obj,$(DML2_RELATIVE_O_FILES),$(eval CFLAGS_REMOVE_$(AMDDALPATH)/$(obj) := $(dml2_rcflags)))
+
+# FPU flags step 4: Replace CFLAGS per file for files with additional flags beyond dml2_ccflags and dml2_rcflags
+CFLAGS_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_ccflags) $(frame_warn_flag)
+CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_ccflags) $(frame_warn_flag)
+CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_ccflags) $(frame_warn_flag)
+CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper.o := $(dml2_rcflags)
+CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_wrapper.o := $(dml2_rcflags)
 CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/display_mode_core.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/display_mode_util.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper_fpu.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_utils.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_policy.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_translation_helper.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_mall_phantom.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml_display_rq_dlg_calc.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_dc_resource_mgmt.o := $(dml2_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml2_wrapper.o := $(dml2_ccflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_wrapper.o := $(dml2_ccflags)
 
 DML2 = display_mode_core.o display_mode_util.o dml2_wrapper_fpu.o dml2_wrapper.o \
 		dml2_utils.o dml2_policy.o dml2_translation_helper.o dml2_dc_resource_mgmt.o dml2_mall_phantom.o \
@@ -81,40 +85,6 @@ AMD_DAL_DML2 = $(addprefix $(AMDDALPATH)/dc/dml2_0/,$(DML2))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_DML2)
 
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_ccflags) $(frame_warn_flag)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_ccflags) $(frame_warn_flag)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_interfaces.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn3.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_translation_helper.o := $(dml2_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_utils.o := $(dml2_ccflags)
-
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_core/dml2_core_utils.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_interfaces.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_top/dml2_top_soc15.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_factory.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_dcn4.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_mcg/dml2_mcg_factory.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn3.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_factory.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/src/dml2_standalone_libraries/lib_float_math.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_translation_helper.o := $(dml2_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml2_0/dml21/dml21_utils.o := $(dml2_rcflags)
-
 DML21 := src/dml2_top/dml2_top_interfaces.o
 DML21 += src/dml2_top/dml2_top_soc15.o
 DML21 += src/dml2_core/dml2_core_dcn4.o
@@ -131,6 +101,7 @@ DML21 += src/dml2_pmo/dml2_pmo_dcn4_fams2.o
 DML21 += src/dml2_standalone_libraries/lib_float_math.o
 DML21 += dml21_translation_helper.o
 DML21 += dml21_wrapper.o
+DML21 += dml21_wrapper_fpu.o
 DML21 += dml21_utils.o
 
 AMD_DAL_DML21 = $(addprefix $(AMDDALPATH)/dc/dml2_0/dml21/,$(DML21))
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
index 2623e917ec28..1a98578f223c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
@@ -9,6 +9,10 @@
 #include "dml21_utils.h"
 #include "dml21_translation_helper.h"
 #include "dml2_dc_resource_mgmt.h"
+#include "dml2_wrapper.h"
+#include "dml2_wrapper_fpu.h"
+#include "dml21_wrapper.h"
+#include "dml21_wrapper_fpu.h"
 #include "dc_fpu.h"
 
 #if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
@@ -40,44 +44,11 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
 	return true;
 }
 
-static void dml21_populate_configuration_options(const struct dc *in_dc,
-		struct dml2_context *dml_ctx,
-		const struct dml2_configuration_options *config)
-{
-	dml_ctx->config = *config;
-
-	/* UCLK P-State options */
-	if (in_dc->debug.dml21_force_pstate_method) {
-		dml_ctx->config.pmo.force_pstate_method_enable = true;
-		for (int i = 0; i < MAX_PIPES; i++)
-			dml_ctx->config.pmo.force_pstate_method_values[i] = in_dc->debug.dml21_force_pstate_method_values[i];
-	} else {
-		dml_ctx->config.pmo.force_pstate_method_enable = false;
-	}
-}
-
-static void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config)
-{
-
-	dml_ctx->architecture = dml2_architecture_21;
-
-	dml21_populate_configuration_options(in_dc, dml_ctx, config);
-
-	DC_FP_START();
-
-	dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, &dml_ctx->config, in_dc);
-
-	dml2_initialize_instance(&dml_ctx->v21.dml_init);
-
-	DC_FP_END();
-}
-
 bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config)
 {
 	/* Allocate memory for initializing DML21 instance */
-	if (!dml21_allocate_memory(dml_ctx)) {
+	if (!dml21_allocate_memory(dml_ctx))
 		return false;
-	}
 
 	dml21_init(in_dc, *dml_ctx, config);
 
@@ -90,337 +61,6 @@ void dml21_destroy(struct dml2_context *dml2)
 	vfree(dml2->v21.mode_programming.programming);
 }
 
-static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state,
-	struct dml2_context *in_ctx, unsigned int pipe_cnt)
-{
-	unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0;
-	struct dml2_per_plane_programming *pln_prog = NULL;
-	struct dml2_per_stream_programming *stream_prog = NULL;
-	struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
-	struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
-	int num_pipes;
-	unsigned int dml_phantom_prog_idx;
-
-	context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
-
-	/* copy global DCHUBBUB arbiter registers */
-	memcpy(&context->bw_ctx.bw.dcn.arb_regs, &in_ctx->v21.mode_programming.programming->global_regs.arb_regs, sizeof(struct dml2_display_arb_regs));
-
-	/* legacy only */
-	context->bw_ctx.bw.dcn.compbuf_size_kb = (int)in_ctx->v21.mode_programming.programming->global_regs.arb_regs.compbuf_size * 64;
-
-	context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0;
-	context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0;
-	context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0;
-
-	/* phantom's start after main planes */
-	dml_phantom_prog_idx = in_ctx->v21.mode_programming.programming->display_config.num_planes;
-
-	for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) {
-		pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
-
-		if (!pln_prog->plane_descriptor)
-			continue;
-
-		stream_prog = &in_ctx->v21.mode_programming.programming->stream_programming[pln_prog->plane_descriptor->stream_index];
-		num_dpps_required = pln_prog->num_dpps_required;
-
-		if (num_dpps_required == 0) {
-			continue;
-		}
-		num_pipes = dml21_find_dc_pipes_for_plane(dc, context, in_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
-
-		if (num_pipes <= 0)
-			continue;
-
-		/* program each pipe */
-		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
-			dml21_program_dc_pipe(in_ctx, context, dc_main_pipes[dc_pipe_index], pln_prog, stream_prog);
-
-			if (pln_prog->phantom_plane.valid && dc_phantom_pipes[dc_pipe_index]) {
-				dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog);
-			}
-		}
-
-		/* copy per plane mcache allocation */
-		memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation));
-		if (pln_prog->phantom_plane.valid) {
-			memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx],
-					&pln_prog->phantom_plane.mcache_allocation,
-					sizeof(struct dml2_mcache_surface_allocation));
-
-			dml_phantom_prog_idx++;
-		}
-	}
-
-	/* assign global clocks */
-	context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
-	context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
-	if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) {
-		context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz =
-			in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000;
-	} else {
-		context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000;
-	}
-
-	if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) {
-		context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
-			in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000;
-	} else {
-		context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000;
-	}
-
-	/* get global mall allocation */
-	if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) {
-		context->bw_ctx.bw.dcn.clk.num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes);
-	} else {
-		context->bw_ctx.bw.dcn.clk.num_ways = 0;
-	}
-}
-
-static void dml21_prepare_mcache_params(struct dml2_context *dml_ctx, struct dc_state *context, struct dc_mcache_params *mcache_params)
-{
-	int dc_plane_idx = 0;
-	int dml_prog_idx, stream_idx, plane_idx;
-	struct dml2_per_plane_programming *pln_prog = NULL;
-
-	for (stream_idx = 0; stream_idx < context->stream_count; stream_idx++) {
-		for (plane_idx = 0; plane_idx < context->stream_status[stream_idx].plane_count; plane_idx++) {
-			dml_prog_idx = map_plane_to_dml21_display_cfg(dml_ctx, context->streams[stream_idx]->stream_id, context->stream_status[stream_idx].plane_states[plane_idx], context);
-			if (dml_prog_idx == INVALID) {
-				continue;
-			}
-			pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
-			mcache_params[dc_plane_idx].valid = pln_prog->mcache_allocation.valid;
-			mcache_params[dc_plane_idx].num_mcaches_plane0 = pln_prog->mcache_allocation.num_mcaches_plane0;
-			mcache_params[dc_plane_idx].num_mcaches_plane1 = pln_prog->mcache_allocation.num_mcaches_plane1;
-			mcache_params[dc_plane_idx].requires_dedicated_mall_mcache = pln_prog->mcache_allocation.requires_dedicated_mall_mcache;
-			mcache_params[dc_plane_idx].last_slice_sharing.plane0_plane1 = pln_prog->mcache_allocation.last_slice_sharing.plane0_plane1;
-			memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane0,
-				pln_prog->mcache_allocation.mcache_x_offsets_plane0,
-				sizeof(int) * (DML2_MAX_MCACHES + 1));
-			memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane1,
-				pln_prog->mcache_allocation.mcache_x_offsets_plane1,
-				sizeof(int) * (DML2_MAX_MCACHES + 1));
-			dc_plane_idx++;
-		}
-	}
-}
-
-static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
-{
-	bool result = false;
-	struct dml2_build_mode_programming_in_out *mode_programming = &dml_ctx->v21.mode_programming;
-	struct dc_mcache_params mcache_params[MAX_PLANES] = {0};
-
-	memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg));
-	memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
-	memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params, 0, sizeof(struct dml2_core_mode_programming_in_out));
-
-	if (!context)
-		return true;
-
-	if (context->stream_count == 0) {
-		dml21_init_min_clocks_for_dc_state(dml_ctx, context);
-		dml21_build_fams2_programming(in_dc, context, dml_ctx);
-		return true;
-	}
-
-	/* scrub phantom's from current dc_state */
-	dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context);
-	dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context);
-
-	/* Populate stream, plane mappings and other fields in display config. */
-	result = dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
-	if (!result)
-		return false;
-
-	DC_FP_START();
-	result = dml2_build_mode_programming(mode_programming);
-	DC_FP_END();
-	if (!result)
-		return false;
-
-	/* Check and map HW resources */
-	if (result && !dml_ctx->config.skip_hw_state_mapping) {
-		dml21_map_hw_resources(dml_ctx);
-		dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, in_dc->current_state);
-		/* if subvp phantoms are present, expand them into dc context */
-		dml21_handle_phantom_streams_planes(in_dc, context, dml_ctx);
-
-		if (in_dc->res_pool->funcs->program_mcache_pipe_config) {
-			//Prepare mcache params for each plane based on mcache output from DML
-			dml21_prepare_mcache_params(dml_ctx, context, mcache_params);
-
-			//populate mcache regs to each pipe
-			dml_ctx->config.callbacks.allocate_mcache(context, mcache_params);
-		}
-	}
-
-	/* Copy DML CLK, WM and REG outputs to bandwidth context */
-	if (result && !dml_ctx->config.skip_hw_state_mapping) {
-		dml21_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml_ctx, in_dc->res_pool->pipe_count);
-		dml21_copy_clocks_to_dc_state(dml_ctx, context);
-		dml21_extract_watermark_sets(in_dc, &context->bw_ctx.bw.dcn.watermarks, dml_ctx);
-		dml21_build_fams2_programming(in_dc, context, dml_ctx);
-	}
-
-	return true;
-}
-
-static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
-{
-	bool is_supported = false;
-	struct dml2_initialize_instance_in_out *dml_init = &dml_ctx->v21.dml_init;
-	struct dml2_check_mode_supported_in_out *mode_support = &dml_ctx->v21.mode_support;
-
-	memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg));
-	memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
-	memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.check_mode_supported_locals.mode_support_params, 0, sizeof(struct dml2_core_mode_support_in_out));
-
-	if (!context || context->stream_count == 0)
-		return true;
-
-	/* Scrub phantom's from current dc_state */
-	dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context);
-	dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context);
-
-	mode_support->dml2_instance = dml_init->dml2_instance;
-	dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
-	dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params.programming = dml_ctx->v21.mode_programming.programming;
-	DC_FP_START();
-	is_supported = dml2_check_mode_supported(mode_support);
-	DC_FP_END();
-	if (!is_supported)
-		return false;
-
-	return true;
-}
-
-bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx,
-	enum dc_validate_mode validate_mode)
-{
-	bool out = false;
-
-	/* Use dml21_check_mode_support for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */
-	if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
-		out = dml21_check_mode_support(in_dc, context, dml_ctx);
-	else
-		out = dml21_mode_check_and_programming(in_dc, context, dml_ctx);
-
-	return out;
-}
-
-void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
-{
-	unsigned int dml_prog_idx, dml_phantom_prog_idx, dc_pipe_index;
-	int num_pipes;
-	struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
-	struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
-
-	struct dml2_per_plane_programming *pln_prog = NULL;
-	struct dml2_plane_mcache_configuration_descriptor *mcache_config = NULL;
-	struct prepare_mcache_programming_locals *l = &dml_ctx->v21.scratch.prepare_mcache_locals;
-
-	if (context->stream_count == 0) {
-		return;
-	}
-
-	memset(&l->build_mcache_programming_params, 0, sizeof(struct dml2_build_mcache_programming_in_out));
-	l->build_mcache_programming_params.dml2_instance = dml_ctx->v21.dml_init.dml2_instance;
-
-	/* phantom's start after main planes */
-	dml_phantom_prog_idx = dml_ctx->v21.mode_programming.programming->display_config.num_planes;
-
-	/* Build mcache programming parameters per plane per pipe */
-	for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) {
-		pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
-
-		mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_prog_idx];
-		memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor));
-		mcache_config->plane_descriptor = pln_prog->plane_descriptor;
-		mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx];
-		mcache_config->num_pipes = pln_prog->num_dpps_required;
-		l->build_mcache_programming_params.num_configurations++;
-
-		if (pln_prog->num_dpps_required == 0) {
-			continue;
-		}
-
-		num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
-		if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL ||
-		    dc_main_pipes[0]->plane_state == NULL)
-			continue;
-
-		/* get config for each pipe */
-		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
-			ASSERT(dc_main_pipes[dc_pipe_index]);
-			dml21_get_pipe_mcache_config(context, dc_main_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]);
-		}
-
-		/* get config for each phantom pipe */
-		if (pln_prog->phantom_plane.valid &&
-				dc_phantom_pipes[0] &&
-				dc_main_pipes[0]->stream &&
-				dc_phantom_pipes[0]->plane_state) {
-			mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_phantom_prog_idx];
-			memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor));
-			mcache_config->plane_descriptor = pln_prog->plane_descriptor;
-			mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx];
-			mcache_config->num_pipes = pln_prog->num_dpps_required;
-			l->build_mcache_programming_params.num_configurations++;
-
-			for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
-				ASSERT(dc_phantom_pipes[dc_pipe_index]);
-				dml21_get_pipe_mcache_config(context, dc_phantom_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]);
-			}
-
-			/* increment phantom index */
-			dml_phantom_prog_idx++;
-		}
-	}
-
-	/* Call to generate mcache programming per plane per pipe for the given display configuration */
-	dml2_build_mcache_programming(&l->build_mcache_programming_params);
-
-	/* get per plane per pipe mcache programming */
-	for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) {
-		pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
-
-		num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
-		if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL ||
-		    dc_main_pipes[0]->plane_state == NULL)
-			continue;
-
-		/* get config for each pipe */
-		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
-			ASSERT(dc_main_pipes[dc_pipe_index]);
-			if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index]) {
-				memcpy(&dc_main_pipes[dc_pipe_index]->mcache_regs,
-						l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index],
-						sizeof(struct dml2_hubp_pipe_mcache_regs));
-			}
-		}
-
-		/* get config for each phantom pipe */
-		if (pln_prog->phantom_plane.valid &&
-				dc_phantom_pipes[0] &&
-				dc_main_pipes[0]->stream &&
-				dc_phantom_pipes[0]->plane_state) {
-			for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
-				ASSERT(dc_phantom_pipes[dc_pipe_index]);
-				if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index]) {
-					memcpy(&dc_phantom_pipes[dc_pipe_index]->mcache_regs,
-							l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index],
-							sizeof(struct dml2_hubp_pipe_mcache_regs));
-				}
-			}
-			/* increment phantom index */
-			dml_phantom_prog_idx++;
-		}
-	}
-}
-
 void dml21_copy(struct dml2_context *dst_dml_ctx,
 	struct dml2_context *src_dml_ctx)
 {
@@ -446,12 +86,8 @@ void dml21_copy(struct dml2_context *dst_dml_ctx,
 
 	dst_dml_ctx->v21.mode_programming.programming = dst_dml2_programming;
 
-	DC_FP_START();
-
 	/* need to initialize copied instance for internal references to be correct */
 	dml2_initialize_instance(&dst_dml_ctx->v21.dml_init);
-
-	DC_FP_END();
 }
 
 bool dml21_create_copy(struct dml2_context **dst_dml_ctx,
@@ -466,8 +102,3 @@ bool dml21_create_copy(struct dml2_context **dst_dml_ctx,
 	return true;
 }
 
-void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config)
-{
-	dml21_init(in_dc, dml_ctx, config);
-}
-
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h
index b508bbcc0e16..c4813c51251b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.h
@@ -34,36 +34,6 @@ void dml21_copy(struct dml2_context *dst_dml_ctx,
 	struct dml2_context *src_dml_ctx);
 bool dml21_create_copy(struct dml2_context **dst_dml_ctx,
 	struct dml2_context *src_dml_ctx);
-void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config);
-
-/**
- * dml21_validate - Determines if a display configuration is supported or not.
- * @in_dc: dc.
- * @context: dc_state to be validated.
- * @dml_ctx: dml21 context.
- * @validate_mode: DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX
- *           will not populate context.res_ctx.
- *
- * Based on fast_validate option internally would call:
- *
- * -dml21_mode_check_and_programming - for DC_VALIDATE_MODE_AND_PROGRAMMING option
- * Calculates if dc_state can be supported on the input display
- * configuration. If supported, generates the necessary HW
- * programming for the new dc_state.
- *
- * -dml21_check_mode_support - for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX option
- * Calculates if dc_state can be supported for the input display
- * config.
- *
- * Context: Two threads may not invoke this function concurrently unless they reference
- *          separate dc_states for validation.
- * Return: True if mode is supported, false otherwise.
- */
-bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx,
-	enum dc_validate_mode validate_mode);
-
-/* Prepare hubp mcache_regs for hubp mcache ID and split coordinate programming */
-void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx);
 
 /* Structure for inputting external SOCBB and DCNIP values for tool based debugging. */
 struct socbb_ip_params_external {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
new file mode 100644
index 000000000000..d5885bbd14c4
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2024 Advanced Micro Devices, Inc.
+
+#include "dml2_internal_types.h"
+#include "dml_top.h"
+#include "dml2_core_dcn4_calcs.h"
+#include "dml2_internal_shared_types.h"
+#include "dml21_utils.h"
+#include "dml21_translation_helper.h"
+#include "dml2_dc_resource_mgmt.h"
+#include "dml2_wrapper.h"
+#include "dml2_wrapper_fpu.h"
+#include "dml21_wrapper.h"
+#include "dml21_wrapper_fpu.h"
+
+#define INVALID -1
+
+static void dml21_populate_configuration_options(const struct dc *in_dc,
+		struct dml2_context *dml_ctx,
+		const struct dml2_configuration_options *config)
+{
+	dml_ctx->config = *config;
+
+	/* UCLK P-State options */
+	if (in_dc->debug.dml21_force_pstate_method) {
+		dml_ctx->config.pmo.force_pstate_method_enable = true;
+		for (int i = 0; i < MAX_PIPES; i++)
+			dml_ctx->config.pmo.force_pstate_method_values[i] = in_dc->debug.dml21_force_pstate_method_values[i];
+	} else {
+		dml_ctx->config.pmo.force_pstate_method_enable = false;
+	}
+}
+
+void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config)
+{
+	dml_ctx->architecture = dml2_architecture_21;
+
+	dml21_populate_configuration_options(in_dc, dml_ctx, config);
+
+	dml21_populate_dml_init_params(&dml_ctx->v21.dml_init, &dml_ctx->config, in_dc);
+
+	dml2_initialize_instance(&dml_ctx->v21.dml_init);
+}
+
+void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config)
+{
+	dml21_init(in_dc, dml_ctx, config);
+}
+
+static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state,
+	struct dml2_context *in_ctx, unsigned int pipe_cnt)
+{
+	unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0;
+	struct dml2_per_plane_programming *pln_prog = NULL;
+	struct dml2_per_stream_programming *stream_prog = NULL;
+	struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
+	struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
+	int num_pipes;
+	unsigned int dml_phantom_prog_idx;
+
+	context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
+
+	/* copy global DCHUBBUB arbiter registers */
+	memcpy(&context->bw_ctx.bw.dcn.arb_regs, &in_ctx->v21.mode_programming.programming->global_regs.arb_regs, sizeof(struct dml2_display_arb_regs));
+
+	/* legacy only */
+	context->bw_ctx.bw.dcn.compbuf_size_kb = (int)in_ctx->v21.mode_programming.programming->global_regs.arb_regs.compbuf_size * 64;
+
+	context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0;
+	context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0;
+	context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0;
+
+	/* phantom's start after main planes */
+	dml_phantom_prog_idx = in_ctx->v21.mode_programming.programming->display_config.num_planes;
+
+	for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) {
+		pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
+
+		if (!pln_prog->plane_descriptor)
+			continue;
+
+		stream_prog = &in_ctx->v21.mode_programming.programming->stream_programming[pln_prog->plane_descriptor->stream_index];
+		num_dpps_required = pln_prog->num_dpps_required;
+
+		if (num_dpps_required == 0) {
+			continue;
+		}
+		num_pipes = dml21_find_dc_pipes_for_plane(dc, context, in_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
+
+		if (num_pipes <= 0)
+			continue;
+
+		/* program each pipe */
+		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
+			dml21_program_dc_pipe(in_ctx, context, dc_main_pipes[dc_pipe_index], pln_prog, stream_prog);
+
+			if (pln_prog->phantom_plane.valid && dc_phantom_pipes[dc_pipe_index]) {
+				dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog);
+			}
+		}
+
+		/* copy per plane mcache allocation */
+		memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx], &pln_prog->mcache_allocation, sizeof(struct dml2_mcache_surface_allocation));
+		if (pln_prog->phantom_plane.valid) {
+			memcpy(&context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx],
+					&pln_prog->phantom_plane.mcache_allocation,
+					sizeof(struct dml2_mcache_surface_allocation));
+
+			dml_phantom_prog_idx++;
+		}
+	}
+
+	/* assign global clocks */
+	context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
+	context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
+	if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) {
+		context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz =
+			in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000;
+	} else {
+		context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000;
+	}
+
+	if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) {
+		context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz =
+			in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000;
+	} else {
+		context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000;
+	}
+
+	/* get global mall allocation */
+	if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) {
+		context->bw_ctx.bw.dcn.clk.num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes);
+	} else {
+		context->bw_ctx.bw.dcn.clk.num_ways = 0;
+	}
+}
+
+static void dml21_prepare_mcache_params(struct dml2_context *dml_ctx, struct dc_state *context, struct dc_mcache_params *mcache_params)
+{
+	int dc_plane_idx = 0;
+	int dml_prog_idx, stream_idx, plane_idx;
+	struct dml2_per_plane_programming *pln_prog = NULL;
+
+	for (stream_idx = 0; stream_idx < context->stream_count; stream_idx++) {
+		for (plane_idx = 0; plane_idx < context->stream_status[stream_idx].plane_count; plane_idx++) {
+			dml_prog_idx = map_plane_to_dml21_display_cfg(dml_ctx, context->streams[stream_idx]->stream_id, context->stream_status[stream_idx].plane_states[plane_idx], context);
+			if (dml_prog_idx == INVALID) {
+				continue;
+			}
+			pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
+			mcache_params[dc_plane_idx].valid = pln_prog->mcache_allocation.valid;
+			mcache_params[dc_plane_idx].num_mcaches_plane0 = pln_prog->mcache_allocation.num_mcaches_plane0;
+			mcache_params[dc_plane_idx].num_mcaches_plane1 = pln_prog->mcache_allocation.num_mcaches_plane1;
+			mcache_params[dc_plane_idx].requires_dedicated_mall_mcache = pln_prog->mcache_allocation.requires_dedicated_mall_mcache;
+			mcache_params[dc_plane_idx].last_slice_sharing.plane0_plane1 = pln_prog->mcache_allocation.last_slice_sharing.plane0_plane1;
+			memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane0,
+				pln_prog->mcache_allocation.mcache_x_offsets_plane0,
+				sizeof(int) * (DML2_MAX_MCACHES + 1));
+			memcpy(mcache_params[dc_plane_idx].mcache_x_offsets_plane1,
+				pln_prog->mcache_allocation.mcache_x_offsets_plane1,
+				sizeof(int) * (DML2_MAX_MCACHES + 1));
+			dc_plane_idx++;
+		}
+	}
+}
+
+static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
+{
+	bool is_supported = false;
+	struct dml2_initialize_instance_in_out *dml_init = &dml_ctx->v21.dml_init;
+	struct dml2_check_mode_supported_in_out *mode_support = &dml_ctx->v21.mode_support;
+
+	memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg));
+	memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
+	memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.check_mode_supported_locals.mode_support_params, 0, sizeof(struct dml2_core_mode_support_in_out));
+
+	if (!context || context->stream_count == 0)
+		return true;
+
+	/* Scrub phantom's from current dc_state */
+	dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context);
+	dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context);
+
+	mode_support->dml2_instance = dml_init->dml2_instance;
+	dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
+	dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params.programming = dml_ctx->v21.mode_programming.programming;
+
+	is_supported = dml2_check_mode_supported(mode_support);
+
+	if (!is_supported)
+		return false;
+
+	return true;
+}
+
+static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
+{
+	bool result = false;
+	struct dml2_build_mode_programming_in_out *mode_programming = &dml_ctx->v21.mode_programming;
+	struct dc_mcache_params mcache_params[MAX_PLANES] = {0};
+
+	memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg));
+	memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping));
+	memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params, 0, sizeof(struct dml2_core_mode_programming_in_out));
+
+	if (!context)
+		return true;
+
+	if (context->stream_count == 0) {
+		dml21_init_min_clocks_for_dc_state(dml_ctx, context);
+		dml21_build_fams2_programming(in_dc, context, dml_ctx);
+		return true;
+	}
+
+	/* scrub phantom's from current dc_state */
+	dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context);
+	dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context);
+
+	/* Populate stream, plane mappings and other fields in display config. */
+	result = dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx);
+	if (!result)
+		return false;
+
+	result = dml2_build_mode_programming(mode_programming);
+
+	if (!result)
+		return false;
+
+	/* Check and map HW resources */
+	if (result && !dml_ctx->config.skip_hw_state_mapping) {
+		dml21_map_hw_resources(dml_ctx);
+		dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, in_dc->current_state);
+		/* if subvp phantoms are present, expand them into dc context */
+		dml21_handle_phantom_streams_planes(in_dc, context, dml_ctx);
+
+		if (in_dc->res_pool->funcs->program_mcache_pipe_config) {
+			//Prepare mcache params for each plane based on mcache output from DML
+			dml21_prepare_mcache_params(dml_ctx, context, mcache_params);
+
+			//populate mcache regs to each pipe
+			dml_ctx->config.callbacks.allocate_mcache(context, mcache_params);
+		}
+	}
+
+	/* Copy DML CLK, WM and REG outputs to bandwidth context */
+	if (result && !dml_ctx->config.skip_hw_state_mapping) {
+		dml21_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml_ctx, in_dc->res_pool->pipe_count);
+		dml21_copy_clocks_to_dc_state(dml_ctx, context);
+		dml21_extract_watermark_sets(in_dc, &context->bw_ctx.bw.dcn.watermarks, dml_ctx);
+		dml21_build_fams2_programming(in_dc, context, dml_ctx);
+	}
+
+	return true;
+}
+
+bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx,
+	enum dc_validate_mode validate_mode)
+{
+	bool out = false;
+
+	/* Use dml21_check_mode_support for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */
+	if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
+		out = dml21_check_mode_support(in_dc, context, dml_ctx);
+	else
+		out = dml21_mode_check_and_programming(in_dc, context, dml_ctx);
+
+	return out;
+}
+
+void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx)
+{
+	unsigned int dml_prog_idx, dml_phantom_prog_idx, dc_pipe_index;
+	int num_pipes;
+	struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__];
+	struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0};
+
+	struct dml2_per_plane_programming *pln_prog = NULL;
+	struct dml2_plane_mcache_configuration_descriptor *mcache_config = NULL;
+	struct prepare_mcache_programming_locals *l = &dml_ctx->v21.scratch.prepare_mcache_locals;
+
+	if (context->stream_count == 0) {
+		return;
+	}
+
+	memset(&l->build_mcache_programming_params, 0, sizeof(struct dml2_build_mcache_programming_in_out));
+	l->build_mcache_programming_params.dml2_instance = dml_ctx->v21.dml_init.dml2_instance;
+
+	/* phantom's start after main planes */
+	dml_phantom_prog_idx = dml_ctx->v21.mode_programming.programming->display_config.num_planes;
+
+	/* Build mcache programming parameters per plane per pipe */
+	for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) {
+		pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
+
+		mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_prog_idx];
+		memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor));
+		mcache_config->plane_descriptor = pln_prog->plane_descriptor;
+		mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx];
+		mcache_config->num_pipes = pln_prog->num_dpps_required;
+		l->build_mcache_programming_params.num_configurations++;
+
+		if (pln_prog->num_dpps_required == 0) {
+			continue;
+		}
+
+		num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
+		if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL ||
+		    dc_main_pipes[0]->plane_state == NULL)
+			continue;
+
+		/* get config for each pipe */
+		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
+			ASSERT(dc_main_pipes[dc_pipe_index]);
+			dml21_get_pipe_mcache_config(context, dc_main_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]);
+		}
+
+		/* get config for each phantom pipe */
+		if (pln_prog->phantom_plane.valid &&
+				dc_phantom_pipes[0] &&
+				dc_main_pipes[0]->stream &&
+				dc_phantom_pipes[0]->plane_state) {
+			mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_phantom_prog_idx];
+			memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor));
+			mcache_config->plane_descriptor = pln_prog->plane_descriptor;
+			mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx];
+			mcache_config->num_pipes = pln_prog->num_dpps_required;
+			l->build_mcache_programming_params.num_configurations++;
+
+			for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
+				ASSERT(dc_phantom_pipes[dc_pipe_index]);
+				dml21_get_pipe_mcache_config(context, dc_phantom_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]);
+			}
+
+			/* increment phantom index */
+			dml_phantom_prog_idx++;
+		}
+	}
+
+	/* Call to generate mcache programming per plane per pipe for the given display configuration */
+	dml2_build_mcache_programming(&l->build_mcache_programming_params);
+
+	/* get per plane per pipe mcache programming */
+	for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) {
+		pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx];
+
+		num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx);
+		if (num_pipes <= 0 || dc_main_pipes[0]->stream == NULL ||
+		    dc_main_pipes[0]->plane_state == NULL)
+			continue;
+
+		/* get config for each pipe */
+		for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
+			ASSERT(dc_main_pipes[dc_pipe_index]);
+			if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index]) {
+				memcpy(&dc_main_pipes[dc_pipe_index]->mcache_regs,
+						l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index],
+						sizeof(struct dml2_hubp_pipe_mcache_regs));
+			}
+		}
+
+		/* get config for each phantom pipe */
+		if (pln_prog->phantom_plane.valid &&
+				dc_phantom_pipes[0] &&
+				dc_main_pipes[0]->stream &&
+				dc_phantom_pipes[0]->plane_state) {
+			for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) {
+				ASSERT(dc_phantom_pipes[dc_pipe_index]);
+				if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index]) {
+					memcpy(&dc_phantom_pipes[dc_pipe_index]->mcache_regs,
+							l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index],
+							sizeof(struct dml2_hubp_pipe_mcache_regs));
+				}
+			}
+			/* increment phantom index */
+			dml_phantom_prog_idx++;
+		}
+	}
+}
+
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h
new file mode 100644
index 000000000000..2972c6eed21a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2024 Advanced Micro Devices, Inc.
+
+#ifndef _DML21_WRAPPER_FPU_H_
+#define _DML21_WRAPPER_FPU_H_
+
+#include "os_types.h"
+#include "dml_top_soc_parameter_types.h"
+#include "dml_top_display_cfg_types.h"
+
+struct dc;
+struct dc_state;
+struct dml2_configuration_options;
+struct dml2_context;
+enum dc_validate_mode;
+
+/**
+ * dml21_init - Initialize DML21 context
+ * @in_dc: dc.
+ * @dml_ctx: DML21 context to initialize.
+ * @config: dml21 configuration options.
+ *
+ * Performs FPU-requiring initialization. Must be called with FPU protection.
+ */
+void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config);
+
+/**
+ * dml21_validate - Determines if a display configuration is supported or not.
+ * @in_dc: dc.
+ * @context: dc_state to be validated.
+ * @dml_ctx: dml21 context.
+ * @validate_mode: DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX
+ *           will not populate context.res_ctx.
+ *
+ * Based on fast_validate option internally would call:
+ *
+ * -dml21_mode_check_and_programming - for DC_VALIDATE_MODE_AND_PROGRAMMING option
+ * Calculates if dc_state can be supported on the input display
+ * configuration. If supported, generates the necessary HW
+ * programming for the new dc_state.
+ *
+ * -dml21_check_mode_support - for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX option
+ * Calculates if dc_state can be supported for the input display
+ * config.
+ *
+ * Context: Two threads may not invoke this function concurrently unless they reference
+ *          separate dc_states for validation.
+ * Return: True if mode is supported, false otherwise.
+ */
+
+void dml21_reinit(const struct dc *in_dc, struct dml2_context *dml_ctx,
+		  const struct dml2_configuration_options *config);
+bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx,
+	enum dc_validate_mode validate_mode);
+
+/* Prepare hubp mcache_regs for hubp mcache ID and split coordinate programming */
+void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx);
+
+#endif /* _DML21_WRAPPER_FPU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
index 307186eb6af0..9215e38343ba 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper.c
@@ -6,7 +6,20 @@
  */
 
 #include "dml2_internal_types.h"
+#include "dml2_wrapper.h"
 #include "dml2_wrapper_fpu.h"
+#include "dml21_wrapper.h"
+#include "dml21_wrapper_fpu.h"
+
+#include "dc_fpu.h"
+
+struct dml2_context *dml2_allocate_memory(void)
+{
+	struct dml2_context *dml2;
+
+	DC_RUN_WITH_PREEMPTION_ENABLED(dml2 = vzalloc(sizeof(struct dml2_context)));
+	return dml2;
+}
 
 bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2,
 	enum dc_validate_mode validate_mode)
@@ -23,16 +36,12 @@ bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2
 		return out;
 	}
 
-	DC_FP_START();
-
 	/* Use dml_validate_only for DC_VALIDATE_MODE_ONLY and DC_VALIDATE_MODE_AND_STATE_INDEX path */
 	if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
 		out = dml2_validate_only(context, validate_mode);
 	else
 		out = dml2_validate_and_build_resource(in_dc, context, validate_mode);
 
-	DC_FP_END();
-
 	return out;
 }
 
@@ -70,15 +79,11 @@ static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_op
 		break;
 	}
 
-	DC_FP_START();
-
 	initialize_dml2_ip_params(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.ip);
 
 	initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc);
 
 	initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states);
-
-	DC_FP_END();
 }
 
 bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c
index 203eef747262..66624cfc27b1 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml2_wrapper_fpu.c
@@ -31,8 +31,10 @@
 #include "dml2_translation_helper.h"
 #include "dml2_mall_phantom.h"
 #include "dml2_dc_resource_mgmt.h"
-#include "dml21_wrapper.h"
+#include "dml2_wrapper.h"
 #include "dml2_wrapper_fpu.h"
+#include "dml21_wrapper.h"
+#include "dml21_wrapper_fpu.h"
 
 void initialize_dml2_ip_params(struct dml2_context *dml2, const struct dc *in_dc, struct ip_params_st *out)
 {
@@ -546,11 +548,6 @@ void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2)
 	}
 }
 
-inline struct dml2_context *dml2_allocate_memory(void)
-{
-	return (struct dml2_context *) vzalloc(sizeof(struct dml2_context));
-}
-
 void dml2_destroy(struct dml2_context *dml2)
 {
 	if (!dml2)
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 3/8] drm/amd/display: Move FPU Guards From DML To DC - Part 1
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable
  Cc: amd-gfx, Rafal Ostrowski, Dillon Varone, Alex Hung, Alex Deucher,
	Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

From: Rafal Ostrowski <rafal.ostrowski@amd.com>

[ Upstream commit 3539437f354bd24c98928a80d4db3a23fa2a7b19 ]

[Why]
FPU guards (DC_FP_START/DC_FP_END) are required to wrap around code that
can manipulates floats. To do this properly, the FPU guards must be used
in a file that is not compiled as a FPU unit. If the guards are used in
a file that is a FPU unit, other sections in the file that aren't guarded
may be end up being compiled to use FPU operations.

[How]
Added DC_FP_START and DC_FP_END to DC functions that call DML functions
using FPU.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
[ Resolve empty line differences in dc_stream.c, ignore dcn42 which is
  not supported by 7.0.y. ]
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c    |   25 +-
 .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.h    |   17 +-
 .../display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c  |    2 -
 .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c  |    2 -
 drivers/gpu/drm/amd/display/dc/core/dc.c      |    5 +-
 .../gpu/drm/amd/display/dc/core/dc_state.c    |   75 +-
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |   15 +-
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c |    4 +-
 .../dc/resource/dcn35/dcn35_resource.c        |   10 +-
 .../dc/resource/dcn35/dcn35_resource.h        |    1 +
 .../dc/resource/dcn351/dcn351_resource.c      |   10 +-
 .../dc/resource/dcn36/dcn36_resource.c        |    4 +-
 .../dc/resource/dcn401/dcn401_resource.c      |   30 +-
 .../dc/resource/dcn42/dcn42_resource.c        | 2355 +++++++++++++++++
 14 files changed, 2508 insertions(+), 47 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
index e46f8ce41d87..8ba9b4f56f87 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
@@ -53,11 +53,30 @@ inline void dc_assert_fp_enabled(void)
 {
 	int depth;
 
-	depth = __this_cpu_read(fpu_recursion_depth);
+	depth = this_cpu_read(fpu_recursion_depth);
 
 	ASSERT(depth >= 1);
 }
 
+/**
+ * dc_assert_fp_enabled - Check if FPU protection is enabled
+ *
+ * This function tells if the code is already under FPU protection or not. A
+ * function that works as an API for a set of FPU operations can use this
+ * function for checking if the caller invoked it after DC_FP_START(). For
+ * example, take a look at dcn20_fpu.c file.
+ *
+ * Similar to dc_assert_fp_enabled, but does not assert, returns status instead.
+ */
+inline bool dc_is_fp_enabled(void)
+{
+	int depth;
+
+	depth = this_cpu_read(fpu_recursion_depth);
+
+	return (depth >= 1);
+}
+
 /**
  * dc_fpu_begin - Enables FPU protection
  * @function_name: A string containing the function name for debug purposes
@@ -77,7 +96,7 @@ void dc_fpu_begin(const char *function_name, const int line)
 
 	WARN_ON_ONCE(!in_task());
 	preempt_disable();
-	depth = __this_cpu_inc_return(fpu_recursion_depth);
+	depth = this_cpu_inc_return(fpu_recursion_depth);
 	if (depth == 1) {
 		BUG_ON(!kernel_fpu_available());
 		kernel_fpu_begin();
@@ -100,7 +119,7 @@ void dc_fpu_end(const char *function_name, const int line)
 {
 	int depth;
 
-	depth = __this_cpu_dec_return(fpu_recursion_depth);
+	depth = this_cpu_dec_return(fpu_recursion_depth);
 	if (depth == 0) {
 		kernel_fpu_end();
 	} else {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h
index 4e921632bc4e..5e95419d3798 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.h
@@ -28,15 +28,30 @@
 #define __DC_FPU_H__
 
 void dc_assert_fp_enabled(void);
+bool dc_is_fp_enabled(void);
 void dc_fpu_begin(const char *function_name, const int line);
 void dc_fpu_end(const char *function_name, const int line);
 
 #ifndef _LINUX_FPU_COMPILATION_UNIT
 #define DC_FP_START()	dc_fpu_begin(__func__, __LINE__)
 #define DC_FP_END()	dc_fpu_end(__func__, __LINE__)
+#ifdef CONFIG_DRM_AMD_DC_FP
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) \
+	do { \
+		bool dc_fp_enabled = dc_is_fp_enabled(); \
+		if (dc_fp_enabled) \
+			DC_FP_END(); \
+		code; \
+		if (dc_fp_enabled) \
+			DC_FP_START(); \
+	} while (0)
+#else
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif // !CONFIG_DRM_AMD_DC_FP
 #else
 #define DC_FP_START()	BUILD_BUG()
 #define DC_FP_END()	BUILD_BUG()
-#endif
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif // !_LINUX_FPU_COMPILATION_UNIT
 
 #endif /* __DC_FPU_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
index b0aba3a6f13c..e06f06158ac8 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
@@ -421,10 +421,8 @@ static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
 	clk_mgr_base->bw_params->dc_mode_softmax_memclk = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
 
 	/* Refresh bounding box */
-	DC_FP_START();
 	clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
 			clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
-	DC_FP_END();
 }
 
 static bool dcn3_is_smu_present(struct clk_mgr *clk_mgr_base)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
index 2856b0337e87..4007ab353ffd 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
@@ -1059,11 +1059,9 @@ static void dcn32_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
 	if (!clk_mgr->dpm_present)
 		dcn32_patch_dpm_table(clk_mgr_base->bw_params);
 
-	DC_FP_START();
 	/* Refresh bounding box */
 	clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
 			clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
-	DC_FP_END();
 }
 
 static bool dcn32_are_clock_states_equal(struct dc_clocks *a,
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 3e87b6a553be..0686141af3eb 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1165,11 +1165,8 @@ static bool dc_construct(struct dc *dc,
 #ifdef CONFIG_DRM_AMD_DC_FP
 	dc->clk_mgr->force_smu_not_present = init_params->force_smu_not_present;
 
-	if (dc->res_pool->funcs->update_bw_bounding_box) {
-		DC_FP_START();
+	if (dc->res_pool->funcs->update_bw_bounding_box)
 		dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
-		DC_FP_END();
-	}
 	dc->soc_and_ip_translator = dc_create_soc_and_ip_translator(dc_ctx->dce_version);
 	if (!dc->soc_and_ip_translator)
 		goto fail;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index a40e5c44143f..13d334c2cb6b 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -205,19 +205,33 @@ struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *p
 	state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC;
 
 #ifdef CONFIG_DRM_AMD_DC_FP
+	bool status;
+
 	if (dc->debug.using_dml2) {
-		if (!dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2)) {
+		DC_FP_START();
+		status = dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2);
+		DC_FP_END();
+
+		if (!status) {
 			dc_state_release(state);
 			return NULL;
 		}
 
-		if (dc->caps.dcmode_power_limits_present && !dml2_create(dc, &dc->dml2_dc_power_options, &state->bw_ctx.dml2_dc_power_source)) {
-			dc_state_release(state);
-			return NULL;
+		if (dc->caps.dcmode_power_limits_present) {
+			bool status;
+
+			DC_FP_START();
+			status = dml2_create(dc, &dc->dml2_dc_power_options, &state->bw_ctx.dml2_dc_power_source);
+			DC_FP_END();
+
+			if (!status) {
+				dc_state_release(state);
+				return NULL;
+			}
 		}
-	}
-#endif
 
+	}
+#endif // CONFIG_DRM_AMD_DC_FP
 	kref_init(&state->refcount);
 
 	return state;
@@ -235,14 +249,20 @@ void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state)
 
 #ifdef CONFIG_DRM_AMD_DC_FP
 	dst_state->bw_ctx.dml2 = dst_dml2;
-	if (src_state->bw_ctx.dml2)
+	if (src_state->bw_ctx.dml2) {
+		DC_FP_START();
 		dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
+		DC_FP_END();
+	}
 
 	dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source;
-	if (src_state->bw_ctx.dml2_dc_power_source)
-		dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
-#endif
 
+	if (src_state->bw_ctx.dml2_dc_power_source) {
+		DC_FP_START();
+		dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source);
+		DC_FP_END();
+	}
+#endif // CONFIG_DRM_AMD_DC_FP
 	/* context refcount should not be overridden */
 	dst_state->refcount = refcount;
 }
@@ -258,22 +278,35 @@ struct dc_state *dc_state_create_copy(struct dc_state *src_state)
 	dc_state_copy_internal(new_state, src_state);
 
 #ifdef CONFIG_DRM_AMD_DC_FP
+	bool status;
+
 	new_state->bw_ctx.dml2 = NULL;
 	new_state->bw_ctx.dml2_dc_power_source = NULL;
 
-	if (src_state->bw_ctx.dml2 &&
-			!dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) {
-		dc_state_release(new_state);
-		return NULL;
-	}
+	if (src_state->bw_ctx.dml2) {
+		DC_FP_START();
+		status = dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2);
+		DC_FP_END();
 
-	if (src_state->bw_ctx.dml2_dc_power_source &&
-			!dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) {
-		dc_state_release(new_state);
-		return NULL;
+		if (!status) {
+			dc_state_release(new_state);
+			return NULL;
+		}
 	}
-#endif
 
+
+	if (src_state->bw_ctx.dml2_dc_power_source) {
+		DC_FP_START();
+		status = dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source,
+					  src_state->bw_ctx.dml2_dc_power_source);
+		DC_FP_END();
+
+		if (!status) {
+			dc_state_release(new_state);
+			return NULL;
+		}
+	}
+#endif // CONFIG_DRM_AMD_DC_FP
 	kref_init(&new_state->refcount);
 
 	return new_state;
@@ -351,11 +384,13 @@ static void dc_state_free(struct kref *kref)
 	dc_state_destruct(state);
 
 #ifdef CONFIG_DRM_AMD_DC_FP
+	DC_FP_START();
 	dml2_destroy(state->bw_ctx.dml2);
 	state->bw_ctx.dml2 = 0;
 
 	dml2_destroy(state->bw_ctx.dml2_dc_power_source);
 	state->bw_ctx.dml2_dc_power_source = 0;
+	DC_FP_END();
 #endif
 
 	kvfree(state);
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index baf820e6eae8..dca64e1671f6 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -42,6 +42,13 @@
 #define MAX(x, y) ((x > y) ? x : y)
 #endif
 
+#include "dc_fpu.h"
+
+#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif // !DC_RUN_WITH_PREEMPTION_ENABLED
+
+
 /*******************************************************************************
  * Private functions
  ******************************************************************************/
@@ -170,11 +177,15 @@ struct dc_stream_state *dc_create_stream_for_sink(
 	if (sink == NULL)
 		goto fail;
 
-	stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC);
+	DC_RUN_WITH_PREEMPTION_ENABLED(stream = kzalloc_obj(struct dc_stream_state, GFP_ATOMIC));
+
 	if (stream == NULL)
 		goto fail;
 
-	stream->update_scratch = kzalloc((int32_t) dc_update_scratch_space_size(), GFP_ATOMIC);
+	DC_RUN_WITH_PREEMPTION_ENABLED(stream->update_scratch =
+					kzalloc((int32_t) dc_update_scratch_space_size(),
+						GFP_ATOMIC));
+
 	if (stream->update_scratch == NULL)
 		goto fail;
 
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 4dfb6c865831..a6c3a1f5fbfa 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -371,8 +371,8 @@ void dcn401_init_hw(struct dc *dc)
 		    dc->res_pool->funcs->update_bw_bounding_box &&
 		    dc->clk_mgr && dc->clk_mgr->bw_params) {
 			/* update bounding box if FAMS2 disabled, or if dchub clk has changed */
-			dc->res_pool->funcs->update_bw_bounding_box(dc,
-								    dc->clk_mgr->bw_params);
+			if (dc->clk_mgr)
+				dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
 		}
 	}
 }
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
index 598b2f25881d..adbd23fcc9b7 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
@@ -1773,9 +1773,11 @@ static enum dc_status dcn35_validate_bandwidth(struct dc *dc,
 {
 	bool out = false;
 
+	DC_FP_START();
 	out = dml2_validate(dc, context,
 			context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2,
 			validate_mode);
+	DC_FP_END();
 
 	if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
 		return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
@@ -1809,6 +1811,12 @@ static int populate_dml_pipes_from_context_fpu(struct dc *dc,
 	return ret;
 }
 
+void dcn35_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn35_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
 static struct resource_funcs dcn35_res_pool_funcs = {
 	.destroy = dcn35_destroy_resource_pool,
 	.link_enc_create = dcn35_link_encoder_create,
@@ -1830,7 +1838,7 @@ static struct resource_funcs dcn35_res_pool_funcs = {
 	.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
 	.acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
 	.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
-	.update_bw_bounding_box = dcn35_update_bw_bounding_box_fpu,
+	.update_bw_bounding_box = dcn35_update_bw_bounding_box,
 	.patch_unknown_plane_state = dcn35_patch_unknown_plane_state,
 	.get_panel_config_defaults = dcn35_get_panel_config_defaults,
 	.get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h
index 9c56ae76e0c7..6c2c61c711b9 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h
@@ -312,4 +312,5 @@ struct resource_pool *dcn35_create_resource_pool(
 #define DPP_REG_LIST_DCN35_RI(id)\
 	DPP_REG_LIST_DCN30_COMMON_RI(id)
 
+void dcn35_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
 #endif /* _DCN35_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
index 7e15d07df7a3..dc70b771633f 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
@@ -1753,9 +1753,11 @@ static enum dc_status dcn351_validate_bandwidth(struct dc *dc,
 {
 	bool out = false;
 
+	DC_FP_START();
 	out = dml2_validate(dc, context,
 			context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2,
 			validate_mode);
+	DC_FP_END();
 
 	if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
 		return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
@@ -1782,6 +1784,12 @@ static int populate_dml_pipes_from_context_fpu(struct dc *dc,
 
 }
 
+static void dcn351_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn351_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
 static struct resource_funcs dcn351_res_pool_funcs = {
 	.destroy = dcn351_destroy_resource_pool,
 	.link_enc_create = dcn35_link_encoder_create,
@@ -1803,7 +1811,7 @@ static struct resource_funcs dcn351_res_pool_funcs = {
 	.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
 	.acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
 	.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
-	.update_bw_bounding_box = dcn351_update_bw_bounding_box_fpu,
+	.update_bw_bounding_box = dcn351_update_bw_bounding_box,
 	.patch_unknown_plane_state = dcn35_patch_unknown_plane_state,
 	.get_panel_config_defaults = dcn35_get_panel_config_defaults,
 	.get_preferred_eng_id_dpia = dcn351_get_preferred_eng_id_dpia,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
index 83fee2ca61bf..2667a2e8b04f 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c
@@ -1760,9 +1760,11 @@ static enum dc_status dcn35_validate_bandwidth(struct dc *dc,
 {
 	bool out = false;
 
+	DC_FP_START();
 	out = dml2_validate(dc, context,
 			context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2,
 			validate_mode);
+	DC_FP_END();
 
 	if (validate_mode != DC_VALIDATE_MODE_AND_PROGRAMMING)
 		return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
@@ -1810,7 +1812,7 @@ static struct resource_funcs dcn36_res_pool_funcs = {
 	.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
 	.acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
 	.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
-	.update_bw_bounding_box = dcn35_update_bw_bounding_box_fpu,
+	.update_bw_bounding_box = dcn35_update_bw_bounding_box,
 	.patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
 	.get_panel_config_defaults = dcn35_get_panel_config_defaults,
 	.get_preferred_eng_id_dpia = dcn36_get_preferred_eng_id_dpia,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
index e37aab939a41..237d1a561da7 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
@@ -1643,8 +1643,10 @@ static struct dc_cap_funcs cap_funcs = {
 	.get_subvp_en = dcn32_subvp_in_use,
 };
 
-static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+static void dcn401_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
 {
+	dc_assert_fp_enabled();
+
 	/* re-calculate the available MALL size if required */
 	if (bw_params->num_channels > 0) {
 		dc->caps.max_cab_allocation_bytes = dcn401_calc_num_avail_chans_for_mall(
@@ -1653,17 +1655,19 @@ static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b
 		dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
 	}
 
-	DC_FP_START();
-
 	if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2)
 		dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2);
 
 	if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2_dc_power_source)
 		dml2_reinit(dc, &dc->dml2_dc_power_options, &dc->current_state->bw_ctx.dml2_dc_power_source);
+}
 
+static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn401_update_bw_bounding_box_fpu(dc, bw_params);
 	DC_FP_END();
 }
-
 enum dc_status dcn401_patch_unknown_plane_state(struct dc_plane_state *plane_state)
 {
 	plane_state->tiling_info.gfxversion = DcGfxAddr3;
@@ -1688,10 +1692,13 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc,
 		}
 	}
 
-	if (dc->debug.using_dml2)
+	if (dc->debug.using_dml2) {
+		DC_FP_START();
 		status = dml2_validate(dc, context,
 				context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2,
 				validate_mode) ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
+		DC_FP_END();
+	}
 
 	if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING && status == DC_OK && dc_state_is_subvp_in_use(context)) {
 		/* check new stream configuration still supports cursor if subvp used */
@@ -1710,10 +1717,13 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc,
 
 	if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING && status == DC_FAIL_HW_CURSOR_SUPPORT) {
 		/* attempt to validate again with subvp disabled due to cursor */
-		if (dc->debug.using_dml2)
+		if (dc->debug.using_dml2) {
+			DC_FP_START();
 			status = dml2_validate(dc, context,
 					context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2,
 					validate_mode) ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
+			DC_FP_END();
+		}
 	}
 
 	return status;
@@ -1722,9 +1732,13 @@ enum dc_status dcn401_validate_bandwidth(struct dc *dc,
 void dcn401_prepare_mcache_programming(struct dc *dc,
 		struct dc_state *context)
 {
-	if (dc->debug.using_dml21)
+	if (dc->debug.using_dml21) {
+		DC_FP_START();
 		dml2_prepare_mcache_programming(dc, context,
-				context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2);
+			context->power_source == DC_POWER_SOURCE_DC ?
+			context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2);
+		DC_FP_END();
+	}
 }
 
 static void dcn401_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
new file mode 100644
index 000000000000..b9532ebcced4
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
@@ -0,0 +1,2355 @@
+// SPDX-License-Identifier: MIT
+//
+// Copyright 2026 Advanced Micro Devices, Inc.
+
+#include "dm_services.h"
+#include "dc.h"
+
+#include "dcn32/dcn32_init.h"
+#include "dcn42/dcn42_init.h"
+
+#include "resource.h"
+#include "include/irq_service_interface.h"
+
+#include "dcn42_resource.h"
+#include "dcn42_resource_fpu.h"
+#include "dcn20/dcn20_resource.h"
+#include "dcn30/dcn30_resource.h"
+#include "dcn31/dcn31_resource.h"
+#include "dcn32/dcn32_resource.h"
+#include "dcn35/dcn35_resource.h"
+#include "dcn321/dcn321_resource.h"
+#include "dcn401/dcn401_resource.h"
+
+#include "dcn10/dcn10_ipp.h"
+#include "dcn35/dcn35_hubbub.h"
+#include "dcn42/dcn42_hubbub.h"
+#include "dcn401/dcn401_mpc.h"
+#include "dcn42/dcn42_mpc.h"
+#include "dcn35/dcn35_hubp.h"
+#include "dcn42/dcn42_hubp.h"
+#include "irq/dcn42/irq_service_dcn42.h"
+#include "dcn42/dcn42_dpp.h"
+#include "dcn401/dcn401_dsc.h"
+#include "dcn42/dcn42_optc.h"
+#include "dcn20/dcn20_hwseq.h"
+#include "dcn30/dcn30_hwseq.h"
+#include "dce110/dce110_hwseq.h"
+#include "dcn35/dcn35_opp.h"
+#include "dcn30/dcn30_vpg.h"
+#include "dcn31/dcn31_vpg.h"
+#include "dcn42/dcn42_dio_stream_encoder.h"
+#include "dcn42/dcn42_pg_cntl.h"
+#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_link_encoder.h"
+#include "dcn32/dcn32_hpo_dp_link_encoder.h"
+#include "dcn42/dcn42_hpo_dp_link_encoder.h"
+#include "dcn31/dcn31_apg.h"
+#include "dcn31/dcn31_dio_link_encoder.h"
+#include "dcn401/dcn401_dio_link_encoder.h"
+#include "dcn10/dcn10_link_encoder.h"
+#include "dcn321/dcn321_dio_link_encoder.h"
+#include "dce/dce_clock_source.h"
+#include "dce/dce_audio.h"
+#include "dce/dce_hwseq.h"
+#include "clk_mgr.h"
+#include "dio/virtual/virtual_stream_encoder.h"
+#include "dml/display_mode_vba.h"
+#include "dcn42/dcn42_dccg.h"
+#include "dcn10/dcn10_resource.h"
+#include "link_service.h"
+#include "dcn31/dcn31_panel_cntl.h"
+
+#include "dcn30/dcn30_dwb.h"
+#include "dcn42/dcn42_mmhubbub.h"
+#include "dcn42/dcn42_dio_link_encoder.h"
+
+#include "dcn/dcn_4_2_0_offset.h"
+#include "dcn/dcn_4_2_0_sh_mask.h"
+#include "dpcs/dpcs_4_0_0_offset.h"
+#include "dpcs/dpcs_4_0_0_sh_mask.h"
+
+#include "reg_helper.h"
+#include "dce/dmub_abm.h"
+#include "dce/dmub_psr.h"
+#include "dce/dmub_replay.h"
+#include "dce/dce_aux.h"
+#include "dce/dce_i2c.h"
+
+#include "dml/dcn30/display_mode_vba_30.h"
+#include "vm_helper.h"
+#include "dcn20/dcn20_vmid.h"
+
+#include "dc_state_priv.h"
+#include "link_enc_cfg.h"
+
+#include "dml2_0/dml2_wrapper.h"
+
+#define regBIF_BX0_BIOS_SCRATCH_3                            0x003b
+#define regBIF_BX0_BIOS_SCRATCH_3_BASE_IDX                   1
+#define regBIF_BX0_BIOS_SCRATCH_6                            0x003e
+#define regBIF_BX0_BIOS_SCRATCH_6_BASE_IDX                   1
+
+#define DC_LOGGER_INIT(logger)
+
+enum dcn401_clk_src_array_id {
+	DCN401_CLK_SRC_PLL0,
+	DCN401_CLK_SRC_PLL1,
+	DCN401_CLK_SRC_PLL2,
+	DCN401_CLK_SRC_PLL3,
+	DCN401_CLK_SRC_PLL4,
+	DCN401_CLK_SRC_TOTAL
+};
+
+/* begin
+ * macros to expend register list macro defined in HW object header file
+ */
+
+/* DCN */
+#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
+
+#define BASE(seg) BASE_INNER(seg)
+
+#define SR(reg_name)                                       \
+	REG_STRUCT.reg_name = BASE(reg##reg_name##_BASE_IDX) + \
+						  reg##reg_name
+#define SR_ARR(reg_name, id)                                   \
+	REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + \
+							  reg##reg_name
+#define SR_ARR_INIT(reg_name, id, value) \
+	REG_STRUCT[id].reg_name = value
+
+#define SRI(reg_name, block, id)                                         \
+	REG_STRUCT.reg_name = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+						  reg##block##id##_##reg_name
+
+#define SRI_ARR(reg_name, block, id)                                         \
+	REG_STRUCT[id].reg_name = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+							  reg##block##id##_##reg_name
+
+/*
+ * Used when a reg_name would otherwise begin with an integer
+ */
+#define SRI_ARR_US(reg_name, block, id)                                   \
+	REG_STRUCT[id].reg_name = BASE(reg##block##id##reg_name##_BASE_IDX) + \
+							  reg##block##id##reg_name
+#define SR_ARR_I2C(reg_name, id) \
+	REG_STRUCT[id - 1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name
+
+#define SRI_ARR_I2C(reg_name, block, id)                                         \
+	REG_STRUCT[id - 1].reg_name = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+								  reg##block##id##_##reg_name
+
+
+#define SRI_ARR_ALPHABET(reg_name, block, index, id)                            \
+	REG_STRUCT[index].reg_name = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+								 reg##block##id##_##reg_name
+
+#define SRI2(reg_name, block, id)                \
+	.reg_name = BASE(reg##reg_name##_BASE_IDX) + \
+				reg##reg_name
+#define SRI2_ARR(reg_name, block, id)                          \
+	REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + \
+							  reg##reg_name
+
+#define SRIR(var_name, reg_name, block, id)                    \
+	.var_name = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+				reg##block##id##_##reg_name
+
+#define SRII(reg_name, block, id)                                            \
+	REG_STRUCT.reg_name[id] = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+							  reg##block##id##_##reg_name
+
+#define SRII_ARR_2(reg_name, block, id, inst)                                      \
+	REG_STRUCT[inst].reg_name[id] = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+									reg##block##id##_##reg_name
+
+#define SRII_MPC_RMU(reg_name, block, id)                                  \
+	.RMU##_##reg_name[id] = BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+							reg##block##id##_##reg_name
+
+#define SRII_DWB(reg_name, temp_name, block, id)                              \
+	REG_STRUCT.reg_name[id] = \
+		BASE(reg##block##id##_##temp_name##_BASE_IDX) + \
+							  reg##block##id##_##temp_name
+
+#define DCCG_SRII(reg_name, block, id)                                                 \
+	REG_STRUCT.block##_##reg_name[id] = \
+		BASE(reg##block##id##_##reg_name##_BASE_IDX) + \
+										reg##block##id##_##reg_name
+
+#define SF_DWB2(reg_name, block, id, field_name, post_fix) \
+	.field_name = reg_name##__##field_name##post_fix
+
+#define VUPDATE_SRII(reg_name, block, id)                                    \
+	REG_STRUCT.reg_name[id] = BASE(reg##reg_name##_##block##id##_BASE_IDX) + \
+							  reg##reg_name##_##block##id
+
+/* NBIO */
+#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg]
+
+#define NBIO_BASE(seg) \
+	NBIO_BASE_INNER(seg)
+
+#define NBIO_SR(reg_name)                                               \
+	REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX0_##reg_name##_BASE_IDX) + \
+						  regBIF_BX0_##reg_name
+#define NBIO_SR_ARR(reg_name, id)                                           \
+	REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX0_##reg_name##_BASE_IDX) + \
+							  regBIF_BX0_##reg_name
+
+#define CTX ctx
+#define REG(reg_name) \
+	(ctx->dcn_reg_offsets[reg##reg_name##_BASE_IDX] + reg##reg_name)
+
+static struct bios_registers bios_regs;
+
+#define bios_regs_init()     \
+	NBIO_SR(BIOS_SCRATCH_3), \
+		NBIO_SR(BIOS_SCRATCH_6)
+
+#define clk_src_regs_init(index, pllid) \
+	CS_COMMON_REG_LIST_DCN42_RI(index, pllid)
+
+static struct dce110_clk_src_regs clk_src_regs[5];
+
+static const struct dce110_clk_src_shift cs_shift = {
+	CS_COMMON_MASK_SH_LIST_DCN3_1_4(__SHIFT)
+};
+static const struct dce110_clk_src_mask cs_mask = {
+	CS_COMMON_MASK_SH_LIST_DCN3_1_4(_MASK)
+};
+#define abm_regs_init(id) \
+	ABM_DCN42_REG_LIST_RI(id)
+
+static struct dce_abm_registers abm_regs[4];
+
+static const struct dce_abm_shift abm_shift = {
+	ABM_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dce_abm_mask abm_mask = {
+	ABM_MASK_SH_LIST_DCN42(_MASK)};
+
+#define audio_regs_init(id) \
+	AUD_COMMON_REG_LIST_RI(id)
+
+static struct dce_audio_registers audio_regs[5];
+
+static const struct dce_audio_shift audio_shift = {
+		DCN42_AUD_COMMON_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_audio_mask audio_mask = {
+		DCN42_AUD_COMMON_MASK_SH_LIST(_MASK)
+};
+
+#define vpg_regs_init(id) \
+	VPG_DCN401_REG_LIST_RI(id)
+
+static struct dcn31_vpg_registers vpg_regs[10];
+
+static const struct dcn31_vpg_shift vpg_shift = {
+	DCN31_VPG_MASK_SH_LIST(__SHIFT)};
+
+static const struct dcn31_vpg_mask vpg_mask = {
+	DCN31_VPG_MASK_SH_LIST(_MASK)};
+
+#define apg_regs_init(id) \
+	APG_DCN31_REG_LIST_RI(id)
+
+static struct dcn31_apg_registers apg_regs[10];
+
+static const struct dcn31_apg_shift apg_shift = {
+	DCN31_APG_MASK_SH_LIST(__SHIFT)};
+
+static const struct dcn31_apg_mask apg_mask = {
+	DCN31_APG_MASK_SH_LIST(_MASK)};
+
+#define stream_enc_regs_init(id) \
+	SE_DCN42_REG_LIST_RI(id)
+
+static struct dcn10_stream_enc_registers stream_enc_regs[5];
+
+static const struct dcn10_stream_encoder_shift se_shift = {
+	SE_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn10_stream_encoder_mask se_mask = {
+	SE_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
+#define aux_regs_init(id) \
+	DCN2_AUX_REG_LIST_RI(id)
+
+static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5];
+
+#define hpd_regs_init(id) \
+	HPD_REG_LIST_RI(id)
+
+static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5];
+
+#define link_regs_init(id, phyid) \
+	LE_DCN401_REG_LIST_RI(id)
+
+static struct dcn10_link_enc_registers link_enc_regs[5];
+
+static const struct dcn10_link_enc_shift le_shift = {
+	LINK_ENCODER_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn10_link_enc_mask le_mask = {
+	LINK_ENCODER_MASK_SH_LIST_DCN42(_MASK)};
+
+#define hpo_dp_stream_encoder_reg_init(id) \
+	DCN42_HPO_DP_STREAM_ENC_REG_LIST_RI(id)
+
+static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4];
+
+static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = {
+	DCN4_2_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT)};
+
+static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = {
+	DCN4_2_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK)};
+
+#define hpo_dp_link_encoder_reg_init(id) \
+	DCN42_HPO_DP_LINK_ENC_REG_LIST_RI(id)
+
+static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[4];
+
+static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = {
+	DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT)};
+
+static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {
+	DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)};
+
+#define dpp_regs_init(id) \
+	DPP_REG_LIST_DCN42_COMMON_RI(id)
+
+static struct dcn42_dpp_registers dpp_regs[4];
+
+static const struct dcn42_dpp_shift tf_shift = {
+	DPP_REG_LIST_SH_MASK_DCN42_COMMON(__SHIFT)};
+
+static const struct dcn42_dpp_mask tf_mask = {
+	DPP_REG_LIST_SH_MASK_DCN42_COMMON(_MASK)};
+
+#define opp_regs_init(id) \
+	OPP_REG_LIST_DCN401_RI(id)
+
+static struct dcn20_opp_registers opp_regs[4];
+
+static const struct dcn20_opp_shift opp_shift = {
+	OPP_MASK_SH_LIST_DCN20(__SHIFT)};
+
+static const struct dcn20_opp_mask opp_mask = {
+	OPP_MASK_SH_LIST_DCN20(_MASK)};
+
+#define aux_engine_regs_init(id)                                              \
+	AUX_COMMON_REG_LIST0_RI(id), SR_ARR_INIT(AUXN_IMPCAL, id, 0),             \
+		SR_ARR_INIT(AUXP_IMPCAL, id, 0),                                      \
+		SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK), \
+		SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK)
+
+static struct dce110_aux_registers aux_engine_regs[5];
+
+static const struct dce110_aux_registers_shift aux_shift = {
+	DCN_AUX_MASK_SH_LIST(__SHIFT)};
+
+static const struct dce110_aux_registers_mask aux_mask = {
+	DCN_AUX_MASK_SH_LIST(_MASK)};
+
+#define dwbc_regs_dcn401_init(id) \
+	DWBC_COMMON_REG_LIST_DCN30_RI(id)
+
+static struct dcn30_dwbc_registers dwbc401_regs[1];
+
+static const struct dcn30_dwbc_shift dwbc401_shift = {
+	DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT)};
+
+static const struct dcn30_dwbc_mask dwbc401_mask = {
+	DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK)};
+
+#define mcif_wb_regs_dcn3_init(id) \
+	MCIF_WB_COMMON_REG_LIST_DCN3_5_RI(id)
+
+static struct dcn35_mmhubbub_registers mcif_wb35_regs[1];
+
+static const struct dcn35_mmhubbub_shift mcif_wb35_shift = {
+	MCIF_WB_COMMON_MASK_SH_LIST_DCN3_5(__SHIFT)};
+
+static const struct dcn35_mmhubbub_mask mcif_wb35_mask = {
+	MCIF_WB_COMMON_MASK_SH_LIST_DCN3_5(_MASK)};
+
+#define dsc_regs_init(id) \
+	DSC_REG_LIST_DCN401_RI(id)
+
+static struct dcn401_dsc_registers dsc_regs[4];
+
+static const struct dcn401_dsc_shift dsc_shift = {
+	DSC_REG_LIST_SH_MASK_DCN401(__SHIFT)};
+
+static const struct dcn401_dsc_mask dsc_mask = {
+	DSC_REG_LIST_SH_MASK_DCN401(_MASK)};
+
+static struct dcn42_mpc_registers mpc_regs;
+
+#define dcn_mpc_regs_init()                \
+	MPC_REG_LIST_DCN42(0),                 \
+		MPC_REG_LIST_DCN42(1),             \
+		MPC_REG_LIST_DCN42(2),             \
+		MPC_REG_LIST_DCN42(3),             \
+		MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0), \
+		MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1), \
+		MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2), \
+		MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3), \
+		MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0), \
+		MPC_RMCM_REG_LIST_DCN42(0),		   \
+		MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_mpc_shift mpc_shift = {
+	MPC_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_mpc_mask mpc_mask = {
+	MPC_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
+#define optc_regs_init(id) \
+	OPTC_COMMON_REG_LIST_DCN42_RI(id)
+
+static struct dcn_optc_registers optc_regs[4];
+
+static const struct dcn_optc_shift optc_shift = {
+	OPTC_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn_optc_mask optc_mask = {
+	OPTC_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
+#define hubp_regs_init(id) \
+	HUBP_REG_LIST_DCN42_RI(id)
+
+static struct dcn_hubp2_registers hubp_regs[4];
+
+static const struct dcn_hubp2_shift hubp_shift = {
+	HUBP_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn_hubp2_mask hubp_mask = {
+	HUBP_MASK_SH_LIST_DCN42(_MASK)};
+
+static struct dcn_hubbub_registers hubbub_reg;
+
+#define hubbub_reg_init() \
+	HUBBUB_REG_LIST_DCN42(0)
+
+static const struct dcn_hubbub_shift hubbub_shift = {
+	HUBBUB_MASK_SH_LIST_DCN4_2(__SHIFT)};
+
+static const struct dcn_hubbub_mask hubbub_mask = {
+	HUBBUB_MASK_SH_LIST_DCN4_2(_MASK)};
+
+static struct dccg_registers dccg_regs;
+
+#define dccg_regs_init() \
+	DCCG_REG_LIST_DCN42_RI()
+
+static const struct dccg_shift dccg_shift = {
+	DCCG_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dccg_mask dccg_mask = {
+	DCCG_MASK_SH_LIST_DCN42(_MASK)};
+
+static struct pg_cntl_registers pg_cntl_regs;
+
+#define pg_cntl_dcn42_regs_init() \
+	PG_CNTL_REG_LIST_DCN42()
+
+static const struct pg_cntl_shift pg_cntl_shift = {
+		PG_CNTL_MASK_SH_LIST_DCN42(__SHIFT)
+};
+
+static const struct pg_cntl_mask pg_cntl_mask = {
+		PG_CNTL_MASK_SH_LIST_DCN42(_MASK)
+};
+#define SRII2(reg_name_pre, reg_name_post, id)                                                       \
+	.reg_name_pre##_##reg_name_post[id] = \
+		BASE(reg##reg_name_pre##id##_##reg_name_post##_BASE_IDX) + \
+					reg##reg_name_pre##id##_##reg_name_post
+
+#define HWSEQ_DCN42_REG_LIST()                \
+	SR(DCHUBBUB_GLOBAL_TIMER_CNTL),           \
+		SR(DIO_MEM_PWR_CTRL),                 \
+		SR(ODM_MEM_PWR_CTRL3),                \
+		SR(MMHUBBUB_MEM_PWR_CNTL),            \
+		SR(DCCG_GATE_DISABLE_CNTL),           \
+		SR(DCCG_GATE_DISABLE_CNTL2),          \
+		SR(DCFCLK_CNTL),                      \
+		SR(DC_MEM_GLOBAL_PWR_REQ_CNTL),       \
+		SRII(PIXEL_RATE_CNTL, OTG, 0),        \
+		SRII(PIXEL_RATE_CNTL, OTG, 1),        \
+		SRII(PIXEL_RATE_CNTL, OTG, 2),        \
+		SRII(PIXEL_RATE_CNTL, OTG, 3),\
+		SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0), \
+		SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1), \
+		SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2), \
+		SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\
+		SR(MICROSECOND_TIME_BASE_DIV),        \
+		SR(MILLISECOND_TIME_BASE_DIV),        \
+		SR(DISPCLK_FREQ_CHANGE_CNTL),         \
+		SR(RBBMIF_TIMEOUT_DIS),               \
+		SR(RBBMIF_TIMEOUT_DIS_2),             \
+		SR(DCHUBBUB_CRC_CTRL),                \
+		SR(DPP_TOP0_DPP_CRC_CTRL),            \
+		SR(DPP_TOP0_DPP_CRC_VAL_R),           \
+		SR(DPP_TOP0_DPP_CRC_VAL_G),           \
+		SR(DPP_TOP0_DPP_CRC_VAL_B),           \
+		SR(MPC_CRC_CTRL),                     \
+		SR(MPC_CRC_RESULT_R),                 \
+		SR(MPC_CRC_RESULT_G),                 \
+		SR(MPC_CRC_RESULT_B),                 \
+		SR(MPC_CRC_RESULT_A),                 \
+		SR(DOMAIN0_PG_CONFIG),                \
+		SR(DOMAIN1_PG_CONFIG),                \
+		SR(DOMAIN2_PG_CONFIG),                \
+		SR(DOMAIN3_PG_CONFIG),                \
+		SR(DOMAIN16_PG_CONFIG),               \
+		SR(DOMAIN17_PG_CONFIG),               \
+		SR(DOMAIN18_PG_CONFIG),               \
+		SR(DOMAIN19_PG_CONFIG), \
+		SR(DOMAIN22_PG_CONFIG),               \
+		SR(DOMAIN23_PG_CONFIG),               \
+		SR(DOMAIN24_PG_CONFIG),               \
+		SR(DOMAIN25_PG_CONFIG),               \
+		SR(DOMAIN26_PG_CONFIG),               \
+		SR(DOMAIN0_PG_STATUS),                \
+		SR(DOMAIN1_PG_STATUS),                \
+		SR(DOMAIN2_PG_STATUS),                \
+		SR(DOMAIN3_PG_STATUS),                \
+		SR(DOMAIN16_PG_STATUS),               \
+		SR(DOMAIN17_PG_STATUS),               \
+		SR(DOMAIN18_PG_STATUS),               \
+		SR(DOMAIN19_PG_STATUS),               \
+		SR(DOMAIN22_PG_STATUS),               \
+		SR(DOMAIN23_PG_STATUS),               \
+		SR(DOMAIN24_PG_STATUS),               \
+		SR(DOMAIN25_PG_STATUS),               \
+		SR(DOMAIN26_PG_STATUS),               \
+		SR(DC_IP_REQUEST_CNTL),               \
+		SR(AZALIA_AUDIO_DTO),                 \
+		SR(HPO_TOP_HW_CONTROL),               \
+		SR(AZALIA_CONTROLLER_CLOCK_GATING)
+
+static struct dce_hwseq_registers hwseq_reg;
+
+#define hwseq_reg_init() \
+	HWSEQ_DCN42_REG_LIST()
+
+#define HWSEQ_DCN42_MASK_SH_LIST(mask_sh)                                            \
+	HWSEQ_DCN_MASK_SH_LIST(mask_sh),                                                 \
+		HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \
+		HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \
+		HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                  \
+		HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                     \
+		HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                  \
+		HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                     \
+		HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                  \
+		HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                     \
+		HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                  \
+		HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                     \
+		HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+		HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+		HWS_SF(, DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN22_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN23_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN23_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN24_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN24_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN25_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN25_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN26_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh),                 \
+		HWS_SF(, DOMAIN26_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh),                    \
+		HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),               \
+		HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),               \
+		HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),               \
+		HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),               \
+		HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN22_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN23_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN24_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh),              \
+		HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh),                        \
+		HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh),                \
+		HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh),      \
+		HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh),                            \
+		HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh),           \
+		HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \
+		HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \
+		HWS_SF(, DMU_CLK_CNTL, DISPCLK_R_DMU_GATE_DIS, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DISPCLK_G_RBBMIF_GATE_DIS, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, RBBMIF_FGCG_REP_DIS, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DPREFCLK_ALLOW_DS_CLKSTOP, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DISPCLK_ALLOW_DS_CLKSTOP, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DPPCLK_ALLOW_DS_CLKSTOP, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DTBCLK_ALLOW_DS_CLKSTOP, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DCFCLK_ALLOW_DS_CLKSTOP, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, DPIACLK_ALLOW_DS_CLKSTOP, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, LONO_DISPCLK_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, LONO_SOCCLK_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DMU_CLK_CNTL, LONO_DMCUBCLK_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKA_FE_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKB_FE_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKC_FE_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKD_FE_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKE_FE_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKA_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKB_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKC_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKD_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKE_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh), \
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK0_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK1_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK2_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK3_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK4_GATE_DISABLE, mask_sh),\
+		HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK5_GATE_DISABLE, mask_sh)
+
+static const struct dce_hwseq_shift hwseq_shift = {
+	HWSEQ_DCN42_MASK_SH_LIST(__SHIFT)};
+
+static const struct dce_hwseq_mask hwseq_mask = {
+	HWSEQ_DCN42_MASK_SH_LIST(_MASK)};
+
+#define vmid_regs_init(id) \
+	DCN20_VMID_REG_LIST_RI(id)
+
+static struct dcn_vmid_registers vmid_regs[16];
+
+static const struct dcn20_vmid_shift vmid_shifts = {
+	DCN20_VMID_MASK_SH_LIST(__SHIFT)};
+
+static const struct dcn20_vmid_mask vmid_masks = {
+	DCN20_VMID_MASK_SH_LIST(_MASK)};
+
+static const struct resource_caps res_cap_dcn42 = {
+	.num_timing_generator = 4,
+	.num_opp = 4,
+	.num_dpp = 4,
+	.num_video_plane = 4,
+	.num_audio = 5,
+	.num_stream_encoder = 5,
+	.num_dig_link_enc = 5,
+	.num_usb4_dpia = 6,
+	.num_hpo_dp_stream_encoder = 4,
+	.num_hpo_dp_link_encoder = 4,
+	.num_pll = 5,
+	.num_dwb = 1,
+	.num_ddc = 5,
+	.num_vmid = 16,
+	.num_mpc_3dlut = 2,
+	.num_dsc = 4,
+	.num_rmcm = 2,
+};
+
+static const struct dc_plane_cap plane_cap = {
+	.type = DC_PLANE_TYPE_DCN_UNIVERSAL,
+	.per_pixel_alpha = true,
+
+	.pixel_format_support = {
+		.argb8888 = true,
+		.nv12 = true,
+		.fp16 = true,
+		.p010 = true,
+		.ayuv = false,
+	},
+
+	.max_upscale_factor = {.argb8888 = 16000, .nv12 = 16000, .fp16 = 16000},
+
+	// 6:1 downscaling ratio: 1000/6 = 166.666
+	.max_downscale_factor = {.argb8888 = 167, .nv12 = 167, .fp16 = 167},
+
+	.min_width = 64,
+	.min_height = 64};
+
+static const struct dc_debug_options debug_defaults_drv = {
+	.disable_dmcu = true,
+	.force_abm_enable = false,
+	.clock_trace = true,
+	.disable_pplib_clock_request = false,
+	.disable_dpp_power_gate = true,
+	.disable_hubp_power_gate = true,
+	.disable_optc_power_gate = true,
+	.pipe_split_policy = MPC_SPLIT_AVOID,
+	.force_single_disp_pipe_split = false,
+	.disable_dcc = DCC_ENABLE,
+	.vsr_support = true,
+	.performance_trace = false,
+	.max_downscale_src_width = 4096, /*up to 4K for APU*/
+	.disable_pplib_wm_range = false,
+	.scl_reset_length10 = true,
+	.sanity_checks = false,
+	.underflow_assert_delay_us = 0xFFFFFFFF,
+	.dwb_fi_phase = -1, // -1 = disable,
+	.dmub_command_table = true,
+	.pstate_enabled = true,
+	.enable_mem_low_power = {
+		.bits = {
+			.vga = false,
+			.i2c = true,
+			.dscl = true,
+			.cm = true,
+			.mpc = true,
+			.optc = true,
+			.vpg = true,
+		}},
+	.root_clock_optimization = {
+		.bits = {
+			.dpp = true,
+			.dsc = true,/*dscclk and dsc pg*/
+			.hdmistream = false,
+			.hdmichar = true,
+			.dpstream = true,
+			.symclk32_se = true,
+			.symclk32_le = true,
+			.symclk_fe = true,
+			.physymclk = false,
+			.dpiasymclk = true,
+		}
+	},
+	.seamless_boot_odm_combine = DML_FAIL_SOURCE_PIXEL_FORMAT,
+	.enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/
+	.minimum_z8_residency_time = 1, /* Always allow when other conditions are met */
+	.support_eDP1_5 = true,
+	.use_max_lb = true,
+	.force_disable_subvp = false,
+	.exit_idle_opt_for_cursor_updates = true,
+	.using_dml2 = true,
+	.using_dml21 = true,
+	.enable_single_display_2to1_odm_policy = true,
+
+	// must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions
+	.enable_double_buffered_dsc_pg_support = true,
+	.enable_dp_dig_pixel_rate_div_policy = 1,
+	.allow_sw_cursor_fallback = false,
+	.psp_disabled_wa = true,
+	.alloc_extra_way_for_cursor = true,
+	.min_prefetch_in_strobe_ns = 60000, // 60us
+	.disable_unbounded_requesting = false,
+	.dcc_meta_propagation_delay_us = 10,
+	.disable_timeout = true,
+	.min_disp_clk_khz = 50000,
+	.static_screen_wait_frames = 2,
+	.disable_z10 = false,
+	.ignore_pg = true,
+	.disable_stutter_for_wm_program = true,
+	.min_deep_sleep_dcfclk_khz = 8000,
+	.replay_skip_crtc_disabled = true,
+	.psr_skip_crtc_disable = true,
+};
+
+static const struct dc_check_config config_defaults = {
+	.enable_legacy_fast_update = false,
+};
+
+static struct dce_aux *dcn42_aux_engine_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct aux_engine_dce110 *aux_engine =
+		kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
+
+	if (!aux_engine)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT aux_engine_regs
+	aux_engine_regs_init(0),
+		aux_engine_regs_init(1),
+		aux_engine_regs_init(2),
+		aux_engine_regs_init(3),
+		aux_engine_regs_init(4);
+
+	dce110_aux_engine_construct(aux_engine, ctx, inst,
+								SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
+								&aux_engine_regs[inst],
+								&aux_mask,
+								&aux_shift,
+								ctx->dc->caps.extended_aux_timeout_support);
+
+	return &aux_engine->base;
+}
+
+#define i2c_inst_regs_init(id) \
+	I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id)
+
+static struct dce_i2c_registers i2c_hw_regs[5];
+
+static const struct dce_i2c_shift i2c_shifts = {
+	I2C_COMMON_MASK_SH_LIST_DCN35(__SHIFT)
+};
+static const struct dce_i2c_mask i2c_masks = {
+	I2C_COMMON_MASK_SH_LIST_DCN35(_MASK)
+};
+
+/* ========================================================== */
+
+/*
+ * DPIA index | Preferred Encoder     |    Host Router
+ *   0        |      C                |       0
+ *   1        |      First Available  |       0
+ *   2        |      D                |       1
+ *   3        |      First Available  |       1
+ *   4        |      E                |       2
+ *   5        |      First Available  |       2
+ */
+/* ========================================================== */
+static const enum engine_id dpia_to_preferred_enc_id_table[] = {
+		ENGINE_ID_DIGC,
+		ENGINE_ID_DIGC,
+		ENGINE_ID_DIGD,
+		ENGINE_ID_DIGD,
+		ENGINE_ID_DIGE,
+		ENGINE_ID_DIGE
+};
+
+static enum engine_id dcn42_get_preferred_eng_id_dpia(unsigned int dpia_index)
+{
+	return dpia_to_preferred_enc_id_table[dpia_index];
+}
+
+static struct dce_i2c_hw *dcn42_i2c_hw_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dce_i2c_hw *dce_i2c_hw =
+		kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL);
+
+	if (!dce_i2c_hw)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT i2c_hw_regs
+	i2c_inst_regs_init(1),
+	i2c_inst_regs_init(2),
+	i2c_inst_regs_init(3),
+	i2c_inst_regs_init(4),
+	i2c_inst_regs_init(5);
+	dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst,
+						  &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks);
+
+	return dce_i2c_hw;
+}
+
+static struct clock_source *dcn42_clock_source_create(
+	struct dc_context *ctx,
+	struct dc_bios *bios,
+	enum clock_source_id id,
+	const struct dce110_clk_src_regs *regs,
+	bool dp_clk_src)
+{
+	struct dce110_clk_src *clk_src =
+		kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL);
+
+	if (!clk_src)
+		return NULL;
+
+	if (dcn401_clk_src_construct(clk_src, ctx, bios, id,
+								 regs, &cs_shift, &cs_mask)) {
+		clk_src->base.dp_clk_src = dp_clk_src;
+		return &clk_src->base;
+	}
+
+	kfree(clk_src);
+	BREAK_TO_DEBUGGER();
+	return NULL;
+}
+
+static struct hubbub *dcn42_hubbub_create(struct dc_context *ctx)
+{
+	int i;
+
+	struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub),
+					  GFP_KERNEL);
+
+	if (!hubbub3)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT hubbub_reg
+	hubbub_reg_init();
+
+#undef REG_STRUCT
+#define REG_STRUCT vmid_regs
+	vmid_regs_init(0),
+		vmid_regs_init(1),
+		vmid_regs_init(2),
+		vmid_regs_init(3),
+		vmid_regs_init(4),
+		vmid_regs_init(5),
+		vmid_regs_init(6),
+		vmid_regs_init(7),
+		vmid_regs_init(8),
+		vmid_regs_init(9),
+		vmid_regs_init(10),
+		vmid_regs_init(11),
+		vmid_regs_init(12),
+		vmid_regs_init(13),
+		vmid_regs_init(14),
+		vmid_regs_init(15);
+
+	hubbub42_construct(hubbub3, ctx,
+					   &hubbub_reg,
+					   &hubbub_shift,
+					   &hubbub_mask,
+					   DCN42_DEFAULT_DET_SIZE,
+					   8,
+					   DCN42_CRB_SIZE_KB);
+	for (i = 0; i < res_cap_dcn42.num_vmid; i++) {
+		struct dcn20_vmid *vmid = &hubbub3->vmid[i];
+
+		vmid->ctx = ctx;
+
+		vmid->regs = &vmid_regs[i];
+		vmid->shifts = &vmid_shifts;
+		vmid->masks = &vmid_masks;
+	}
+
+	return &hubbub3->base;
+}
+
+static struct hubp *dcn42_hubp_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dcn20_hubp *hubp2 =
+		kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL);
+
+	if (!hubp2)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT hubp_regs
+	hubp_regs_init(0),
+		hubp_regs_init(1),
+		hubp_regs_init(2),
+		hubp_regs_init(3);
+
+	if (hubp42_construct(hubp2, ctx, inst,
+						 &hubp_regs[inst], &hubp_shift, &hubp_mask))
+		return &hubp2->base;
+
+	BREAK_TO_DEBUGGER();
+	kfree(hubp2);
+	return NULL;
+}
+static const struct dc_panel_config dcn42_panel_config_defaults = {
+	.psr = {
+		.disable_psr = false,
+		.disallow_psrsu = false,
+		.disallow_replay = false,
+	},
+	.ilr = {
+		.optimize_edp_link_rate = true,
+	},
+};
+
+static void dcn42_dpp_destroy(struct dpp **dpp)
+{
+	kfree(TO_DCN42_DPP(*dpp));
+	*dpp = NULL;
+}
+
+static struct dpp *dcn42_dpp_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dcn42_dpp *dpp42 =
+		kzalloc(sizeof(struct dcn42_dpp), GFP_KERNEL);
+
+	if (!dpp42)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT dpp_regs
+	dpp_regs_init(0),
+		dpp_regs_init(1),
+		dpp_regs_init(2),
+		dpp_regs_init(3);
+
+	if (dpp42_construct(dpp42, ctx, inst,
+						&dpp_regs[inst], &tf_shift, &tf_mask))
+		return &dpp42->base;
+
+	BREAK_TO_DEBUGGER();
+	kfree(dpp42);
+	return NULL;
+}
+
+static struct mpc *dcn42_mpc_create(
+	struct dc_context *ctx,
+	int num_mpcc,
+	int num_rmu)
+{
+	struct dcn42_mpc *mpc401 = kzalloc(sizeof(struct dcn42_mpc),
+										GFP_KERNEL);
+
+	if (!mpc401)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT mpc_regs
+	dcn_mpc_regs_init();
+
+	dcn42_mpc_construct(mpc401, ctx,
+						 &mpc_regs,
+						 &mpc_shift,
+						 &mpc_mask,
+						 num_mpcc,
+						 num_rmu);
+
+	return &mpc401->base;
+}
+
+static struct output_pixel_processor *dcn42_opp_create(
+	struct dc_context *ctx, uint32_t inst)
+{
+	struct dcn20_opp *opp4 =
+		kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL);
+
+	if (!opp4) {
+		BREAK_TO_DEBUGGER();
+		return NULL;
+	}
+
+#undef REG_STRUCT
+#define REG_STRUCT opp_regs
+	opp_regs_init(0),
+		opp_regs_init(1),
+		opp_regs_init(2),
+		opp_regs_init(3);
+	dcn20_opp_construct(opp4, ctx, inst,
+						&opp_regs[inst], &opp_shift, &opp_mask);
+	return &opp4->base;
+}
+
+static struct timing_generator *dcn42_timing_generator_create(
+	struct dc_context *ctx,
+	uint32_t instance)
+{
+	struct optc *tgn10 =
+		kzalloc(sizeof(struct optc), GFP_KERNEL);
+
+	if (!tgn10)
+		return NULL;
+#undef REG_STRUCT
+#define REG_STRUCT optc_regs
+	optc_regs_init(0),
+		optc_regs_init(1),
+		optc_regs_init(2),
+		optc_regs_init(3);
+	tgn10->base.inst = instance;
+	tgn10->base.ctx = ctx;
+
+	tgn10->tg_regs = &optc_regs[instance];
+	tgn10->tg_shift = &optc_shift;
+	tgn10->tg_mask = &optc_mask;
+
+	dcn42_timing_generator_init(tgn10);
+
+	return &tgn10->base;
+}
+
+static const struct encoder_feature_support link_enc_feature = {
+	.max_hdmi_deep_color = COLOR_DEPTH_121212,
+	.max_hdmi_pixel_clock = 600000,
+	.hdmi_ycbcr420_supported = true,
+	.dp_ycbcr420_supported = true,
+	.fec_supported = true,
+	.flags.bits.IS_HBR2_CAPABLE = true,
+	.flags.bits.IS_HBR3_CAPABLE = true,
+	.flags.bits.IS_TPS3_CAPABLE = true,
+	.flags.bits.IS_TPS4_CAPABLE = true};
+
+static struct link_encoder *dcn42_link_encoder_create(
+	struct dc_context *ctx,
+	const struct encoder_init_data *enc_init_data)
+{
+	struct dcn20_link_encoder *enc20 =
+		kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);
+
+	if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs))
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT link_enc_aux_regs
+	aux_regs_init(0),
+		aux_regs_init(1),
+		aux_regs_init(2),
+		aux_regs_init(3),
+		aux_regs_init(4);
+#undef REG_STRUCT
+#define REG_STRUCT link_enc_hpd_regs
+	hpd_regs_init(0),
+		hpd_regs_init(1),
+		hpd_regs_init(2),
+		hpd_regs_init(3),
+		hpd_regs_init(4);
+#undef REG_STRUCT
+#define REG_STRUCT link_enc_regs
+	link_regs_init(0, A),
+		link_regs_init(1, B),
+		link_regs_init(2, C),
+		link_regs_init(3, D),
+		link_regs_init(4, E);
+
+	dcn42_link_encoder_construct(enc20,
+								  enc_init_data,
+								  &link_enc_feature,
+								  &link_enc_regs[enc_init_data->transmitter],
+								  &link_enc_aux_regs[enc_init_data->channel - 1],
+								  &link_enc_hpd_regs[enc_init_data->hpd_source],
+								  &le_shift,
+								  &le_mask);
+	return &enc20->enc10.base;
+}
+
+static void read_dce_straps(
+	struct dc_context *ctx,
+	struct resource_straps *straps)
+{
+	generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX),
+		FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio);
+}
+
+static struct audio *dcn42_create_audio(
+	struct dc_context *ctx, unsigned int inst)
+{
+
+#undef REG_STRUCT
+#define REG_STRUCT audio_regs
+	audio_regs_init(0),
+		audio_regs_init(1),
+		audio_regs_init(2),
+		audio_regs_init(3),
+		audio_regs_init(4);
+
+	return dce_audio_create(ctx, inst,
+							&audio_regs[inst], &audio_shift, &audio_mask);
+}
+
+static struct vpg *dcn42_vpg_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dcn31_vpg *vpg4 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL);
+
+	if (!vpg4)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT vpg_regs
+	vpg_regs_init(0),
+		vpg_regs_init(1),
+		vpg_regs_init(2),
+		vpg_regs_init(3),
+		vpg_regs_init(4),
+		vpg_regs_init(5),
+		vpg_regs_init(6),
+		vpg_regs_init(7),
+		vpg_regs_init(8),
+		vpg_regs_init(9);
+	vpg31_construct(vpg4, ctx, inst,
+					&vpg_regs[inst],
+					&vpg_shift,
+					&vpg_mask);
+
+	return &vpg4->base;
+}
+
+static struct apg *dcn42_apg_create(
+	struct dc_context *ctx,
+	uint32_t inst)
+{
+	struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL);
+
+	if (!apg31)
+		return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT apg_regs
+	apg_regs_init(0),
+		apg_regs_init(1),
+		apg_regs_init(2),
+		apg_regs_init(3),
+		apg_regs_init(4),
+		apg_regs_init(5),
+		apg_regs_init(6),
+		apg_regs_init(7),
+		apg_regs_init(8),
+		apg_regs_init(9);
+
+	apg31_construct(apg31, ctx, inst,
+					&apg_regs[inst],
+					&apg_shift,
+					&apg_mask);
+
+	return &apg31->base;
+}
+
+static struct stream_encoder *dcn42_stream_encoder_create(
+	enum engine_id eng_id,
+	struct dc_context *ctx)
+{
+	struct dcn10_stream_encoder *enc1;
+	struct vpg *vpg;
+	struct apg *apg;
+
+	uint32_t vpg_inst;
+	uint32_t apg_inst;
+
+	/* Mapping of VPG, DME register blocks to DIO block instance */
+	if (eng_id <= ENGINE_ID_DIGE) {
+		vpg_inst = eng_id;
+		apg_inst = eng_id;
+	} else
+		return NULL;
+
+	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
+	vpg = dcn42_vpg_create(ctx, vpg_inst);
+	apg = dcn42_apg_create(ctx, apg_inst);
+
+	if (!enc1 || !vpg || !apg) {
+		kfree(enc1);
+		kfree(vpg);
+		kfree(apg);
+		return NULL;
+	}
+#undef REG_STRUCT
+#define REG_STRUCT stream_enc_regs
+	stream_enc_regs_init(0),
+		stream_enc_regs_init(1),
+		stream_enc_regs_init(2),
+		stream_enc_regs_init(3),
+		stream_enc_regs_init(4);
+
+	dcn42_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,
+									eng_id, vpg, apg,
+									&stream_enc_regs[eng_id],
+									&se_shift, &se_mask);
+	return &enc1->base;
+}
+
+static struct hpo_dp_stream_encoder *dcn42_hpo_dp_stream_encoder_create(
+	enum engine_id eng_id,
+	struct dc_context *ctx)
+{
+	struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31;
+	struct vpg *vpg;
+	struct apg *apg;
+	uint32_t hpo_dp_inst;
+	uint32_t vpg_inst;
+	uint32_t apg_inst;
+
+	ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3));
+	hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0;
+
+	/* Mapping of VPG register blocks to HPO DP block instance:
+	 * VPG[5] -> HPO_DP[0]
+	 * VPG[6] -> HPO_DP[1]
+	 * VPG[7] -> HPO_DP[2]
+	 * VPG[8] -> HPO_DP[3]
+	 */
+	vpg_inst = hpo_dp_inst + 5;
+
+	/* Mapping of APG register blocks to HPO DP block instance:
+	 * APG[6] -> HPO_DP[0]
+	 * APG[7] -> HPO_DP[1]
+	 * APG[8] -> HPO_DP[2]
+	 * APG[9] -> HPO_DP[3]
+	 */
+	apg_inst = hpo_dp_inst + 5;
+
+	/* allocate HPO stream encoder and create VPG sub-block */
+	hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL);
+	vpg = dcn42_vpg_create(ctx, vpg_inst);
+	apg = dcn42_apg_create(ctx, apg_inst);
+
+	if (!hpo_dp_enc31 || !vpg || !apg) {
+		kfree(hpo_dp_enc31);
+		kfree(vpg);
+		kfree(apg);
+		return NULL;
+	}
+
+#undef REG_STRUCT
+#define REG_STRUCT hpo_dp_stream_enc_regs
+	hpo_dp_stream_encoder_reg_init(0),
+		hpo_dp_stream_encoder_reg_init(1),
+		hpo_dp_stream_encoder_reg_init(2),
+		hpo_dp_stream_encoder_reg_init(3);
+
+	dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios,
+				hpo_dp_inst, eng_id, vpg, apg,
+				&hpo_dp_stream_enc_regs[hpo_dp_inst],
+				&hpo_dp_se_shift, &hpo_dp_se_mask);
+
+	return &hpo_dp_enc31->base;
+}
+
+static struct hpo_dp_link_encoder *dcn42_hpo_dp_link_encoder_create(
+	uint8_t inst,
+	struct dc_context *ctx)
+{
+	struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31;
+
+	/* allocate HPO link encoder */
+	hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL);
+	if (!hpo_dp_enc31)
+		return NULL; /* out of memory */
+
+#undef REG_STRUCT
+#define REG_STRUCT hpo_dp_link_enc_regs
+	hpo_dp_link_encoder_reg_init(0),
+	hpo_dp_link_encoder_reg_init(1),
+	hpo_dp_link_encoder_reg_init(2),
+	hpo_dp_link_encoder_reg_init(3);
+
+	hpo_dp_link_encoder42_construct(hpo_dp_enc31, ctx, inst,
+				&hpo_dp_link_enc_regs[inst],
+				&hpo_dp_le_shift, &hpo_dp_le_mask);
+
+	return &hpo_dp_enc31->base;
+}
+
+static struct dce_hwseq *dcn42_hwseq_create(
+	struct dc_context *ctx)
+{
+	struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL);
+
+#undef REG_STRUCT
+#define REG_STRUCT hwseq_reg
+	hwseq_reg_init();
+
+	if (hws) {
+		hws->ctx = ctx;
+		hws->regs = &hwseq_reg;
+		hws->shifts = &hwseq_shift;
+		hws->masks = &hwseq_mask;
+	}
+
+	return hws;
+}
+
+static const struct resource_create_funcs res_create_funcs = {
+	.read_dce_straps = read_dce_straps,
+	.create_audio = dcn42_create_audio,
+	.create_stream_encoder = dcn42_stream_encoder_create,
+	.create_hpo_dp_stream_encoder = dcn42_hpo_dp_stream_encoder_create,
+	.create_hpo_dp_link_encoder = dcn42_hpo_dp_link_encoder_create,
+	.create_hwseq = dcn42_hwseq_create,
+};
+
+static void dcn42_dsc_destroy(struct display_stream_compressor **dsc)
+{
+	kfree(container_of(*dsc, struct dcn401_dsc, base));
+	*dsc = NULL;
+}
+
+static void dcn42_resource_destruct(struct dcn42_resource_pool *pool)
+{
+	unsigned int i;
+
+	for (i = 0; i < pool->base.stream_enc_count; i++) {
+		if (pool->base.stream_enc[i] != NULL) {
+			if (pool->base.stream_enc[i]->vpg != NULL) {
+				kfree(DCN31_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg));
+				pool->base.stream_enc[i]->vpg = NULL;
+			}
+			if (pool->base.stream_enc[i]->apg != NULL) {
+				kfree(DCN31_APG_FROM_APG(pool->base.stream_enc[i]->apg));
+				pool->base.stream_enc[i]->apg = NULL;
+			}
+			kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i]));
+			pool->base.stream_enc[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) {
+		if (pool->base.hpo_dp_stream_enc[i] != NULL) {
+			if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) {
+				kfree(DCN31_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg));
+				pool->base.hpo_dp_stream_enc[i]->vpg = NULL;
+			}
+			if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) {
+				kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg));
+				pool->base.hpo_dp_stream_enc[i]->apg = NULL;
+			}
+			kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i]));
+			pool->base.hpo_dp_stream_enc[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) {
+		if (pool->base.hpo_dp_link_enc[i] != NULL) {
+			kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i]));
+			pool->base.hpo_dp_link_enc[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
+		if (pool->base.dscs[i] != NULL)
+			dcn42_dsc_destroy(&pool->base.dscs[i]);
+	}
+
+	if (pool->base.mpc != NULL) {
+		kfree(TO_DCN20_MPC(pool->base.mpc));
+		pool->base.mpc = NULL;
+	}
+	if (pool->base.hubbub != NULL) {
+		kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
+		pool->base.hubbub = NULL;
+	}
+	for (i = 0; i < pool->base.pipe_count; i++) {
+		if (pool->base.dpps[i] != NULL)
+			dcn42_dpp_destroy(&pool->base.dpps[i]);
+
+		if (pool->base.ipps[i] != NULL)
+			pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]);
+
+		if (pool->base.hubps[i] != NULL) {
+			kfree(TO_DCN20_HUBP(pool->base.hubps[i]));
+			pool->base.hubps[i] = NULL;
+		}
+
+		if (pool->base.irqs != NULL)
+			dal_irq_service_destroy(&pool->base.irqs);
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
+		if (pool->base.engines[i] != NULL)
+			dce110_engine_destroy(&pool->base.engines[i]);
+		if (pool->base.hw_i2cs[i] != NULL) {
+			kfree(pool->base.hw_i2cs[i]);
+			pool->base.hw_i2cs[i] = NULL;
+		}
+		if (pool->base.sw_i2cs[i] != NULL) {
+			kfree(pool->base.sw_i2cs[i]);
+			pool->base.sw_i2cs[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_opp; i++) {
+		if (pool->base.opps[i] != NULL)
+			pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]);
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+		if (pool->base.timing_generators[i] != NULL) {
+			kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i]));
+			pool->base.timing_generators[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_dwb; i++) {
+		if (pool->base.dwbc[i] != NULL) {
+			kfree(TO_DCN30_DWBC(pool->base.dwbc[i]));
+			pool->base.dwbc[i] = NULL;
+		}
+		if (pool->base.mcif_wb[i] != NULL) {
+			kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i]));
+			pool->base.mcif_wb[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.audio_count; i++) {
+		if (pool->base.audios[i])
+			dce_aud_destroy(&pool->base.audios[i]);
+	}
+
+	for (i = 0; i < pool->base.clk_src_count; i++) {
+		if (pool->base.clock_sources[i] != NULL) {
+			dcn20_clock_source_destroy(&pool->base.clock_sources[i]);
+			pool->base.clock_sources[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) {
+		if (pool->base.mpc_lut[i] != NULL) {
+			dc_3dlut_func_release(pool->base.mpc_lut[i]);
+			pool->base.mpc_lut[i] = NULL;
+		}
+		if (pool->base.mpc_shaper[i] != NULL) {
+			dc_transfer_func_release(pool->base.mpc_shaper[i]);
+			pool->base.mpc_shaper[i] = NULL;
+		}
+	}
+
+	if (pool->base.dp_clock_source != NULL) {
+		dcn20_clock_source_destroy(&pool->base.dp_clock_source);
+		pool->base.dp_clock_source = NULL;
+	}
+
+	for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+		if (pool->base.multiple_abms[i] != NULL)
+			dce_abm_destroy(&pool->base.multiple_abms[i]);
+	}
+
+	if (pool->base.psr != NULL)
+		dmub_psr_destroy(&pool->base.psr);
+
+	if (pool->base.pg_cntl != NULL)
+		dcn_pg_cntl_destroy(&pool->base.pg_cntl);
+	if (pool->base.dccg != NULL)
+		dcn_dccg_destroy(&pool->base.dccg);
+
+	if (pool->base.oem_device != NULL) {
+		struct dc *dc = pool->base.oem_device->ctx->dc;
+
+		dc->link_srv->destroy_ddc_service(&pool->base.oem_device);
+	}
+}
+
+static void dcn42_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx)
+{
+	const struct dc_stream_state *stream = pipe_ctx->stream;
+	struct dc_link *link = stream->link;
+	struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
+	struct pixel_clk_params *pixel_clk_params = &pipe_ctx->stream_res.pix_clk_params;
+
+	pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz;
+
+	if (pipe_ctx->dsc_padding_params.dsc_hactive_padding != 0)
+		pixel_clk_params->requested_pix_clk_100hz = pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz;
+
+	if (!pipe_ctx->stream->ctx->dc->config.unify_link_enc_assignment)
+		link_enc = link_enc_cfg_get_link_enc(link);
+	if (link_enc)
+		pixel_clk_params->encoder_object_id = link_enc->id;
+
+	pixel_clk_params->signal_type = pipe_ctx->stream->signal;
+	pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1;
+	/* TODO: un-hardcode*/
+
+	/* TODO - DP2.0 HW: calculate requested_sym_clk for UHBR rates */
+
+	pixel_clk_params->requested_sym_clk = LINK_RATE_LOW *
+		LINK_RATE_REF_FREQ_IN_KHZ;
+	pixel_clk_params->flags.ENABLE_SS = 0;
+	pixel_clk_params->color_depth =
+		stream->timing.display_color_depth;
+	pixel_clk_params->flags.DISPLAY_BLANKED = 1;
+	pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding;
+
+	if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
+		pixel_clk_params->color_depth = COLOR_DEPTH_888;
+
+	if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
+		pixel_clk_params->requested_pix_clk_100hz *= 2;
+	if (dc_is_tmds_signal(stream->signal) &&
+			stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
+		pixel_clk_params->requested_pix_clk_100hz /= 2;
+
+	pipe_ctx->clock_source->funcs->get_pix_clk_dividers(
+			pipe_ctx->clock_source,
+			&pipe_ctx->stream_res.pix_clk_params,
+			&pipe_ctx->pll_settings);
+
+	pixel_clk_params->dio_se_pix_per_cycle = 1;
+	if (dc_is_tmds_signal(stream->signal) &&
+			stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
+		pixel_clk_params->dio_se_pix_per_cycle = 2;
+	} else if (dc_is_dp_signal(stream->signal)) {
+		/* round up to nearest power of 2, or max at 8 pixels per cycle */
+		if (pixel_clk_params->requested_pix_clk_100hz > 4 * stream->ctx->dc->clk_mgr->dprefclk_khz * 10) {
+			pixel_clk_params->dio_se_pix_per_cycle = 8;
+		} else if (pixel_clk_params->requested_pix_clk_100hz > 2 * stream->ctx->dc->clk_mgr->dprefclk_khz * 10) {
+			pixel_clk_params->dio_se_pix_per_cycle = 4;
+		} else if (pixel_clk_params->requested_pix_clk_100hz > stream->ctx->dc->clk_mgr->dprefclk_khz * 10) {
+			pixel_clk_params->dio_se_pix_per_cycle = 2;
+		} else {
+			pixel_clk_params->dio_se_pix_per_cycle = 1;
+		}
+	}
+}
+
+static bool dcn42_dwbc_create(struct dc_context *ctx, struct resource_pool *pool)
+{
+	int i;
+	uint32_t dwb_count = pool->res_cap->num_dwb;
+
+	for (i = 0; i < dwb_count; i++) {
+		struct dcn30_dwbc *dwbc42 = kzalloc(sizeof(struct dcn30_dwbc),
+											GFP_KERNEL);
+
+		if (!dwbc42) {
+			dm_error("DC: failed to create dwbc42!\n");
+			return false;
+		}
+
+#undef REG_STRUCT
+#define REG_STRUCT dwbc401_regs
+		dwbc_regs_dcn401_init(0);
+
+		dcn30_dwbc_construct(dwbc42, ctx,
+				&dwbc401_regs[i],
+				&dwbc401_shift,
+				&dwbc401_mask,
+				i);
+
+		pool->dwbc[i] = &dwbc42->base;
+	}
+	return true;
+}
+
+static void dcn42_mmhubbub_init(struct dcn30_mmhubbub *mcif_wb30,
+								struct dc_context *ctx)
+{
+	dcn42_mmhubbub_set_fgcg(
+		mcif_wb30,
+		ctx->dc->debug.enable_fine_grain_clock_gating.bits.mmhubbub);
+}
+
+static bool dcn42_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool)
+{
+	int i;
+	uint32_t pipe_count = pool->res_cap->num_dwb;
+
+	for (i = 0; i < pipe_count; i++) {
+		struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub),
+												   GFP_KERNEL);
+
+		if (!mcif_wb30) {
+			dm_error("DC: failed to create mcif_wb30!\n");
+			return false;
+		}
+
+#undef REG_STRUCT
+#define REG_STRUCT mcif_wb35_regs
+		mcif_wb_regs_dcn3_init(0);
+
+		dcn35_mmhubbub_construct(mcif_wb30, ctx,
+					&mcif_wb35_regs[i],
+					&mcif_wb35_shift,
+					&mcif_wb35_mask,
+					i);
+
+		dcn42_mmhubbub_init(mcif_wb30, ctx);
+
+		pool->mcif_wb[i] = &mcif_wb30->base;
+	}
+	return true;
+}
+
+static struct display_stream_compressor *dcn42_dsc_create(
+	struct dc_context *ctx, uint32_t inst)
+{
+	struct dcn401_dsc *dsc =
+		kzalloc(sizeof(struct dcn401_dsc), GFP_KERNEL);
+
+	if (!dsc) {
+		BREAK_TO_DEBUGGER();
+		return NULL;
+	}
+
+#undef REG_STRUCT
+#define REG_STRUCT dsc_regs
+	dsc_regs_init(0),
+		dsc_regs_init(1),
+		dsc_regs_init(2),
+		dsc_regs_init(3);
+
+	dsc401_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask);
+	dsc401_set_fgcg(dsc, ctx->dc->debug.enable_fine_grain_clock_gating.bits.dsc);
+
+	dsc->max_image_width = 5760;
+
+	return &dsc->base;
+}
+
+static void dcn42_destroy_resource_pool(struct resource_pool **pool)
+{
+	struct dcn42_resource_pool *dcn42_pool = TO_DCN42_RES_POOL(*pool);
+
+	dcn42_resource_destruct(dcn42_pool);
+	kfree(dcn42_pool);
+	*pool = NULL;
+}
+
+static struct dc_cap_funcs cap_funcs = {
+	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap};
+
+static void dcn42_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	dc_assert_fp_enabled();
+
+	if (dc->current_state && dc->current_state->bw_ctx.dml2)
+		dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2);
+}
+
+static void dcn42_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	DC_FP_START();
+	dcn42_update_bw_bounding_box_fpu(dc, bw_params);
+	DC_FP_END();
+}
+enum dc_status dcn42_validate_bandwidth(struct dc *dc,
+							  struct dc_state *context,
+							  enum dc_validate_mode validate_mode)
+{
+	bool out = false;
+
+	DC_FP_START();
+
+	out = dml2_validate(dc, context, context->bw_ctx.dml2,
+						validate_mode);
+
+	if (validate_mode == DC_VALIDATE_MODE_AND_PROGRAMMING) {
+		/*not required for mode enumeration*/
+		dcn42_decide_zstate_support(dc, context);
+	}
+
+	DC_FP_END();
+
+	return out ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
+}
+void dcn42_prepare_mcache_programming(struct dc *dc,
+									  struct dc_state *context)
+{
+	if (dc->debug.using_dml21) {
+		DC_FP_START();
+		dml2_prepare_mcache_programming(dc, context,
+			context->power_source == DC_POWER_SOURCE_DC ?
+			context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2);
+		DC_FP_END();
+	}
+}
+/* Create a minimal link encoder object not associated with a particular
+ * physical connector.
+ * resource_funcs.link_enc_create_minimal
+ */
+static struct link_encoder *dcn42_link_enc_create_minimal(
+		struct dc_context *ctx, enum engine_id eng_id)
+{
+	struct dcn20_link_encoder *enc20;
+
+	if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc)
+		return NULL;
+
+	enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);
+	if (!enc20)
+		return NULL;
+
+	dcn31_link_encoder_construct_minimal(
+			enc20,
+			ctx,
+			&link_enc_feature,
+			&link_enc_regs[eng_id - ENGINE_ID_DIGA],
+			eng_id);
+
+	return &enc20->enc10.base;
+}
+static void dcn42_get_panel_config_defaults(struct dc_panel_config *panel_config)
+{
+	*panel_config = dcn42_panel_config_defaults;
+}
+static unsigned int dcn42_get_max_hw_cursor_size(const struct dc *dc,
+			struct dc_state *state,
+			const struct dc_stream_state *stream)
+{
+	return dc->caps.max_cursor_size;
+}
+static struct resource_funcs dcn42_res_pool_funcs = {
+	.destroy = dcn42_destroy_resource_pool,
+	.link_enc_create = dcn42_link_encoder_create,
+	.link_enc_create_minimal = dcn42_link_enc_create_minimal,
+	.link_encs_assign = link_enc_cfg_link_encs_assign,
+	.link_enc_unassign = link_enc_cfg_link_enc_unassign,
+	.panel_cntl_create = dcn32_panel_cntl_create,
+	.validate_bandwidth = dcn42_validate_bandwidth,
+	.calculate_wm_and_dlg = NULL,
+	.populate_dml_pipes = NULL,
+	.acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe,
+	.acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head,
+	.release_pipe = dcn20_release_pipe,
+	.add_stream_to_ctx = dcn30_add_stream_to_ctx,
+	.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
+	.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
+	.populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context,
+	.set_mcif_arb_params = dcn30_set_mcif_arb_params,
+	.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
+	.acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut,
+	.release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut,
+	.update_bw_bounding_box = dcn42_update_bw_bounding_box,
+	.patch_unknown_plane_state = dcn35_patch_unknown_plane_state,
+	.get_panel_config_defaults = dcn42_get_panel_config_defaults,
+	.get_preferred_eng_id_dpia = dcn42_get_preferred_eng_id_dpia,
+	.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
+	.add_phantom_pipes = dcn32_add_phantom_pipes,
+	.calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes,
+	.prepare_mcache_programming = dcn42_prepare_mcache_programming,
+	.build_pipe_pix_clk_params = dcn42_build_pipe_pix_clk_params,
+	.get_power_profile = dcn401_get_power_profile,
+	.get_vstartup_for_pipe = dcn401_get_vstartup_for_pipe,
+	.get_max_hw_cursor_size = dcn42_get_max_hw_cursor_size,
+	.get_default_tiling_info = dcn10_get_default_tiling_info
+};
+
+static uint32_t read_pipe_fuses(struct dc_context *ctx)
+{
+	uint32_t value = REG_READ(CC_DC_PIPE_DIS);
+
+	if (value == 0 && ctx->dce_environment == DCE_ENV_DIAG)
+		value = 0xF;
+	/* DCN401 support max 4 pipes */
+	value = value & 0xf;
+	return value;
+}
+
+static bool dcn42_resource_construct(
+	uint8_t num_virtual_links,
+	struct dc *dc,
+	struct dcn42_resource_pool *pool)
+{
+	int i, j;
+	struct dc_context *ctx = dc->ctx;
+	struct irq_service_init_data init_data;
+	uint32_t pipe_fuses;
+	uint32_t num_pipes;
+
+#undef REG_STRUCT
+#define REG_STRUCT bios_regs
+	bios_regs_init();
+
+#undef REG_STRUCT
+#define REG_STRUCT clk_src_regs
+	clk_src_regs_init(0, A),
+	clk_src_regs_init(1, B),
+	clk_src_regs_init(2, C),
+	clk_src_regs_init(3, D),
+	clk_src_regs_init(4, E);
+
+#undef REG_STRUCT
+#define REG_STRUCT abm_regs
+	abm_regs_init(0),
+		abm_regs_init(1),
+		abm_regs_init(2),
+		abm_regs_init(3);
+#undef REG_STRUCT
+#define REG_STRUCT dccg_regs
+	dccg_regs_init();
+
+	ctx->dc_bios->regs = &bios_regs;
+
+	pool->base.res_cap = &res_cap_dcn42;
+
+	/* max number of pipes for ASIC before checking for pipe fuses */
+	num_pipes = pool->base.res_cap->num_dpp;
+	pipe_fuses = read_pipe_fuses(ctx);
+
+	for (i = 0; i < pool->base.res_cap->num_dpp; i++)
+		if (pipe_fuses & 1 << i)
+			num_pipes--;
+
+	if (pipe_fuses & 1)
+		ASSERT(0); // Unexpected - Pipe 0 should always be fully functional!
+
+	if (pipe_fuses & CC_DC_PIPE_DIS__DC_FULL_DIS_MASK)
+		ASSERT(0); // Entire DCN is harvested!
+
+	pool->base.funcs = &dcn42_res_pool_funcs;
+
+	/*************************************************
+	 *  Resource + asic cap harcoding                *
+	 *************************************************/
+	pool->base.underlay_pipe_index = (unsigned int)NO_UNDERLAY_PIPE;
+	pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator;
+	pool->base.pipe_count = num_pipes;
+	pool->base.mpcc_count = num_pipes;
+	dc->caps.ips_v2_support = true;
+	dc->caps.max_downscale_ratio = 600;
+	dc->caps.i2c_speed_in_khz = 100;
+	dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/
+	/* TODO: Bring max cursor size back to 256 after subvp cursor corruption is fixed*/
+	dc->caps.max_cursor_size = 64;
+	dc->caps.max_buffered_cursor_size = 64;
+	dc->caps.cursor_not_scaled = true;
+	dc->caps.min_horizontal_blanking_period = 80;
+	dc->caps.dmdata_alloc_size = 2048;
+	dc->caps.mall_size_per_mem_channel = 4;
+	/* total size = mall per channel * num channels * 1024 * 1024 */
+	dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel *
+		dc->ctx->dc_bios->vram_info.num_chans * 1048576;
+	dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
+	dc->caps.cache_line_size = 64;
+	dc->caps.cache_num_ways = 16;
+
+	/* Calculate the available MALL space */
+	dc->caps.max_cab_allocation_bytes =
+		dcn32_calc_num_avail_chans_for_mall(dc, dc->ctx->dc_bios->vram_info.num_chans) *
+				dc->caps.mall_size_per_mem_channel * 1024 * 1024;
+	dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
+
+	dc->caps.subvp_fw_processing_delay_us = 15;
+	dc->caps.subvp_drr_max_vblank_margin_us = 40;
+	dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
+	dc->caps.subvp_swath_height_margin_lines = 16;
+	dc->caps.subvp_pstate_allow_width_us = 20;
+	dc->caps.subvp_vertical_int_margin_us = 30;
+	dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin
+
+	dc->caps.max_slave_planes = 2;
+	dc->caps.max_slave_yuv_planes = 2;
+	dc->caps.max_slave_rgb_planes = 2;
+	dc->caps.post_blend_color_processing = true;
+	dc->caps.force_dp_tps4_for_cp2520 = true;
+	if (dc->config.forceHBR2CP2520)
+		dc->caps.force_dp_tps4_for_cp2520 = false;
+	dc->caps.dp_hdmi21_pcon_support = true;
+	dc->caps.dp_hpo = true;
+	dc->caps.edp_dsc_support = true;
+	dc->caps.extended_aux_timeout_support = true;
+	dc->caps.dmcub_support = true;
+	dc->caps.is_apu = true;
+	dc->caps.seamless_odm = true;
+	dc->caps.zstate_support = true;
+	dc->caps.ips_support = true;
+	dc->caps.max_v_total = (1 << 15) - 1;
+	dc->caps.vtotal_limited_by_fp2 = true;
+
+	dc->caps.seamless_odm = true;
+	dc->caps.zstate_support = true;
+	dc->caps.ips_support = true;
+	dc->caps.max_v_total = (1 << 15) - 1;
+	dc->caps.vtotal_limited_by_fp2 = true;
+
+	/* Color pipeline capabilities */
+	dc->caps.color.dpp.dcn_arch = 1;
+	dc->caps.color.dpp.input_lut_shared = 0;
+	dc->caps.color.dpp.icsc = 1;
+	dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr
+	dc->caps.color.dpp.dgam_rom_caps.srgb = 1;
+	dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1;
+	dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1;
+	dc->caps.color.dpp.dgam_rom_caps.pq = 1;
+	dc->caps.color.dpp.dgam_rom_caps.hlg = 1;
+	dc->caps.color.dpp.post_csc = 1;
+	dc->caps.color.dpp.gamma_corr = 1;
+	dc->caps.color.dpp.dgam_rom_for_yuv = 0;
+
+	dc->caps.color.dpp.hw_3d_lut = 0;
+	dc->caps.color.dpp.ogam_ram = 0;
+	// no OGAM ROM on DCN2 and later ASICs
+	dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
+	dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
+	dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0;
+	dc->caps.color.dpp.ogam_rom_caps.pq = 0;
+	dc->caps.color.dpp.ogam_rom_caps.hlg = 0;
+	dc->caps.color.dpp.ocsc = 0;
+
+	dc->caps.color.mpc.gamut_remap = 1;
+	//configurable to be before or after BLND in MPCC
+	dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut;
+	dc->caps.color.mpc.num_rmcm_3dluts = 2;
+	dc->caps.color.mpc.ogam_ram = 1;
+	dc->caps.color.mpc.ogam_rom_caps.srgb = 0;
+	dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0;
+	dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0;
+	dc->caps.color.mpc.ogam_rom_caps.pq = 0;
+	dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
+	dc->caps.color.mpc.ocsc = 1;
+	dc->caps.color.mpc.preblend = true;
+	dc->caps.color.mpc.mcm_3d_lut_caps.dma_3d_lut = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.lut_dim_caps.dim_9 = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.lut_dim_caps.dim_17 = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_layout_support.linear_1d = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_layout_support.swizzle_3d_bgr = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_layout_support.swizzle_3d_rgb = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_format_support.unorm_12msb = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_format_support.unorm_12lsb = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_format_support.float_fp1_5_10 = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_pixel_order_support.order_rgba = 1;
+	dc->caps.color.mpc.mcm_3d_lut_caps.mem_pixel_order_support.order_bgra = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.dma_3d_lut = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_17 = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_33 = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_layout_support.linear_1d = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_layout_support.swizzle_3d_bgr = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_layout_support.swizzle_3d_rgb = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_format_support.unorm_12msb = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_format_support.unorm_12lsb = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_format_support.float_fp1_5_10 = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_pixel_order_support.order_rgba = 1;
+	dc->caps.color.mpc.rmcm_3d_lut_caps.mem_pixel_order_support.order_bgra = 1;
+
+	dc->caps.num_of_host_routers = 3;
+	dc->caps.num_of_dpias_per_host_router = 2;
+
+	/* max_disp_clock_khz_at_vmin is slightly lower than the STA value in order
+	 * to provide some margin.
+	 * It's expected for furture ASIC to have equal or higher value, in order to
+	 * have determinstic power improvement from generate to genration.
+	 * (i.e., we should not expect new ASIC generation with lower vmin rate)
+	 */
+	dc->caps.max_disp_clock_khz_at_vmin = 650000;
+	dc->config.use_spl = true;
+	dc->config.prefer_easf = true;
+
+	dc->config.dcn_sharpness_range.sdr_rgb_min = 0;
+	dc->config.dcn_sharpness_range.sdr_rgb_max = 1750;
+	dc->config.dcn_sharpness_range.sdr_rgb_mid = 750;
+	dc->config.dcn_sharpness_range.sdr_yuv_min = 0;
+	dc->config.dcn_sharpness_range.sdr_yuv_max = 3500;
+	dc->config.dcn_sharpness_range.sdr_yuv_mid = 1500;
+	dc->config.dcn_sharpness_range.hdr_rgb_min = 0;
+	dc->config.dcn_sharpness_range.hdr_rgb_max = 2750;
+	dc->config.dcn_sharpness_range.hdr_rgb_mid = 1500;
+
+	dc->config.dcn_override_sharpness_range.sdr_rgb_min = 0;
+	dc->config.dcn_override_sharpness_range.sdr_rgb_max = 3250;
+	dc->config.dcn_override_sharpness_range.sdr_rgb_mid = 1250;
+	dc->config.dcn_override_sharpness_range.sdr_yuv_min = 0;
+	dc->config.dcn_override_sharpness_range.sdr_yuv_max = 3500;
+	dc->config.dcn_override_sharpness_range.sdr_yuv_mid = 1500;
+	dc->config.dcn_override_sharpness_range.hdr_rgb_min = 0;
+	dc->config.dcn_override_sharpness_range.hdr_rgb_max = 2750;
+	dc->config.dcn_override_sharpness_range.hdr_rgb_mid = 1500;
+
+	dc->config.use_pipe_ctx_sync_logic = true;
+	dc->config.dc_mode_clk_limit_support = false;
+	dc->config.enable_windowed_mpo_odm = true;
+	/* Use psp mailbox to enable assr */
+	dc->config.use_assr_psp_message = true;
+	/* dcn42 and afterward always support external panel replay */
+	dc->config.frame_update_cmd_version2 = true;
+
+	/* read VBIOS LTTPR caps */
+	{
+		if (ctx->dc_bios->funcs->get_lttpr_caps) {
+			enum bp_result bp_query_result;
+			uint8_t is_vbios_lttpr_enable = 0;
+
+			bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable);
+			dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable;
+		}
+
+		dc->caps.vbios_lttpr_aware = true;
+	}
+	dc->check_config = config_defaults;
+
+	if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
+		dc->debug = debug_defaults_drv;
+
+	/*HW default is to have all the FGCG enabled, SW no need to program them*/
+	dc->debug.enable_fine_grain_clock_gating.u32All = 0xFFFF;
+	// Init the vm_helper
+	if (dc->vm_helper)
+		vm_helper_init(dc->vm_helper, 16);
+
+	/*************************************************
+	 *  Create resources                             *
+	 *************************************************/
+
+	/* Clock Sources for Pixel Clock*/
+	pool->base.clock_sources[DCN401_CLK_SRC_PLL0] =
+		dcn42_clock_source_create(ctx, ctx->dc_bios,
+								  CLOCK_SOURCE_COMBO_PHY_PLL0,
+								  &clk_src_regs[0], false);
+	pool->base.clock_sources[DCN401_CLK_SRC_PLL1] =
+		dcn42_clock_source_create(ctx, ctx->dc_bios,
+								  CLOCK_SOURCE_COMBO_PHY_PLL1,
+								  &clk_src_regs[1], false);
+	pool->base.clock_sources[DCN401_CLK_SRC_PLL2] =
+		dcn42_clock_source_create(ctx, ctx->dc_bios,
+								  CLOCK_SOURCE_COMBO_PHY_PLL2,
+								  &clk_src_regs[2], false);
+	pool->base.clock_sources[DCN401_CLK_SRC_PLL3] =
+		dcn42_clock_source_create(ctx, ctx->dc_bios,
+								  CLOCK_SOURCE_COMBO_PHY_PLL3,
+								  &clk_src_regs[3], false);
+	pool->base.clock_sources[DCN401_CLK_SRC_PLL4] =
+		dcn42_clock_source_create(ctx, ctx->dc_bios,
+								  CLOCK_SOURCE_COMBO_PHY_PLL4,
+								  &clk_src_regs[4], false);
+
+	pool->base.clk_src_count = DCN401_CLK_SRC_TOTAL;
+
+	/* todo: not reuse phy_pll registers */
+	pool->base.dp_clock_source =
+		dcn42_clock_source_create(ctx, ctx->dc_bios,
+								  CLOCK_SOURCE_ID_DP_DTO,
+								  &clk_src_regs[0], true);
+
+	for (i = 0; i < pool->base.clk_src_count; i++) {
+		if (pool->base.clock_sources[i] == NULL) {
+			dm_error("DC: failed to create clock sources!\n");
+			BREAK_TO_DEBUGGER();
+			goto create_fail;
+		}
+	}
+
+	/* DCCG */
+	pool->base.dccg = dccg42_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask);
+	if (pool->base.dccg == NULL) {
+		dm_error("DC: failed to create dccg!\n");
+		BREAK_TO_DEBUGGER();
+		goto create_fail;
+	}
+
+#undef REG_STRUCT
+#define REG_STRUCT pg_cntl_regs
+	pg_cntl_dcn42_regs_init();
+
+	pool->base.pg_cntl = pg_cntl42_create(ctx, &pg_cntl_regs, &pg_cntl_shift, &pg_cntl_mask);
+	if (pool->base.pg_cntl == NULL) {
+		dm_error("DC: failed to create power gate control!\n");
+		BREAK_TO_DEBUGGER();
+		goto create_fail;
+	}
+	/* IRQ Service */
+	init_data.ctx = dc->ctx;
+	pool->base.irqs = dal_irq_service_dcn42_create(&init_data);
+	if (!pool->base.irqs)
+		goto create_fail;
+
+	/* HUBBUB */
+	pool->base.hubbub = dcn42_hubbub_create(ctx);
+	if (pool->base.hubbub == NULL) {
+		BREAK_TO_DEBUGGER();
+		dm_error("DC: failed to create hubbub!\n");
+		goto create_fail;
+	}
+
+	/* HUBPs, DPPs, OPPs, TGs, ABMs */
+	for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+		/* if pipe is disabled, skip instance of HW pipe,
+		 * i.e, skip ASIC register instance
+		 */
+		if (pipe_fuses & 1 << i)
+			continue;
+
+		pool->base.hubps[j] = dcn42_hubp_create(ctx, i);
+		if (pool->base.hubps[j] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create hubps!\n");
+			goto create_fail;
+		}
+
+		pool->base.dpps[j] = dcn42_dpp_create(ctx, i);
+		if (pool->base.dpps[j] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create dpps!\n");
+			goto create_fail;
+		}
+
+		pool->base.opps[j] = dcn42_opp_create(ctx, i);
+		if (pool->base.opps[j] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC: failed to create output pixel processor!\n");
+			goto create_fail;
+		}
+
+		pool->base.timing_generators[j] = dcn42_timing_generator_create(
+			ctx, i);
+		if (pool->base.timing_generators[j] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create tg!\n");
+			goto create_fail;
+		}
+
+		pool->base.multiple_abms[j] = dmub_abm_create(ctx,
+													  &abm_regs[i],
+													  &abm_shift,
+													  &abm_mask);
+		if (pool->base.multiple_abms[j] == NULL) {
+			dm_error("DC: failed to create abm for pipe %d!\n", i);
+			BREAK_TO_DEBUGGER();
+			goto create_fail;
+		}
+
+		/* index for resource pool arrays for next valid pipe */
+		j++;
+	}
+
+	/* PSR */
+	pool->base.psr = dmub_psr_create(ctx);
+	if (pool->base.psr == NULL) {
+		dm_error("DC: failed to create psr obj!\n");
+		BREAK_TO_DEBUGGER();
+		goto create_fail;
+	}
+
+	/* Replay */
+	pool->base.replay = dmub_replay_create(ctx);
+	if (pool->base.replay == NULL) {
+		dm_error("DC: failed to create replay obj!\n");
+		BREAK_TO_DEBUGGER();
+		goto create_fail;
+	}
+
+	/* MPCCs */
+	pool->base.mpc = dcn42_mpc_create(ctx, pool->base.res_cap->num_timing_generator,
+			pool->base.res_cap->num_mpc_3dlut);
+	if (pool->base.mpc == NULL) {
+		BREAK_TO_DEBUGGER();
+		dm_error("DC: failed to create mpc!\n");
+		goto create_fail;
+	}
+
+	/* DSCs */
+	for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
+		pool->base.dscs[i] = dcn42_dsc_create(ctx, i);
+		if (pool->base.dscs[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error("DC: failed to create display stream compressor %d!\n", i);
+			goto create_fail;
+		}
+	}
+
+	/* DWB */
+	if (!dcn42_dwbc_create(ctx, &pool->base)) {
+		BREAK_TO_DEBUGGER();
+		dm_error("DC: failed to create dwbc!\n");
+		goto create_fail;
+	}
+
+	/* MMHUBBUB */
+	if (!dcn42_mmhubbub_create(ctx, &pool->base)) {
+		BREAK_TO_DEBUGGER();
+		dm_error("DC: failed to create mcif_wb!\n");
+		goto create_fail;
+	}
+
+	/* AUX and I2C */
+	for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
+		pool->base.engines[i] = dcn42_aux_engine_create(ctx, i);
+
+		if (pool->base.engines[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC:failed to create aux engine!!\n");
+			goto create_fail;
+		}
+		pool->base.hw_i2cs[i] = dcn42_i2c_hw_create(ctx, i);
+		if (pool->base.hw_i2cs[i] == NULL) {
+			BREAK_TO_DEBUGGER();
+			dm_error(
+				"DC:failed to create hw i2c!!\n");
+			goto create_fail;
+		}
+		pool->base.sw_i2cs[i] = NULL;
+	}
+	/* DCN4.2 has 6 DPIA */
+	pool->base.usb4_dpia_count = dc->caps.num_of_host_routers * dc->caps.num_of_dpias_per_host_router;
+	if (dc->debug.dpia_debug.bits.disable_dpia)
+		pool->base.usb4_dpia_count = 0;
+
+	/* Audio, HWSeq, Stream Encoders including HPO and virtual, MPC 3D LUTs */
+	if (!resource_construct(num_virtual_links, dc, &pool->base,
+							&res_create_funcs))
+		goto create_fail;
+
+	/* HW Sequencer init functions and Plane caps */
+	dcn42_hw_sequencer_init_functions(dc);
+
+	dc->caps.max_planes = pool->base.pipe_count;
+
+	for (i = 0; i < dc->caps.max_planes; ++i)
+		dc->caps.planes[i] = plane_cap;
+
+	dc->caps.max_odm_combine_factor = 4;
+
+	dc->cap_funcs = cap_funcs;
+	dc->dcn_ip->max_num_dpp = pool->base.pipe_count;
+
+	// For now enable SDPIF_REQUEST_RATE_LIMIT on DCN4_01 when vram_info.num_chans provided
+	if (dc->config.sdpif_request_limit_words_per_umc == 0)
+		dc->config.sdpif_request_limit_words_per_umc = 16;
+
+	dc->dml2_options.dcn_pipe_count = pool->base.pipe_count;
+	 /*this will use real soc clock table*/
+	dc->dml2_options.use_native_soc_bb_construction = true;
+	dc->dml2_options.minimize_dispclk_using_odm = false;
+	if (dc->config.EnableMinDispClkODM)
+		dc->dml2_options.minimize_dispclk_using_odm = true;
+	dc->dml2_options.enable_windowed_mpo_odm = dc->config.enable_windowed_mpo_odm;
+	dc->dml2_options.map_dc_pipes_with_callbacks = true;
+	dc->dml2_options.force_tdlut_enable = true;
+
+	resource_init_common_dml2_callbacks(dc, &dc->dml2_options);
+	dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch =
+			&dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch;
+	dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc;
+	dc->dml2_options.svp_pstate.callbacks.calculate_mall_ways_from_bytes =
+		pool->base.funcs->calculate_mall_ways_from_bytes;
+
+	dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us;
+	dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us;
+	dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us;
+	dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines;
+
+	dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp;
+	dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch;
+
+	dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size;
+	dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways;
+	dc->dml2_options.mall_cfg.max_cab_allocation_bytes =
+				dc->caps.max_cab_allocation_bytes;
+	dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE;
+	dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE;
+	dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES;
+	dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH;
+
+	dc->dml2_options.max_segments_per_hubp = 24;
+	dc->dml2_options.det_segment_size = DCN42_CRB_SEGMENT_SIZE_KB;
+	dc->dml2_options.gpuvm_enable = true;
+	dc->dml2_options.hostvm_enable = true;
+
+	/* SPL */
+	dc->caps.scl_caps.sharpener_support = true;
+
+	return true;
+
+create_fail:
+
+	dcn42_resource_destruct(pool);
+
+	return false;
+}
+struct resource_pool *dcn42_create_resource_pool(
+	const struct dc_init_data *init_data,
+	struct dc *dc)
+{
+	struct dcn42_resource_pool *pool =
+		kzalloc(sizeof(struct dcn401_resource_pool), GFP_KERNEL);
+
+	if (!pool)
+		return NULL;
+
+	if (dcn42_resource_construct(init_data->num_virtual_links, dc, pool))
+		return &pool->base;
+
+	BREAK_TO_DEBUGGER();
+	kfree(pool);
+	return NULL;
+}
-- 
2.54.0


^ permalink raw reply related

* [PATCH v7.0.y 2/8] drm/amd/display: Backport dml21 DC_RUN_WITH_PREEMPTION_ENABLED addition from DC 3.2.373
From: Xi Ruoyao @ 2026-05-27 14:44 UTC (permalink / raw)
  To: stable; +Cc: amd-gfx, Xi Ruoyao
In-Reply-To: <20260527144428.1095001-1-xry111@xry111.site>

It's a part of the upstream commit e56e3cff2a1b ("drm/amd/display: Sync
dcn42 with DC 3.2.373") needed for the following backports moving FPU
guards from DML to DC.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 .../amd/display/dc/dml2_0/dml21/dml21_wrapper.c    | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
index 96c62bd6a37b..2623e917ec28 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper.c
@@ -9,16 +9,21 @@
 #include "dml21_utils.h"
 #include "dml21_translation_helper.h"
 #include "dml2_dc_resource_mgmt.h"
+#include "dc_fpu.h"
+
+#if !defined(DC_RUN_WITH_PREEMPTION_ENABLED)
+#define DC_RUN_WITH_PREEMPTION_ENABLED(code) code
+#endif // !DC_RUN_WITH_PREEMPTION_ENABLED
 
 #define INVALID -1
 
 static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
 {
-	*dml_ctx = vzalloc(sizeof(struct dml2_context));
+	DC_RUN_WITH_PREEMPTION_ENABLED(*dml_ctx = vzalloc(sizeof(struct dml2_context)));
 	if (!(*dml_ctx))
 		return false;
 
-	(*dml_ctx)->v21.dml_init.dml2_instance = vzalloc(sizeof(struct dml2_instance));
+	DC_RUN_WITH_PREEMPTION_ENABLED((*dml_ctx)->v21.dml_init.dml2_instance = vzalloc(sizeof(struct dml2_instance)));
 	if (!((*dml_ctx)->v21.dml_init.dml2_instance))
 		return false;
 
@@ -28,7 +33,7 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx)
 	(*dml_ctx)->v21.mode_support.display_config = &(*dml_ctx)->v21.display_config;
 	(*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config;
 
-	(*dml_ctx)->v21.mode_programming.programming = vzalloc(sizeof(struct dml2_display_cfg_programming));
+	DC_RUN_WITH_PREEMPTION_ENABLED((*dml_ctx)->v21.mode_programming.programming = vzalloc(sizeof(struct dml2_display_cfg_programming)));
 	if (!((*dml_ctx)->v21.mode_programming.programming))
 		return false;
 
@@ -70,8 +75,9 @@ static void dml21_init(const struct dc *in_dc, struct dml2_context *dml_ctx, con
 bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config)
 {
 	/* Allocate memory for initializing DML21 instance */
-	if (!dml21_allocate_memory(dml_ctx))
+	if (!dml21_allocate_memory(dml_ctx)) {
 		return false;
+	}
 
 	dml21_init(in_dc, *dml_ctx, config);
 
-- 
2.54.0


^ permalink raw reply related

* [PATCH] io_uring/io-wq: re-check IO_WQ_BIT_EXIT for each linked work item
From: Runyu Xiao @ 2026-05-27 14:37 UTC (permalink / raw)
  To: axboe, io-uring; +Cc: linux-kernel, gregkh, jianhao.xu, Runyu Xiao, stable

Commit bdf0bf73006e ("io_uring/io-wq: check IO_WQ_BIT_EXIT inside work
run loop") fixed the obvious case where io_worker_handle_work() took one
exit-bit snapshot before draining pending work, but the fix stops one
level too early.

io_worker_handle_work() now re-checks IO_WQ_BIT_EXIT in its outer work
run loop, yet it still snapshots that bit once before processing a
whole dependent linked-work chain. If io_wq_exit_start() sets
IO_WQ_BIT_EXIT after the first linked item has started, the remaining
linked items can still reuse stale do_kill = false, skip
IO_WQ_WORK_CANCEL, and continue running after exit has begun.

That means the previous fix did not fully eliminate the exit-latency
problem; it only narrowed it to linked chains. A long or slow linked
chain can still keep io-wq exit waiting for work that should already
have been canceled.

The issue was found on Linux v6.18.21 by our static-analysis tool,
which flagged linked-work loops that snapshot shared exit state
outside per-item cancel decisions, and was then confirmed by manual
auditing of io_worker_handle_work(). It was later reproduced with a
QEMU no-device validation selftest that preserved the same contract:
a three-node unbound linked chain, an exit actor setting
IO_WQ_BIT_EXIT after work1, and slow post-exit linked work. With a
3000 ms delay injected into each post-exit item, the buggy path
spends about 6066 ms after exit running work2/work3, while the fixed
path cancels both and finishes in about 2 ms.

Re-check test_bit(IO_WQ_BIT_EXIT, &wq->state) for each iteration of the
dependent-link loop, right before deciding whether to cancel the
current work item. That closes the remaining stale-snapshot window and
prevents linked post-exit work from stretching shutdown latency.

Build-tested by compiling io_uring/io-wq.o on x86_64 with the local
.config. No special hardware was required.

Fixes: bdf0bf73006e ("io_uring/io-wq: check IO_WQ_BIT_EXIT inside work run loop")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 io_uring/io-wq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/io_uring/io-wq.c b/io_uring/io-wq.c
index 49a9c914b4e9..28d81398ebee 100644
--- a/io_uring/io-wq.c
+++ b/io_uring/io-wq.c
@@ -601,7 +601,6 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
 	struct io_wq *wq = worker->wq;
 
 	do {
-		bool do_kill = test_bit(IO_WQ_BIT_EXIT, &wq->state);
 		struct io_wq_work *work;
 
 		/*
@@ -637,6 +636,7 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
 
 		/* handle a whole dependent link */
 		do {
+			bool do_kill = test_bit(IO_WQ_BIT_EXIT, &wq->state);
 			struct io_wq_work *next_hashed, *linked;
 			unsigned int work_flags = atomic_read(&work->flags);
 			unsigned int hash = __io_wq_is_hashed(work_flags)
-- 
2.34.1

^ permalink raw reply related

* [REGRESSION] Speaker pop/chirp on Meteor Lake ALC287 (17aa:231e) -- 6.12.73 to 6.12.85
From: Mike Karcic @ 2026-05-27 14:25 UTC (permalink / raw)
  To: stable@vger.kernel.org
  Cc: regressions@lists.linux.dev, linux-sound@vger.kernel.org,
	linux-kernel@vger.kernel.org, tiwai@suse.de,
	sean@starlabs.systems

Speaker pop/chirp regression on a Lenovo ThinkPad with Meteor Lake and
Realtek ALC287 (subsystem ID 17aa:231e). The chirp occurs on speaker
power state transitions when audio starts or stops. It is not present
on kernel 6.12.73 and is present on 6.12.85. A desktop with ALC897
(subsystem ID 1f660202) on kernel 6.19.14 is unaffected, so this is
codec/fixup-specific.

Tested on the same LMDE (Debian 13) installation with multiple kernels
selectable from GRUB. All userspace, firmware, and configuration are
identical between tests. Cold boot between kernel switches is required,
as warm reboot can carry codec register state forward. The kernel is
not tainted on any tested version.

Bisection results (Debian package versions):
  6.12.48  -- no chirp
  6.12.73  -- no chirp
  6.12.85  -- chirp present
  6.12.86  -- chirp present
  6.12.90  -- chirp present

Also broken: 6.19.14-101.fc44.x86_64 (Fedora/Aurora 44)

The regression window (6.12.73 to 6.12.85) includes two commits
targeting speaker pop on the Star Labs StarFighter (ALC233, SSID
7017:2014) that touch patch_realtek.c:

  1cb3c20688fc ("ALSA: hda/realtek: Fix speaker pop on Star Labs StarFighter")
  Fixes commit ("ALSA: hda/realtek: Sequence GPIO2 on Star Labs StarFighter")

These are quirk-gated to SSID 7017:2014 and should not run on
17aa:231e, but they are the most prominent sound changes in the
regression window. The actual culprit may be a different commit
in the 6.12.74-6.12.85 range. I was unable to narrow further as
Debian does not publish intermediate point-release packages.

I can build and test vanilla kernels for a proper bisection if
guided, and I can test proposed fixes.

Hardware:
  Lenovo ThinkPad, Meteor Lake
  Codec: Realtek ALC287
  Subsystem ID: 17aa:231e
  PCI: 0000:00:1f.3
  Machine driver: skl_hda_dsp_generic
  Codec fixup: "ALC287: picked fixup for PCI SSID 17aa:231e"

Unaffected hardware (same 6.19.14 kernel, no chirp):
  Desktop, Realtek ALC897, Subsystem ID: 1f660202

Controlled variables (identical across all tested 6.12 kernels):
  SOF firmware: 2.12.0.1 (firmware-sof-signed 2025.01-1)
  Topology: intel/sof-ace-tplg/sof-hda-generic-2ch.tplg
  Topology ABI: 3:29:1 (Kernel ABI: 3:23:1 on all tested)
  ALSA UCM: alsa-ucm-conf 1.2.14-1
  PipeWire: 1.4.2, WirePlumber: 0.5.8
  power_save: 10, hda_model: (null)
  Desktop: KDE Plasma 6 (Wayland)

Eliminated causes:
  - Topology files in sof-ipc4-tplg/ and sof-ace-tplg/ are
    byte-identical (confirmed via binary diff). Path irrelevant.
  - SOF firmware version (same 2.12.0.1 on all tested kernels).
  - Topology ABI mismatch (3:29:1 vs 3:23:1 present on working
    kernel too).
  - power_save (10 on all kernels).
  - PipeWire/WirePlumber (identical versions on all kernels).
  - Desktop environment (KDE on all; a KDE install triggered a
    kernel update which was the actual cause of the regression
    appearing).

dmesg (6.12.48, working):
  sof-audio-pci-intel-mtl 0000:00:1f.3: Firmware paths/files for ipc type 1:
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware file:     intel/sof-ipc4/mtl/sof-mtl.ri
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware lib path: intel/sof-ipc4-lib/mtl
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Topology file:     intel/sof-ace-tplg/sof-hda-generic-2ch.tplg
  sof-audio-pci-intel-mtl 0000:00:1f.3: Booted firmware version: 2.12.0.1
  sof-audio-pci-intel-mtl 0000:00:1f.3: Topology: ABI 3:29:1 Kernel ABI 3:23:1
  snd_hda_codec_alc269 ehdaudio0D0: ALC287: picked fixup for PCI SSID 17aa:231e
  snd_hda_codec_alc269 ehdaudio0D0: autoconfig for ALC287: line_outs=1 (0x17/0x0/0x0/0x0/0x0) type:speaker

dmesg (6.19.14, affected):
  sof-audio-pci-intel-mtl 0000:00:1f.3: Digital mics found on Skylake+ platform, using SOF driver
  sof-audio-pci-intel-mtl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if 0x040380
  sof-audio-pci-intel-mtl 0000:00:1f.3: hda codecs found, mask 5
  sof-audio-pci-intel-mtl 0000:00:1f.3: using HDA machine driver skl_hda_dsp_generic now
  sof-audio-pci-intel-mtl 0000:00:1f.3: Firmware paths/files for ipc type 1:
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware file:     intel/sof-ipc4/mtl/sof-mtl.ri
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware lib path: intel/sof-ipc4-lib/mtl
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Topology file:     intel/sof-ipc4-tplg/sof-hda-generic-2ch.tplg
  sof-audio-pci-intel-mtl 0000:00:1f.3: Booted firmware version: 2.14.1.1
  sof-audio-pci-intel-mtl 0000:00:1f.3: Topology: ABI 3:29:1 Kernel ABI 3:23:1
  snd_hda_codec_alc269 ehdaudio0D0: ALC287: picked fixup for PCI SSID 17aa:231e
  snd_hda_codec_alc269 ehdaudio0D0: autoconfig for ALC287: line_outs=1 (0x17/0x0/0x0/0x0/0x0) type:speaker

Note: The kernel is not tainted on any tested version.

^ permalink raw reply

* [REGRESSION] Speaker pop/chirp on Meteor Lake ALC287 (17aa:231e) -- 6.12.73 to 6.12.85
From: Mike Karcic @ 2026-05-27 14:21 UTC (permalink / raw)
  To: stable; +Cc: regressions, linux-sound, linux-kernel, tiwai, sean

Speaker pop/chirp regression on a Lenovo ThinkPad with Meteor Lake and
Realtek ALC287 (subsystem ID 17aa:231e). The chirp occurs on speaker
power state transitions when audio starts or stops. It is not present
on kernel 6.12.73 and is present on 6.12.85. A desktop with ALC897
(subsystem ID 1f660202) on kernel 6.19.14 is unaffected, so this is
codec/fixup-specific.

Tested on the same LMDE (Debian 13) installation with multiple kernels
selectable from GRUB. All userspace, firmware, and configuration are
identical between tests. Cold boot between kernel switches is required,
as warm reboot can carry codec register state forward. The kernel is
not tainted on any tested version.

Bisection results (Debian package versions):
  6.12.48  -- no chirp
  6.12.73  -- no chirp
  6.12.85  -- chirp present
  6.12.86  -- chirp present
  6.12.90  -- chirp present

Also broken: 6.19.14-101.fc44.x86_64 (Fedora/Aurora 44)

The regression window (6.12.73 to 6.12.85) includes two commits
targeting speaker pop on the Star Labs StarFighter (ALC233, SSID
7017:2014) that touch patch_realtek.c:

  1cb3c20688fc ("ALSA: hda/realtek: Fix speaker pop on Star Labs StarFighter")
  Fixes commit ("ALSA: hda/realtek: Sequence GPIO2 on Star Labs StarFighter")

These are quirk-gated to SSID 7017:2014 and should not run on
17aa:231e, but they are the most prominent sound changes in the
regression window. The actual culprit may be a different commit
in the 6.12.74-6.12.85 range. I was unable to narrow further as
Debian does not publish intermediate point-release packages.

I can build and test vanilla kernels for a proper bisection if
guided, and I can test proposed fixes.

Hardware:
  Lenovo ThinkPad, Meteor Lake
  Codec: Realtek ALC287
  Subsystem ID: 17aa:231e
  PCI: 0000:00:1f.3
  Machine driver: skl_hda_dsp_generic
  Codec fixup: "ALC287: picked fixup for PCI SSID 17aa:231e"

Unaffected hardware (same 6.19.14 kernel, no chirp):
  Desktop, Realtek ALC897, Subsystem ID: 1f660202

Controlled variables (identical across all tested 6.12 kernels):
  SOF firmware: 2.12.0.1 (firmware-sof-signed 2025.01-1)
  Topology: intel/sof-ace-tplg/sof-hda-generic-2ch.tplg
  Topology ABI: 3:29:1 (Kernel ABI: 3:23:1 on all tested)
  ALSA UCM: alsa-ucm-conf 1.2.14-1
  PipeWire: 1.4.2, WirePlumber: 0.5.8
  power_save: 10, hda_model: (null)
  Desktop: KDE Plasma 6 (Wayland)

Eliminated causes:
  - Topology files in sof-ipc4-tplg/ and sof-ace-tplg/ are
    byte-identical (confirmed via binary diff). Path irrelevant.
  - SOF firmware version (same 2.12.0.1 on all tested kernels).
  - Topology ABI mismatch (3:29:1 vs 3:23:1 present on working
    kernel too).
  - power_save (10 on all kernels).
  - PipeWire/WirePlumber (identical versions on all kernels).
  - Desktop environment (KDE on all; a KDE install triggered a
    kernel update which was the actual cause of the regression
    appearing).

dmesg (6.12.48, working):
  sof-audio-pci-intel-mtl 0000:00:1f.3: Firmware paths/files for ipc type 1:
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware file:
intel/sof-ipc4/mtl/sof-mtl.ri
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware lib path:
intel/sof-ipc4-lib/mtl
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Topology file:
intel/sof-ace-tplg/sof-hda-generic-2ch.tplg
  sof-audio-pci-intel-mtl 0000:00:1f.3: Booted firmware version: 2.12.0.1
  sof-audio-pci-intel-mtl 0000:00:1f.3: Topology: ABI 3:29:1 Kernel ABI 3:23:1
  snd_hda_codec_alc269 ehdaudio0D0: ALC287: picked fixup for PCI SSID 17aa:231e
  snd_hda_codec_alc269 ehdaudio0D0: autoconfig for ALC287: line_outs=1
(0x17/0x0/0x0/0x0/0x0) type:speaker

dmesg (6.19.14, affected):
  sof-audio-pci-intel-mtl 0000:00:1f.3: Digital mics found on Skylake+
platform, using SOF driver
  sof-audio-pci-intel-mtl 0000:00:1f.3: DSP detected with PCI
class/subclass/prog-if 0x040380
  sof-audio-pci-intel-mtl 0000:00:1f.3: hda codecs found, mask 5
  sof-audio-pci-intel-mtl 0000:00:1f.3: using HDA machine driver
skl_hda_dsp_generic now
  sof-audio-pci-intel-mtl 0000:00:1f.3: Firmware paths/files for ipc type 1:
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware file:
intel/sof-ipc4/mtl/sof-mtl.ri
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Firmware lib path:
intel/sof-ipc4-lib/mtl
  sof-audio-pci-intel-mtl 0000:00:1f.3:  Topology file:
intel/sof-ipc4-tplg/sof-hda-generic-2ch.tplg
  sof-audio-pci-intel-mtl 0000:00:1f.3: Booted firmware version: 2.14.1.1
  sof-audio-pci-intel-mtl 0000:00:1f.3: Topology: ABI 3:29:1 Kernel ABI 3:23:1
  snd_hda_codec_alc269 ehdaudio0D0: ALC287: picked fixup for PCI SSID 17aa:231e
  snd_hda_codec_alc269 ehdaudio0D0: autoconfig for ALC287: line_outs=1
(0x17/0x0/0x0/0x0/0x0) type:speaker

Note: The kernel is not tainted on any tested version.

-- 
Mike

^ permalink raw reply

* Re: [PATCH] net/mlx5: Reorder completion before putting command entry in cmd_work_handler
From: Moshe Shemesh @ 2026-05-27 14:19 UTC (permalink / raw)
  To: Nikolay Kuratov, linux-kernel
  Cc: netdev, linux-rdma, Saeed Mahameed, Akiva Goldberger,
	Tariq Toukan, stable
In-Reply-To: <20260526162932.501584-1-kniv@yandex-team.ru>



On 5/26/2026 7:29 PM, Nikolay Kuratov wrote:
> Assuming callback != NULL && !page_queue, cmd_work_handler takes
> command entry with refcnt == 1 from mlx5_cmd_invoke.
> If either semaphore timeout or index allocation error happens,
> it does final cmd_ent_put(ent). To avoid access to freed memory,
> notify slotted completion before cmd_ent_put.
> 
> This is theoretical issue found by Svace static analyser.
> 
> Cc:stable@vger.kernel.org
> Fixes: 485d65e135712 ("net/mlx5: Add a timeout to acquire the command queue semaphore")
> Fixes: 0e2909c6bec90 ("net/mlx5: Fix variable not being completed when function returns")
> Signed-off-by: Nikolay Kuratov<kniv@yandex-team.ru>
> ---
>   drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Moshe Shemesh <moshe@nvidia.com>

Thanks.

^ permalink raw reply

* Re: [PATCH v2 0/2] zram: fix UAF in zram_bvec_write_partial() and drop dead bio plumbing
From: Cunlong Li @ 2026-05-27 14:15 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Minchan Kim, Jens Axboe, Andrew Morton, Christoph Hellwig,
	linux-block, linux-mm, linux-kernel, stable
In-Reply-To: <ahabSU6QcGJ4T4ZP@google.com>

On Wed, May 27, 2026 at 04:21:53PM +0900, Sergey Senozhatsky wrote:
> On (26/05/27 12:49), Cunlong Li wrote:
> > Patch 1 fixes a use-after-free in zram_bvec_write_partial() that
> > happens on PAGE_SIZE > 4K configurations when a partial write hits a
> > ZRAM_WB slot.
> > 
> > Patch 2 is a follow-up cleanup that drops the now-unused bio parameter
> > from zram_bvec_write_partial() and zram_bvec_write(), no functional
> > change.
> 
> Did you test it?

Compile-tested only so far; I haven't had a chance to run a
PAGE_SIZE > 4K reproducer yet.

Thanks for the review.

> 
> Looks reasonable (unless I'm missing something):
> Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox