Linux-Next discussions
 help / color / mirror / Atom feed
* linux-next: Tree for Jul 17
From: Mark Brown @ 2026-07-18  0:02 UTC (permalink / raw)
  To: Linux Next Mailing List; +Cc: Linux Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 2106 bytes --]

Hi all,

Changes since 20260716:

The qcom tree acquired a build failure, I used the version from
next-20260716 instead.

The bluetooth tree acquired a conflict with the origin tree.

The drm-next tree acquired multiple conflicts with the drm-fixes tree.

The kvm tree acquired a conflict with the tip tree.

The tty tree lost it's build failure.

The scsi-mkp tree lost it's build failure.

The nvmem tree acquired a conflict with the iio tree.

Some interaction between gpio-brgl, kunit and most likely a third tree
triggered a KUnit regression.

Non-merge commits (relative to Linus' tree): 6698
 6416 files changed, 277182 insertions(+), 104787 deletions(-)

----------------------------------------------------------------------------

I have created today's linux-next tree at
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
(patches at https://www.kernel.org/pub/linux/kernel/next/ ).  If you
are tracking the linux-next tree using git, you should not use "git pull"
to do so as that will try to merge the new linux-next release with the
old one.  You should use "git fetch" and checkout or reset to the new
master.

You can see which trees have been included by looking in the Next/Trees
file in the source.  There is also the merge.log file in the Next
directory.  Between each merge, the tree was built with a defconfig
for arm64, an allmodconfig for x86_64, a multi_v7_defconfig for arm,
an arm64 build of various kselftests, a KUnit build and run on arm64,
and a native build of tools/perf.  After the final fixups (if any), I do
an x86_64 modules_install followed by builds for x86_64 allnoconfig,
arm64 allyesconfig, powerpc allnoconfig (32 and 64 bit),
ppc44x_defconfig and pseries_le_defconfig and i386, s390, sparc and
sparc64 defconfig and htmldocs.

Below is a summary of the state of the merge.

I am currently merging 429 trees (counting Linus' and 133 trees of bug
fix patches pending for the current release).

Stats about the size of the tree over time can be seen at
http://neuling.org/linux-next-size.html .

Thanks to Paul Gortmaker for triage and bug fixes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the nvmem tree with the iio tree
From: Mark Brown @ 2026-07-18  0:02 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Jonathan Cameron, Linux Kernel Mailing List,
	Linux Next Mailing List, Roman Vivchar

[-- Attachment #1: Type: text/plain, Size: 1444 bytes --]

Hi all,

Today's linux-next merge of the nvmem tree got a conflict in:

  MAINTAINERS

between commit:

  348ff65577603 ("dt-bindings: iio: adc: mediatek,mt6359-auxadc: add mt6323 PMIC AUXADC")

from the iio tree and commit:

  b3c090960d869 ("nvmem: add mt6323 PMIC EFUSE driver")

from the nvmem tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc MAINTAINERS
index d8c06178fe7c1,36f7ee6ba3194..0000000000000
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@@ -16588,13 -16560,11 +16593,18 @@@ S:	Maintaine
  F:	Documentation/devicetree/bindings/mmc/mtk-sd.yaml
  F:	drivers/mmc/host/mtk-sd.c
  
 +MEDIATEK MT6323 PMIC AUXADC DRIVER
 +M:	Roman Vivchar <rva333@protonmail.com>
 +L:	linux-iio@vger.kernel.org
 +S:	Maintained
 +F:	drivers/iio/adc/mt6323-auxadc.c
 +F:	include/dt-bindings/iio/adc/mediatek,mt6323-auxadc.h
 +
+ MEDIATEK MT6323 PMIC NVMEM DRIVER
+ M:	Roman Vivchar <rva333@protonmail.com>
+ S:	Maintained
+ F:	drivers/nvmem/mt6323-efuse.c
+ 
  MEDIATEK MT6735 CLOCK & RESET DRIVERS
  M:	Yassine Oudjana <y.oudjana@protonmail.com>
  L:	linux-clk@vger.kernel.org

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: test failure after merge of the kunit-next tree
From: Mark Brown @ 2026-07-18  0:02 UTC (permalink / raw)
  To: Shuah Khan, Linus Walleij, Bartosz Golaszewski, David Gow
  Cc: Linux Kernel Mailing List, Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 2365 bytes --]

Hi all,

After merging the kunit-next tree, today's linux-next build
(arm64 kunit) failed like this:

[22:59:27] Configuring KUnit Kernel ...
[22:59:27] Building KUnit Kernel ...
Populating config with:
$ make ARCH=arm64 O=/tmp/next/arm64_kunit olddefconfig CROSS_COMPILE=aarch64-linux-gnu-
Building with:
$ make all compile_commands.json scripts_gdb ARCH=arm64 O=/tmp/next/arm64_kunit --jobs=192 CROSS_COMPILE=aarch64-linux-gnu-
[22:59:30] Starting KUnit Kernel (1/1)...
Running tests with:
$ qemu-system-aarch64 -nodefaults -m 1024 -kernel /tmp/next/arm64_kunit/arch/arm64/boot/Image.gz -append 'kunit.enable=1 console=ttyAMA0 kunit_shutdown=reboot' -no-reboot -nographic -accel kvm -accel hvf -accel tcg -serial stdio -machine virt -cpu max
[23:00:36] ============================================================
[23:00:36] ========== gpio-unbind-with-consumers (1 subtest) ==========
[23:00:36] # gpio_unbind_with_consumers: ASSERTION FAILED at drivers/gpio/gpiolib-kunit.c:393
[23:00:36] Expected ret == 0x0001, but
[23:00:36]     ret == 0 (0x0)
[23:00:36]     0x0001 == 1 (0x1)
[23:00:36] [FAILED] gpio_unbind_with_consumers
[23:00:36] # module: gpiolib_kunit
[23:00:36] =========== [FAILED] gpio-unbind-with-consumers ============
[23:00:36] # gpio-swnode-hog:     # failed to initialize (-17)
[23:00:36] [FAILED] gpio-swnode-hog
[23:00:36] ============================================================
[23:00:36] Testing complete. Ran 9377 tests: passed: 9284, failed: 2, skipped: 91
[23:00:36] Failures: gpio-unbind-with-consumers, gpio-swnode-hog
[23:00:36] Test results stored in /tmp/next/arm64_kunit.json
[23:00:36] Elapsed time: 69.716s total, 0.002s configuring, 3.680s building, 66.027s running

This is caused by commit

  a05cfd98c5eca (gpio: kunit: add test cases for software node hogs)

which was from the gpio-brgl tree, it has only just become visible since 

  34b5c0132952c (kunit: configs: enable GPIO kunit test cases in all_tests.config)

was added causing the gpiolib tests to actually be run though neither of
these commits was added today (the KUnit tree did not change for a
while).  I'm not clear why this has started failing today, presumably
some third commit from another tree has started triggering a regression
since neither of these trees has changed.

I have left this for today.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: warnings from validate_blend_mode_for_alpha_formats() in next-20260715
From: Leandro Ribeiro @ 2026-07-17 22:54 UTC (permalink / raw)
  To: Alex Deucher, Bert Karwatzki, Wentland, Harry, Leo (Sunpeng) Li,
	Alex Hung
  Cc: Alex Deucher, linux-kernel, amd-gfx, linux-next, Jesse Zhang,
	Amber Lin, Mario Limonciello
In-Reply-To: <CADnq5_PEN=iuspWbQ9C3gJZ5qJVOLmJ5hrsi6FH0Dg2Y_u2mZQ@mail.gmail.com>



On 7/17/26 11:55 AM, Alex Deucher wrote:
> + Some display folks
> 
> On Fri, Jul 17, 2026 at 9:04 AM Bert Karwatzki <spasswolf@web.de> wrote:
>>
>> commit 860e748bddcc ("drm: ensure blend mode supported if pixel format with alpha exposed")
>> introduces validate_blend_mode_for_alpha_formats() which prints warnings for amdpgu as
>> amdgpu only set blend_mode_property for planes of type DRM_PLANE_TYPE_OVERLAY. I tried to fix
>> this by removing he (plane->type == DRM_PLANE_TYPE_OVERLAY) check in amdgpu_dm_plane_init():
>>
>>         printk(KERN_INFO "%s: plane=%px plane->type=0x%x plane_cap=%px\n", __func__, plane, plane->type, plane_cap);
>>         if (plane_cap)
>>                 printk(KERN_INFO "%s: per_pixel_alpha =%u\n", __func__, plane_cap->per_pixel_alpha);
>>         if (plane_cap && plane_cap->per_pixel_alpha) {
>>                 unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>>                                           BIT(DRM_MODE_BLEND_PREMULTI) |
>>                                           BIT(DRM_MODE_BLEND_COVERAGE);
>>
>>                 printk(KERN_INFO "%s: creating alpha and blend mode properties for plane %px\n", __func__, plane);
>>                 drm_plane_create_alpha_property(plane);
>>                 drm_plane_create_blend_mode_property(plane, blend_caps);
>>         }
>>
>> But this does not completely silence the warnings becuase for planes of type DRM_PLANE_TYPE_CURSOR plane_cap is NULL.
>> Is this a problem that should be fixed in amdgpu or is should validate_blend_mode_for_alpha_formats() only be called
>> for planes of certain types?

IMO validate_blend_mode_for_alpha_formats() should be called for all
types of planes. I can't think of anything special about a cursor plane
that would justify it being allowed to expose formats with alpha but not
the blend mode property.

I'm not familiar with the AMD codebase to suggest the best fix, but the
driver would need some way to know whether cursor planes are exposing
formats with alpha.

>>
>> Bert Karwatzki
>>

-- 
Leandro Ribeiro


^ permalink raw reply

* linux-next: manual merge of the kvm tree with the tip tree
From: Mark Brown @ 2026-07-17 16:11 UTC (permalink / raw)
  To: Paolo Bonzini, KVM
  Cc: Borislav Petkov, Ingo Molnar, Juergen Gross,
	Linux Kernel Mailing List, Linux Next Mailing List,
	Sean Christopherson

[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]

Hi all,

Today's linux-next merge of the kvm tree got a conflict in:

  arch/x86/kvm/x86.c

between commits:

  3eaa50e1e255e ("x86/cpu: Hide and rename static_cpu_has()")
  1620ddc0dcefc ("KVM/x86: Stop using 32-bit MSR interfaces")

from the tip tree and commit:

  7a26830801584 ("KVM: x86: Move the bulk of MSR specific code from x86.c to msrs.{c,h}")

from the kvm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --git a/arch/x86/kvm/msrs.c b/arch/x86/kvm/msrs.c
index c230b18d87e38..764cda8045a17 100644
--- a/arch/x86/kvm/msrs.c
+++ b/arch/x86/kvm/msrs.c
@@ -2579,9 +2579,9 @@ static void kvm_probe_feature_msr(u32 msr_index)
 
 static void kvm_probe_msr_to_save(u32 msr_index)
 {
-	u32 dummy[2];
+	u64 dummy;
 
-	if (rdmsr_safe(msr_index, &dummy[0], &dummy[1]))
+	if (rdmsrq_safe(msr_index, &dummy))
 		return;
 
 	/*

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply related

* Re: linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 15:12 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Chenyu Chen, Dmytro Laktyushkin, Gabe Teeger,
	George Zhang, Linux Kernel Mailing List, Linux Next Mailing List,
	Matthew Stewart, Peichen Huang, Pengpeng Hou
In-Reply-To: <alo-x_TORE2vBFlX@sirena.org.uk>

[-- Attachment #1: Type: text/plain, Size: 859 bytes --]

On Fri, Jul 17, 2026 at 03:40:07PM +0100, Mark Brown wrote:

> Today's linux-next merge of the drm tree got a conflict in:
> 
>   drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
> 
> between commits:
> 
>   6351003b1f4ec ("drm/amd/display: wire DCN42B mcache programming callback")
>   57cf172be2827 ("drm/amd/display: fix dcn42b det allocation order")
>   c4bc7ffb91586 ("drm/amd/display: Fix DCN42B null registers & register masks")
> 
> from the drm-fixes tree and commits:
> 
>   85453fb4ff726 ("drm/amd/display: wire DCN42B mcache programming callback")

Actually the merge here doesn't build.  I'll try to fix it up but
*please* try not to do this constant, routine cherry picking.  Sometimes
it's the sensible thing to do but most of the time I'd expect to see the
fixes go up onto the -next branch with a merge.  

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: linux-next: build failure in the final build
From: Johan Hovold @ 2026-07-17 15:06 UTC (permalink / raw)
  To: Mark Brown
  Cc: Greg Kroah-Hartman, Manuel Ebner, Linux Kernel Mailing List,
	Linux Next Mailing List
In-Reply-To: <99d6a70c-3986-4267-9934-e8d8b293cb47@sirena.org.uk>

[-- Attachment #1: Type: text/plain, Size: 872 bytes --]

On Fri, Jul 17, 2026 at 03:54:05PM +0100, Mark Brown wrote:
> On Fri, Jul 17, 2026 at 04:40:38PM +0200, Johan Hovold wrote:
> 
> > I was also waiting on Mark to follow up on this, otherwise I can take
> > closer look at it.
> 
> > Based on a quick look it seemed like Mark was right about missing static
> > keywords in a driver indirectly enabled by the "offending" commit.
> 
> IIRC I replied to the patch for the offending commit the other day.  At
> some point I will get fed up and just revert the usb tree back to one
> that works, it's a real pain doing that for issues in the final build.
> 
> This seems like it really ought to be straightforward to reproduce
> localy...

Oh, sorry. I misunderstood your comment about doing "something about
this tomorrow" to mean that you intended to send a fix yourself.

I'll send a fix in a bit.

Johan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply

* Re: warnings from validate_blend_mode_for_alpha_formats() in next-20260715
From: Alex Deucher @ 2026-07-17 14:55 UTC (permalink / raw)
  To: Bert Karwatzki, Wentland, Harry, Leo (Sunpeng) Li, Alex Hung
  Cc: Alex Deucher, Leandro Ribeiro, linux-kernel, amd-gfx, linux-next,
	Jesse Zhang, Amber Lin, Mario Limonciello
In-Reply-To: <20260716152933.6744-1-spasswolf@web.de>

+ Some display folks

On Fri, Jul 17, 2026 at 9:04 AM Bert Karwatzki <spasswolf@web.de> wrote:
>
> commit 860e748bddcc ("drm: ensure blend mode supported if pixel format with alpha exposed")
> introduces validate_blend_mode_for_alpha_formats() which prints warnings for amdpgu as
> amdgpu only set blend_mode_property for planes of type DRM_PLANE_TYPE_OVERLAY. I tried to fix
> this by removing he (plane->type == DRM_PLANE_TYPE_OVERLAY) check in amdgpu_dm_plane_init():
>
>         printk(KERN_INFO "%s: plane=%px plane->type=0x%x plane_cap=%px\n", __func__, plane, plane->type, plane_cap);
>         if (plane_cap)
>                 printk(KERN_INFO "%s: per_pixel_alpha =%u\n", __func__, plane_cap->per_pixel_alpha);
>         if (plane_cap && plane_cap->per_pixel_alpha) {
>                 unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
>                                           BIT(DRM_MODE_BLEND_PREMULTI) |
>                                           BIT(DRM_MODE_BLEND_COVERAGE);
>
>                 printk(KERN_INFO "%s: creating alpha and blend mode properties for plane %px\n", __func__, plane);
>                 drm_plane_create_alpha_property(plane);
>                 drm_plane_create_blend_mode_property(plane, blend_caps);
>         }
>
> But this does not completely silence the warnings becuase for planes of type DRM_PLANE_TYPE_CURSOR plane_cap is NULL.
> Is this a problem that should be fixed in amdgpu or is should validate_blend_mode_for_alpha_formats() only be called
> for planes of certain types?
>
> Bert Karwatzki
>

^ permalink raw reply

* Re: linux-next: build failure in the final build
From: Mark Brown @ 2026-07-17 14:54 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Greg Kroah-Hartman, Manuel Ebner, Linux Kernel Mailing List,
	Linux Next Mailing List
In-Reply-To: <alo-5gLdvyqY-TwB@hovoldconsulting.com>

[-- Attachment #1: Type: text/plain, Size: 593 bytes --]

On Fri, Jul 17, 2026 at 04:40:38PM +0200, Johan Hovold wrote:

> I was also waiting on Mark to follow up on this, otherwise I can take
> closer look at it.

> Based on a quick look it seemed like Mark was right about missing static
> keywords in a driver indirectly enabled by the "offending" commit.

IIRC I replied to the patch for the offending commit the other day.  At
some point I will get fed up and just revert the usb tree back to one
that works, it's a real pain doing that for issues in the final build.

This seems like it really ought to be straightforward to reproduce
localy...

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 14:41 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Ce Sun, Linux Kernel Mailing List,
	Linux Next Mailing List, Mario Limonciello, Tvrtko Ursulin,
	Yang Wang

[-- Attachment #1: Type: text/plain, Size: 4214 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h

between commit:

  6e4bc34568e38 ("drm/amd: Create a device link between APU display and XHCI devices")

from the drm-fixes tree and commits:

  07c93d7eeb0d9 ("drm/amd: Create a device link between APU display and XHCI devices")
  958430a1f068f ("drm/amd/pm: retire legacy smu ras driver framework")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index e3a89e9a9df41,7ea7c4a5279be..0000000000000
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@@ -852,8 -852,6 +852,6 @@@ struct pptable_funcs 
  	 */
  	int (*set_default_dpm_table)(struct smu_context *smu);
  
- 	int (*set_power_state)(struct smu_context *smu);
- 
  	/**
  	 * @populate_umd_state_clk: Populate the UMD power state table with
  	 *                          defaults.
@@@ -906,16 -904,6 +904,6 @@@
  					      struct
  					      pp_clock_levels_with_latency
  					      *clocks);
- 	/**
- 	 * @get_clock_by_type_with_voltage: Get the speed and voltage of a clock
- 	 *                                  domain.
- 	 */
- 	int (*get_clock_by_type_with_voltage)(struct smu_context *smu,
- 					      enum amd_pp_clock_type type,
- 					      struct
- 					      pp_clock_levels_with_voltage
- 					      *clocks);
- 
  	/**
  	 * @get_power_profile_mode: Print all power profile modes to
  	 *                          buffer. Star current mode.
@@@ -1357,11 -1345,6 +1345,6 @@@
  	 */
  	int (*register_irq_handler)(struct smu_context *smu);
  
- 	/**
- 	 * @set_azalia_d3_pme: Wake the audio decode engine from d3 sleep.
- 	 */
- 	int (*set_azalia_d3_pme)(struct smu_context *smu);
- 
  	/**
  	 * @get_max_sustainable_clocks_by_dc: Get a copy of the max sustainable
  	 *                                    clock speeds table.
@@@ -1378,18 -1361,6 +1361,6 @@@
  	 */
  	int (*get_bamaco_support)(struct smu_context *smu);
  
- 	/**
- 	 * @baco_get_state: Get the current BACO state.
- 	 *
- 	 * Return: Current BACO state.
- 	 */
- 	enum smu_baco_state (*baco_get_state)(struct smu_context *smu);
- 
- 	/**
- 	 * @baco_set_state: Enter/exit BACO.
- 	 */
- 	int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state);
- 
  	/**
  	 * @baco_enter: Enter BACO.
  	 */
@@@ -1651,12 -1622,6 +1622,6 @@@
  	int (*ras_send_msg)(struct smu_context *smu,
  			    enum smu_message_type msg, uint32_t param, uint32_t *read_arg);
  
- 	/**
- 	 * @get_ras_smu_drv: Get RAS smu driver interface
- 	 * Return: ras_smu_drv *
- 	 */
- 	int (*get_ras_smu_drv)(struct smu_context *smu, const struct ras_smu_drv **ras_smu_drv);
- 
  	/**
  	 * @set_power_dep: Create or destroy a power dependency link
  	 * from an integrated xHCI controller to the GPU so that the GPU is
@@@ -1962,7 -1927,13 +1927,13 @@@ int smu_link_reset(struct smu_context *
  
  extern const struct amd_ip_funcs smu_ip_funcs;
  
- bool is_support_sw_smu(struct amdgpu_device *adev);
+ void amdgpu_smu_early_init(struct amdgpu_device *adev);
+ 
+ static inline bool is_support_sw_smu(struct amdgpu_device *adev)
+ {
+ 	return adev->is_sw_smu;
+ }
+ 
  bool is_support_cclk_dpm(struct amdgpu_device *adev);
  int smu_write_watermarks_table(struct smu_context *smu);
  
@@@ -2005,7 -1976,6 +1976,6 @@@ int smu_set_pm_policy(struct smu_contex
  		      int level);
  ssize_t smu_get_pm_policy_info(struct smu_context *smu,
  			       enum pp_pm_policy p_type, char *sysbuf);
- const struct ras_smu_drv *smu_get_ras_smu_driver(void *handle);
  
  int amdgpu_smu_ras_send_msg(struct amdgpu_device *adev, enum smu_message_type msg,
  			    uint32_t param, uint32_t *readarg);

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 14:40 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Arnd Bergmann, Bhuvanachandra Pinninti,
	Charlene Liu, Chenyu Chen, George Zhang, Honglei Huang, James Lin,
	Leo Li, Linux Kernel Mailing List, Linux Next Mailing List,
	Rafal Ostrowski, Tom Chung

[-- Attachment #1: Type: text/plain, Size: 38293 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/display/dc/core/dc.c

between commit:

  d73f4e118dc4c ("drm/amd/display: check GRPH_FLIP status before sending event")

from the drm-fixes tree and commits:

  f64a9be565368 ("drm/amd/display: check GRPH_FLIP status before sending event")
  72b94048020ce ("drm/amd/display: limit reuse dsc capable bootup timing")
  98e08a815ef60 ("drm/amd/display: Tear down dangling pipe on boot to fix s0i3")
  2a5810782369b ("drm/amd/display: program dither on all OPP heads under ODM combine")
  f3403ab74a29f ("drm/amd/display: Add block sequence support for bandwidth programming operations")
  991e0516a8072 ("drm/amd/display: use kvzalloc to allocate struct dc")
  9e0896fa6f7db ("drm/amd/display: avoid large stack allocation in commit_planes_do_stream_update_sequence")
  c1199393ec559 ("drm/amd/display: Refactor surface_update_flags to flat struct with helpers")
  b008c67efb36b ("drm/amd/display: Introduce dc_plane_cm and migrate surface update color path")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/display/dc/core/dc.c
index e25b94b65daca,8d77158229f1b..0000000000000
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@@ -769,22 -769,23 +769,23 @@@ void dc_stream_set_dither_option(struc
  {
  	struct bit_depth_reduction_params params;
  	struct dc_link *link = stream->link;
- 	struct pipe_ctx *pipes = NULL;
+ 	struct resource_context *res_ctx = &link->dc->current_state->res_ctx;
+ 	struct pipe_ctx *otg_master;
+ 	struct pipe_ctx *opp_heads[MAX_PIPES];
+ 	int opp_cnt;
  	int i;
  
- 	for (i = 0; i < MAX_PIPES; i++) {
- 		if (link->dc->current_state->res_ctx.pipe_ctx[i].stream ==
- 				stream) {
- 			pipes = &link->dc->current_state->res_ctx.pipe_ctx[i];
- 			break;
- 		}
- 	}
- 
- 	if (!pipes)
+ 	otg_master = resource_get_otg_master_for_stream(res_ctx, stream);
+ 	if (!otg_master)
  		return;
  	if (option > DITHER_OPTION_MAX)
  		return;
  
+ 	opp_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads);
+ 
+ 	if (opp_cnt == 0)
+ 		return;
+ 
  	dc_exit_ips_for_hw_access(stream->ctx->dc);
  
  	stream->dither_option = option;
@@@ -793,16 -794,30 +794,30 @@@
  	resource_build_bit_depth_reduction_params(stream, &params);
  	stream->bit_depth_params = params;
  
- 	if (pipes->plane_res.xfm &&
- 	    pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth) {
- 		pipes->plane_res.xfm->funcs->transform_set_pixel_storage_depth(
- 			pipes->plane_res.xfm,
- 			pipes->plane_res.scl_data.lb_params.depth,
- 			&stream->bit_depth_params);
- 	}
+ 	/*
+ 	 * Program bit-depth reduction (dither) on every OPP head of the
+ 	 * stream. Under ODM combine there is more than one OPP head and they
+ 	 * must all be kept in sync, otherwise (e.g. when CRC capture requests
+ 	 * dither off) a secondary ODM segment can keep dither enabled and
+ 	 * produce a different CRC than the primary segment.
+ 	 */
+ 	for (i = 0; i < opp_cnt; i++) {
+ 		struct pipe_ctx *opp_head = opp_heads[i];
  
- 	pipes->stream_res.opp->funcs->
- 		opp_program_bit_depth_reduction(pipes->stream_res.opp, &params);
+ 		if (opp_head->plane_res.xfm &&
+ 		    opp_head->plane_res.xfm->funcs->transform_set_pixel_storage_depth) {
+ 			opp_head->plane_res.xfm->funcs->transform_set_pixel_storage_depth(
+ 				opp_head->plane_res.xfm,
+ 				opp_head->plane_res.scl_data.lb_params.depth,
+ 				&stream->bit_depth_params);
+ 		}
+ 
+ 		if (opp_head->stream_res.opp &&
+ 		    opp_head->stream_res.opp->funcs->opp_program_bit_depth_reduction) {
+ 			opp_head->stream_res.opp->funcs->opp_program_bit_depth_reduction(
+ 				opp_head->stream_res.opp, &params);
+ 		}
+ 	}
  }
  
  bool dc_stream_set_gamut_remap(struct dc *dc, const struct dc_stream_state *stream)
@@@ -1930,6 -1945,13 +1945,13 @@@ bool dc_validate_boot_timing(const stru
  		struct display_stream_compressor *dsc = NULL;
  		struct dcn_dsc_state dsc_state = {0};
  
+ 		if (dc->ctx->dce_version < DCN_VERSION_4_2) {
+ 			/*vbios enabled eDP dsc for one of DCN315  only but it has known issue,
+ 			since there is no production bios update, block it there*/
+ 			DC_LOG_DEBUG("boot timing validation failed due to unsupported DSC on this ASIC\n");
+ 			return false;
+ 		}
+ 
  		/* Find DSC associated with this timing generator */
  		if (tg_inst < (unsigned int)dc->res_pool->res_cap->num_dsc) {
  			dsc = dc->res_pool->dscs[tg_inst];
@@@ -2310,7 -2332,7 +2332,7 @@@ static enum dc_status dc_commit_state_n
  	for (i = 0; i < context->stream_count; i++) {
  		uint32_t prev_dsc_changed = context->streams[i]->update_flags.bits.dsc_changed;
  
- 		context->streams[i]->update_flags.raw = 0xFFFFFFFF;
+ 		stream_update_flags_set_full(&context->streams[i]->update_flags);
  		context->streams[i]->update_flags.bits.dsc_changed = prev_dsc_changed;
  	}
  
@@@ -2416,7 -2438,7 +2438,7 @@@
  
  	/* Clear update flags that were set earlier to avoid redundant programming */
  	for (i = 0; i < context->stream_count; i++) {
- 		context->streams[i]->update_flags.raw = 0x0;
+ 		stream_update_flags_clear(&context->streams[i]->update_flags);
  	}
  
  	old_state = dc->current_state;
@@@ -2764,7 -2786,7 +2786,7 @@@ static bool is_surface_in_context
  
  static struct surface_update_descriptor get_plane_info_update_type(const struct dc_surface_update *u)
  {
- 	union surface_update_flags *update_flags = &u->surface->update_flags;
+ 	struct pipe_update_bits *update_bits = &u->surface->update_bits;
  	struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
  
  	if (!u->plane_info)
@@@ -2774,37 -2796,37 +2796,37 @@@
  	elevate_update_type(&update_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  
  	if (u->plane_info->color_space != u->surface->color_space) {
- 		update_flags->bits.color_space_change = 1;
+ 		update_bits->color_space_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) {
- 		update_flags->bits.horizontal_mirror_change = 1;
+ 		update_bits->horizontal_mirror_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->plane_info->rotation != u->surface->rotation) {
- 		update_flags->bits.rotation_change = 1;
+ 		update_bits->rotation_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  
  	if (u->plane_info->format != u->surface->format) {
- 		update_flags->bits.pixel_format_change = 1;
+ 		update_bits->pixel_format_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  
  	if (u->plane_info->stereo_format != u->surface->stereo_format) {
- 		update_flags->bits.stereo_format_change = 1;
+ 		update_bits->stereo_format_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  
  	if (u->plane_info->per_pixel_alpha != u->surface->per_pixel_alpha) {
- 		update_flags->bits.per_pixel_alpha_change = 1;
+ 		update_bits->per_pixel_alpha_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->plane_info->global_alpha_value != u->surface->global_alpha_value) {
- 		update_flags->bits.global_alpha_change = 1;
+ 		update_bits->global_alpha_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  	}
  
@@@ -2816,7 -2838,7 +2838,7 @@@
  		 * stutter period calculation. Triggering a full update will
  		 * recalculate stutter period.
  		 */
- 		update_flags->bits.dcc_change = 1;
+ 		update_bits->dcc_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  
@@@ -2825,25 -2847,25 +2847,25 @@@
  		/* different bytes per element will require full bandwidth
  		 * and DML calculation
  		 */
- 		update_flags->bits.bpp_change = 1;
+ 		update_bits->bpp_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  
  	if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch
  			|| u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) {
- 		update_flags->bits.plane_size_change = 1;
+ 		update_bits->plane_size_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	const struct dc_tiling_info *tiling = &u->plane_info->tiling_info;
  
  	if (memcmp(tiling, &u->surface->tiling_info, sizeof(*tiling)) != 0) {
- 		update_flags->bits.swizzle_change = 1;
+ 		update_bits->swizzle_change = 1;
  
  		if (tiling->flags.avoid_full_update_on_tiling_change) {
  			elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  		} else {
- 			update_flags->bits.bandwidth_change = 1;
+ 			update_bits->bandwidth_change = 1;
  			elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  		}
  	}
@@@ -2853,10 -2875,10 +2875,10 @@@
  }
  
  static struct surface_update_descriptor get_scaling_info_update_type(
- 		const struct dc_check_config *check_config,
- 		const struct dc_surface_update *u)
+ 	const struct dc_check_config *check_config,
+ 	const struct dc_surface_update *u)
  {
- 	union surface_update_flags *update_flags = &u->surface->update_flags;
+ 	struct pipe_update_bits *update_bits = &u->surface->update_bits;
  	struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
  
  	if (!u->scaling_info)
@@@ -2873,26 -2895,26 +2895,26 @@@
  			|| u->scaling_info->clip_rect.height != u->surface->clip_rect.height
  			|| u->scaling_info->scaling_quality.integer_scaling !=
  					u->surface->scaling_quality.integer_scaling) {
- 		update_flags->bits.scaling_change = 1;
+ 		update_bits->scaling_change = 1;
  		elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  
  		if (u->scaling_info->src_rect.width > u->surface->src_rect.width
  				|| u->scaling_info->src_rect.height > u->surface->src_rect.height)
  			/* Making src rect bigger requires a bandwidth change */
- 			update_flags->bits.clock_change = 1;
+ 			update_bits->clock_change = 1;
  
  		if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width
  			|| u->scaling_info->dst_rect.height < u->surface->dst_rect.height)
  				&& (u->scaling_info->dst_rect.width < u->surface->src_rect.width
  					|| u->scaling_info->dst_rect.height < u->surface->src_rect.height))
  			/* Making dst rect smaller requires a bandwidth change */
- 			update_flags->bits.bandwidth_change = 1;
+ 			update_bits->bandwidth_change = 1;
  
  		if (u->scaling_info->src_rect.width > (int)check_config->max_optimizable_video_width &&
  			(u->scaling_info->clip_rect.width > u->surface->clip_rect.width ||
  			 u->scaling_info->clip_rect.height > u->surface->clip_rect.height))
  			 /* Changing clip size of a large surface may result in MPC slice count change */
- 			update_flags->bits.bandwidth_change = 1;
+ 			update_bits->bandwidth_change = 1;
  	}
  
  	if (u->scaling_info->src_rect.x != u->surface->src_rect.x
@@@ -2902,7 -2924,7 +2924,7 @@@
  			|| u->scaling_info->dst_rect.x != u->surface->dst_rect.x
  			|| u->scaling_info->dst_rect.y != u->surface->dst_rect.y) {
  		elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
- 		update_flags->bits.position_change = 1;
+ 		update_bits->position_change = 1;
  	}
  
  	return update_type;
@@@ -2913,15 -2935,15 +2935,15 @@@ static struct surface_update_descripto
  		struct dc_surface_update *u)
  {
  	struct surface_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE };
- 	union surface_update_flags *update_flags = &u->surface->update_flags;
+ 	struct pipe_update_bits *update_bits = &u->surface->update_bits;
  
  	if (u->surface->force_full_update) {
- 		update_flags->raw = 0xFFFFFFFF;
+ 		dc_pipe_update_bits_set_full(update_bits);
  		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  		return overall_type;
  	}
  
- 	update_flags->raw = 0; // Reset all flags
+ 	dc_pipe_update_bits_clear(update_bits);
  
  	struct surface_update_descriptor inner_type = get_plane_info_update_type(u);
  
@@@ -2931,87 -2953,112 +2953,112 @@@
  	elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor);
  
  	if (u->flip_addr) {
- 		update_flags->bits.addr_update = 1;
+ 		update_bits->addr_update = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  
  		if (u->flip_addr->address.tmz_surface != u->surface->address.tmz_surface) {
- 			update_flags->bits.tmz_changed = 1;
+ 			update_bits->tmz_changed = 1;
  			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  		}
  	}
  	if (u->in_transfer_func) {
- 		update_flags->bits.in_transfer_func_change = 1;
+ 		update_bits->in_transfer_func_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->input_csc_color_matrix) {
- 		update_flags->bits.input_csc_change = 1;
+ 		update_bits->input_csc_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->cursor_csc_color_matrix) {
- 		update_flags->bits.cursor_csc_color_matrix_change = 1;
+ 		update_bits->cursor_csc_color_matrix_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->coeff_reduction_factor) {
- 		update_flags->bits.coeff_reduction_change = 1;
+ 		update_bits->coeff_reduction_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
  
  	if (u->gamut_remap_matrix) {
- 		update_flags->bits.gamut_remap_change = 1;
+ 		update_bits->gamut_remap_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
  
- 	if (u->blend_tf || (u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) {
- 		update_flags->bits.gamma_change = 1;
+ 	if ((u->cm && u->cm->flags.bits.blend_enable) ||
+ 			(u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) {
+ 		update_bits->gamma_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
  
- 	if (u->lut3d_func || u->func_shaper) {
- 		update_flags->bits.lut_3d = 1;
+ 	if (u->cm && (u->cm->flags.bits.lut3d_enable || u->cm->flags.bits.shaper_enable)) {
+ 		update_bits->lut_3d = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
  
+ 	if (u->cm && u->cm->flags.bits.lut3d_dma_enable != u->surface->cm.flags.bits.lut3d_dma_enable &&
+ 			u->cm->flags.bits.lut3d_enable && u->surface->cm.flags.bits.lut3d_enable) {
+ 		/* Toggling 3DLUT loading between DMA and Host is illegal */
+ 		BREAK_TO_DEBUGGER();
+ 	}
+ 
+ 	if (u->cm && u->cm->flags.bits.lut3d_enable && !u->cm->flags.bits.lut3d_dma_enable) {
+ 		/* Host loading 3DLUT requires full update but only stream lock  */
+ 		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ 	}
+ 
  	if (u->hdr_mult.value)
  		if (u->hdr_mult.value != u->surface->hdr_mult.value) {
  			// TODO: Should be fast?
- 			update_flags->bits.hdr_mult = 1;
+ 			update_bits->hdr_mult = 1;
  			elevate_update_type(&overall_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM);
  		}
  
  	if (u->sdr_white_level_nits)
  		if (u->sdr_white_level_nits != u->surface->sdr_white_level_nits) {
  			// TODO: Should be fast?
- 			update_flags->bits.sdr_white_level_nits = 1;
+ 			update_bits->sdr_white_level_nits = 1;
  			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  		}
  
  	if (u->cm_hist_control) {
- 		update_flags->bits.cm_hist_change = 1;
+ 		update_bits->cm_hist_change = 1;
  		elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
  	}
- 	if (u->cm2_params) {
- 		if (u->cm2_params->component_settings.shaper_3dlut_setting != u->surface->mcm_shaper_3dlut_setting
- 				|| u->cm2_params->component_settings.lut1d_enable != u->surface->mcm_lut1d_enable
- 				|| u->cm2_params->cm2_luts.lut3d_data.lut3d_src != u->surface->mcm_luts.lut3d_data.lut3d_src) {
- 			update_flags->bits.mcm_transfer_function_enable_change = 1;
+ 
+ 	if (u->cm) {
+ 		const union dc_plane_cm_flags blend_only_flags = {
+ 			.bits = {
+ 				.blend_enable = 1,
+ 			}
+ 		};
+ 
+ 		if (u->cm->flags.bits.shaper_enable != u->surface->cm.flags.bits.shaper_enable
+ 				|| u->cm->flags.bits.blend_enable != u->surface->cm.flags.bits.blend_enable
+ 				|| u->cm->flags.bits.lut3d_enable != u->surface->cm.flags.bits.lut3d_enable
+ 				|| u->cm->flags.bits.lut3d_dma_enable != u->surface->cm.flags.bits.lut3d_dma_enable) {
+ 			update_bits->mcm_transfer_function_enable_change = 1;
+ 			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
+ 		}
+ 
+ 		if ((u->cm->flags.all != blend_only_flags.all && u->cm->flags.all != 0) ||
+ 				(u->surface->cm.flags.all != blend_only_flags.all && u->surface->cm.flags.all != 0)) {
  			elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  		}
  	}
  
- 	if (update_flags->bits.lut_3d &&
- 			u->surface->mcm_luts.lut3d_data.lut3d_src != DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
+ 	if (update_bits->lut_3d &&
+ 			!u->surface->cm.flags.bits.lut3d_dma_enable) {
  		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  
  	if (check_config->enable_legacy_fast_update &&
- 			(update_flags->bits.gamma_change ||
- 			update_flags->bits.gamut_remap_change ||
- 			update_flags->bits.input_csc_change ||
- 			update_flags->bits.cm_hist_change ||
- 			update_flags->bits.coeff_reduction_change)) {
+ 			(update_bits->gamma_change ||
+ 			update_bits->gamut_remap_change ||
+ 			update_bits->input_csc_change ||
+ 			update_bits->cm_hist_change ||
+ 			update_bits->coeff_reduction_change)) {
  		elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
  	}
  	return overall_type;
@@@ -3036,7 -3083,7 +3083,7 @@@ static void force_immediate_gsl_plane_f
  	if (has_flip_immediate_plane && surface_count > 1) {
  		for (i = 0; i < surface_count; i++) {
  			if (updates[i].surface->flip_immediate)
- 				updates[i].surface->update_flags.bits.addr_update = 1;
+ 				updates[i].surface->update_bits.addr_update = 1;
  		}
  	}
  }
@@@ -3191,9 -3238,9 +3238,9 @@@ struct surface_update_descriptor dc_che
  		struct dc_stream_update *stream_update)
  {
  	if (stream_update)
- 		stream_update->stream->update_flags.raw = 0;
+ 		stream_update_flags_clear(&stream_update->stream->update_flags);
  	for (int i = 0; i < surface_count; i++)
- 		updates[i].surface->update_flags.raw = 0;
+ 		dc_pipe_update_bits_clear(&updates[i].surface->update_bits);
  
  	return check_update_surfaces_for_stream(check_config, updates, surface_count, stream_update);
  }
@@@ -3304,24 -3351,55 +3351,55 @@@ static void copy_surface_update_to_plan
  			sizeof(struct dc_transfer_func_distributed_points));
  	}
  
- 	if (srf_update->cm2_params) {
- 		surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting;
- 		surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable;
- 		surface->mcm_luts = srf_update->cm2_params->cm2_luts;
+ 	/* Shaper, 3DLUT, 1DLUT */
+ 	if (srf_update->cm) {
+ 		struct kref refcount = surface->cm.refcount;
+ 
+ 		memcpy(&surface->cm, srf_update->cm, sizeof(surface->cm));
+ 		surface->cm.refcount = refcount;
+ 
+ #ifndef TRIM_CM2
+ 		/* Populate mcm_luts from cm for legacy consumers (dml2, hwseq) */
+ 		surface->mcm_luts.lut1d_func = &surface->cm.blend_func;
+ 		surface->mcm_luts.shaper = &surface->cm.shaper_func;
+ 		if (srf_update->cm->flags.bits.lut3d_dma_enable) {
+ 			surface->mcm_luts.lut3d_data.lut3d_src = DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.addr = surface->cm.lut3d_dma.addr;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.layout =
+ 				(surface->cm.lut3d_dma.swizzle == CM_LUT_3D_SWIZZLE_LINEAR_RGB) ?
+ 					DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB :
+ 				(surface->cm.lut3d_dma.swizzle == CM_LUT_3D_SWIZZLE_LINEAR_BGR) ?
+ 					DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR :
+ 					DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.format =
+ 				(surface->cm.lut3d_dma.format == CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB) ?
+ 					DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB :
+ 				(surface->cm.lut3d_dma.format == CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB) ?
+ 					DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB :
+ 					DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias =
+ 				surface->cm.lut3d_dma.bias;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale =
+ 				surface->cm.lut3d_dma.scale;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.component_order =
+ 				DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA;
+ 			surface->mcm_luts.lut3d_data.gpu_mem_params.size = DC_CM2_GPU_MEM_SIZE_TRANSFORMED;
+ 			surface->mcm_luts.lut3d_data.mpc_3dlut_enable = (srf_update->cm->flags.bits.lut3d_enable != 0);
+ 		} else {
+ 			surface->mcm_luts.lut3d_data.lut3d_src = DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM;
+ 			surface->mcm_luts.lut3d_data.lut3d_func = &surface->cm.lut3d_func;
+ 		}
+ 
+ 		if (srf_update->cm->flags.bits.shaper_enable &&
+ 				srf_update->cm->flags.bits.lut3d_enable)
+ 			surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT;
+ 		else if (srf_update->cm->flags.bits.shaper_enable)
+ 			surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER;
+ 		else
+ 			surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL;
+ #endif /* TRIM_CM2 */
  	}
  
- 	if (srf_update->func_shaper) {
- 		memcpy(&surface->in_shaper_func, srf_update->func_shaper,
- 		sizeof(surface->in_shaper_func));
- 
- 		if (surface->mcm_shaper_3dlut_setting >= DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER)
- 			surface->mcm_luts.shaper = &surface->in_shaper_func;
- 	}
- 
- 	if (srf_update->lut3d_func)
- 		memcpy(&surface->lut3d_func, srf_update->lut3d_func,
- 		sizeof(surface->lut3d_func));
- 
  	if (srf_update->hdr_mult.value)
  		surface->hdr_mult =
  				srf_update->hdr_mult;
@@@ -3330,15 -3408,10 +3408,10 @@@
  		surface->sdr_white_level_nits =
  				srf_update->sdr_white_level_nits;
  
- 	if (srf_update->blend_tf) {
- 		memcpy(&surface->blend_tf, srf_update->blend_tf,
- 		sizeof(surface->blend_tf));
- 
- 		if (surface->mcm_lut1d_enable)
- 			surface->mcm_luts.lut1d_func = &surface->blend_tf;
- 	}
- 
- 	if (srf_update->cm2_params || srf_update->blend_tf)
+ 	if (srf_update->cm &&
+ 			(srf_update->cm->flags.bits.blend_enable ||
+ 			srf_update->cm->flags.bits.shaper_enable ||
+ 			srf_update->cm->flags.bits.lut3d_enable))
  		surface->lut_bank_a = !surface->lut_bank_a;
  
  	if (srf_update->input_csc_color_matrix)
@@@ -3714,11 -3787,11 +3787,11 @@@ static bool update_planes_and_stream_st
  	if (update_type == UPDATE_TYPE_FULL) {
  		if (stream_update) {
  			uint32_t dsc_changed = stream_update->stream->update_flags.bits.dsc_changed;
- 			stream_update->stream->update_flags.raw = 0xFFFFFFFF;
+ 			stream_update_flags_set_full(&stream_update->stream->update_flags);
  			stream_update->stream->update_flags.bits.dsc_changed = dsc_changed;
  		}
  		for (i = 0; i < surface_count; i++)
- 			srf_updates[i].surface->update_flags.raw = 0xFFFFFFFF;
+ 			dc_pipe_update_bits_set_full(&srf_updates[i].surface->update_bits);
  	}
  
  	if (update_type >= update_surface_trace_level)
@@@ -3767,7 -3840,7 +3840,7 @@@
  
  		if (update_type != UPDATE_TYPE_MED)
  			continue;
- 		if (surface->update_flags.bits.position_change) {
+ 		if (surface->update_bits.position_change) {
  			for (j = 0; j < dc->res_pool->pipe_count; j++) {
  				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
  
@@@ -4205,8 -4278,8 +4278,8 @@@ static void commit_planes_do_stream_upd
  					hwss_add_dc_set_optimized_required(&seq_state, dc, true);
  
  				} else {
- 					if (get_seamless_boot_stream_count(context) == 0)
- 						hwss_add_prepare_bandwidth(&seq_state, dc, dc->current_state);
+ 					if (get_seamless_boot_stream_count(context) == 0 && dc->hwss.prepare_bandwidth_sequence)
+ 						dc->hwss.prepare_bandwidth_sequence(dc, dc->current_state, &seq_state);
  					hwss_add_link_set_dpms_on(&seq_state, dc->current_state, dpms_pipe_ctx);
  				}
  			} else if (pipe_ctx->stream->link->wa_flags.blank_stream_on_ocs_change && stream_update->output_color_space
@@@ -4550,14 -4623,23 +4623,23 @@@ static void build_dmub_update_dirty_rec
  	}
  }
  
- static bool check_address_only_update(union surface_update_flags update_flags)
+ /**
+  * dc_check_address_only_update - Check if addr_update is the sole flag set
+  *
+  * @update_bits: The pipe update bits to check
+  *
+  * Determines whether an update contains only an address change with no other
+  * pending updates.
+  *
+  * Return: %true if addr_update is the sole bit set, %false otherwise.
+  */
+ bool dc_check_address_only_update(struct pipe_update_bits update_bits)
  {
- 	union surface_update_flags addr_only_update_flags;
- 	addr_only_update_flags.raw = 0;
- 	addr_only_update_flags.bits.addr_update = 1;
+ 	struct pipe_update_bits check = update_bits;  /* 1. Copy all flags from input */
  
- 	return update_flags.bits.addr_update &&
- 			!(update_flags.raw & ~addr_only_update_flags.raw);
+ 	check.addr_update = 0;                        /* 2. Zero the addr_update bit in the copy */
+ 	return update_bits.addr_update &&             /* 3. Check addr_update was set in original */
+ 			!dc_pipe_update_bits_is_any_set(&check); /* 4. Check no other bits remain in the copy */
  }
  
  /**
@@@ -4617,7 -4699,7 +4699,7 @@@ static void commit_plane_for_stream_off
  				continue;
  
  			/* update pipe context for plane */
- 			if (pipe_ctx->plane_state->update_flags.bits.addr_update)
+ 			if (pipe_ctx->plane_state->update_bits.addr_update)
  				dc->hwss.update_plane_addr(dc, pipe_ctx);
  		}
  	}
@@@ -4655,8 -4737,8 +4737,8 @@@ static void commit_planes_for_stream_fa
  		should_offload_fams2_flip = true;
  		for (i = 0; i < surface_count; i++) {
  			if (srf_updates[i].surface &&
- 					srf_updates[i].surface->update_flags.raw &&
- 					!check_address_only_update(srf_updates[i].surface->update_flags)) {
+ 					dc_pipe_update_bits_is_any_set(&srf_updates[i].surface->update_bits) &&
+ 					!dc_check_address_only_update(srf_updates[i].surface->update_bits)) {
  				/* more than address update, need to acquire FAMS2 lock */
  				should_offload_fams2_flip = false;
  				break;
@@@ -4747,7 -4829,7 +4829,7 @@@
  	 * so no need to clear here.
  	 */
  	if (top_pipe_to_program->stream)
- 		top_pipe_to_program->stream->update_flags.raw = 0;
+ 		stream_update_flags_clear(&top_pipe_to_program->stream->update_flags);
  }
  
  static void commit_planes_for_stream(struct dc *dc,
@@@ -5073,11 -5155,9 +5155,9 @@@
  				if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state))
  					continue;
  
- 				if (srf_updates[i].cm2_params &&
- 						srf_updates[i].cm2_params->cm2_luts.lut3d_data.lut3d_src ==
- 								DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM &&
- 						srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting ==
- 								DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT &&
+ 				if (srf_updates[i].cm &&
+ 						srf_updates[i].cm->flags.bits.lut3d_enable &&
+ 						srf_updates[i].cm->flags.bits.lut3d_dma_enable &&
  						dc->hwss.trigger_3dlut_dma_load)
  					dc->hwss.trigger_3dlut_dma_load(dc, pipe_ctx);
  
@@@ -5087,7 -5167,7 +5167,7 @@@
  					dc->hwss.program_triplebuffer(
  						dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
  				}
- 				if (pipe_ctx->plane_state->update_flags.bits.addr_update)
+ 				if (pipe_ctx->plane_state->update_bits.addr_update)
  					dc->hwss.update_plane_addr(dc, pipe_ctx);
  			}
  		}
@@@ -5178,7 -5258,7 +5258,7 @@@
  
  		if (pipe_ctx->bottom_pipe || pipe_ctx->next_odm_pipe ||
  				!pipe_ctx->stream || !should_update_pipe_for_stream(context, pipe_ctx, stream) ||
- 				!pipe_ctx->plane_state->update_flags.bits.addr_update ||
+ 				!pipe_ctx->plane_state->update_bits.addr_update ||
  				pipe_ctx->plane_state->skip_manual_trigger)
  			continue;
  
@@@ -5617,7 -5697,7 +5697,7 @@@ static bool commit_minimal_transition_s
  	/* force full surface update */
  	for (i = 0; i < dc->current_state->stream_count; i++) {
  		for (j = 0; j < (unsigned int)dc->current_state->stream_status[i].plane_count; j++) {
- 			dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF;
+ 			dc_pipe_update_bits_set_full(&dc->current_state->stream_status[i].plane_states[j]->update_bits);
  		}
  	}
  
@@@ -5792,14 -5872,9 +5872,9 @@@ static bool full_update_required
  				(srf_updates[i].sdr_white_level_nits &&
  				srf_updates[i].sdr_white_level_nits != srf_updates->surface->sdr_white_level_nits) ||
  				srf_updates[i].in_transfer_func ||
- 				srf_updates[i].func_shaper ||
- 				srf_updates[i].lut3d_func ||
  				srf_updates[i].surface->force_full_update ||
  				(srf_updates[i].flip_addr &&
- 				srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface) ||
- 				(srf_updates[i].cm2_params &&
- 				 (srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting != srf_updates[i].surface->mcm_shaper_3dlut_setting ||
- 				  srf_updates[i].cm2_params->component_settings.lut1d_enable != srf_updates[i].surface->mcm_lut1d_enable))))
+ 				srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface)))
  			return true;
  	}
  
@@@ -6063,17 -6138,17 +6138,17 @@@ static bool update_planes_and_stream_v3
  	return true;
  }
  
- static void clear_update_flags(struct dc_surface_update *srf_updates,
+ static void clear_update_bits(struct dc_surface_update *srf_updates,
  	int surface_count, struct dc_stream_state *stream)
  {
  	int i;
  
  	if (stream)
- 		stream->update_flags.raw = 0;
+ 		stream_update_flags_clear(&stream->update_flags);
  
  	for (i = 0; i < surface_count; i++)
  		if (srf_updates[i].surface)
- 			srf_updates[i].surface->update_flags.raw = 0;
+ 			dc_pipe_update_bits_clear(&srf_updates[i].surface->update_bits);
  }
  
  bool dc_update_planes_and_stream(struct dc *dc,
@@@ -6125,7 -6200,7 +6200,7 @@@ void dc_commit_updates_for_stream(struc
  	}
  
  	if (ret && dc->ctx->dce_version >= DCN_VERSION_3_2)
- 		clear_update_flags(srf_updates, surface_count, stream);
+ 		clear_update_bits(srf_updates, surface_count, stream);
  }
  
  uint8_t dc_get_current_stream_count(struct dc *dc)
@@@ -6165,6 -6240,115 +6240,6 @@@ void dc_interrupt_ack(struct dc *dc, en
  	dal_irq_service_ack(dc->res_pool->irqs, src);
  }
  
 -/* Preserve this tg if a physical link is still lighting a present display */
 -static bool should_preserve_tg(struct dc *dc, struct timing_generator *tg)
 -{
 -	unsigned int i, j;
 -
 -	/* Check if a physical link is lighting this tg */
 -	for (i = 0; i < dc->link_count; i++) {
 -		struct dc_link *link = dc->links[i];
 -		int fe;
 -
 -		if (!link || link->ep_type != DISPLAY_ENDPOINT_PHY ||
 -				!link->link_enc ||
 -				!link->link_enc->funcs->is_dig_enabled ||
 -				!link->link_enc->funcs->is_dig_enabled(link->link_enc) ||
 -				!link->link_enc->funcs->get_dig_frontend)
 -			continue;
 -
 -		/* Get the DIG front-end this link's encoder drives; skip if none */
 -		fe = link->link_enc->funcs->get_dig_frontend(link->link_enc);
 -		if (fe == ENGINE_ID_UNKNOWN)
 -			continue;
 -
 -		/* Find the stream encoder bound to this link's front-end */
 -		for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
 -			struct stream_encoder *se = dc->res_pool->stream_enc[j];
 -
 -			/* Skip unless this stream encoder feeds our front-end and drives this tg */
 -			if (se->id != fe || !se->funcs->dig_source_otg ||
 -					(int)se->funcs->dig_source_otg(se) != tg->inst)
 -				continue;
 -
 -			/* This link drives the OTG: keep a seamless-boot eDP, or
 -			 * any external link whose sink is still connected.
 -			 */
 -			if (link->connector_signal == SIGNAL_TYPE_EDP)
 -				return true;
 -			if (link->link_enc->funcs->get_hpd_state &&
 -					dc->link_srv->get_hpd_state(link))
 -				return true;
 -		}
 -	}
 -
 -	return false;
 -}
 -
 -/*
 - * GOP/vBIOS may leave an OPTC enabled for a display present at power-on but no
 - * longer driven (e.g. external DP unplugged at boot). Such a dangling pipe keeps
 - * DCN out of idle and blocks s0i3. If nothing needs to survive (no committed
 - * stream or seamless-boot eDP) and no sink is still connected, power down all hw
 - * blocks.
 - */
 -void dc_disable_dangling_timing_generators(struct dc *dc)
 -{
 -	struct dce_hwseq *hws = dc->hwseq;
 -	bool any_dangling = false;
 -	bool any_preserved = false;
 -	bool any_connected = false;
 -	unsigned int i;
 -
 -	/* No real hw to touch on a virtual/emulated environment */
 -	if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW)
 -		return;
 -
 -	/* Wake hw out of IPS before reading/touching tg state */
 -	dc_exit_ips_for_hw_access(dc);
 -
 -	/* Classify every enabled tg as either to-preserve or dangling */
 -	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
 -		struct timing_generator *tg = dc->res_pool->timing_generators[i];
 -
 -		if (!tg || !tg->funcs->is_tg_enabled ||
 -				!tg->funcs->is_tg_enabled(tg))
 -			continue;
 -
 -		if (should_preserve_tg(dc, tg))
 -			any_preserved = true;
 -		else
 -			any_dangling = true;
 -	}
 -
 -	/* A physically connected sink (HPD asserted) will be re-lit by a
 -	 * subsequent atomic commit. For that case we don't call the global
 -	 * power_down().
 -	 */
 -	for (i = 0; i < dc->link_count; i++) {
 -		struct dc_link *link = dc->links[i];
 -
 -		if (link && link->ep_type == DISPLAY_ENDPOINT_PHY &&
 -				link->link_enc && link->link_enc->funcs &&
 -				link->link_enc->funcs->get_hpd_state &&
 -				dc->link_srv->get_hpd_state(link)) {
 -			any_connected = true;
 -			break;
 -		}
 -	}
 -
 -	if (!any_dangling)
 -		return;
 -
 -	if (!any_preserved && !any_connected && hws && hws->funcs.power_down) {
 -		/* Truly headless / all sinks unplugged: nothing to preserve */
 -		DC_LOG_DC("%s: powering down dangling hw blocks to allow idle\n",
 -				__func__);
 -		hws->funcs.power_down(dc);
 -		return;
 -	}
 -}
 -
  /*
   * dc_get_flip_pending_on_otg() - Check if a GRPH_FLIP is still pending on OTG
   *
@@@ -6183,7 -6367,7 +6258,7 @@@
  bool dc_get_flip_pending_on_otg(struct dc *dc, int otg_inst)
  {
  	bool flip_pending = false;
- 	int i;
+ 	unsigned int i;
  
  	if (!dc || !dc->current_state)
  		return false;
@@@ -7587,7 -7771,7 +7662,7 @@@ bool dc_capture_register_software_state
  			struct dc_plane_state *plane_state = pipe_ctx->plane_state;
  
  			/* MPCC blending tree and mode control - capture actual blend configuration */
- 			state->mpc.mpcc_mode[i] = (plane_state->blend_tf.type != TF_TYPE_BYPASS) ? 1 : 0;
+ 			state->mpc.mpcc_mode[i] = (plane_state->cm.blend_func.type != TF_TYPE_BYPASS) ? 1 : 0;
  			state->mpc.mpcc_alpha_blend_mode[i] = plane_state->per_pixel_alpha ? 1 : 0;
  			state->mpc.mpcc_alpha_multiplied_mode[i] = plane_state->pre_multiplied_alpha ? 1 : 0;
  			state->mpc.mpcc_blnd_active_overlap_only[i] = 0; /* Default - no overlap restriction */
@@@ -7920,7 -8104,7 +7995,7 @@@ struct dc_update_scratch_space 
  	struct dc_stream_state *stream;
  	struct dc_stream_update *stream_update;
  	bool update_v3;
- 	bool do_clear_update_flags;
+ 	bool do_clear_update_bits;
  	enum surface_update_type update_type;
  	struct dc_state *new_context;
  	enum update_v3_flow flow;
@@@ -7963,8 -8147,8 +8038,8 @@@ static bool update_planes_and_stream_cl
  		const struct dc_update_scratch_space *scratch
  )
  {
- 	if (scratch->do_clear_update_flags)
- 		clear_update_flags(scratch->surface_updates, scratch->surface_count, scratch->stream);
+ 	if (scratch->do_clear_update_bits)
+ 		clear_update_bits(scratch->surface_updates, scratch->surface_count, scratch->stream);
  
  	return false;
  }
@@@ -8218,8 -8402,8 +8293,8 @@@ static bool update_planes_and_stream_cl
  		ASSERT(false);
  	}
  
- 	if (scratch->do_clear_update_flags)
- 		clear_update_flags(scratch->surface_updates, scratch->surface_count, scratch->stream);
+ 	if (scratch->do_clear_update_bits)
+ 		clear_update_bits(scratch->surface_updates, scratch->surface_count, scratch->stream);
  
  	return false;
  }
@@@ -8242,7 -8426,7 +8317,7 @@@ struct dc_update_scratch_space *dc_upda
  		.stream = stream,
  		.stream_update = stream_update,
  		.update_v3 = version >= DCN_VERSION_4_01 || version == DCN_VERSION_3_2 || version == DCN_VERSION_3_21,
- 		.do_clear_update_flags = version >= DCN_VERSION_1_0,
+ 		.do_clear_update_bits = version >= DCN_VERSION_1_0,
  	};
  
  	return scratch;

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 14:40 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Jesse Zhang, Linux Kernel Mailing List,
	Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 14782 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c

between commits:

  614e8a989d462 ("drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue")
  cee666427f280 ("drm/amdgpu/userq: fix indefinite fence wait during GPU reset")

from the drm-fixes tree and commits:

  8396b9de4198a ("drm/amdgpu: trigger GPU recovery when userq destroy fails to unmap a hung queue")
  9102b39fa924d ("drm/amdgpu/userq: fix indefinite fence wait during GPU reset")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 572f2949cb64e,babaabe2d891d..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@@ -33,6 -33,7 +33,7 @@@
  #include "amdgpu_userq.h"
  #include "amdgpu_hmm.h"
  #include "amdgpu_userq_fence.h"
+ #include "amdgpu_trace.h"
  
  u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev)
  {
@@@ -88,14 -89,7 +89,7 @@@ static void amdgpu_userq_mgr_reset_work
  		container_of(work, struct amdgpu_userq_mgr,
  			     reset_work);
  	struct amdgpu_device *adev = uq_mgr->adev;
- 	const int queue_types[] = {
- 		AMDGPU_RING_TYPE_COMPUTE,
- 		AMDGPU_RING_TYPE_GFX,
- 		AMDGPU_RING_TYPE_SDMA
- 	};
- 	const int num_queue_types = ARRAY_SIZE(queue_types);
- 	bool gpu_reset = false;
- 	int i, r;
+ 	struct amdgpu_reset_context reset_context;
  
  	if (unlikely(adev->debug_disable_gpu_ring_reset)) {
  		dev_err(adev->dev, "userq reset disabled by debug mask\n");
@@@ -109,42 -103,15 +103,15 @@@
  	if (!amdgpu_gpu_recovery)
  		return;
  
- 	/*
- 	 * Iterate through all queue types to detect and reset problematic queues
- 	 * Process each queue type in the defined order
- 	 */
- 	for (i = 0; i < num_queue_types; i++) {
- 		int ring_type = queue_types[i];
- 		const struct amdgpu_userq_funcs *funcs =
- 			adev->userq_funcs[ring_type];
+ 	memset(&reset_context, 0, sizeof(reset_context));
  
- 		if (!amdgpu_userq_is_reset_type_supported(adev, ring_type,
- 							  AMDGPU_RESET_TYPE_PER_QUEUE))
- 				continue;
+ 	reset_context.method = AMD_RESET_METHOD_NONE;
+ 	reset_context.reset_req_dev = adev;
+ 	reset_context.src = AMDGPU_RESET_SRC_USERQ;
+ 	set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
+ 	/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
  
- 		if (atomic_read(&uq_mgr->userq_count[ring_type]) > 0 &&
- 		    funcs && funcs->detect_and_reset) {
- 			r = funcs->detect_and_reset(adev, ring_type);
- 			if (r) {
- 				gpu_reset = true;
- 				break;
- 			}
- 		}
- 	}
- 
- 	if (gpu_reset) {
- 		struct amdgpu_reset_context reset_context;
- 
- 		memset(&reset_context, 0, sizeof(reset_context));
- 
- 		reset_context.method = AMD_RESET_METHOD_NONE;
- 		reset_context.reset_req_dev = adev;
- 		reset_context.src = AMDGPU_RESET_SRC_USERQ;
- 		set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
- 		/*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/
- 
- 		amdgpu_device_gpu_recover(adev, NULL, &reset_context);
- 	}
+ 	amdgpu_device_gpu_recover(adev, NULL, &reset_context);
  }
  
  static void amdgpu_userq_hang_detect_work(struct work_struct *work)
@@@ -152,12 -119,45 +119,45 @@@
  	struct amdgpu_usermode_queue *queue =
  		container_of(work, struct amdgpu_usermode_queue,
  			     hang_detect_work.work);
+ 	struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
+ 	struct amdgpu_device *adev = uq_mgr->adev;
+ 	const struct amdgpu_userq_funcs *userq_funcs =
+ 		adev->userq_funcs[queue->queue_type];
+ 	bool gpu_reset = false;
+ 
+ 	if (unlikely(adev->debug_disable_gpu_ring_reset)) {
+ 		dev_err(adev->dev, "userq reset disabled by debug mask\n");
+ 		return;
+ 	}
+ 
+ 	/*
+ 	 * If GPU recovery feature is disabled system-wide,
+ 	 * skip all reset detection logic
+ 	 */
+ 	if (!amdgpu_gpu_recovery)
+ 		return;
+ 
+ 	if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type,
+ 						 AMDGPU_RESET_TYPE_PER_QUEUE)) {
+ 		int r;
+ 
+ 		if (queue->queue_type == AMDGPU_HW_IP_COMPUTE)
+ 			r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL,
+ 							 queue, NULL, NULL);
+ 		else
+ 			r = userq_funcs->reset(queue);
+ 		if (r)
+ 			gpu_reset = true;
+ 	} else {
+ 		gpu_reset = true;
+ 	}
  
  	/*
  	 * Don't schedule the work here! Scheduling or queue work from one reset
  	 * handler to another is illegal if you don't take extra precautions!
  	 */
- 	amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
+ 	if (gpu_reset)
+ 		amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work);
  }
  
  /*
@@@ -293,11 -293,15 +293,15 @@@ static int amdgpu_userq_preempt_helper(
  	int r;
  
  	if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
+ 		trace_amdgpu_userq_state_start(queue);
+ 
  		r = userq_funcs->preempt(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  			return r;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_PREEMPTED);
  			queue->state = AMDGPU_USERQ_STATE_PREEMPTED;
  		}
  	}
@@@ -313,10 -317,14 +317,14 @@@ static int amdgpu_userq_restore_helper(
  	int r = 0;
  
  	if (queue->state == AMDGPU_USERQ_STATE_PREEMPTED) {
+ 		trace_amdgpu_userq_state_start(queue);
+ 
  		r = userq_funcs->restore(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
  			queue->state = AMDGPU_USERQ_STATE_MAPPED;
  		}
  	}
@@@ -334,12 -342,15 +342,15 @@@ static int amdgpu_userq_unmap_helper(st
  
  	if ((queue->state == AMDGPU_USERQ_STATE_MAPPED) ||
  	    (queue->state == AMDGPU_USERQ_STATE_PREEMPTED)) {
+ 		trace_amdgpu_userq_state_start(queue);
  
  		r = userq_funcs->unmap(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  			return r;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_UNMAPPED);
  			queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
  		}
  	}
@@@ -356,11 -367,15 +367,15 @@@ static int amdgpu_userq_map_helper(stru
  	int r;
  
  	if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) {
+ 		trace_amdgpu_userq_state_start(queue);
+ 
  		r = userq_funcs->map(queue);
  		if (r) {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  			return r;
  		} else {
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
  			queue->state = AMDGPU_USERQ_STATE_MAPPED;
  		}
  	}
@@@ -507,6 -522,8 +522,8 @@@ amdgpu_userq_destroy(struct amdgpu_user
  	const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type];
  	int r = 0;
  
+ 	trace_amdgpu_userq_destroy_start(queue);
+ 
  	cancel_delayed_work_sync(&uq_mgr->resume_work);
  
  	/* Cancel any pending hang detection work and cleanup */
@@@ -541,6 -558,7 +558,7 @@@
  	amdgpu_bo_unreserve(queue->db_obj.obj);
  	amdgpu_bo_unref(&queue->db_obj.obj);
  
+ 	trace_amdgpu_userq_destroy_end(queue, r);
  	kfree(queue);
  
  	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@@ -638,6 -656,8 +656,8 @@@ amdgpu_userq_create(struct drm_file *fi
  	queue->queue_type = args->in.ip_type;
  	queue->vm = &fpriv->vm;
  	queue->priority = priority;
+ 	queue->xcp_id = (fpriv->xcp_id != AMDGPU_XCP_NO_PARTITION) ?
+ 				fpriv->xcp_id : 0;
  	queue->userq_mgr = uq_mgr;
  	INIT_DELAYED_WORK(&queue->hang_detect_work,
  			  amdgpu_userq_hang_detect_work);
@@@ -680,6 -700,8 +700,8 @@@
  	}
  
  	queue->doorbell_index = index;
+ 	queue->doorbell_offset = (u32)args->in.doorbell_offset;
+ 	trace_amdgpu_userq_create_start(queue);
  	r = uq_funcs->mqd_create(queue, &args->in);
  	if (r) {
  		drm_file_err(uq_mgr->file, "Failed to create Queue\n");
@@@ -703,6 -725,7 +725,7 @@@
  		r = amdgpu_userq_map_helper(queue);
  		if (r) {
  			drm_file_err(uq_mgr->file, "Failed to map Queue\n");
+ 			trace_amdgpu_userq_create_end(queue, r);
  			mutex_unlock(&uq_mgr->userq_mutex);
  			goto erase_doorbell;
  		}
@@@ -719,11 -742,13 +742,13 @@@
  		 * This drops the last reference which should take care of
  		 * all cleanup.
  		 */
+ 		trace_amdgpu_userq_create_end(queue, r);
  		amdgpu_userq_put(queue);
  		return r;
  	}
  
  	amdgpu_debugfs_userq_init(filp, queue, qid);
+ 	trace_amdgpu_userq_create_end(queue, 0);
  	args->out.queue_id = qid;
  	return 0;
  
@@@ -739,6 -764,7 +764,7 @@@ clean_doorbell_bo
  free_fence_drv:
  	amdgpu_userq_fence_driver_free(queue);
  free_queue:
+ 	trace_amdgpu_userq_create_end(queue, r);
  	kfree(queue);
  err_pm_runtime:
  	pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@@ -871,16 -897,10 +897,10 @@@ int amdgpu_userq_ioctl(struct drm_devic
  static int
  amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
  {
- 	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
- 	struct amdgpu_vm *vm = &fpriv->vm;
  	struct amdgpu_usermode_queue *queue;
  	unsigned long queue_id;
  	int ret = 0, r;
  
- 
- 	if (amdgpu_bo_reserve(vm->root.bo, false))
- 		return false;
- 
  	mutex_lock(&uq_mgr->userq_mutex);
  	/* Resume all the queues for this process */
  	xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
@@@ -888,6 -908,7 +908,7 @@@
  		if (!amdgpu_userq_buffer_vas_mapped(queue)) {
  			drm_file_err(uq_mgr->file,
  				     "trying restore queue without va mapping\n");
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_INVALID_VA);
  			queue->state = AMDGPU_USERQ_STATE_INVALID_VA;
  			continue;
  		}
@@@ -895,10 -916,8 +916,8 @@@
  		r = amdgpu_userq_map_helper(queue);
  		if (r)
  			ret = r;
- 
  	}
  	mutex_unlock(&uq_mgr->userq_mutex);
- 	amdgpu_bo_unreserve(vm->root.bo);
  
  	if (ret)
  		drm_file_err(uq_mgr->file,
@@@ -932,7 -951,8 +951,8 @@@ amdgpu_userq_bo_validate(struct amdgpu_
  		spin_unlock(&vm->individual_lock);
  
  		bo = bo_va->base.bo;
- 		ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 2);
+ 		ret = drm_exec_prepare_obj(exec, &bo->tbo.base,
+ 					   TTM_NUM_MOVE_FENCES + 1);
  		if (unlikely(ret))
  			return ret;
  
@@@ -955,7 -975,7 +975,7 @@@
  
  /* Make sure the whole VM is ready to be used */
  static int
- amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr)
+ amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr)
  {
  	struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr);
  	bool invalidated = false, new_addition = false;
@@@ -1081,8 -1101,12 +1101,12 @@@ retry_lock
  	dma_fence_wait(vm->last_update, false);
  
  	ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec);
- 	if (ret)
+ 	if (ret) {
  		drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n");
+ 		goto unlock_all;
+ 	}
+ 
+ 	ret = amdgpu_userq_restore_all(uq_mgr);
  
  unlock_all:
  	drm_exec_fini(&exec);
@@@ -1108,18 -1132,34 +1132,34 @@@ static void amdgpu_userq_restore_worker
  	if (!dma_fence_is_signaled(ev_fence))
  		goto put_fence;
  
- 	ret = amdgpu_userq_vm_validate(uq_mgr);
+ 	ret = amdgpu_userq_vm_validate_and_restore_queue(uq_mgr);
  	if (ret) {
  		drm_file_err(uq_mgr->file, "Failed to validate BOs to restore ret=%d\n", ret);
  		goto put_fence;
  	}
  
- 	amdgpu_userq_restore_all(uq_mgr);
- 
  put_fence:
  	dma_fence_put(ev_fence);
  }
  
+ void amdgpu_userq_process_reset_irq(struct amdgpu_device *adev,
+ 				    u32 pasid, u32 doorbell_offset)
+ {
+ 	struct xarray *xa = &adev->userq_doorbell_xa;
+ 	struct amdgpu_usermode_queue *queue;
+ 	unsigned long flags, idx;
+ 
+ 	xa_lock_irqsave(xa, flags);
+ 	xa_for_each(xa, idx, queue) {
+ 		if (queue->vm && queue->vm->pasid == pasid &&
+ 		    queue->doorbell_offset == doorbell_offset) {
+ 			amdgpu_userq_start_hang_detect_work(queue);
+ 			break;
+ 		}
+ 	}
+ 	xa_unlock_irqrestore(xa, flags);
+ }
+ 
  static int
  amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
  {
@@@ -1175,6 -1215,7 +1215,7 @@@ int amdgpu_userq_mgr_init(struct amdgpu
  	xa_init_flags(&userq_mgr->userq_xa, XA_FLAGS_ALLOC);
  	userq_mgr->adev = adev;
  	userq_mgr->file = file_priv;
+ 	mutex_init(&userq_mgr->proc_ctx_lock);
  
  	INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
  	INIT_WORK(&userq_mgr->reset_work, amdgpu_userq_mgr_reset_work);
@@@ -1228,6 -1269,11 +1269,11 @@@ void amdgpu_userq_mgr_fini(struct amdgp
  	 */
  	cancel_work_sync(&userq_mgr->reset_work);
  
+ 	amdgpu_bo_free_kernel(&userq_mgr->proc_ctx_obj.obj,
+ 			      &userq_mgr->proc_ctx_obj.gpu_addr,
+ 			      &userq_mgr->proc_ctx_obj.cpu_ptr);
+ 
+ 	mutex_destroy(&userq_mgr->proc_ctx_lock);
  	mutex_destroy(&userq_mgr->userq_mutex);
  }
  
@@@ -1377,12 -1423,14 +1423,14 @@@ void amdgpu_userq_pre_reset(struct amdg
  	/* TODO: We probably need a new lock for the queue state */
  	xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
  		if (queue->state == AMDGPU_USERQ_STATE_MAPPED) {
+ 			trace_amdgpu_userq_state_start(queue);
  			userq_funcs = adev->userq_funcs[queue->queue_type];
  			userq_funcs->unmap(queue);
  			/* just mark all queues as hung at this point.
  			 * if unmap succeeds, we could map again
  			 * in amdgpu_userq_post_reset() if vram is not lost
  			 */
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG);
  			queue->state = AMDGPU_USERQ_STATE_HUNG;
  		}
  		/* Force-complete any pending fence regardless of queue state so
@@@ -1406,6 -1454,8 +1454,8 @@@ int amdgpu_userq_post_reset(struct amdg
  
  	xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) {
  		if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) {
+ 			trace_amdgpu_userq_state_start(queue);
+ 
  			userq_funcs = adev->userq_funcs[queue->queue_type];
  			/* Re-map queue */
  			r = userq_funcs->map(queue);
@@@ -1413,6 -1463,7 +1463,7 @@@
  				dev_err(adev->dev, "Failed to remap queue %ld\n", queue_id);
  				continue;
  			}
+ 			trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED);
  			queue->state = AMDGPU_USERQ_STATE_MAPPED;
  		}
  	}

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: linux-next: build failure in the final build
From: Johan Hovold @ 2026-07-17 14:40 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Manuel Ebner, Mark Brown, Linux Kernel Mailing List,
	Linux Next Mailing List
In-Reply-To: <2026071734-papyrus-unmovable-5826@gregkh>

On Fri, Jul 17, 2026 at 04:35:44PM +0200, Greg Kroah-Hartman wrote:
> On Fri, Jul 17, 2026 at 03:47:55PM +0200, Manuel Ebner wrote:
> > Hi Mark, 
> > 
> > On Wed, 2026-07-15 at 16:37 +0100, Mark Brown wrote:
> > > On Mon, Jul 13, 2026 at 06:48:32PM +0100, Mark Brown wrote:
> > > > Hi all,
> > > > 
> > > > In the final builds, today's linux-next build (arm64 allyesconfig)
> > > > failed like this:
> > > 
> > > This error is due to a71f5aef1be98 (USB: gadget: fsl-udc: enable compile
> > > testing) from the usb tree, a dependency change as expected.  I'll do
> > > something about this tomorrow.
> > 
> > I stumbled across the same build errors. Are you still on this?
> 
> Should I revert that commit to resolve this?

I think we should fix the broken driver that is now being built instead.

I was also waiting on Mark to follow up on this, otherwise I can take
closer look at it.

Based on a quick look it seemed like Mark was right about missing static
keywords in a driver indirectly enabled by the "offending" commit.

Johan

^ permalink raw reply

* linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 14:40 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Linux Kernel Mailing List, Linux Next Mailing List,
	Mario Limonciello

[-- Attachment #1: Type: text/plain, Size: 16124 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c

between commit:

  8ad5ab4da7db2 ("drm/amdgpu: Disable PCIe dynamic speed switching on Ryzen Pinnacle Ridge")

from the drm-fixes tree and commits:

  9ceb4e034a327 ("drm/amdgpu: Disable PCIe dynamic speed switching on Ryzen Pinnacle Ridge")
  a57c68224d739 ("drm/amd: Move dynamic PCIe switching quirks to X86_MATCH_* macros")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index e5f26e5892bac,472e96ae884e5..0000000000000
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@@ -72,8 -72,10 +72,10 @@@
  
  #include "amdgpu_xgmi.h"
  #include "amdgpu_ras.h"
+ #include "amdgpu_wb.h"
  #include "amdgpu_ras_mgr.h"
  #include "amdgpu_pmu.h"
+ #include "amdgpu_smu.h"
  #include "amdgpu_fru_eeprom.h"
  #include "amdgpu_reset.h"
  #include "amdgpu_virt.h"
@@@ -1005,109 -1007,6 +1007,6 @@@ int amdgpu_device_pci_reset(struct amdg
  	return pci_reset_function(adev->pdev);
  }
  
- /*
-  * amdgpu_device_wb_*()
-  * Writeback is the method by which the GPU updates special pages in memory
-  * with the status of certain GPU events (fences, ring pointers,etc.).
-  */
- 
- /**
-  * amdgpu_device_wb_fini - Disable Writeback and free memory
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * Disables Writeback and frees the Writeback memory (all asics).
-  * Used at driver shutdown.
-  */
- static void amdgpu_device_wb_fini(struct amdgpu_device *adev)
- {
- 	if (adev->wb.wb_obj) {
- 		amdgpu_bo_free_kernel(&adev->wb.wb_obj,
- 				      &adev->wb.gpu_addr,
- 				      (void **)&adev->wb.wb);
- 		adev->wb.wb_obj = NULL;
- 	}
- }
- 
- /**
-  * amdgpu_device_wb_init - Init Writeback driver info and allocate memory
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * Initializes writeback and allocates writeback memory (all asics).
-  * Used at driver startup.
-  * Returns 0 on success or an -error on failure.
-  */
- static int amdgpu_device_wb_init(struct amdgpu_device *adev)
- {
- 	int r;
- 
- 	if (adev->wb.wb_obj == NULL) {
- 		/* AMDGPU_MAX_WB * sizeof(uint32_t) * 8 = AMDGPU_MAX_WB 256bit slots */
- 		r = amdgpu_bo_create_kernel(adev, AMDGPU_MAX_WB * sizeof(uint32_t) * 8,
- 					    PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
- 					    &adev->wb.wb_obj, &adev->wb.gpu_addr,
- 					    (void **)&adev->wb.wb);
- 		if (r) {
- 			dev_warn(adev->dev, "(%d) create WB bo failed\n", r);
- 			return r;
- 		}
- 
- 		adev->wb.num_wb = AMDGPU_MAX_WB;
- 		memset(&adev->wb.used, 0, sizeof(adev->wb.used));
- 
- 		/* clear wb memory */
- 		memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8);
- 	}
- 
- 	return 0;
- }
- 
- /**
-  * amdgpu_device_wb_get - Allocate a wb entry
-  *
-  * @adev: amdgpu_device pointer
-  * @wb: wb index
-  *
-  * Allocate a wb slot for use by the driver (all asics).
-  * Returns 0 on success or -EINVAL on failure.
-  */
- int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb)
- {
- 	unsigned long flags, offset;
- 
- 	spin_lock_irqsave(&adev->wb.lock, flags);
- 	offset = find_first_zero_bit(adev->wb.used, adev->wb.num_wb);
- 	if (offset < adev->wb.num_wb) {
- 		__set_bit(offset, adev->wb.used);
- 		spin_unlock_irqrestore(&adev->wb.lock, flags);
- 		*wb = offset << 3; /* convert to dw offset */
- 		return 0;
- 	} else {
- 		spin_unlock_irqrestore(&adev->wb.lock, flags);
- 		return -EINVAL;
- 	}
- }
- 
- /**
-  * amdgpu_device_wb_free - Free a wb entry
-  *
-  * @adev: amdgpu_device pointer
-  * @wb: wb index
-  *
-  * Free a wb slot allocated for use by the driver (all asics)
-  */
- void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb)
- {
- 	unsigned long flags;
- 
- 	wb >>= 3;
- 	spin_lock_irqsave(&adev->wb.lock, flags);
- 	if (wb < adev->wb.num_wb)
- 		__clear_bit(wb, adev->wb.used);
- 	spin_unlock_irqrestore(&adev->wb.lock, flags);
- }
- 
  /**
   * amdgpu_device_resize_fb_bar - try to resize FB BAR
   *
@@@ -1304,37 -1203,44 +1203,44 @@@ bool amdgpu_device_seamless_boot_suppor
  	return amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0);
  }
  
- /*
-  * Intel hosts such as Rocket Lake, Alder Lake, Raptor Lake and Sapphire Rapids
-  * don't support dynamic speed switching. Until we have confirmation from Intel
-  * that a specific host supports it, it's safer that we keep it disabled for all.
-  *
-  * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/
-  * https://gitlab.freedesktop.org/drm/amd/-/issues/2663
-  */
- static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev)
- {
  #if IS_ENABLED(CONFIG_X86)
- 	struct cpuinfo_x86 *c = &cpu_data(0);
- 
- 	/* eGPU change speeds based on USB4 fabric conditions */
- 	if (dev_is_removable(adev->dev))
- 		return true;
- 
- 	if (c->x86_vendor == X86_VENDOR_INTEL)
- 		return false;
- 
+ static const struct x86_cpu_id amdgpu_pcie_dynamic_switching_quirks[] = {
+ 	/*
+ 	 * Intel hosts such as Rocket Lake, Alder Lake, Raptor Lake and Sapphire Rapids
+ 	 * don't support dynamic speed switching. Until we have confirmation from Intel
+ 	 * that a specific host supports it, it's safer that we keep it disabled for all.
+ 	 *
+ 	 * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/
+ 	 * https://gitlab.freedesktop.org/drm/amd/-/issues/2663
+ 	 */
+ 	X86_MATCH_VENDOR_FAM(INTEL, X86_FAMILY_ANY, NULL),
  	/*
  	 * AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs don't
  	 * support PCIe dynamic speed switching.
  	 * https://gitlab.freedesktop.org/drm/amd/-/work_items/5436
  	 */
- 	if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 0x17 &&
- 	    c->x86_model == 0x08)
+ 	X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x08, NULL),
+ 	{}
+ };
+ 
+ static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev)
+ {
+ 	/* eGPU change speeds based on USB4 fabric conditions */
+ 	if (dev_is_removable(adev->dev))
+ 		return true;
+ 
+ 	/* Hosts have problems with dynamic speed switching */
+ 	if (x86_match_cpu(amdgpu_pcie_dynamic_switching_quirks))
  		return false;
- #endif
+ 
  	return true;
  }
+ #else
+ static inline bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev)
+ {
+ 	return true;
+ }
+ #endif
  
  static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
  {
@@@ -2140,6 -2046,8 +2046,8 @@@ static int amdgpu_device_ip_early_init(
  	adev->cg_flags &= amdgpu_cg_mask;
  	adev->pg_flags &= amdgpu_pg_mask;
  
+ 	amdgpu_smu_early_init(adev);
+ 
  	return 0;
  }
  
@@@ -2380,10 -2288,10 +2288,10 @@@ static int amdgpu_device_ip_init(struc
  					r);
  				goto init_failed;
  			}
- 			r = amdgpu_device_wb_init(adev);
+ 			r = amdgpu_wb_init(adev);
  			if (r) {
  				dev_err(adev->dev,
- 					"amdgpu_device_wb_init failed %d\n", r);
+ 					"amdgpu_wb_init failed %d\n", r);
  				goto init_failed;
  			}
  			adev->ip_blocks[i].status.hw = true;
@@@ -2915,7 -2823,7 +2823,7 @@@ static int amdgpu_device_ip_fini(struc
  		if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
  			amdgpu_ucode_free_bo(adev);
  			amdgpu_free_static_csa(&adev->virt.csa_obj);
- 			amdgpu_device_wb_fini(adev);
+ 			amdgpu_wb_fini(adev);
  			amdgpu_device_mem_scratch_fini(adev);
  			amdgpu_ib_pool_fini(adev);
  			amdgpu_seq64_fini(adev);
@@@ -3687,6 -3595,10 +3595,10 @@@ static void amdgpu_device_sys_interface
  		amdgpu_pm_sysfs_fini(adev);
  	if (adev->ucode_sysfs_en)
  		amdgpu_ucode_sysfs_fini(adev);
+ 
+ 	amdgpu_discovery_sysfs_fini(adev);
+ 	amdgpu_preempt_mgr_sysfs_fini(adev);
+ 
  	amdgpu_device_attr_sysfs_fini(adev);
  	amdgpu_fru_sysfs_fini(adev);
  
@@@ -3783,6 -3695,7 +3695,7 @@@ int amdgpu_device_init(struct amdgpu_de
  
  	spin_lock_init(&adev->irq.lock);
  
+ 	amdgpu_early_init_rlc_reg_funcs(adev);
  	amdgpu_device_init_apu_flags(adev);
  
  	r = amdgpu_device_check_arguments(adev);
@@@ -4218,6 -4131,7 +4131,7 @@@ void amdgpu_device_fini_hw(struct amdgp
  
  	if (adev->mman.initialized)
  		drain_workqueue(adev->mman.bdev.wq);
+ 
  	adev->shutdown = true;
  
  	unregister_pm_notifier(&adev->pm_nb);
@@@ -4716,161 -4630,6 +4630,6 @@@ exit
  	return 0;
  }
  
- /**
-  * amdgpu_device_ip_check_soft_reset - did soft reset succeed
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * The list of all the hardware IPs that make up the asic is walked and
-  * the check_soft_reset callbacks are run.  check_soft_reset determines
-  * if the asic is still hung or not.
-  * Returns true if any of the IPs are still in a hung state, false if not.
-  */
- static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev)
- {
- 	int i;
- 	bool asic_hang = false;
- 
- 	if (amdgpu_sriov_vf(adev))
- 		return true;
- 
- 	if (amdgpu_asic_need_full_reset(adev))
- 		return true;
- 
- 	for (i = 0; i < adev->num_ip_blocks; i++) {
- 		if (!adev->ip_blocks[i].status.valid)
- 			continue;
- 		if (adev->ip_blocks[i].version->funcs->check_soft_reset)
- 			adev->ip_blocks[i].status.hang =
- 				adev->ip_blocks[i].version->funcs->check_soft_reset(
- 					&adev->ip_blocks[i]);
- 		if (adev->ip_blocks[i].status.hang) {
- 			dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name);
- 			asic_hang = true;
- 		}
- 	}
- 	return asic_hang;
- }
- 
- /**
-  * amdgpu_device_ip_pre_soft_reset - prepare for soft reset
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * The list of all the hardware IPs that make up the asic is walked and the
-  * pre_soft_reset callbacks are run if the block is hung.  pre_soft_reset
-  * handles any IP specific hardware or software state changes that are
-  * necessary for a soft reset to succeed.
-  * Returns 0 on success, negative error code on failure.
-  */
- static int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev)
- {
- 	int i, r = 0;
- 
- 	for (i = 0; i < adev->num_ip_blocks; i++) {
- 		if (!adev->ip_blocks[i].status.valid)
- 			continue;
- 		if (adev->ip_blocks[i].status.hang &&
- 		    adev->ip_blocks[i].version->funcs->pre_soft_reset) {
- 			r = adev->ip_blocks[i].version->funcs->pre_soft_reset(&adev->ip_blocks[i]);
- 			if (r)
- 				return r;
- 		}
- 	}
- 
- 	return 0;
- }
- 
- /**
-  * amdgpu_device_ip_need_full_reset - check if a full asic reset is needed
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * Some hardware IPs cannot be soft reset.  If they are hung, a full gpu
-  * reset is necessary to recover.
-  * Returns true if a full asic reset is required, false if not.
-  */
- static bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev)
- {
- 	int i;
- 
- 	if (amdgpu_asic_need_full_reset(adev))
- 		return true;
- 
- 	for (i = 0; i < adev->num_ip_blocks; i++) {
- 		if (!adev->ip_blocks[i].status.valid)
- 			continue;
- 		if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) ||
- 		    (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) ||
- 		    (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_ACP) ||
- 		    (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) ||
- 		     adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) {
- 			if (adev->ip_blocks[i].status.hang) {
- 				dev_info(adev->dev, "Some block need full reset!\n");
- 				return true;
- 			}
- 		}
- 	}
- 	return false;
- }
- 
- /**
-  * amdgpu_device_ip_soft_reset - do a soft reset
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * The list of all the hardware IPs that make up the asic is walked and the
-  * soft_reset callbacks are run if the block is hung.  soft_reset handles any
-  * IP specific hardware or software state changes that are necessary to soft
-  * reset the IP.
-  * Returns 0 on success, negative error code on failure.
-  */
- static int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev)
- {
- 	int i, r = 0;
- 
- 	for (i = 0; i < adev->num_ip_blocks; i++) {
- 		if (!adev->ip_blocks[i].status.valid)
- 			continue;
- 		if (adev->ip_blocks[i].status.hang &&
- 		    adev->ip_blocks[i].version->funcs->soft_reset) {
- 			r = adev->ip_blocks[i].version->funcs->soft_reset(&adev->ip_blocks[i]);
- 			if (r)
- 				return r;
- 		}
- 	}
- 
- 	return 0;
- }
- 
- /**
-  * amdgpu_device_ip_post_soft_reset - clean up from soft reset
-  *
-  * @adev: amdgpu_device pointer
-  *
-  * The list of all the hardware IPs that make up the asic is walked and the
-  * post_soft_reset callbacks are run if the asic was hung.  post_soft_reset
-  * handles any IP specific hardware or software state changes that are
-  * necessary after the IP has been soft reset.
-  * Returns 0 on success, negative error code on failure.
-  */
- static int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev)
- {
- 	int i, r = 0;
- 
- 	for (i = 0; i < adev->num_ip_blocks; i++) {
- 		if (!adev->ip_blocks[i].status.valid)
- 			continue;
- 		if (adev->ip_blocks[i].status.hang &&
- 		    adev->ip_blocks[i].version->funcs->post_soft_reset)
- 			r = adev->ip_blocks[i].version->funcs->post_soft_reset(&adev->ip_blocks[i]);
- 		if (r)
- 			return r;
- 	}
- 
- 	return 0;
- }
- 
  /**
   * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf
   *
@@@ -5162,20 -4921,7 +4921,7 @@@ int amdgpu_device_pre_asic_reset(struc
  
  	/* Don't suspend on bare metal if we are not going to HW reset the ASIC */
  	if (!amdgpu_sriov_vf(adev)) {
- 
- 		if (!need_full_reset)
- 			need_full_reset = amdgpu_device_ip_need_full_reset(adev);
- 
- 		if (!need_full_reset && amdgpu_gpu_recovery &&
- 		    amdgpu_device_ip_check_soft_reset(adev)) {
- 			amdgpu_device_ip_pre_soft_reset(adev);
- 			r = amdgpu_device_ip_soft_reset(adev);
- 			amdgpu_device_ip_post_soft_reset(adev);
- 			if (r || amdgpu_device_ip_check_soft_reset(adev)) {
- 				dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n");
- 				need_full_reset = true;
- 			}
- 		}
+ 		need_full_reset = true;
  
  		if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags)) {
  			dev_info(tmp_adev->dev, "Dumping IP State\n");
@@@ -5628,8 -5374,7 +5374,7 @@@ static void amdgpu_device_halt_activiti
  		drm_client_dev_suspend(adev_to_drm(tmp_adev));
  
  		/* disable ras on ALL IPs */
- 		if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev) &&
- 		    amdgpu_device_ip_need_full_reset(tmp_adev))
+ 		if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev))
  			amdgpu_ras_suspend(tmp_adev);
  
  		amdgpu_userq_pre_reset(tmp_adev);
@@@ -6901,7 -6646,7 +6646,7 @@@ ssize_t amdgpu_get_soft_full_reset_mask
  
  	if (unlikely(!ring->adev->debug_disable_soft_recovery) &&
  	    !amdgpu_sriov_vf(ring->adev) && ring->funcs->soft_recovery)
- 		size |= AMDGPU_RESET_TYPE_SOFT_RESET;
+ 		size |= AMDGPU_RESET_TYPE_SOFT_RECOVERY;
  
  	return size;
  }
@@@ -6917,8 -6662,8 +6662,8 @@@ ssize_t amdgpu_show_reset_mask(char *bu
  
  	}
  
- 	if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RESET)
- 		size += sysfs_emit_at(buf, size, "soft ");
+ 	if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RECOVERY)
+ 		size += sysfs_emit_at(buf, size, "soft_recovery ");
  
  	if (supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE)
  		size += sysfs_emit_at(buf, size, "queue ");

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 14:40 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alessandro Rinaldi, Alex Deucher, Alex Hung, Aurabindo Pillai,
	Austin Zheng, Chenyu Chen, Geoffrey McRae, George Zhang,
	Harry Wentland, James Lin, Leo Li, Linux Kernel Mailing List,
	Linux Next Mailing List, Mario Limonciello, Matthew Schwartz,
	Michał Mirosław, Rafal Ostrowski, Thomas Zimmermann,
	Timur Kristóf, Tom Chung, WenTao Liang

[-- Attachment #1: Type: text/plain, Size: 277772 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

between commits:

  d094bc1f17783 ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
  d73f4e118dc4c ("drm/amd/display: check GRPH_FLIP status before sending event")
  c9ab9622f5b27 ("Revert "drm/amd/display: Restore 5s vbl offdelay for NV3x+ DGPUs"")
  d094bc1f17783 ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
  efd29b1cab549 ("drm/amd/display: set new_stream to NULL after release")
  aa377fdcb475c ("drm/amd/display: Force PWM backlight on Lenovo Legion 5 15ARH05")
  a991960f8bdc4 ("drm/amd/display: Set native cursor mode for disabled CRTCs")
  86e2b8644e92d ("drm/amd/display: Fix backlight max_brightness to match exported range")

from the drm-fixes tree and commits:

  99f3af19073b3 ("drm/amd/display: set new_stream to NULL after release")
  2f79f0130f828 ("drm/amd/display: Set native cursor mode for disabled CRTCs")
  ee186ae23ab0f ("Revert "drm/amd/display: Restore 5s vbl offdelay for NV3x+ DGPUs"")
  f64a9be565368 ("drm/amd/display: check GRPH_FLIP status before sending event")
  c87e6635d2db0 ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
  0d6453fd6e17a ("drm/amd/display: Fix DM IRQ teardown races")
  a5cd2fbe7b45f ("drm/amd/display/amdgpu_dm: show error names")
  163b0b32bfbee ("drm/amd/display: don't re-evaluate cursor mode on cursor plane movement")
  98e08a815ef60 ("drm/amd/display: Tear down dangling pipe on boot to fix s0i3")
  e4ae30a12aa95 ("drm/amd/display: Fix DM I2C teardown race")
  acf97c57d091f ("drm/amd/display: Re-evaluate cursor mode on plane position/size change")
  9bcf6af12bacb ("drm/amd/display: hold a vblank ref while writeback is pending")
  a24019f6480fa ("drm/amd/display: Handle struct drm_plane_state.ignore_damage_clips")
  947e46eb2fb9f ("drm/amdgpu: Delete check_soft_reset() from amd_ip_funcs")
  13158e5dbd896 ("drm/amd/display: Fix mem_type change detection for async flips")
  c26b643aa31b7 ("drm/amd/display: Add KUnit tests for amdgpu_dm")
  c1199393ec559 ("drm/amd/display: Refactor surface_update_flags to flat struct with helpers")
  0e967e086e751 ("drm/amd/display: Extract connector and encoder code to amdgpu_dm_connector")
  0618dec494157 ("drm/amd/display: Move HPD and IRQ handler code to amdgpu_dm_irq")
  4734e045f49d9 ("drm/amd/display: Extract DMUB code to amdgpu_dm_dmub")
  ee55bf7d6a63f ("drm/amd/display: Extract audio code to amdgpu_dm_audio")
  f5165625b8b27 ("drm/amd/display: Extract backlight code to amdgpu_dm_backlight")
  b008c67efb36b ("drm/amd/display: Introduce dc_plane_cm and migrate surface update color path")
  60597d2cb2199 ("drm/amd/display: Use handle_hpd_irq_helper for HPD RX")
  b7e70a466b3d0 ("drm/amd/display: Add detect reason to handle_hpd_irq_helper")
  0fde96e06f1cd ("drm/amd/display: Deprecate DMUB register offload functionality")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 9c564cd5edeea,e7080880b2211..0000000000000
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@@ -66,6 -66,11 +66,11 @@@
  #endif
  #include "amdgpu_dm_psr.h"
  #include "amdgpu_dm_replay.h"
+ #include "amdgpu_dm_backlight.h"
+ #include "amdgpu_dm_audio.h"
+ #include "amdgpu_dm_dmub.h"
+ #include "amdgpu_dm_connector.h"
+ #include "amdgpu_dm_kunit_helpers.h"
  
  #include "ivsrcid/ivsrcid_vislands30.h"
  
@@@ -94,7 -99,6 +99,6 @@@
  #include <drm/drm_mode.h>
  #include <drm/drm_utils.h>
  #include <drm/drm_vblank.h>
- #include <drm/drm_audio_component.h>
  #include <drm/drm_colorop.h>
  #include <drm/drm_gem_atomic_helper.h>
  
@@@ -107,60 -111,9 +111,9 @@@
  #include "modules/inc/mod_power.h"
  #include "modules/power/power_helpers.h"
  
- static_assert(AMDGPU_DMUB_NOTIFICATION_MAX == DMUB_NOTIFICATION_MAX, "AMDGPU_DMUB_NOTIFICATION_MAX mismatch");
- 
- #define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB);
- #define FIRMWARE_SIENNA_CICHLID_DMUB "amdgpu/sienna_cichlid_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID_DMUB);
- #define FIRMWARE_NAVY_FLOUNDER_DMUB "amdgpu/navy_flounder_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER_DMUB);
- #define FIRMWARE_GREEN_SARDINE_DMUB "amdgpu/green_sardine_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE_DMUB);
- #define FIRMWARE_VANGOGH_DMUB "amdgpu/vangogh_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB);
- #define FIRMWARE_DIMGREY_CAVEFISH_DMUB "amdgpu/dimgrey_cavefish_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB);
- #define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB);
- #define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB);
- #define FIRMWARE_DCN_314_DMUB "amdgpu/dcn_3_1_4_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_314_DMUB);
- #define FIRMWARE_DCN_315_DMUB "amdgpu/dcn_3_1_5_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_315_DMUB);
- #define FIRMWARE_DCN316_DMUB "amdgpu/dcn_3_1_6_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN316_DMUB);
- 
- #define FIRMWARE_DCN_V3_2_0_DMCUB "amdgpu/dcn_3_2_0_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_0_DMCUB);
- #define FIRMWARE_DCN_V3_2_1_DMCUB "amdgpu/dcn_3_2_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_1_DMCUB);
- 
- #define FIRMWARE_RAVEN_DMCU		"amdgpu/raven_dmcu.bin"
  MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU);
- 
- #define FIRMWARE_NAVI12_DMCU            "amdgpu/navi12_dmcu.bin"
  MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
  
- #define FIRMWARE_DCN_35_DMUB "amdgpu/dcn_3_5_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_35_DMUB);
- 
- #define FIRMWARE_DCN_351_DMUB "amdgpu/dcn_3_5_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_351_DMUB);
- 
- #define FIRMWARE_DCN_36_DMUB "amdgpu/dcn_3_6_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB);
- 
- #define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB);
- 
- #define FIRMWARE_DCN_42_DMUB "amdgpu/dcn_4_2_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB);
- 
- #define FIRMWARE_DCN_42B_DMUB "amdgpu/dcn_4_2_1_dmcub.bin"
- MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB);
- 
  /**
   * DOC: overview
   *
@@@ -174,46 -127,7 +127,7 @@@
  /* basic init/fini API */
  static int amdgpu_dm_init(struct amdgpu_device *adev);
  static void amdgpu_dm_fini(struct amdgpu_device *adev);
- static bool is_freesync_video_mode(const struct drm_display_mode *mode, struct amdgpu_dm_connector *aconnector);
  static void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
- static struct amdgpu_i2c_adapter *
- create_i2c(struct ddc_service *ddc_service, bool oem);
- 
- static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link)
- {
- 	switch (link->dpcd_caps.dongle_type) {
- 	case DISPLAY_DONGLE_NONE:
- 		return DRM_MODE_SUBCONNECTOR_Native;
- 	case DISPLAY_DONGLE_DP_VGA_CONVERTER:
- 		return DRM_MODE_SUBCONNECTOR_VGA;
- 	case DISPLAY_DONGLE_DP_DVI_CONVERTER:
- 	case DISPLAY_DONGLE_DP_DVI_DONGLE:
- 		return DRM_MODE_SUBCONNECTOR_DVID;
- 	case DISPLAY_DONGLE_DP_HDMI_CONVERTER:
- 	case DISPLAY_DONGLE_DP_HDMI_DONGLE:
- 		return DRM_MODE_SUBCONNECTOR_HDMIA;
- 	case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
- 	default:
- 		return DRM_MODE_SUBCONNECTOR_Unknown;
- 	}
- }
- 
- static void update_subconnector_property(struct amdgpu_dm_connector *aconnector)
- {
- 	struct dc_link *link = aconnector->dc_link;
- 	struct drm_connector *connector = &aconnector->base;
- 	enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
- 		return;
- 
- 	if (aconnector->dc_sink)
- 		subconnector = get_subconnector_type(link);
- 
- 	drm_object_property_set_value(&connector->base,
- 			connector->dev->mode_config.dp_subconnector_property,
- 			subconnector);
- }
  
  /*
   * initializes drm_device display related structures, based on the information
@@@ -226,32 -140,23 +140,23 @@@ static int amdgpu_dm_initialize_drm_dev
  /* removes and deallocates the drm structures, created by the above function */
  static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm);
  
- static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
- 				    struct amdgpu_dm_connector *amdgpu_dm_connector,
- 				    u32 link_index,
- 				    struct amdgpu_encoder *amdgpu_encoder);
- static int amdgpu_dm_encoder_init(struct drm_device *dev,
- 				  struct amdgpu_encoder *aencoder,
- 				  uint32_t link_index);
- 
- static int amdgpu_dm_connector_get_modes(struct drm_connector *connector);
- 
  static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state);
  static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state);
+ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
  
  static int amdgpu_dm_atomic_check(struct drm_device *dev,
  				  struct drm_atomic_commit *state);
  
- static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector);
- static void handle_hpd_rx_irq(void *param);
- 
- static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
- 					 int bl_idx,
- 					 u32 user_brightness);
- 
- static bool
+ STATIC_IFN_KUNIT bool
  is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
  				 struct drm_crtc_state *new_crtc_state);
+ 
+ static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
+ {
+ 	if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter)
+ 		dc_exit_ips_for_hw_access(dc);
+ }
+ 
  /*
   * dm_vblank_get_counter
   *
@@@ -332,40 -237,14 +237,14 @@@ static int dm_wait_for_idle(struct amdg
  	return 0;
  }
  
- static bool dm_check_soft_reset(struct amdgpu_ip_block *ip_block)
- {
- 	return false;
- }
- 
  static int dm_soft_reset(struct amdgpu_ip_block *ip_block)
  {
  	/* XXX todo */
  	return 0;
  }
  
- static struct amdgpu_crtc *
- get_crtc_by_otg_inst(struct amdgpu_device *adev,
- 		     int otg_inst)
- {
- 	struct drm_device *dev = adev_to_drm(adev);
- 	struct drm_crtc *crtc;
- 	struct amdgpu_crtc *amdgpu_crtc;
- 
- 	if (WARN_ON(otg_inst == -1))
- 		return adev->mode_info.crtcs[0];
- 
- 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- 		amdgpu_crtc = to_amdgpu_crtc(crtc);
- 
- 		if (amdgpu_crtc->otg_inst == otg_inst)
- 			return amdgpu_crtc;
- 	}
- 
- 	return NULL;
- }
- 
- static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
- 					      struct dm_crtc_state *new_state)
+ STATIC_IFN_KUNIT bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
+ 						 struct dm_crtc_state *new_state)
  {
  	if (new_state->stream->adjust.timing_adjust_pending)
  		return true;
@@@ -376,13 -255,14 +255,14 @@@
  	else
  		return false;
  }
+ EXPORT_IF_KUNIT(is_dc_timing_adjust_needed);
  
  /*
   * DC will program planes with their z-order determined by their ordering
   * in the dc_surface_updates array. This comparator is used to sort them
   * by descending zpos.
   */
- static int dm_plane_layer_index_cmp(const void *a, const void *b)
+ STATIC_IFN_KUNIT int dm_plane_layer_index_cmp(const void *a, const void *b)
  {
  	const struct dc_surface_update *sa = (struct dc_surface_update *)a;
  	const struct dc_surface_update *sb = (struct dc_surface_update *)b;
@@@ -390,6 -270,7 +270,7 @@@
  	/* Sort by descending dc_plane layer_index (i.e. normalized_zpos) */
  	return sb->surface->layer_index - sa->surface->layer_index;
  }
+ EXPORT_IF_KUNIT(dm_plane_layer_index_cmp);
  
  /**
   * update_planes_and_stream_adapter() - Send planes to be updated in DC
@@@ -430,687 -311,6 +311,6 @@@ static inline bool update_planes_and_st
  					   stream_update);
  }
  
- /**
-  * dm_pflip_high_irq() - Handle pageflip interrupt
-  * @interrupt_params: ignored
-  *
-  * Handles the pageflip interrupt by notifying all interested parties
-  * that the pageflip has been completed.
-  */
- static void dm_pflip_high_irq(void *interrupt_params)
- {
- 	struct amdgpu_crtc *amdgpu_crtc;
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct drm_device *dev = adev_to_drm(adev);
- 	unsigned long flags;
- 	struct drm_pending_vblank_event *e;
- 	u32 vpos, hpos, v_blank_start, v_blank_end;
- 	bool vrr_active;
- 
- 	amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
- 
- 	/* IRQ could occur when in initial stage */
- 	/* TODO work and BO cleanup */
- 	if (amdgpu_crtc == NULL) {
- 		drm_dbg_state(dev, "CRTC is null, returning.\n");
- 		return;
- 	}
- 
- 	spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 
- 	if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
- 		drm_dbg_state(dev,
- 			      "amdgpu_crtc->pflip_status = %d != AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p]\n",
- 			      amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED,
- 			      amdgpu_crtc->crtc_id, amdgpu_crtc);
- 		spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- 		return;
- 	}
- 
- 	/* page flip completed. */
- 	e = amdgpu_crtc->event;
- 	amdgpu_crtc->event = NULL;
- 
- 	WARN_ON(!e);
- 
- 	vrr_active = amdgpu_dm_crtc_vrr_active_irq(amdgpu_crtc);
- 
- 	/* Fixed refresh rate, or VRR scanout position outside front-porch? */
- 	if (!vrr_active ||
- 	    !dc_stream_get_scanoutpos(amdgpu_crtc->dm_irq_params.stream, &v_blank_start,
- 				      &v_blank_end, &hpos, &vpos) ||
- 	    (vpos < v_blank_start)) {
- 		/* Update to correct count and vblank timestamp if racing with
- 		 * vblank irq. This also updates to the correct vblank timestamp
- 		 * even in VRR mode, as scanout is past the front-porch atm.
- 		 */
- 		drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
- 
- 		/* Wake up userspace by sending the pageflip event with proper
- 		 * count and timestamp of vblank of flip completion.
- 		 */
- 		if (e) {
- 			drm_crtc_send_vblank_event(&amdgpu_crtc->base, e);
- 
- 			/* Event sent, so done with vblank for this flip */
- 			drm_crtc_vblank_put(&amdgpu_crtc->base);
- 		}
- 	} else if (e) {
- 		/* VRR active and inside front-porch: vblank count and
- 		 * timestamp for pageflip event will only be up to date after
- 		 * drm_crtc_handle_vblank() has been executed from late vblank
- 		 * irq handler after start of back-porch (vline 0). We queue the
- 		 * pageflip event for send-out by drm_crtc_handle_vblank() with
- 		 * updated timestamp and count, once it runs after us.
- 		 *
- 		 * We need to open-code this instead of using the helper
- 		 * drm_crtc_arm_vblank_event(), as that helper would
- 		 * call drm_crtc_accurate_vblank_count(), which we must
- 		 * not call in VRR mode while we are in front-porch!
- 		 */
- 
- 		/* sequence will be replaced by real count during send-out. */
- 		e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base);
- 		e->pipe = amdgpu_crtc->crtc_id;
- 
- 		list_add_tail(&e->base.link, &adev_to_drm(adev)->vblank_event_list);
- 		e = NULL;
- 	}
- 
- 	/* Keep track of vblank of this flip for flip throttling. We use the
- 	 * cooked hw counter, as that one incremented at start of this vblank
- 	 * of pageflip completion, so last_flip_vblank is the forbidden count
- 	 * for queueing new pageflips if vsync + VRR is enabled.
- 	 */
- 	amdgpu_crtc->dm_irq_params.last_flip_vblank =
- 		amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base);
- 
- 	amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
- 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- 
- 	drm_dbg_state(dev,
- 		      "crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n",
- 		      amdgpu_crtc->crtc_id, amdgpu_crtc, vrr_active, (int)!e);
- }
- 
- static void dm_handle_vmin_vmax_update(struct work_struct *offload_work)
- {
- 	struct vupdate_offload_work *work = container_of(offload_work, struct vupdate_offload_work, work);
- 	struct amdgpu_device *adev = work->adev;
- 	struct dc_stream_state *stream = work->stream;
- 	struct dc_crtc_timing_adjust *adjust = work->adjust;
- 
- 	mutex_lock(&adev->dm.dc_lock);
- 	dc_stream_adjust_vmin_vmax(adev->dm.dc, stream, adjust);
- 	mutex_unlock(&adev->dm.dc_lock);
- 
- 	dc_stream_release(stream);
- 	kfree(work->adjust);
- 	kfree(work);
- }
- 
- static void schedule_dc_vmin_vmax(struct amdgpu_device *adev,
- 	struct dc_stream_state *stream,
- 	struct dc_crtc_timing_adjust *adjust)
- {
- 	struct vupdate_offload_work *offload_work = kzalloc_obj(*offload_work,
- 								GFP_NOWAIT);
- 	if (!offload_work) {
- 		drm_dbg_driver(adev_to_drm(adev), "Failed to allocate vupdate_offload_work\n");
- 		return;
- 	}
- 
- 	struct dc_crtc_timing_adjust *adjust_copy = kzalloc_obj(*adjust_copy,
- 								GFP_NOWAIT);
- 	if (!adjust_copy) {
- 		drm_dbg_driver(adev_to_drm(adev), "Failed to allocate adjust_copy\n");
- 		kfree(offload_work);
- 		return;
- 	}
- 
- 	dc_stream_retain(stream);
- 	memcpy(adjust_copy, adjust, sizeof(*adjust_copy));
- 
- 	INIT_WORK(&offload_work->work, dm_handle_vmin_vmax_update);
- 	offload_work->adev = adev;
- 	offload_work->stream = stream;
- 	offload_work->adjust = adjust_copy;
- 
- 	queue_work(system_percpu_wq, &offload_work->work);
- }
- 
- /**
-  * dm_crtc_high_irq_handler() - Common OTG vblank/flip event handling
-  * @adev: amdgpu device
-  * @acrtc: the CRTC to service
-  *
-  * Performs writeback completion, vblank event handling, CRC processing, VRR BTR
-  * updates and pageflip completion delivery.
-  *
-  * On DCN this is driven by VUPDATE_NO_LOCK (the register latch point) from
-  * dm_vupdate_high_irq(); on DCE it is driven by VLINE0 at the start of vblank
-  * from dm_crtc_high_irq().
-  */
- static void dm_crtc_high_irq_handler(struct amdgpu_device *adev,
- 				     struct amdgpu_crtc *acrtc)
- {
- 	struct drm_writeback_job *job;
- 	unsigned long flags;
- 	int vrr_active;
- 	bool is_dcn = amdgpu_ip_version(adev, DCE_HWIP, 0) != 0;
- 
- 	if (acrtc->wb_conn) {
- 		spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
- 
- 		if (acrtc->wb_pending) {
- 			job = list_first_entry_or_null(&acrtc->wb_conn->job_queue,
- 						       struct drm_writeback_job,
- 						       list_entry);
- 			acrtc->wb_pending = false;
- 			spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
- 
- 			if (job) {
- 				unsigned int v_total, refresh_hz;
- 				struct dc_stream_state *stream = acrtc->dm_irq_params.stream;
- 
- 				v_total = stream->adjust.v_total_max ?
- 					  stream->adjust.v_total_max : stream->timing.v_total;
- 				refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz *
- 					     100LL, (v_total * stream->timing.h_total));
- 				mdelay(1000 / refresh_hz);
- 
- 				drm_writeback_signal_completion(acrtc->wb_conn, 0);
- 				dc_stream_fc_disable_writeback(adev->dm.dc,
- 							       acrtc->dm_irq_params.stream, 0);
- 			}
- 		} else
- 			spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
- 	}
- 
- 	vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
- 
- 	drm_dbg_vbl(adev_to_drm(adev),
- 		    "crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
- 		    vrr_active, acrtc->dm_irq_params.active_planes);
- 
- 	/**
- 	 * Core vblank handling.
- 	 *
- 	 * On DCN this handler runs at VUPDATE_NO_LOCK, the register latch
- 	 * point, which is the correct place to timestamp both VRR and non-VRR
- 	 * vblanks.
- 	 *
- 	 * On DCE this handler runs at the start of front-porch, where only
- 	 * non-VRR timestamping is valid; VRR vblank is deferred to
- 	 * dm_vupdate_high_irq() after end of front-porch.
- 	 */
- 	if (is_dcn || !vrr_active)
- 		amdgpu_dm_crtc_handle_vblank(acrtc);
- 
- 	/**
- 	 * Following stuff must happen at start of vblank, for crc
- 	 * computation and below-the-range btr support in vrr mode.
- 	 */
- 	amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
- 
- 	/* BTR updates need to happen before VUPDATE on Vega and above. */
- 	if (adev->family < AMDGPU_FAMILY_AI)
- 		return;
- 
- 	spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 
- 	if (acrtc->dm_irq_params.stream &&
- 		acrtc->dm_irq_params.vrr_params.supported) {
- 		bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
- 		bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
- 		bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE;
- 
- 		mod_freesync_handle_v_update(adev->dm.freesync_module,
- 					     acrtc->dm_irq_params.stream,
- 					     &acrtc->dm_irq_params.vrr_params);
- 
- 		/* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */
- 		if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
- 			schedule_dc_vmin_vmax(adev, acrtc->dm_irq_params.stream,
- 					&acrtc->dm_irq_params.vrr_params.adjust);
- 		}
- 	}
- 
- 	/*
- 	 * Deliver pageflip completion events (DCN only).
- 	 *
- 	 * Since GRPH_PFLIP is not used, VUPDATE_NO_LOCK is the flip latch
- 	 * point. Deliver any pending pageflip completion event from here,
- 	 * once HW has consumed the new address (the OTG no longer reports a
- 	 * pending flip).
- 	 *
- 	 * Also handle the case here where there aren't any active planes and
- 	 * DCN HUBP may be clock-gated, so the flip-pending status may be
- 	 * undefined.
- 	 */
- 	if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
- 	    acrtc->event) {
- 
- 		if (!dc_get_flip_pending_on_otg(adev->dm.dc, acrtc->otg_inst)) {
- 			drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
- 			acrtc->event = NULL;
- 			drm_crtc_vblank_put(&acrtc->base);
- 			acrtc->pflip_status = AMDGPU_FLIP_NONE;
- 		}
- 		/*
- 		 * If the flip is still pending, leave it armed and
- 		 * retry on the next vupdate.
- 		 */
- 	} else if (is_dcn && acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
- 		   acrtc->dm_irq_params.active_planes == 0) {
- 
- 		if (acrtc->event) {
- 			drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
- 			acrtc->event = NULL;
- 			drm_crtc_vblank_put(&acrtc->base);
- 		}
- 		acrtc->pflip_status = AMDGPU_FLIP_NONE;
- 	}
- 
- 	spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- }
- 
- static void dm_vupdate_high_irq(void *interrupt_params)
- {
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_crtc *acrtc;
- 	struct drm_device *drm_dev;
- 	struct drm_vblank_crtc *vblank;
- 	ktime_t frame_duration_ns, previous_timestamp;
- 	unsigned long flags;
- 	int vrr_active;
- 
- 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE);
- 	if (!acrtc)
- 		return;
- 
- 	vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
- 	drm_dev = acrtc->base.dev;
- 	vblank = drm_crtc_vblank_crtc(&acrtc->base);
- 	previous_timestamp = atomic64_read(&irq_params->previous_timestamp);
- 	frame_duration_ns = vblank->time - previous_timestamp;
- 
- 	if (frame_duration_ns > 0) {
- 		trace_amdgpu_refresh_rate_track(acrtc->base.index,
- 					frame_duration_ns,
- 					ktime_divns(NSEC_PER_SEC, frame_duration_ns));
- 		atomic64_set(&irq_params->previous_timestamp, vblank->time);
- 	}
- 
- 	drm_dbg_vbl(drm_dev,
- 		    "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id,
- 		    vrr_active);
- 
- 	/*
- 	 * On DCN, VUPDATE_NO_LOCK is the single OTG interrupt used to deliver
- 	 * vblank and pageflip completion events; VSTARTUP and GRPH_PFLIP are
- 	 * not used. Run the full handler here.
- 	 */
- 	if (amdgpu_ip_version(adev, DCE_HWIP, 0) != 0) {
- 		dm_crtc_high_irq_handler(adev, acrtc);
- 		return;
- 	}
- 
- 	/* DCE only below. */
- 
- 	/* Core vblank handling is done here after end of front-porch in
- 	 * vrr mode, as vblank timestamping will give valid results
- 	 * while now done after front-porch. This will also deliver
- 	 * page-flip completion events that have been queued to us
- 	 * if a pageflip happened inside front-porch.
- 	 */
- 	if (vrr_active && acrtc->dm_irq_params.stream) {
- 		bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
- 		bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
- 		bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state
- 			== VRR_STATE_ACTIVE_VARIABLE;
- 
- 		amdgpu_dm_crtc_handle_vblank(acrtc);
- 
- 		/* BTR processing for pre-DCE12 ASICs */
- 		if (adev->family < AMDGPU_FAMILY_AI) {
- 			spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
- 			mod_freesync_handle_v_update(
- 				adev->dm.freesync_module,
- 				acrtc->dm_irq_params.stream,
- 				&acrtc->dm_irq_params.vrr_params);
- 
- 			if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
- 				schedule_dc_vmin_vmax(adev,
- 					acrtc->dm_irq_params.stream,
- 					&acrtc->dm_irq_params.vrr_params.adjust);
- 			}
- 			spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
- 		}
- 	}
- }
- 
- /**
-  * dm_crtc_high_irq() - Handles CRTC interrupt
-  * @interrupt_params: used for determining the CRTC instance
-  *
-  * Handles the CRTC/VSYNC interrupt by notifying DRM's VBLANK event handler.
-  *
-  * Used on DCE (VLINE0, set to vblank start). On DCN the equivalent handling is
-  * driven by VUPDATE_NO_LOCK in dm_vupdate_high_irq().
-  */
- static void dm_crtc_high_irq(void *interrupt_params)
- {
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_crtc *acrtc;
- 
- 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
- 	if (!acrtc)
- 		return;
- 
- 	dm_crtc_high_irq_handler(adev, acrtc);
- }
- 
- #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- /**
-  * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
-  * DCN generation ASICs
-  * @interrupt_params: interrupt parameters
-  *
-  * Used to set crc window/read out crc value at vertical line 0 position
-  */
- static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
- {
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_crtc *acrtc;
- 
- 	acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VLINE0);
- 
- 	if (!acrtc)
- 		return;
- 
- 	amdgpu_dm_crtc_handle_crc_window_irq(&acrtc->base);
- }
- #endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
- 
- /**
-  * dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
-  * @adev: amdgpu_device pointer
-  * @notify: dmub notification structure
-  *
-  * Dmub AUX or SET_CONFIG command completion processing callback
-  * Copies dmub notification to DM which is to be read by AUX command.
-  * issuing thread and also signals the event to wake up the thread.
-  */
- static void dmub_aux_setconfig_callback(struct amdgpu_device *adev,
- 					struct dmub_notification *notify)
- {
- 	if (adev->dm.dmub_notify)
- 		memcpy(adev->dm.dmub_notify, notify, sizeof(struct dmub_notification));
- 	if (notify->type == DMUB_NOTIFICATION_AUX_REPLY)
- 		complete(&adev->dm.dmub_aux_transfer_done);
- }
- 
- static void dmub_aux_fused_io_callback(struct amdgpu_device *adev,
- 					struct dmub_notification *notify)
- {
- 	if (!adev || !notify) {
- 		ASSERT(false);
- 		return;
- 	}
- 
- 	const struct dmub_cmd_fused_request *req = &notify->fused_request;
- 	const uint8_t ddc_line = req->u.aux.ddc_line;
- 
- 	if (ddc_line >= ARRAY_SIZE(adev->dm.fused_io)) {
- 		ASSERT(false);
- 		return;
- 	}
- 
- 	struct fused_io_sync *sync = &adev->dm.fused_io[ddc_line];
- 
- 	static_assert(sizeof(*req) <= sizeof(sync->reply_data), "Size mismatch");
- 	memcpy(sync->reply_data, req, sizeof(*req));
- 	complete(&sync->replied);
- }
- 
- /**
-  * dmub_hpd_callback - DMUB HPD interrupt processing callback.
-  * @adev: amdgpu_device pointer
-  * @notify: dmub notification structure
-  *
-  * Dmub Hpd interrupt processing callback. Gets displayindex through the
-  * ink index and calls helper to do the processing.
-  */
- static void dmub_hpd_callback(struct amdgpu_device *adev,
- 			      struct dmub_notification *notify)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct amdgpu_dm_connector *hpd_aconnector = NULL;
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter iter;
- 	struct dc_link *link;
- 	u8 link_index = 0;
- 	struct drm_device *dev;
- 
- 	if (adev == NULL)
- 		return;
- 
- 	if (notify == NULL) {
- 		drm_err(adev_to_drm(adev), "DMUB HPD callback notification was NULL");
- 		return;
- 	}
- 
- 	if (notify->link_index > adev->dm.dc->link_count) {
- 		drm_err(adev_to_drm(adev), "DMUB HPD index (%u)is abnormal", notify->link_index);
- 		return;
- 	}
- 
- 	/* Skip DMUB HPD IRQ in suspend/resume. We will probe them later. */
- 	if (notify->type == DMUB_NOTIFICATION_HPD && adev->in_suspend) {
- 		drm_info(adev_to_drm(adev), "Skip DMUB HPD IRQ callback in suspend/resume\n");
- 		return;
- 	}
- 
- 	link_index = notify->link_index;
- 	link = adev->dm.dc->links[link_index];
- 	dev = adev->dm.ddev;
- 
- 	drm_connector_list_iter_begin(dev, &iter);
- 	drm_for_each_connector_iter(connector, &iter) {
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (link && aconnector->dc_link == link) {
- 			if (notify->type == DMUB_NOTIFICATION_HPD)
- 				drm_info(adev_to_drm(adev), "DMUB HPD IRQ callback: link_index=%u\n", link_index);
- 			else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ)
- 				drm_info(adev_to_drm(adev), "DMUB HPD RX IRQ callback: link_index=%u\n", link_index);
- 			else
- 				drm_warn(adev_to_drm(adev), "DMUB Unknown HPD callback type %d, link_index=%u\n",
- 						notify->type, link_index);
- 
- 			hpd_aconnector = aconnector;
- 			break;
- 		}
- 	}
- 	drm_connector_list_iter_end(&iter);
- 
- 	if (hpd_aconnector) {
- 		if (notify->type == DMUB_NOTIFICATION_HPD) {
- 			if (hpd_aconnector->dc_link->hpd_status == (notify->hpd_status == DP_HPD_PLUG))
- 				drm_warn(adev_to_drm(adev), "DMUB reported hpd status unchanged. link_index=%u\n", link_index);
- 			handle_hpd_irq_helper(hpd_aconnector);
- 		} else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) {
- 			handle_hpd_rx_irq(hpd_aconnector);
- 		}
- 	}
- }
- 
- /**
-  * dmub_hpd_sense_callback - DMUB HPD sense processing callback.
-  * @adev: amdgpu_device pointer
-  * @notify: dmub notification structure
-  *
-  * HPD sense changes can occur during low power states and need to be
-  * notified from firmware to driver.
-  */
- static void dmub_hpd_sense_callback(struct amdgpu_device *adev,
- 			      struct dmub_notification *notify)
- {
- 	drm_dbg_driver(adev_to_drm(adev), "DMUB HPD SENSE callback.\n");
- }
- 
- /**
-  * register_dmub_notify_callback - Sets callback for DMUB notify
-  * @adev: amdgpu_device pointer
-  * @type: Type of dmub notification
-  * @callback: Dmub interrupt callback function
-  * @dmub_int_thread_offload: offload indicator
-  *
-  * API to register a dmub callback handler for a dmub notification
-  * Also sets indicator whether callback processing to be offloaded.
-  * to dmub interrupt handling thread
-  * Return: true if successfully registered, false if there is existing registration
-  */
- static bool register_dmub_notify_callback(struct amdgpu_device *adev,
- 					  enum dmub_notification_type type,
- 					  dmub_notify_interrupt_callback_t callback,
- 					  bool dmub_int_thread_offload)
- {
- 	if (callback != NULL && type < ARRAY_SIZE(adev->dm.dmub_thread_offload)) {
- 		adev->dm.dmub_callback[type] = callback;
- 		adev->dm.dmub_thread_offload[type] = dmub_int_thread_offload;
- 	} else
- 		return false;
- 
- 	return true;
- }
- 
- static void dm_handle_hpd_work(struct work_struct *work)
- {
- 	struct dmub_hpd_work *dmub_hpd_wrk;
- 
- 	dmub_hpd_wrk = container_of(work, struct dmub_hpd_work, handle_hpd_work);
- 
- 	if (!dmub_hpd_wrk->dmub_notify) {
- 		drm_err(adev_to_drm(dmub_hpd_wrk->adev), "dmub_hpd_wrk dmub_notify is NULL");
- 		return;
- 	}
- 
- 	if (dmub_hpd_wrk->dmub_notify->type < ARRAY_SIZE(dmub_hpd_wrk->adev->dm.dmub_callback)) {
- 		dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev,
- 		dmub_hpd_wrk->dmub_notify);
- 	}
- 
- 	kfree(dmub_hpd_wrk->dmub_notify);
- 	kfree(dmub_hpd_wrk);
- 
- }
- 
- static const char *dmub_notification_type_str(enum dmub_notification_type e)
- {
- 	switch (e) {
- 	case DMUB_NOTIFICATION_NO_DATA:
- 		return "NO_DATA";
- 	case DMUB_NOTIFICATION_AUX_REPLY:
- 		return "AUX_REPLY";
- 	case DMUB_NOTIFICATION_HPD:
- 		return "HPD";
- 	case DMUB_NOTIFICATION_HPD_IRQ:
- 		return "HPD_IRQ";
- 	case DMUB_NOTIFICATION_SET_CONFIG_REPLY:
- 		return "SET_CONFIG_REPLY";
- 	case DMUB_NOTIFICATION_DPIA_NOTIFICATION:
- 		return "DPIA_NOTIFICATION";
- 	case DMUB_NOTIFICATION_HPD_SENSE_NOTIFY:
- 		return "HPD_SENSE_NOTIFY";
- 	case DMUB_NOTIFICATION_FUSED_IO:
- 		return "FUSED_IO";
- 	default:
- 		return "<unknown>";
- 	}
- }
- 
- #define DMUB_TRACE_MAX_READ 64
- /**
-  * dm_dmub_outbox1_low_irq() - Handles Outbox interrupt
-  * @interrupt_params: used for determining the Outbox instance
-  *
-  * Handles the Outbox Interrupt
-  * event handler.
-  */
- static void dm_dmub_outbox1_low_irq(void *interrupt_params)
- {
- 	struct dmub_notification notify = {0};
- 	struct common_irq_params *irq_params = interrupt_params;
- 	struct amdgpu_device *adev = irq_params->adev;
- 	struct amdgpu_display_manager *dm = &adev->dm;
- 	struct dmcub_trace_buf_entry entry = { 0 };
- 	u32 count = 0;
- 	struct dmub_hpd_work *dmub_hpd_wrk;
- 
- 	do {
- 		if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) {
- 			trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count,
- 							entry.param0, entry.param1);
- 
- 			drm_dbg_driver(adev_to_drm(adev), "trace_code:%u, tick_count:%u, param0:%u, param1:%u\n",
- 				 entry.trace_code, entry.tick_count, entry.param0, entry.param1);
- 		} else
- 			break;
- 
- 		count++;
- 
- 	} while (count <= DMUB_TRACE_MAX_READ);
- 
- 	if (count > DMUB_TRACE_MAX_READ)
- 		drm_dbg_driver(adev_to_drm(adev), "Warning : count > DMUB_TRACE_MAX_READ");
- 
- 	if (dc_enable_dmub_notifications(adev->dm.dc) &&
- 		irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) {
- 
- 		do {
- 			dc_stat_get_dmub_notification(adev->dm.dc, &notify);
- 			if (notify.type >= ARRAY_SIZE(dm->dmub_thread_offload)) {
- 				drm_err(adev_to_drm(adev), "DM: notify type %d invalid!", notify.type);
- 				continue;
- 			}
- 			if (!dm->dmub_callback[notify.type]) {
- 				drm_warn(adev_to_drm(adev), "DMUB notification skipped due to no handler: type=%s\n",
- 					dmub_notification_type_str(notify.type));
- 				continue;
- 			}
- 			if (dm->dmub_thread_offload[notify.type] == true) {
- 				dmub_hpd_wrk = kzalloc_obj(*dmub_hpd_wrk,
- 							   GFP_ATOMIC);
- 				if (!dmub_hpd_wrk) {
- 					drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk");
- 					return;
- 				}
- 				dmub_hpd_wrk->dmub_notify = kmemdup(&notify, sizeof(struct dmub_notification),
- 								    GFP_ATOMIC);
- 				if (!dmub_hpd_wrk->dmub_notify) {
- 					kfree(dmub_hpd_wrk);
- 					drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk->dmub_notify");
- 					return;
- 				}
- 				INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work);
- 				dmub_hpd_wrk->adev = adev;
- 				queue_work(adev->dm.delayed_hpd_wq, &dmub_hpd_wrk->handle_hpd_work);
- 			} else {
- 				dm->dmub_callback[notify.type](adev, &notify);
- 			}
- 		} while (notify.pending_notification);
- 	}
- }
- 
  static int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
  		  enum amd_clockgating_state state)
  {
@@@ -1127,401 -327,6 +327,6 @@@ static int dm_set_powergating_state(str
  static int dm_early_init(struct amdgpu_ip_block *ip_block);
  
  /* Allocate memory for FBC compressed data  */
- static void amdgpu_dm_fbc_init(struct drm_connector *connector)
- {
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct dm_compressor_info *compressor = &adev->dm.compressor;
- 	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector);
- 	struct drm_display_mode *mode;
- 	unsigned long max_size = 0;
- 
- 	if (adev->dm.dc->fbc_compressor == NULL)
- 		return;
- 
- 	if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP)
- 		return;
- 
- 	if (compressor->bo_ptr)
- 		return;
- 
- 
- 	list_for_each_entry(mode, &connector->modes, head) {
- 		if (max_size < (unsigned long) mode->htotal * mode->vtotal)
- 			max_size = (unsigned long) mode->htotal * mode->vtotal;
- 	}
- 
- 	if (max_size) {
- 		int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE,
- 			    AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr,
- 			    &compressor->gpu_addr, &compressor->cpu_addr);
- 
- 		if (r)
- 			drm_err(adev_to_drm(adev), "DM: Failed to initialize FBC\n");
- 		else {
- 			adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr;
- 			drm_info(adev_to_drm(adev), "DM: FBC alloc %lu\n", max_size*4);
- 		}
- 
- 	}
- 
- }
- 
- static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
- 					  int pipe, bool *enabled,
- 					  unsigned char *buf, int max_bytes)
- {
- 	struct drm_device *dev = dev_get_drvdata(kdev);
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter conn_iter;
- 	struct amdgpu_dm_connector *aconnector;
- 	int ret = 0;
- 
- 	*enabled = false;
- 
- 	mutex_lock(&adev->dm.audio_lock);
- 
- 	drm_connector_list_iter_begin(dev, &conn_iter);
- 	drm_for_each_connector_iter(connector, &conn_iter) {
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (aconnector->audio_inst != port)
- 			continue;
- 
- 		*enabled = true;
- 		mutex_lock(&connector->eld_mutex);
- 		ret = drm_eld_size(connector->eld);
- 		memcpy(buf, connector->eld, min(max_bytes, ret));
- 		mutex_unlock(&connector->eld_mutex);
- 
- 		break;
- 	}
- 	drm_connector_list_iter_end(&conn_iter);
- 
- 	mutex_unlock(&adev->dm.audio_lock);
- 
- 	drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
- 
- 	return ret;
- }
- 
- static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
- 	.get_eld = amdgpu_dm_audio_component_get_eld,
- };
- 
- static int amdgpu_dm_audio_component_bind(struct device *kdev,
- 				       struct device *hda_kdev, void *data)
- {
- 	struct drm_device *dev = dev_get_drvdata(kdev);
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct drm_audio_component *acomp = data;
- 
- 	acomp->ops = &amdgpu_dm_audio_component_ops;
- 	acomp->dev = kdev;
- 	adev->dm.audio_component = acomp;
- 
- 	return 0;
- }
- 
- static void amdgpu_dm_audio_component_unbind(struct device *kdev,
- 					  struct device *hda_kdev, void *data)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev));
- 	struct drm_audio_component *acomp = data;
- 
- 	acomp->ops = NULL;
- 	acomp->dev = NULL;
- 	adev->dm.audio_component = NULL;
- }
- 
- static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
- 	.bind	= amdgpu_dm_audio_component_bind,
- 	.unbind	= amdgpu_dm_audio_component_unbind,
- };
- 
- static int amdgpu_dm_audio_init(struct amdgpu_device *adev)
- {
- 	int i, ret;
- 
- 	if (!amdgpu_audio)
- 		return 0;
- 
- 	adev->mode_info.audio.enabled = true;
- 
- 	adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
- 
- 	for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
- 		adev->mode_info.audio.pin[i].channels = -1;
- 		adev->mode_info.audio.pin[i].rate = -1;
- 		adev->mode_info.audio.pin[i].bits_per_sample = -1;
- 		adev->mode_info.audio.pin[i].status_bits = 0;
- 		adev->mode_info.audio.pin[i].category_code = 0;
- 		adev->mode_info.audio.pin[i].connected = false;
- 		adev->mode_info.audio.pin[i].id =
- 			adev->dm.dc->res_pool->audios[i]->inst;
- 		adev->mode_info.audio.pin[i].offset = 0;
- 	}
- 
- 	ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
- 	if (ret < 0)
- 		return ret;
- 
- 	adev->dm.audio_registered = true;
- 
- 	return 0;
- }
- 
- static void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
- {
- 	if (!amdgpu_audio)
- 		return;
- 
- 	if (!adev->mode_info.audio.enabled)
- 		return;
- 
- 	if (adev->dm.audio_registered) {
- 		component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
- 		adev->dm.audio_registered = false;
- 	}
- 
- 	/* TODO: Disable audio? */
- 
- 	adev->mode_info.audio.enabled = false;
- }
- 
- static  void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
- {
- 	struct drm_audio_component *acomp = adev->dm.audio_component;
- 
- 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
- 		drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin);
- 
- 		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
- 						 pin, -1);
- 	}
- }
- 
- static int dm_dmub_hw_init(struct amdgpu_device *adev)
- {
- 	const struct dmcub_firmware_header_v1_0 *hdr;
- 	struct dmub_srv *dmub_srv = adev->dm.dmub_srv;
- 	struct dmub_srv_fb_info *fb_info = adev->dm.dmub_fb_info;
- 	const struct firmware *dmub_fw = adev->dm.dmub_fw;
- 	struct dc *dc = adev->dm.dc;
- 	struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu;
- 	struct abm *abm = adev->dm.dc->res_pool->abm;
- 	struct dc_context *ctx = adev->dm.dc->ctx;
- 	struct dmub_srv_hw_params hw_params;
- 	enum dmub_status status;
- 	const unsigned char *fw_inst_const, *fw_bss_data;
- 	u32 i, fw_inst_const_size, fw_bss_data_size;
- 	bool has_hw_support;
- 
- 	if (!dmub_srv)
- 		/* DMUB isn't supported on the ASIC. */
- 		return 0;
- 
- 	if (!fb_info) {
- 		drm_err(adev_to_drm(adev), "No framebuffer info for DMUB service.\n");
- 		return -EINVAL;
- 	}
- 
- 	if (!dmub_fw) {
- 		/* Firmware required for DMUB support. */
- 		drm_err(adev_to_drm(adev), "No firmware provided for DMUB.\n");
- 		return -EINVAL;
- 	}
- 
- 	/* initialize register offsets for ASICs with runtime initialization available */
- 	if (dmub_srv->hw_funcs.init_reg_offsets)
- 		dmub_srv->hw_funcs.init_reg_offsets(dmub_srv, ctx);
- 
- 	status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error checking HW support for DMUB: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	if (!has_hw_support) {
- 		drm_info(adev_to_drm(adev), "DMUB unsupported on ASIC\n");
- 		return 0;
- 	}
- 
- 	/* Reset DMCUB if it was previously running - before we overwrite its memory. */
- 	status = dmub_srv_hw_reset(dmub_srv);
- 	if (status != DMUB_STATUS_OK)
- 		drm_warn(adev_to_drm(adev), "Error resetting DMUB HW: %d\n", status);
- 
- 	hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data;
- 
- 	fw_inst_const = dmub_fw->data +
- 			le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 			PSP_HEADER_BYTES_256;
- 
- 	fw_bss_data = dmub_fw->data +
- 		      le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 		      le32_to_cpu(hdr->inst_const_bytes);
- 
- 	/* Copy firmware and bios info into FB memory. */
- 	fw_inst_const_size = adev->dm.fw_inst_size;
- 
- 	fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes);
- 
- 	/* if adev->firmware.load_type == AMDGPU_FW_LOAD_PSP,
- 	 * amdgpu_ucode_init_single_fw will load dmub firmware
- 	 * fw_inst_const part to cw0; otherwise, the firmware back door load
- 	 * will be done by dm_dmub_hw_init
- 	 */
- 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
- 		memcpy(fb_info->fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const,
- 				fw_inst_const_size);
- 	}
- 
- 	if (fw_bss_data_size)
- 		memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr,
- 		       fw_bss_data, fw_bss_data_size);
- 
- 	/* Copy firmware bios info into FB memory. */
- 	memcpy(fb_info->fb[DMUB_WINDOW_3_VBIOS].cpu_addr, adev->bios,
- 	       adev->bios_size);
- 
- 	/* Reset regions that need to be reset. */
- 	memset(fb_info->fb[DMUB_WINDOW_4_MAILBOX].cpu_addr, 0,
- 	fb_info->fb[DMUB_WINDOW_4_MAILBOX].size);
- 
- 	memset(fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].cpu_addr, 0,
- 	       fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size);
- 
- 	memset(fb_info->fb[DMUB_WINDOW_6_FW_STATE].cpu_addr, 0,
- 	       fb_info->fb[DMUB_WINDOW_6_FW_STATE].size);
- 
- 	memset(fb_info->fb[DMUB_WINDOW_SHARED_STATE].cpu_addr, 0,
- 	       fb_info->fb[DMUB_WINDOW_SHARED_STATE].size);
- 
- 	/* Initialize hardware. */
- 	memset(&hw_params, 0, sizeof(hw_params));
- 	hw_params.soc_fb_info.fb_base = adev->gmc.fb_start;
- 	hw_params.soc_fb_info.fb_offset = adev->vm_manager.vram_base_offset;
- 
- 	/* backdoor load firmware and trigger dmub running */
- 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
- 		hw_params.load_inst_const = true;
- 
- 	if (dmcu)
- 		hw_params.psp_version = dmcu->psp_version;
- 
- 	for (i = 0; i < fb_info->num_fb; ++i)
- 		hw_params.fb[i] = &fb_info->fb[i];
- 
- 	/* Enable usb4 dpia in the FW APU */
- 	if (dc->caps.is_apu &&
- 		dc->res_pool->usb4_dpia_count != 0 &&
- 		!dc->debug.dpia_debug.bits.disable_dpia) {
- 		hw_params.dpia_supported = true;
- 		hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia;
- 		hw_params.dpia_hpd_int_enable_supported = false;
- 		hw_params.enable_non_transparent_setconfig = dc->config.consolidated_dpia_dp_lt;
- 		hw_params.disable_dpia_bw_allocation = !dc->config.usb4_bw_alloc_support;
- 	}
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(3, 5, 0):
- 	case IP_VERSION(3, 5, 1):
- 	case IP_VERSION(3, 6, 0):
- 	case IP_VERSION(4, 2, 0):
- 	case IP_VERSION(4, 2, 1):
- 		hw_params.ips_sequential_ono = adev->external_rev_id > 0x10;
- 		hw_params.lower_hbr3_phy_ssc = true;
- 		break;
- 	default:
- 		break;
- 	}
- 
- 	status = dmub_srv_hw_init(dmub_srv, &hw_params);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error initializing DMUB HW: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	/* Wait for firmware load to finish. */
- 	status = dmub_srv_wait_for_auto_load(dmub_srv, 100000);
- 	if (status != DMUB_STATUS_OK)
- 		drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status);
- 
- 	/* Init DMCU and ABM if available. */
- 	if (dmcu && abm) {
- 		dmcu->funcs->dmcu_init(dmcu);
- 		abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu);
- 	}
- 
- 	if (!adev->dm.dc->ctx->dmub_srv)
- 		adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv);
- 	if (!adev->dm.dc->ctx->dmub_srv) {
- 		drm_err(adev_to_drm(adev), "Couldn't allocate DC DMUB server!\n");
- 		return -ENOMEM;
- 	}
- 
- 	drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n",
- 		 adev->dm.dmcub_fw_version);
- 
- 	/* Keeping sanity checks off if
- 	 * DCN31 >= 4.0.59.0
- 	 * DCN314 >= 8.0.16.0
- 	 * Otherwise, turn on sanity checks
- 	 */
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(3, 1, 2):
- 	case IP_VERSION(3, 1, 3):
- 		if (adev->dm.dmcub_fw_version &&
- 			adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
- 			adev->dm.dmcub_fw_version < DMUB_FW_VERSION(4, 0, 59))
- 				adev->dm.dc->debug.sanity_checks = true;
- 		break;
- 	case IP_VERSION(3, 1, 4):
- 		if (adev->dm.dmcub_fw_version &&
- 			adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) &&
- 			adev->dm.dmcub_fw_version < DMUB_FW_VERSION(8, 0, 16))
- 				adev->dm.dc->debug.sanity_checks = true;
- 		break;
- 	default:
- 		break;
- 	}
- 
- 	return 0;
- }
- 
- static void dm_dmub_hw_resume(struct amdgpu_device *adev)
- {
- 	struct dmub_srv *dmub_srv = adev->dm.dmub_srv;
- 	enum dmub_status status;
- 	bool init;
- 	int r;
- 
- 	if (!dmub_srv) {
- 		/* DMUB isn't supported on the ASIC. */
- 		return;
- 	}
- 
- 	status = dmub_srv_is_hw_init(dmub_srv, &init);
- 	if (status != DMUB_STATUS_OK)
- 		drm_warn(adev_to_drm(adev), "DMUB hardware init check failed: %d\n", status);
- 
- 	if (status == DMUB_STATUS_OK && init) {
- 		/* Wait for firmware load to finish. */
- 		status = dmub_srv_wait_for_auto_load(dmub_srv, 100000);
- 		if (status != DMUB_STATUS_OK)
- 			drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status);
- 	} else {
- 		/* Perform the full hardware initialization. */
- 		r = dm_dmub_hw_init(adev);
- 		if (r)
- 			drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r);
- 	}
- }
- 
  static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
  {
  	u64 pt_base;
@@@ -1599,151 -404,6 +404,6 @@@
  
  }
  
- static void force_connector_state(
- 	struct amdgpu_dm_connector *aconnector,
- 	enum drm_connector_force force_state)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 
- 	mutex_lock(&connector->dev->mode_config.mutex);
- 	aconnector->base.force = force_state;
- 	mutex_unlock(&connector->dev->mode_config.mutex);
- 
- 	mutex_lock(&aconnector->hpd_lock);
- 	drm_kms_helper_connector_hotplug_event(connector);
- 	mutex_unlock(&aconnector->hpd_lock);
- }
- 
- static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
- {
- 	struct hpd_rx_irq_offload_work *offload_work;
- 	struct amdgpu_dm_connector *aconnector;
- 	struct dc_link *dc_link;
- 	struct amdgpu_device *adev;
- 	enum dc_connection_type new_connection_type = dc_connection_none;
- 	unsigned long flags;
- 	union test_response test_response;
- 
- 	memset(&test_response, 0, sizeof(test_response));
- 
- 	offload_work = container_of(work, struct hpd_rx_irq_offload_work, work);
- 	aconnector = offload_work->offload_wq->aconnector;
- 	adev = offload_work->adev;
- 
- 	if (!aconnector) {
- 		drm_err(adev_to_drm(adev), "Can't retrieve aconnector in hpd_rx_irq_offload_work");
- 		goto skip;
- 	}
- 
- 	dc_link = aconnector->dc_link;
- 
- 	mutex_lock(&aconnector->hpd_lock);
- 	if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
- 		drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
- 	mutex_unlock(&aconnector->hpd_lock);
- 
- 	if (new_connection_type == dc_connection_none)
- 		goto skip;
- 
- 	if (amdgpu_in_reset(adev))
- 		goto skip;
- 
- 	if (offload_work->data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY ||
- 		offload_work->data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
- 		dm_handle_mst_sideband_msg_ready_event(&aconnector->mst_mgr, DOWN_OR_UP_MSG_RDY_EVENT);
- 		spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
- 		offload_work->offload_wq->is_handling_mst_msg_rdy_event = false;
- 		spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
- 		goto skip;
- 	}
- 
- 	mutex_lock(&adev->dm.dc_lock);
- 	if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
- 		dc_link_dp_handle_automated_test(dc_link);
- 
- 		if (aconnector->timing_changed) {
- 			/* force connector disconnect and reconnect */
- 			force_connector_state(aconnector, DRM_FORCE_OFF);
- 			msleep(100);
- 			force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED);
- 		}
- 
- 		test_response.bits.ACK = 1;
- 
- 		core_link_write_dpcd(
- 		dc_link,
- 		DP_TEST_RESPONSE,
- 		&test_response.raw,
- 		sizeof(test_response));
- 	} else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
- 			dc_link_check_link_loss_status(dc_link, &offload_work->data) &&
- 			dc_link_dp_allow_hpd_rx_irq(dc_link)) {
- 		/* offload_work->data is from handle_hpd_rx_irq->
- 		 * schedule_hpd_rx_offload_work.this is defer handle
- 		 * for hpd short pulse. upon here, link status may be
- 		 * changed, need get latest link status from dpcd
- 		 * registers. if link status is good, skip run link
- 		 * training again.
- 		 */
- 		union hpd_irq_data irq_data;
- 
- 		memset(&irq_data, 0, sizeof(irq_data));
- 
- 		/* before dc_link_dp_handle_link_loss, allow new link lost handle
- 		 * request be added to work queue if link lost at end of dc_link_
- 		 * dp_handle_link_loss
- 		 */
- 		spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
- 		offload_work->offload_wq->is_handling_link_loss = false;
- 		spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
- 
- 		if ((dc_link_dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) &&
- 			dc_link_check_link_loss_status(dc_link, &irq_data))
- 			dc_link_dp_handle_link_loss(dc_link);
- 	}
- 	mutex_unlock(&adev->dm.dc_lock);
- 
- skip:
- 	kfree(offload_work);
- 
- }
- 
- static struct hpd_rx_irq_offload_work_queue *hpd_rx_irq_create_workqueue(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	int max_caps = dc->caps.max_links;
- 	int i = 0;
- 	struct hpd_rx_irq_offload_work_queue *hpd_rx_offload_wq = NULL;
- 
- 	hpd_rx_offload_wq = kzalloc_objs(*hpd_rx_offload_wq, max_caps);
- 
- 	if (!hpd_rx_offload_wq)
- 		return NULL;
- 
- 
- 	for (i = 0; i < max_caps; i++) {
- 		hpd_rx_offload_wq[i].wq =
- 				    create_singlethread_workqueue("amdgpu_dm_hpd_rx_offload_wq");
- 
- 		if (hpd_rx_offload_wq[i].wq == NULL) {
- 			drm_err(adev_to_drm(adev), "create amdgpu_dm_hpd_rx_offload_wq fail!");
- 			goto out_err;
- 		}
- 
- 		spin_lock_init(&hpd_rx_offload_wq[i].offload_lock);
- 	}
- 
- 	return hpd_rx_offload_wq;
- 
- out_err:
- 	for (i = 0; i < max_caps; i++) {
- 		if (hpd_rx_offload_wq[i].wq)
- 			destroy_workqueue(hpd_rx_offload_wq[i].wq);
- 	}
- 	kfree(hpd_rx_offload_wq);
- 	return NULL;
- }
- 
  struct amdgpu_stutter_quirk {
  	u16 chip_vendor;
  	u16 chip_device;
@@@ -1829,119 -489,6 +489,6 @@@ dm_free_gpu_mem
  
  }
  
- static enum dmub_status
- dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev,
- 				 enum dmub_gpint_command command_code,
- 				 uint16_t param,
- 				 uint32_t timeout_us)
- {
- 	union dmub_gpint_data_register reg, test;
- 	uint32_t i;
- 
- 	/* Assume that VBIOS DMUB is ready to take commands */
- 
- 	reg.bits.status = 1;
- 	reg.bits.command_code = command_code;
- 	reg.bits.param = param;
- 
- 	cgs_write_register(adev->dm.cgs_device, 0x34c0 + 0x01f8, reg.all);
- 
- 	for (i = 0; i < timeout_us; ++i) {
- 		udelay(1);
- 
- 		/* Check if our GPINT got acked */
- 		reg.bits.status = 0;
- 		test = (union dmub_gpint_data_register)
- 			cgs_read_register(adev->dm.cgs_device, 0x34c0 + 0x01f8);
- 
- 		if (test.all == reg.all)
- 			return DMUB_STATUS_OK;
- 	}
- 
- 	return DMUB_STATUS_TIMEOUT;
- }
- 
- static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev)
- {
- 	void *bb;
- 	long long addr;
- 	unsigned int bb_size;
- 	int i = 0;
- 	uint16_t chunk;
- 	enum dmub_gpint_command send_addrs[] = {
- 		DMUB_GPINT__SET_BB_ADDR_WORD0,
- 		DMUB_GPINT__SET_BB_ADDR_WORD1,
- 		DMUB_GPINT__SET_BB_ADDR_WORD2,
- 		DMUB_GPINT__SET_BB_ADDR_WORD3,
- 	};
- 	enum dmub_status ret;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(4, 0, 1):
- 		bb_size = sizeof(struct dml2_soc_bb);
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 	case IP_VERSION(4, 2, 1):
- 		bb_size = sizeof(struct dml2_soc_bb);
- 		break;
- 	default:
- 		return NULL;
- 	}
- 
- 	bb =  dm_allocate_gpu_mem(adev,
- 				  DC_MEM_ALLOC_TYPE_GART,
- 				  bb_size,
- 				  &addr);
- 	if (!bb)
- 		return NULL;
- 
- 	for (i = 0; i < 4; i++) {
- 		/* Extract 16-bit chunk */
- 		chunk = ((uint64_t) addr >> (i * 16)) & 0xFFFF;
- 		/* Send the chunk */
- 		ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000);
- 		if (ret != DMUB_STATUS_OK)
- 			goto free_bb;
- 	}
- 
- 	/* Now ask DMUB to copy the bb */
- 	ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000);
- 	if (ret != DMUB_STATUS_OK)
- 		goto free_bb;
- 
- 	return bb;
- 
- free_bb:
- 	dm_free_gpu_mem(adev, DC_MEM_ALLOC_TYPE_GART, (void *) bb);
- 	return NULL;
- 
- }
- 
- static enum dmub_ips_disable_type dm_get_default_ips_mode(
- 	struct amdgpu_device *adev)
- {
- 	enum dmub_ips_disable_type ret = DMUB_IPS_ENABLE;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(3, 5, 0):
- 	case IP_VERSION(3, 6, 0):
- 	case IP_VERSION(3, 5, 1):
- 		ret =  DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF;
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 	case IP_VERSION(4, 2, 1):
- 		ret =  DMUB_IPS_ENABLE;
- 		break;
- 	default:
- 		/* ASICs older than DCN35 do not have IPSs */
- 		if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 5, 0))
- 			ret = DMUB_IPS_DISABLE_ALL;
- 		break;
- 	}
- 
- 	return ret;
- }
- 
  static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm)
  {
  	struct mod_power_init_params init_data[MAX_NUM_EDP];
@@@ -2006,40 -553,6 +553,6 @@@
  	return 0;
  }
  
- static void hdmi_frl_status_polling_work(struct work_struct *work)
- {
- 	struct amdgpu_display_manager *dm =
- 		container_of(to_delayed_work(work), struct amdgpu_display_manager,
- 				hdmi_frl_status_polling_work);
- 	struct dc *dc = dm->dc;
- 	struct dc_link *dc_link;
- 	bool link_update = false;
- 
- 	for (int i = 0; i < MAX_LINKS; i++) {
- 		dc_link = dc->links[i];
- 
- 		if (!dc_link || !dc_link->local_sink)
- 			continue;
- 
- 		if (!dc_is_hdmi_signal(dc_link->connector_signal))
- 			continue;
- 
- 		if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL)
- 			continue;
- 
- 		link_update = dc_link_frl_poll_status_flag(dc_link);
- 		if (link_update) {
- 			mutex_lock(&dm->dc_lock);
- 			dc_link_detect(dc_link, DETECT_REASON_RETRAIN);
- 			mutex_unlock(&dm->dc_lock);
- 		}
- 	}
- 
- 	queue_delayed_work(dm->hdmi_frl_status_polling_wq,
- 			   &dm->hdmi_frl_status_polling_work,
- 			   msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms));
- }
- 
  static int amdgpu_dm_init(struct amdgpu_device *adev)
  {
  	struct dc_init_data init_data;
@@@ -2266,7 -779,15 +779,15 @@@
  
  	dc_hardware_init(adev->dm.dc);
  
- 	adev->dm.hpd_rx_offload_wq = hpd_rx_irq_create_workqueue(adev);
+ 	/* GOP/vBIOS may leave an OPTC enabled for a display present at power-on
+ 	 * but no longer driven (e.g. an external DP unplugged at boot). Such a
+ 	 * dangling pipe keeps DCN out of idle and blocks s0i3. Power it down
+ 	 * here when nothing needs to be preserved.
+ 	 */
+ 	if (adev->flags & AMD_IS_APU)
+ 		dc_disable_dangling_timing_generators(adev->dm.dc);
+ 
+ 	adev->dm.hpd_rx_offload_wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev);
  	if (!adev->dm.hpd_rx_offload_wq) {
  		drm_err(adev_to_drm(adev), "failed to create hpd rx offload workqueue.\n");
  		goto error;
@@@ -2319,8 -840,6 +840,6 @@@
  			create_singlethread_workqueue("hdmi_frl_status_polling_workqueue");
  		if (!adev->dm.hdmi_frl_status_polling_wq)
  			drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n");
- 		adev->dm.hdmi_frl_status_polling_delay_ms = 200;
- 		INIT_DELAYED_WORK(&adev->dm.hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
  	}
  	if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
  		init_completion(&adev->dm.dmub_aux_transfer_done);
@@@ -2337,8 -856,8 +856,8 @@@
  		}
  
  		amdgpu_dm_outbox_init(adev);
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY,
- 			dmub_aux_setconfig_callback, false)) {
+ 		if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY,
+ 			dm_dmub_aux_setconfig_callback, false)) {
  			drm_err(adev_to_drm(adev), "fail to register dmub aux callback");
  			goto error;
  		}
@@@ -2346,16 -865,17 +865,17 @@@
  		for (size_t i = 0; i < ARRAY_SIZE(adev->dm.fused_io); i++)
  			init_completion(&adev->dm.fused_io[i].replied);
  
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_FUSED_IO,
- 			dmub_aux_fused_io_callback, false)) {
+ 		if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_FUSED_IO,
+ 			dm_dmub_aux_fused_io_callback, false)) {
  			drm_err(adev_to_drm(adev), "fail to register dmub fused io callback");
  			goto error;
  		}
  		/* Enable outbox notification only after IRQ handlers are registered and DMUB is alive.
  		 * It is expected that DMUB will resend any pending notifications at this point. Note
- 		 * that hpd and hpd_irq handler registration are deferred to register_hpd_handlers() to
- 		 * align legacy interface initialization sequence. Connection status will be proactivly
- 		 * detected once in the amdgpu_dm_initialize_drm_device.
+ 		 * that hpd and hpd_irq handler registration are deferred to
+ 		 * amdgpu_dm_register_hpd_handlers() to align legacy interface initialization
+ 		 * sequence. Connection status will be proactivly detected once in the
+ 		 * amdgpu_dm_initialize_drm_device.
  		 */
  		dc_enable_dmub_outbox(adev->dm.dc);
  
@@@ -2498,14 -1018,11 +1018,11 @@@ static void amdgpu_dm_fini(struct amdgp
  		adev->dm.hpd_rx_offload_wq = NULL;
  	}
  
+ 	amdgpu_dm_irq_fini(adev);
+ 
  	/* DC Destroy TODO: Replace destroy DAL */
  	if (adev->dm.dc)
  		dc_destroy(&adev->dm.dc);
- 	/*
- 	 * TODO: pageflip, vlank interrupt
- 	 *
- 	 * amdgpu_dm_irq_fini(adev);
- 	 */
  
  	if (adev->dm.cgs_device) {
  		amdgpu_cgs_destroy_device(adev->dm.cgs_device);
@@@ -2635,224 -1152,6 +1152,6 @@@ static int load_dmcu_fw(struct amdgpu_d
  	return 0;
  }
  
- static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address)
- {
- 	struct amdgpu_device *adev = ctx;
- 
- 	return dm_read_reg(adev->dm.dc->ctx, address);
- }
- 
- static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address,
- 				     uint32_t value)
- {
- 	struct amdgpu_device *adev = ctx;
- 
- 	return dm_write_reg(adev->dm.dc->ctx, address, value);
- }
- 
- static int dm_dmub_sw_init(struct amdgpu_device *adev)
- {
- 	struct dmub_srv_create_params create_params;
- 	struct dmub_srv_fw_meta_info_params fw_meta_info_params;
- 	struct dmub_srv_region_params region_params;
- 	struct dmub_srv_region_info region_info;
- 	struct dmub_srv_memory_params memory_params;
- 	struct dmub_fw_meta_info fw_info;
- 	struct dmub_srv_fb_info *fb_info;
- 	struct dmub_srv *dmub_srv;
- 	const struct dmcub_firmware_header_v1_0 *hdr;
- 	enum dmub_asic dmub_asic;
- 	enum dmub_status status;
- 	static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = {
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_0_INST_CONST
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_1_STACK
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_2_BSS_DATA
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_3_VBIOS
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_4_MAILBOX
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_5_TRACEBUFF
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_6_FW_STATE
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_7_SCRATCH_MEM
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_IB_MEM
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_SHARED_STATE
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_LSDMA_BUFFER
- 		DMUB_WINDOW_MEMORY_TYPE_FB,		//DMUB_WINDOW_CURSOR_OFFLOAD
- 	};
- 	int r;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(2, 1, 0):
- 		dmub_asic = DMUB_ASIC_DCN21;
- 		break;
- 	case IP_VERSION(3, 0, 0):
- 		dmub_asic = DMUB_ASIC_DCN30;
- 		break;
- 	case IP_VERSION(3, 0, 1):
- 		dmub_asic = DMUB_ASIC_DCN301;
- 		break;
- 	case IP_VERSION(3, 0, 2):
- 		dmub_asic = DMUB_ASIC_DCN302;
- 		break;
- 	case IP_VERSION(3, 0, 3):
- 		dmub_asic = DMUB_ASIC_DCN303;
- 		break;
- 	case IP_VERSION(3, 1, 2):
- 	case IP_VERSION(3, 1, 3):
- 		dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31;
- 		break;
- 	case IP_VERSION(3, 1, 4):
- 		dmub_asic = DMUB_ASIC_DCN314;
- 		break;
- 	case IP_VERSION(3, 1, 5):
- 		dmub_asic = DMUB_ASIC_DCN315;
- 		break;
- 	case IP_VERSION(3, 1, 6):
- 		dmub_asic = DMUB_ASIC_DCN316;
- 		break;
- 	case IP_VERSION(3, 2, 0):
- 		dmub_asic = DMUB_ASIC_DCN32;
- 		break;
- 	case IP_VERSION(3, 2, 1):
- 		dmub_asic = DMUB_ASIC_DCN321;
- 		break;
- 	case IP_VERSION(3, 5, 0):
- 	case IP_VERSION(3, 5, 1):
- 		dmub_asic = DMUB_ASIC_DCN35;
- 		break;
- 	case IP_VERSION(3, 6, 0):
- 		dmub_asic = DMUB_ASIC_DCN36;
- 		break;
- 	case IP_VERSION(4, 0, 1):
- 		dmub_asic = DMUB_ASIC_DCN401;
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 		dmub_asic = DMUB_ASIC_DCN42;
- 		break;
- 	case IP_VERSION(4, 2, 1):
- 		dmub_asic = DMUB_ASIC_DCN42B;
- 		break;
- 	default:
- 		/* ASIC doesn't support DMUB. */
- 		return 0;
- 	}
- 
- 	hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data;
- 	adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version);
- 
- 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
- 		adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id =
- 			AMDGPU_UCODE_ID_DMCUB;
- 		adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw =
- 			adev->dm.dmub_fw;
- 		adev->firmware.fw_size +=
- 			ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE);
- 
- 		drm_info(adev_to_drm(adev), "Loading DMUB firmware via PSP: version=0x%08X\n",
- 			 adev->dm.dmcub_fw_version);
- 	}
- 
- 
- 	adev->dm.dmub_srv = kzalloc_obj(*adev->dm.dmub_srv);
- 	dmub_srv = adev->dm.dmub_srv;
- 
- 	if (!dmub_srv) {
- 		drm_err(adev_to_drm(adev), "Failed to allocate DMUB service!\n");
- 		return -ENOMEM;
- 	}
- 
- 	memset(&create_params, 0, sizeof(create_params));
- 	create_params.user_ctx = adev;
- 	create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read;
- 	create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write;
- 	create_params.asic = dmub_asic;
- 
- 	/* Create the DMUB service. */
- 	status = dmub_srv_create(dmub_srv, &create_params);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error creating DMUB service: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	/* Extract the FW meta info. */
- 	memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params));
- 
- 	fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) -
- 					      PSP_HEADER_BYTES_256;
- 	fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes);
- 	fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data +
- 					    le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 					    PSP_HEADER_BYTES_256;
- 	fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data +
- 					  le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
- 					  le32_to_cpu(hdr->inst_const_bytes) : NULL;
- 	fw_meta_info_params.custom_psp_footer_size = 0;
- 
- 	status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info);
- 	if (status != DMUB_STATUS_OK) {
- 		/* Skip returning early, just log the error. */
- 		drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status);
- 		// return -EINVAL;
- 	}
- 
- 	/* Calculate the size of all the regions for the DMUB service. */
- 	memset(&region_params, 0, sizeof(region_params));
- 
- 	region_params.inst_const_size = fw_meta_info_params.inst_const_size;
- 	region_params.bss_data_size = fw_meta_info_params.bss_data_size;
- 	region_params.vbios_size = adev->bios_size;
- 	region_params.fw_bss_data = fw_meta_info_params.fw_bss_data;
- 	region_params.fw_inst_const = fw_meta_info_params.fw_inst_const;
- 	region_params.window_memory_type = window_memory_type;
- 	region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL;
- 
- 	status = dmub_srv_calc_region_info(dmub_srv, &region_params,
- 					   &region_info);
- 
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error calculating DMUB region info: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	/*
- 	 * Allocate a framebuffer based on the total size of all the regions.
- 	 * TODO: Move this into GART.
- 	 */
- 	r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE,
- 				    AMDGPU_GEM_DOMAIN_VRAM |
- 				    AMDGPU_GEM_DOMAIN_GTT,
- 				    &adev->dm.dmub_bo,
- 				    &adev->dm.dmub_bo_gpu_addr,
- 				    &adev->dm.dmub_bo_cpu_addr);
- 	if (r)
- 		return r;
- 
- 	/* Rebase the regions on the framebuffer address. */
- 	memset(&memory_params, 0, sizeof(memory_params));
- 	memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr;
- 	memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr;
- 	memory_params.region_info = &region_info;
- 	memory_params.window_memory_type = window_memory_type;
- 
- 	adev->dm.dmub_fb_info = kzalloc_obj(*adev->dm.dmub_fb_info);
- 	fb_info = adev->dm.dmub_fb_info;
- 
- 	if (!fb_info) {
- 		drm_err(adev_to_drm(adev),
- 			"Failed to allocate framebuffer info for DMUB service!\n");
- 		return -ENOMEM;
- 	}
- 
- 	status = dmub_srv_calc_mem_info(dmub_srv, &memory_params, fb_info);
- 	if (status != DMUB_STATUS_OK) {
- 		drm_err(adev_to_drm(adev), "Error calculating DMUB FB info: %d\n", status);
- 		return -EINVAL;
- 	}
- 
- 	adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev);
- 	adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size;
- 
- 	return 0;
- }
- 
  static int dm_sw_init(struct amdgpu_ip_block *ip_block)
  {
  	struct amdgpu_device *adev = ip_block->adev;
@@@ -2906,41 -1205,6 +1205,6 @@@ static int dm_sw_fini(struct amdgpu_ip_
  	return 0;
  }
  
- static int detect_mst_link_for_all_connectors(struct drm_device *dev)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter iter;
- 	int ret = 0;
- 
- 	drm_connector_list_iter_begin(dev, &iter);
- 	drm_for_each_connector_iter(connector, &iter) {
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (aconnector->dc_link->type == dc_connection_mst_branch &&
- 		    aconnector->mst_mgr.aux) {
- 			drm_dbg_kms(dev, "DM_MST: starting TM on aconnector: %p [id: %d]\n",
- 					 aconnector,
- 					 aconnector->base.base.id);
- 
- 			ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true);
- 			if (ret < 0) {
- 				drm_err(dev, "DM_MST: Failed to start MST\n");
- 				aconnector->dc_link->type =
- 					dc_connection_single;
- 				ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx,
- 								     aconnector->dc_link);
- 				break;
- 			}
- 		}
- 	}
- 	drm_connector_list_iter_end(&iter);
- 
- 	return ret;
- }
  
  static void amdgpu_dm_boot_time_crc_init(struct amdgpu_device *adev)
  {
@@@ -3038,7 -1302,7 +1302,7 @@@ static int dm_late_init(struct amdgpu_i
  		}
  	}
  
- 	return detect_mst_link_for_all_connectors(adev_to_drm(adev));
+ 	return amdgpu_dm_detect_mst_link_for_all_connectors(adev_to_drm(adev));
  }
  
  static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
@@@ -3092,48 -1356,6 +1356,6 @@@ out_fail
  	mutex_unlock(&mgr->lock);
  }
  
- void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector)
- {
- 	struct cec_notifier *n = aconnector->notifier;
- 
- 	if (!n)
- 		return;
- 
- 	cec_notifier_phys_addr_invalidate(n);
- }
- 
- void hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct cec_notifier *n = aconnector->notifier;
- 
- 	if (!n)
- 		return;
- 
- 	cec_notifier_set_phys_addr(n,
- 				   connector->display_info.source_physical_address);
- }
- 
- static void s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_connector *connector;
- 	struct drm_connector_list_iter conn_iter;
- 
- 	drm_connector_list_iter_begin(ddev, &conn_iter);
- 	drm_for_each_connector_iter(connector, &conn_iter) {
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		if (suspend)
- 			hdmi_cec_unset_edid(aconnector);
- 		else
- 			hdmi_cec_set_edid(aconnector);
- 	}
- 	drm_connector_list_iter_end(&conn_iter);
- }
- 
  static void s3_handle_mst(struct drm_device *dev, bool suspend)
  {
  	struct amdgpu_dm_connector *aconnector;
@@@ -3236,7 -1458,7 +1458,7 @@@ static int dm_oem_i2c_hw_init(struct am
  
  	oem_ddc_service = dc_get_oem_i2c_device(adev->dm.dc);
  	if (oem_ddc_service) {
- 		oem_i2c = create_i2c(oem_ddc_service, true);
+ 		oem_i2c = amdgpu_dm_create_i2c(oem_ddc_service, true);
  		if (!oem_i2c) {
  			drm_info(adev_to_drm(adev), "Failed to create oem i2c adapter data\n");
  			return -ENOMEM;
@@@ -3279,17 -1501,26 +1501,26 @@@ static int dm_hw_init(struct amdgpu_ip_
  	struct amdgpu_device *adev = ip_block->adev;
  	int r;
  
+ 	adev->dm.i2c_devres_group = devres_open_group(adev->dev, NULL, GFP_KERNEL);
+ 	if (!adev->dm.i2c_devres_group)
+ 		return -ENOMEM;
+ 
  	/* Create DAL display manager */
  	r = amdgpu_dm_init(adev);
  	if (r)
- 		return r;
+ 		goto err_release_i2c;
  	amdgpu_dm_hpd_init(adev);
  
  	r = dm_oem_i2c_hw_init(adev);
  	if (r)
  		drm_info(adev_to_drm(adev), "Failed to add OEM i2c bus\n");
  
+ 	devres_close_group(adev->dev, adev->dm.i2c_devres_group);
  	return 0;
+ 
+ err_release_i2c:
+ 	devres_release_group(adev->dev, adev->dm.i2c_devres_group);
+ 	return r;
  }
  
  /**
@@@ -3304,9 -1535,11 +1535,11 @@@ static int dm_hw_fini(struct amdgpu_ip_
  {
  	struct amdgpu_device *adev = ip_block->adev;
  
+ 	if (adev->dm.i2c_devres_group)
+ 		devres_release_group(adev->dev, adev->dm.i2c_devres_group);
+ 
  	amdgpu_dm_hpd_fini(adev);
  
- 	amdgpu_dm_irq_fini(adev);
  	amdgpu_dm_fini(adev);
  	return 0;
  }
@@@ -3321,10 -1554,11 +1554,11 @@@ static void dm_gpureset_toggle_interrup
  	int i = 0;
  
  	for (i = 0; i < state->stream_count; i++) {
- 		acrtc = get_crtc_by_otg_inst(
+ 		acrtc = amdgpu_dm_get_crtc_by_otg_inst(
  				adev, state->stream_status[i].primary_otg_inst);
  
- 		if (acrtc && state->stream_status[i].plane_count != 0) {
+ 		if (acrtc && state->stream_status[i].plane_count != 0 &&
+ 		    amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
  			irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
  			rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
  			if (rc)
@@@ -3405,16 -1639,6 +1639,6 @@@ static enum dc_status amdgpu_dm_commit_
  	return dc_commit_streams(dc, &params);
  }
  
- static void hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm)
- {
- 	int i;
- 
- 	if (dm->hpd_rx_offload_wq) {
- 		for (i = 0; i < dm->dc->caps.max_links; i++)
- 			flush_workqueue(dm->hpd_rx_offload_wq[i].wq);
- 	}
- }
- 
  static int dm_cache_state(struct amdgpu_device *adev)
  {
  	int r;
@@@ -3510,7 -1734,7 +1734,7 @@@ static int dm_suspend(struct amdgpu_ip_
  
  		amdgpu_dm_irq_suspend(adev);
  
- 		hpd_rx_irq_work_suspend(dm);
+ 		amdgpu_dm_hpd_rx_irq_work_suspend(dm);
  
  		return 0;
  	}
@@@ -3522,7 -1746,7 +1746,7 @@@
  			return r;
  	}
  
- 	s3_handle_hdmi_cec(adev_to_drm(adev), true);
+ 	amdgpu_dm_s3_handle_hdmi_cec(adev_to_drm(adev), true);
  
  	s3_handle_mst(adev_to_drm(adev), true);
  
@@@ -3536,7 -1760,7 +1760,7 @@@
  	scoped_guard(mutex, &dm->dc_lock)
  		amdgpu_dm_ism_force_full_power(dm);
  
- 	hpd_rx_irq_work_suspend(dm);
+ 	amdgpu_dm_hpd_rx_irq_work_suspend(dm);
  
  	dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
  
@@@ -3548,26 -1772,7 +1772,7 @@@
  	return 0;
  }
  
- struct drm_connector *
- amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state,
- 					     struct drm_crtc *crtc)
- {
- 	u32 i;
- 	struct drm_connector_state *new_con_state;
- 	struct drm_connector *connector;
- 	struct drm_crtc *crtc_from_state;
- 
- 	for_each_new_connector_in_state(state, connector, new_con_state, i) {
- 		crtc_from_state = new_con_state->crtc;
- 
- 		if (crtc_from_state == crtc)
- 			return connector;
- 	}
- 
- 	return NULL;
- }
- 
- static void emulated_link_detect(struct dc_link *link)
+ void amdgpu_dm_emulated_link_detect(struct dc_link *link)
  {
  	struct dc_sink_init_data sink_init_data = { 0 };
  	struct display_sink_capability sink_caps = { 0 };
@@@ -3688,8 -1893,8 +1893,8 @@@ static void dm_gpureset_commit_state(st
  	}
  }
  
- static void apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
- 					    struct dc_sink *sink)
+ void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev,
+ 											   struct dc_sink *sink)
  {
  	struct dc_panel_patch *ppatch = NULL;
  
@@@ -3832,8 -2037,7 +2037,7 @@@ static int dm_resume(struct amdgpu_ip_b
  		for (i = 0; i < dc_state->stream_count; i++) {
  			dc_state->streams[i]->mode_changed = true;
  			for (j = 0; j < dc_state->stream_status[i].plane_count; j++) {
- 				dc_state->stream_status[i].plane_states[j]->update_flags.raw
- 					= 0xffffffff;
+ 				dc_pipe_update_bits_set_full(&dc_state->stream_status[i].plane_states[j]->update_bits);
  			}
  		}
  
@@@ -3896,7 -2100,7 +2100,7 @@@
  	 */
  	amdgpu_dm_irq_resume_early(adev);
  
- 	s3_handle_hdmi_cec(ddev, false);
+ 	amdgpu_dm_s3_handle_hdmi_cec(ddev, false);
  
  	/* On resume we need to rewrite the MSTM control bits to enable MST*/
  	s3_handle_mst(ddev, false);
@@@ -3931,14 -2135,14 +2135,14 @@@
  			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
  
  		if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 			emulated_link_detect(aconnector->dc_link);
+ 			amdgpu_dm_emulated_link_detect(aconnector->dc_link);
  		} else {
  			guard(mutex)(&dm->dc_lock);
  			dc_exit_ips_for_hw_access(dm->dc);
  			ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_RESUMEFROMS3S4);
  			if (ret) {
  				/* w/a delay for certain panels */
- 				apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
+ 				amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
  			}
  		}
  
@@@ -4016,7 -2220,6 +2220,6 @@@ static const struct amd_ip_funcs amdgpu
  	.resume = dm_resume,
  	.is_idle = dm_is_idle,
  	.wait_for_idle = dm_wait_for_idle,
- 	.check_soft_reset = dm_check_soft_reset,
  	.soft_reset = dm_soft_reset,
  	.set_clockgating_state = dm_set_clockgating_state,
  	.set_powergating_state = dm_set_powergating_state,
@@@ -4049,1004 -2252,6 +2252,6 @@@ static struct drm_mode_config_helper_fu
  	.atomic_commit_setup = amdgpu_dm_atomic_setup_commit,
  };
  
- #define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C
- 
- static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_display_info *display_info = &connector->display_info;
- 	struct dc_link *link = aconnector->dc_link;
- 	struct amdgpu_device *adev;
- 
- 	adev = drm_to_adev(connector->dev);
- 
- 	link->panel_type = PANEL_TYPE_NONE;
- 
- 	switch (display_info->amd_vsdb.panel_type) {
- 	case AMD_VSDB_PANEL_TYPE_OLED:
- 		link->panel_type = PANEL_TYPE_OLED;
- 		break;
- 	case AMD_VSDB_PANEL_TYPE_MINILED:
- 		link->panel_type = PANEL_TYPE_MINILED;
- 		break;
- 	}
- 
- 	/* If VSDB didn't determine panel type, check DPCD ext caps */
- 	if (link->panel_type == PANEL_TYPE_NONE) {
- 		if (link->dpcd_sink_ext_caps.bits.miniled == 1)
- 			link->panel_type = PANEL_TYPE_MINILED;
- 		if (link->dpcd_sink_ext_caps.bits.oled == 1)
- 			link->panel_type = PANEL_TYPE_OLED;
- 	}
- 
- 	/*
- 	 * TODO: get panel type from DID2 that has device technology field
- 	 * to specify if it's OLED or not. But we need to wait for DID2
- 	 * support in DC and EDID parser to be able to use it here.
- 	 */
- 
- 	if (link->panel_type == PANEL_TYPE_NONE) {
- 		struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb;
- 		u32 lum1_max = vsdb->luminance_range1.max_luminance;
- 		u32 lum2_max = vsdb->luminance_range2.max_luminance;
- 
- 		if (vsdb->version && link->local_sink &&
- 		    link->local_sink->edid_caps.manufacturer_id ==
- 		    DDC_MANUFACTURERNAME_SAMSUNG &&
- 		    lum1_max >= ((lum2_max * 3) / 2))
- 			link->panel_type = PANEL_TYPE_MINILED;
- 	}
- 
- 	if (link->panel_type == PANEL_TYPE_OLED)
- 		drm_object_property_set_value(&connector->base,
- 		    adev_to_drm(adev)->mode_config.panel_type_property,
- 		    DRM_MODE_PANEL_TYPE_OLED);
- 	else
- 		drm_object_property_set_value(&connector->base,
- 		    adev_to_drm(adev)->mode_config.panel_type_property,
- 		    DRM_MODE_PANEL_TYPE_UNKNOWN);
- 
- 	drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type);
- }
- 
- static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
- {
- 	const struct drm_panel_backlight_quirk *panel_backlight_quirk;
- 	struct amdgpu_dm_backlight_caps *caps;
- 	struct drm_connector *conn_base;
- 	struct amdgpu_device *adev;
- 	struct drm_luminance_range_info *luminance_range;
- 	struct drm_device *drm;
- 
- 	if (aconnector->bl_idx == -1 ||
- 	    aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP)
- 		return;
- 
- 	conn_base = &aconnector->base;
- 	drm = conn_base->dev;
- 	adev = drm_to_adev(drm);
- 
- 	caps = &adev->dm.backlight_caps[aconnector->bl_idx];
- 	caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
- 	caps->aux_support = false;
- 
- 	panel_backlight_quirk = drm_get_panel_backlight_quirk(aconnector->drm_edid);
- 
- 	if (caps->ext_caps->bits.oled == 1
- 	    /*
- 	     * ||
- 	     * caps->ext_caps->bits.sdr_aux_backlight_control == 1 ||
- 	     * caps->ext_caps->bits.hdr_aux_backlight_control == 1
- 	     */)
- 		caps->aux_support = true;
- 
- 	if (amdgpu_backlight == 0)
- 		caps->aux_support = false;
- 	else if (amdgpu_backlight == 1)
- 		caps->aux_support = true;
- 	else if (!IS_ERR_OR_NULL(panel_backlight_quirk) &&
- 		 panel_backlight_quirk->force_pwm)
- 		caps->aux_support = false;
- 	if (caps->aux_support)
- 		aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX;
- 
- 	luminance_range = &conn_base->display_info.luminance_range;
- 
- 	if (luminance_range->max_luminance)
- 		caps->aux_max_input_signal = luminance_range->max_luminance;
- 	else
- 		caps->aux_max_input_signal = 512;
- 
- 	if (luminance_range->min_luminance)
- 		caps->aux_min_input_signal = luminance_range->min_luminance;
- 	else
- 		caps->aux_min_input_signal = 1;
- 
- 	if (!IS_ERR_OR_NULL(panel_backlight_quirk)) {
- 		if (panel_backlight_quirk->min_brightness) {
- 			caps->min_input_signal =
- 				panel_backlight_quirk->min_brightness - 1;
- 			drm_info(drm,
- 				 "Applying panel backlight quirk, min_brightness: %d\n",
- 				 caps->min_input_signal);
- 		}
- 		if (panel_backlight_quirk->brightness_mask) {
- 			drm_info(drm,
- 				 "Applying panel backlight quirk, brightness_mask: 0x%X\n",
- 				 panel_backlight_quirk->brightness_mask);
- 			caps->brightness_mask =
- 				panel_backlight_quirk->brightness_mask;
- 		}
- 	}
- }
- 
- DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))
- 
- void amdgpu_dm_update_connector_after_detect(
- 		struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct dc_sink *sink __free(sink_release) = NULL;
- 	struct drm_device *dev = connector->dev;
- 
- 	/* MST handled by drm_mst framework */
- 	if (aconnector->mst_mgr.mst_state == true)
- 		return;
- 
- 	sink = aconnector->dc_link->local_sink;
- 	if (sink)
- 		dc_sink_retain(sink);
- 
- 	/*
- 	 * Edid mgmt connector gets first update only in mode_valid hook and then
- 	 * the connector sink is set to either fake or physical sink depends on link status.
- 	 * Skip if already done during boot.
- 	 */
- 	if (aconnector->base.force != DRM_FORCE_UNSPECIFIED
- 			&& aconnector->dc_em_sink) {
- 
- 		/*
- 		 * For S3 resume with headless use eml_sink to fake stream
- 		 * because on resume connector->sink is set to NULL
- 		 */
- 		guard(mutex)(&dev->mode_config.mutex);
- 
- 		if (sink) {
- 			if (aconnector->dc_sink) {
- 				amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 				/*
- 				 * retain and release below are used to
- 				 * bump up refcount for sink because the link doesn't point
- 				 * to it anymore after disconnect, so on next crtc to connector
- 				 * reshuffle by UMD we will get into unwanted dc_sink release
- 				 */
- 				dc_sink_release(aconnector->dc_sink);
- 			}
- 			aconnector->dc_sink = sink;
- 			dc_sink_retain(aconnector->dc_sink);
- 			amdgpu_dm_update_freesync_caps(connector,
- 					aconnector->drm_edid, true);
- 		} else {
- 			amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 			if (!aconnector->dc_sink) {
- 				aconnector->dc_sink = aconnector->dc_em_sink;
- 				dc_sink_retain(aconnector->dc_sink);
- 			}
- 		}
- 
- 		return;
- 	}
- 
- 	/*
- 	 * TODO: temporary guard to look for proper fix
- 	 * if this sink is MST sink, we should not do anything
- 	 */
- 	if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- 		return;
- 
- 	if (aconnector->dc_sink == sink) {
- 		/*
- 		 * We got a DP short pulse (Link Loss, DP CTS, etc...).
- 		 * Do nothing!!
- 		 */
- 		drm_dbg_kms(dev, "DCHPD: connector_id=%d: dc_sink didn't change.\n",
- 				 aconnector->connector_id);
- 		return;
- 	}
- 
- 	drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
- 		    aconnector->connector_id, aconnector->dc_sink, sink);
- 
- 	/* When polling, DRM has already locked the mutex for us. */
- 	if (!drm_kms_helper_is_poll_worker())
- 		mutex_lock(&dev->mode_config.mutex);
- 
- 	/*
- 	 * 1. Update status of the drm connector
- 	 * 2. Send an event and let userspace tell us what to do
- 	 */
- 	if (sink) {
- 		/*
- 		 * TODO: check if we still need the S3 mode update workaround.
- 		 * If yes, put it here.
- 		 */
- 		if (aconnector->dc_sink) {
- 			amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 			dc_sink_release(aconnector->dc_sink);
- 		}
- 
- 		aconnector->dc_sink = sink;
- 		dc_sink_retain(aconnector->dc_sink);
- 		drm_edid_free(aconnector->drm_edid);
- 		aconnector->drm_edid = NULL;
- 		if (sink->dc_edid.length == 0) {
- 			hdmi_cec_unset_edid(aconnector);
- 			if (aconnector->dc_link->aux_mode) {
- 				drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
- 			}
- 		} else {
- 			const struct edid *edid = (const struct edid *)sink->dc_edid.raw_edid;
- 
- 			aconnector->drm_edid = drm_edid_alloc(edid, sink->dc_edid.length);
- 			drm_edid_connector_update(connector, aconnector->drm_edid);
- 
- 			hdmi_cec_set_edid(aconnector);
- 			if (aconnector->dc_link->aux_mode)
- 				drm_dp_cec_attach(&aconnector->dm_dp_aux.aux,
- 						  connector->display_info.source_physical_address);
- 		}
- 
- 		if (!aconnector->timing_requested) {
- 			aconnector->timing_requested =
- 				kzalloc_obj(struct dc_crtc_timing);
- 			if (!aconnector->timing_requested)
- 				drm_err(dev,
- 					"failed to create aconnector->requested_timing\n");
- 		}
- 
- 		amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid, true);
- 		update_connector_ext_caps(aconnector);
- 		dm_set_panel_type(aconnector);
- 	} else {
- 		hdmi_cec_unset_edid(aconnector);
- 		drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
- 		amdgpu_dm_update_freesync_caps(connector, NULL, true);
- 		aconnector->num_modes = 0;
- 		dc_sink_release(aconnector->dc_sink);
- 		aconnector->dc_sink = NULL;
- 		drm_edid_free(aconnector->drm_edid);
- 		aconnector->drm_edid = NULL;
- 		kfree(aconnector->timing_requested);
- 		aconnector->timing_requested = NULL;
- 		/* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
- 		if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
- 			connector->state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
- 	}
- 
- 	update_subconnector_property(aconnector);
- 
- 	/* When polling, the mutex will be unlocked for us by DRM. */
- 	if (!drm_kms_helper_is_poll_worker())
- 		mutex_unlock(&dev->mode_config.mutex);
- }
- 
- static bool are_sinks_equal(const struct dc_sink *sink1, const struct dc_sink *sink2)
- {
- 	if (!sink1 || !sink2)
- 		return false;
- 	if (sink1->sink_signal != sink2->sink_signal)
- 		return false;
- 
- 	if (sink1->dc_edid.length != sink2->dc_edid.length)
- 		return false;
- 
- 	if (memcmp(sink1->dc_edid.raw_edid, sink2->dc_edid.raw_edid,
- 		   sink1->dc_edid.length) != 0)
- 		return false;
- 	return true;
- }
- 
- 
- /**
-  * DOC: hdmi_hpd_debounce_work
-  *
-  * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
-  * (such as during power save transitions), this delay determines how long to
-  * wait before processing the HPD event. This allows distinguishing between a
-  * physical unplug (>hdmi_hpd_debounce_delay)
-  * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
-  *
-  * If the toggle is less than this delay, the driver compares sink capabilities
-  * and permits a hotplug event if they changed.
-  *
-  * The default value of 1500ms was chosen based on experimental testing with
-  * various monitors that exhibit spontaneous HPD toggling behavior.
-  */
- static void hdmi_hpd_debounce_work(struct work_struct *work)
- {
- 	struct amdgpu_dm_connector *aconnector =
- 		container_of(to_delayed_work(work), struct amdgpu_dm_connector,
- 			     hdmi_hpd_debounce_work);
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dc *dc = aconnector->dc_link->ctx->dc;
- 	bool fake_reconnect = false;
- 	bool reallow_idle = false;
- 	bool ret = false;
- 	guard(mutex)(&aconnector->hpd_lock);
- 
- 	/* Re-detect the display */
- 	scoped_guard(mutex, &adev->dm.dc_lock) {
- 		if (dc->caps.ips_support && dc->ctx->dmub_srv->idle_allowed) {
- 			dc_allow_idle_optimizations(dc, false);
- 			reallow_idle = true;
- 		}
- 		ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
- 	}
- 
- 	if (ret) {
- 		/* Apply workaround delay for certain panels */
- 		apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
- 		/* Compare sinks to determine if this was a spontaneous HPD toggle */
- 		if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
- 			/*
- 			* Sinks match - this was a spontaneous HDMI HPD toggle.
- 			*/
- 			drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
- 			fake_reconnect = true;
- 		}
- 
- 		/* Update connector state */
- 		amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 		drm_modeset_lock_all(dev);
- 		dm_restore_drm_connector_state(dev, connector);
- 		drm_modeset_unlock_all(dev);
- 
- 		/* Only notify OS if sink actually changed */
- 		if (!fake_reconnect && aconnector->base.force == DRM_FORCE_UNSPECIFIED)
- 			drm_kms_helper_hotplug_event(dev);
- 	}
- 
- 	/* Release the cached sink reference */
- 	if (aconnector->hdmi_prev_sink) {
- 		dc_sink_release(aconnector->hdmi_prev_sink);
- 		aconnector->hdmi_prev_sink = NULL;
- 	}
- 
- 	scoped_guard(mutex, &adev->dm.dc_lock) {
- 		if (reallow_idle && dc->caps.ips_support)
- 			dc_allow_idle_optimizations(dc, true);
- 	}
- }
- 
- static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	enum dc_connection_type new_connection_type = dc_connection_none;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
- 	struct dc *dc = aconnector->dc_link->ctx->dc;
- 	bool ret = false;
- 	bool debounce_required = false;
- 
- 	if (adev->dm.disable_hpd_irq)
- 		return;
- 
- 	/*
- 	 * In case of failure or MST no need to update connector status or notify the OS
- 	 * since (for MST case) MST does this in its own context.
- 	 */
- 	guard(mutex)(&aconnector->hpd_lock);
- 
- 	if (adev->dm.hdcp_workqueue) {
- 		hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index);
- 		dm_con_state->update_hdcp = true;
- 	}
- 	if (aconnector->fake_enable)
- 		aconnector->fake_enable = false;
- 
- 	aconnector->timing_changed = false;
- 
- 	if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
- 		drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
- 
- 	/*
- 	 * Check for HDMI disconnect with debounce enabled.
- 	 */
- 	debounce_required = (aconnector->hdmi_hpd_debounce_delay_ms > 0 &&
- 			      dc_is_hdmi_signal(aconnector->dc_link->connector_signal) &&
- 			      new_connection_type == dc_connection_none &&
- 			      aconnector->dc_link->local_sink != NULL);
- 
- 	if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 		emulated_link_detect(aconnector->dc_link);
- 
- 		drm_modeset_lock_all(dev);
- 		dm_restore_drm_connector_state(dev, connector);
- 		drm_modeset_unlock_all(dev);
- 
- 		if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
- 			drm_kms_helper_connector_hotplug_event(connector);
- 	} else if (debounce_required) {
- 		/*
- 		 * HDMI disconnect detected - schedule delayed work instead of
- 		 * processing immediately. This allows us to coalesce spurious
- 		 * HDMI signals from physical unplugs.
- 		 */
- 		drm_dbg_kms(dev, "HDMI HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
- 			    aconnector->hdmi_hpd_debounce_delay_ms);
- 
- 		/* Cache the current sink for later comparison */
- 		if (aconnector->hdmi_prev_sink)
- 			dc_sink_release(aconnector->hdmi_prev_sink);
- 		aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
- 		if (aconnector->hdmi_prev_sink)
- 			dc_sink_retain(aconnector->hdmi_prev_sink);
- 
- 		/* Schedule delayed detection. */
- 		if (mod_delayed_work(system_percpu_wq,
- 				 &aconnector->hdmi_hpd_debounce_work,
- 				 msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms)))
- 			drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n");
- 
- 	} else {
- 
- 		/* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
- 		if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
- 			return;
- 
- 		scoped_guard(mutex, &adev->dm.dc_lock) {
- 			dc_exit_ips_for_hw_access(dc);
- 			ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
- 		}
- 		if (ret) {
- 			/* w/a delay for certain panels */
- 			apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
- 			amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 			drm_modeset_lock_all(dev);
- 			dm_restore_drm_connector_state(dev, connector);
- 			drm_modeset_unlock_all(dev);
- 
- 			if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
- 				drm_kms_helper_connector_hotplug_event(connector);
- 		}
- 	}
- }
- 
- static void handle_hpd_irq(void *param)
- {
- 	struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
- 
- 	handle_hpd_irq_helper(aconnector);
- 
- }
- 
- static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_rx_irq_offload_work_queue *offload_wq,
- 							union hpd_irq_data hpd_irq_data)
- {
- 	struct hpd_rx_irq_offload_work *offload_work = kzalloc_obj(*offload_work);
- 
- 	if (!offload_work) {
- 		drm_err(adev_to_drm(adev), "Failed to allocate hpd_rx_irq_offload_work.\n");
- 		return;
- 	}
- 
- 	INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work);
- 	offload_work->data = hpd_irq_data;
- 	offload_work->offload_wq = offload_wq;
- 	offload_work->adev = adev;
- 
- 	queue_work(offload_wq->wq, &offload_work->work);
- 	drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work");
- }
- 
- static void handle_hpd_rx_irq(void *param)
- {
- 	struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	struct dc_link *dc_link = aconnector->dc_link;
- 	bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
- 	bool result = false;
- 	enum dc_connection_type new_connection_type = dc_connection_none;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	union hpd_irq_data hpd_irq_data;
- 	bool link_loss = false;
- 	bool has_left_work = false;
- 	int idx = dc_link->link_index;
- 	struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx];
- 	struct dc *dc = aconnector->dc_link->ctx->dc;
- 
- 	memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
- 
- 	if (adev->dm.disable_hpd_irq)
- 		return;
- 
- 	/*
- 	 * TODO:Temporary add mutex to protect hpd interrupt not have a gpio
- 	 * conflict, after implement i2c helper, this mutex should be
- 	 * retired.
- 	 */
- 	mutex_lock(&aconnector->hpd_lock);
- 
- 	result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data,
- 						&link_loss, true, &has_left_work);
- 
- 	if (!has_left_work)
- 		goto out;
- 
- 	if (hpd_irq_data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
- 		schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data);
- 		goto out;
- 	}
- 
- 	if (dc_link_dp_allow_hpd_rx_irq(dc_link)) {
- 		if (hpd_irq_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY ||
- 			hpd_irq_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
- 			bool skip = false;
- 
- 			/*
- 			 * DOWN_REP_MSG_RDY is also handled by polling method
- 			 * mgr->cbs->poll_hpd_irq()
- 			 */
- 			spin_lock(&offload_wq->offload_lock);
- 			skip = offload_wq->is_handling_mst_msg_rdy_event;
- 
- 			if (!skip)
- 				offload_wq->is_handling_mst_msg_rdy_event = true;
- 
- 			spin_unlock(&offload_wq->offload_lock);
- 
- 			if (!skip)
- 				schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data);
- 
- 			goto out;
- 		}
- 
- 		if (link_loss) {
- 			bool skip = false;
- 
- 			spin_lock(&offload_wq->offload_lock);
- 			skip = offload_wq->is_handling_link_loss;
- 
- 			if (!skip)
- 				offload_wq->is_handling_link_loss = true;
- 
- 			spin_unlock(&offload_wq->offload_lock);
- 
- 			if (!skip)
- 				schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data);
- 
- 			goto out;
- 		}
- 	}
- 
- out:
- 	if (result && !is_mst_root_connector) {
- 		/* Downstream Port status changed. */
- 		if (!dc_link_detect_connection_type(dc_link, &new_connection_type))
- 			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
- 
- 		if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 			emulated_link_detect(dc_link);
- 
- 			if (aconnector->fake_enable)
- 				aconnector->fake_enable = false;
- 
- 			amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 
- 			drm_modeset_lock_all(dev);
- 			dm_restore_drm_connector_state(dev, connector);
- 			drm_modeset_unlock_all(dev);
- 
- 			drm_kms_helper_connector_hotplug_event(connector);
- 		} else {
- 			bool ret = false;
- 
- 			mutex_lock(&adev->dm.dc_lock);
- 			dc_exit_ips_for_hw_access(dc);
- 			ret = dc_link_detect(dc_link, DETECT_REASON_HPDRX);
- 			mutex_unlock(&adev->dm.dc_lock);
- 
- 			if (ret) {
- 				if (aconnector->fake_enable)
- 					aconnector->fake_enable = false;
- 
- 				amdgpu_dm_update_connector_after_detect(aconnector);
- 
- 				drm_modeset_lock_all(dev);
- 				dm_restore_drm_connector_state(dev, connector);
- 				drm_modeset_unlock_all(dev);
- 
- 				drm_kms_helper_connector_hotplug_event(connector);
- 			}
- 		}
- 	}
- 	if (hpd_irq_data.bytes.device_service_irq.bits.CP_IRQ) {
- 		if (adev->dm.hdcp_workqueue)
- 			hdcp_handle_cpirq(adev->dm.hdcp_workqueue,  aconnector->base.index);
- 	}
- 
- 	if (dc_link->type != dc_connection_mst_branch)
- 		drm_dp_cec_irq(&aconnector->dm_dp_aux.aux);
- 
- 	mutex_unlock(&aconnector->hpd_lock);
- }
- 
- static int register_hpd_handlers(struct amdgpu_device *adev)
- {
- 	struct drm_device *dev = adev_to_drm(adev);
- 	struct drm_connector *connector;
- 	struct amdgpu_dm_connector *aconnector;
- 	const struct dc_link *dc_link;
- 	struct dc_interrupt_params int_params = {0};
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	if (dc_is_dmub_outbox_supported(adev->dm.dc)) {
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD,
- 			dmub_hpd_callback, true)) {
- 			drm_err(adev_to_drm(adev), "fail to register dmub hpd callback");
- 			return -EINVAL;
- 		}
- 
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ,
- 			dmub_hpd_callback, true)) {
- 			drm_err(adev_to_drm(adev), "fail to register dmub hpd callback");
- 			return -EINVAL;
- 		}
- 
- 		if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_SENSE_NOTIFY,
- 			dmub_hpd_sense_callback, true)) {
- 			drm_err(adev_to_drm(adev), "fail to register dmub hpd sense callback");
- 			return -EINVAL;
- 		}
- 	}
- 
- 	list_for_each_entry(connector,
- 			&dev->mode_config.connector_list, head)	{
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		dc_link = aconnector->dc_link;
- 
- 		if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
- 			int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
- 			int_params.irq_source = dc_link->irq_source_hpd;
- 
- 			if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 				int_params.irq_source  < DC_IRQ_SOURCE_HPD1 ||
- 				int_params.irq_source  > DC_IRQ_SOURCE_HPD6) {
- 				drm_err(adev_to_drm(adev), "Failed to register hpd irq!\n");
- 				return -EINVAL;
- 			}
- 
- 			if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 				handle_hpd_irq, (void *) aconnector))
- 				return -ENOMEM;
- 		}
- 
- 		if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
- 
- 			/* Also register for DP short pulse (hpd_rx). */
- 			int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
- 			int_params.irq_source =	dc_link->irq_source_hpd_rx;
- 
- 			if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 				int_params.irq_source  < DC_IRQ_SOURCE_HPD1RX ||
- 				int_params.irq_source  > DC_IRQ_SOURCE_HPD6RX) {
- 				drm_err(adev_to_drm(adev), "Failed to register hpd rx irq!\n");
- 				return -EINVAL;
- 			}
- 
- 			if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 				handle_hpd_rx_irq, (void *) aconnector))
- 				return -ENOMEM;
- 		}
- 	}
- 	return 0;
- }
- 
- /* Register IRQ sources and initialize IRQ callbacks */
- static int dce110_register_irq_handlers(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	struct common_irq_params *c_irq_params;
- 	struct dc_interrupt_params int_params = {0};
- 	int r;
- 	int i;
- 	unsigned int src_id;
- 	unsigned int client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
- 	/* Use different interrupts for VBLANK on DCE 6 vs. newer. */
- 	const unsigned int vblank_d1 =
- 		adev->dm.dc->ctx->dce_version >= DCE_VERSION_8_0
- 		? VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 : 1;
- 
- 	if (adev->family >= AMDGPU_FAMILY_AI)
- 		client_id = SOC15_IH_CLIENTID_DCE;
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	/*
- 	 * Actions of amdgpu_irq_add_id():
- 	 * 1. Register a set() function with base driver.
- 	 *    Base driver will call set() function to enable/disable an
- 	 *    interrupt in DC hardware.
- 	 * 2. Register amdgpu_dm_irq_handler().
- 	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
- 	 *    coming from DC hardware.
- 	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
- 	 *    for acknowledging and handling.
- 	 */
- 
- 	/* Use VBLANK interrupt */
- 	for (i = 0; i < adev->mode_info.num_crtc; i++) {
- 		src_id = vblank_d1 + i;
- 		r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->crtc_irq);
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, src_id, 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source  < DC_IRQ_SOURCE_VBLANK1 ||
- 			int_params.irq_source  > DC_IRQ_SOURCE_VBLANK6) {
- 			drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_crtc_high_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	if (dc_supports_vrr(adev->dm.dc->ctx->dce_version)) {
- 		/* Use VUPDATE interrupt */
- 		for (i = 0; i < adev->mode_info.num_crtc; i++) {
- 			src_id = VISLANDS30_IV_SRCID_D1_V_UPDATE_INT + i * 2;
- 			r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->vupdate_irq);
- 			if (r) {
- 				drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n");
- 				return r;
- 			}
- 
- 			int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 			int_params.irq_source =
- 				dc_interrupt_to_irq_source(dc, src_id, 0);
- 
- 			if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 				int_params.irq_source  < DC_IRQ_SOURCE_VUPDATE1 ||
- 				int_params.irq_source  > DC_IRQ_SOURCE_VUPDATE6) {
- 				drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n");
- 				return -EINVAL;
- 			}
- 
- 			c_irq_params = &adev->dm.vupdate_params[
- 				int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1];
- 			c_irq_params->adev = adev;
- 			c_irq_params->irq_src = int_params.irq_source;
- 
- 			if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 				dm_vupdate_high_irq, c_irq_params))
- 				return -ENOMEM;
- 		}
- 	}
- 
- 	/* Use GRPH_PFLIP interrupt */
- 	for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP;
- 			i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) {
- 		r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq);
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, i, 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source  < DC_IRQ_SOURCE_PFLIP_FIRST ||
- 			int_params.irq_source  > DC_IRQ_SOURCE_PFLIP_LAST) {
- 			drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_pflip_high_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	/* HPD */
- 	r = amdgpu_irq_add_id(adev, client_id,
- 			VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq);
- 	if (r) {
- 		drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n");
- 		return r;
- 	}
- 
- 	r = register_hpd_handlers(adev);
- 
- 	return r;
- }
- 
- /* Register IRQ sources and initialize IRQ callbacks */
- static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	struct common_irq_params *c_irq_params;
- 	struct dc_interrupt_params int_params = {0};
- 	int r;
- 	int i;
- #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- 	static const unsigned int vrtl_int_srcid[] = {
- 		DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL,
- 		DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL
- 	};
- #endif
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	/*
- 	 * Actions of amdgpu_irq_add_id():
- 	 * 1. Register a set() function with base driver.
- 	 *    Base driver will call set() function to enable/disable an
- 	 *    interrupt in DC hardware.
- 	 * 2. Register amdgpu_dm_irq_handler().
- 	 *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
- 	 *    coming from DC hardware.
- 	 *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
- 	 *    for acknowledging and handling.
- 	 */
- 
- 	/* Use otg vertical line interrupt */
- #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
- 	for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) {
- 		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE,
- 				vrtl_int_srcid[i], &adev->vline0_irq);
- 
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add vline0 irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 ||
- 			int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) {
- 			drm_err(adev_to_drm(adev), "Failed to register vline0 irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.vline0_params[int_params.irq_source
- 					- DC_IRQ_SOURCE_DC1_VLINE0];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_dcn_vertical_interrupt0_high_irq,
- 			c_irq_params))
- 			return -ENOMEM;
- 	}
- #endif
- 
- 	/* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to
- 	 * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx
- 	 * to trigger at end of each vblank, regardless of state of the lock,
- 	 * matching DCE behaviour.
- 	 */
- 	for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT;
- 	     i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1;
- 	     i++) {
- 		r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq);
- 
- 		if (r) {
- 			drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n");
- 			return r;
- 		}
- 
- 		int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
- 		int_params.irq_source =
- 			dc_interrupt_to_irq_source(dc, i, 0);
- 
- 		if (int_params.irq_source == DC_IRQ_SOURCE_INVALID ||
- 			int_params.irq_source  < DC_IRQ_SOURCE_VUPDATE1 ||
- 			int_params.irq_source  > DC_IRQ_SOURCE_VUPDATE6) {
- 			drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n");
- 			return -EINVAL;
- 		}
- 
- 		c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_vupdate_high_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	/* HPD */
- 	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
- 			&adev->hpd_irq);
- 	if (r) {
- 		drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n");
- 		return r;
- 	}
- 
- 	r = register_hpd_handlers(adev);
- 
- 	return r;
- }
- /* Register Outbox IRQ sources and initialize IRQ callbacks */
- static int register_outbox_irq_handlers(struct amdgpu_device *adev)
- {
- 	struct dc *dc = adev->dm.dc;
- 	struct common_irq_params *c_irq_params;
- 	struct dc_interrupt_params int_params = {0};
- 	int r, i;
- 
- 	int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
- 	int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
- 
- 	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT,
- 			&adev->dmub_outbox_irq);
- 	if (r) {
- 		drm_err(adev_to_drm(adev), "Failed to add outbox irq id!\n");
- 		return r;
- 	}
- 
- 	if (dc->ctx->dmub_srv) {
- 		i = DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT;
- 		int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
- 		int_params.irq_source =
- 		dc_interrupt_to_irq_source(dc, i, 0);
- 
- 		c_irq_params = &adev->dm.dmub_outbox_params[0];
- 
- 		c_irq_params->adev = adev;
- 		c_irq_params->irq_src = int_params.irq_source;
- 
- 		if (!amdgpu_dm_irq_register_interrupt(adev, &int_params,
- 			dm_dmub_outbox1_low_irq, c_irq_params))
- 			return -ENOMEM;
- 	}
- 
- 	return 0;
- }
- 
  /*
   * Acquires the lock for the atomic state object and returns
   * the new atomic state.
@@@ -5196,420 -2401,6 +2401,6 @@@ static int amdgpu_dm_mode_config_init(s
  	return 0;
  }
  
- #define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12
- #define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255
- #define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2)
- #define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50
- 
- void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm,
- 				     int bl_idx)
- {
- 	struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[bl_idx];
- 
- 	if (caps->caps_valid)
- 		return;
- 
- #if defined(CONFIG_ACPI)
- 	amdgpu_acpi_get_backlight_caps(caps);
- 
- 	/* validate the firmware value is sane */
- 	if (caps->caps_valid) {
- 		int spread = caps->max_input_signal - caps->min_input_signal;
- 
- 		if (caps->max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
- 		    caps->min_input_signal < 0 ||
- 		    spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT ||
- 		    spread < AMDGPU_DM_MIN_SPREAD) {
- 			drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n",
- 				      caps->min_input_signal, caps->max_input_signal);
- 			caps->caps_valid = false;
- 		}
- 	}
- 
- 	if (!caps->caps_valid) {
- 		caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
- 		caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
- 		caps->caps_valid = true;
- 	}
- #else
- 	if (caps->aux_support)
- 		return;
- 
- 	caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT;
- 	caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT;
- 	caps->caps_valid = true;
- #endif
- }
- 
- static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
- 				unsigned int *min, unsigned int *max)
- {
- 	if (!caps)
- 		return 0;
- 
- 	if (caps->aux_support) {
- 		// Firmware limits are in nits, DC API wants millinits.
- 		*max = 1000 * caps->aux_max_input_signal;
- 		*min = 1000 * caps->aux_min_input_signal;
- 	} else {
- 		// Firmware limits are 8-bit, PWM control is 16-bit.
- 		*max = 0x101 * caps->max_input_signal;
- 		*min = 0x101 * caps->min_input_signal;
- 	}
- 	return 1;
- }
- 
- /* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */
- static inline u32 scale_input_to_fw(int min, int max, u64 input)
- {
- 	return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min);
- }
- 
- /* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */
- static inline u32 scale_fw_to_input(int min, int max, u64 input)
- {
- 	return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), AMDGPU_MAX_BL_LEVEL);
- }
- 
- static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
- 				      unsigned int min, unsigned int max,
- 				      uint32_t *user_brightness)
- {
- 	u32 brightness = scale_input_to_fw(min, max, *user_brightness);
- 	u8 lower_signal, upper_signal, upper_lum, lower_lum, lum;
- 	int left, right;
- 
- 	if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)
- 		return;
- 
- 	if (!caps->data_points)
- 		return;
- 
- 	/*
- 	 * Handle the case where brightness is below the first data point
- 	 * Interpolate between (0,0) and (first_signal, first_lum)
- 	 */
- 	if (brightness < caps->luminance_data[0].input_signal) {
- 		lum = DIV_ROUND_CLOSEST(caps->luminance_data[0].luminance * brightness,
- 					caps->luminance_data[0].input_signal);
- 		goto scale;
- 	}
- 
- 	left = 0;
- 	right = caps->data_points - 1;
- 	while (left <= right) {
- 		int mid = left + (right - left) / 2;
- 		u8 signal = caps->luminance_data[mid].input_signal;
- 
- 		/* Exact match found */
- 		if (signal == brightness) {
- 			lum = caps->luminance_data[mid].luminance;
- 			goto scale;
- 		}
- 
- 		if (signal < brightness)
- 			left = mid + 1;
- 		else
- 			right = mid - 1;
- 	}
- 
- 	/* verify bound */
- 	if (left >= caps->data_points)
- 		left = caps->data_points - 1;
- 
- 	/* At this point, left > right */
- 	lower_signal = caps->luminance_data[right].input_signal;
- 	upper_signal = caps->luminance_data[left].input_signal;
- 	lower_lum = caps->luminance_data[right].luminance;
- 	upper_lum = caps->luminance_data[left].luminance;
- 
- 	/* interpolate */
- 	if (right == left || !lower_lum)
- 		lum = upper_lum;
- 	else
- 		lum = lower_lum + DIV_ROUND_CLOSEST((upper_lum - lower_lum) *
- 						    (brightness - lower_signal),
- 						    upper_signal - lower_signal);
- scale:
- 	*user_brightness = scale_fw_to_input(min, max,
- 					     DIV_ROUND_CLOSEST(lum * brightness, 101));
- }
- 
- static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,
- 					uint32_t brightness)
- {
- 	unsigned int min, max;
- 
- 	if (!get_brightness_range(caps, &min, &max))
- 		return brightness;
- 
- 	convert_custom_brightness(caps, min, max, &brightness);
- 
- 	// Rescale 0..max to min..max
- 	return min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max);
- }
- 
- static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps,
- 				      uint32_t brightness)
- {
- 	unsigned int min, max;
- 
- 	if (!get_brightness_range(caps, &min, &max))
- 		return brightness;
- 
- 	if (brightness < min)
- 		return 0;
- 	// Rescale min..max to 0..max
- 	return DIV_ROUND_CLOSEST_ULL((u64)max * (brightness - min),
- 				 max - min);
- }
- 
- static struct dc_stream_state *dm_find_stream_with_link(
- 	struct amdgpu_display_manager *dm,
- 	struct dc_link *link)
- {
- 	struct dc_state *cur_dc_state = dm->dc->current_state;
- 	struct dc_stream_state *stream = NULL;
- 	int i;
- 
- 	for (i = 0; i < cur_dc_state->stream_count; i++) {
- 		stream = cur_dc_state->streams[i];
- 		if (stream->link == link)
- 			return stream;
- 	}
- 
- 	return NULL;
- }
- 
- static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
- 					 int bl_idx,
- 					 u32 user_brightness)
- {
- 	struct amdgpu_dm_backlight_caps *caps;
- 	struct dc_link *link;
- 	u32 brightness = 0;
- 	bool rc = false, reallow_idle = false;
- 	struct drm_connector *connector;
- 	struct dc_stream_state *stream;
- 	unsigned int min, max;
- 
- 	list_for_each_entry(connector, &dm->ddev->mode_config.connector_list, head) {
- 		struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 
- 		if (aconnector->bl_idx != bl_idx)
- 			continue;
- 
- 		/* if connector is off, save the brightness for next time it's on */
- 		if (!aconnector->base.encoder) {
- 			dm->brightness[bl_idx] = user_brightness;
- 			dm->actual_brightness[bl_idx] = 0;
- 			return;
- 		}
- 	}
- 
- 	amdgpu_dm_update_backlight_caps(dm, bl_idx);
- 	caps = &dm->backlight_caps[bl_idx];
- 
- 	dm->brightness[bl_idx] = user_brightness;
- 	/* update scratch register */
- 	if (bl_idx == 0)
- 		amdgpu_atombios_scratch_regs_set_backlight_level(dm->adev, dm->brightness[bl_idx]);
- 	brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]);
- 	link = (struct dc_link *)dm->backlight_link[bl_idx];
- 
- 	/* Apply brightness quirk */
- 	if (caps->brightness_mask)
- 		brightness |= caps->brightness_mask;
- 
- 	if (trace_amdgpu_dm_brightness_enabled()) {
- 		trace_amdgpu_dm_brightness(__builtin_return_address(0),
- 					   user_brightness,
- 					   brightness,
- 					   caps->aux_support,
- 					   power_supply_is_system_supplied() > 0);
- 	}
- 
- 	stream = dm_find_stream_with_link(dm, link);
- 	if (!stream)
- 		return;
- 
- 	mutex_lock(&dm->dc_lock);
- 	if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) {
- 		dc_allow_idle_optimizations(dm->dc, false);
- 		reallow_idle = true;
- 	}
- 
- 	if (caps->aux_support) {
- 		rc = mod_power_set_backlight_nits(dm->power_module, stream, brightness,
- 			AUX_BL_DEFAULT_TRANSITION_TIME_MS, false, true);
- 	} else {
- 		/* power module uses millipercent */
- 		get_brightness_range(caps, &min, &max);
- 		brightness = DIV_ROUND_CLOSEST(brightness * 100, (max - min)) * 1000;
- 		rc = mod_power_set_backlight_percent(dm->power_module, stream,
- 						     brightness, 0, false);
- 	}
- 
- 	/*
- 	 * Some kms clients create a ramped backlight transition effect
- 	 * by rapidly changing the backlight. Yet we must wait on dmcub
- 	 * fw to exit psr/replay before programming backlight. To
- 	 * prevent lag, keep disable psr/replay and let the next atomic
- 	 * flip clear the event.
- 	 *
- 	 * ToDo: use ISM to handle rapidly backlight change
- 	 *
- 	 * Rapidly backlight change is similar to rapidly cursor events,
- 	 * which is now handled by ISM. ISM can delay the event until system
- 	 * is really idle, so we may use ISM to handle backlight change as well.
- 	 */
- 	amdgpu_dm_psr_set_event(dm, stream, true,
- 		psr_event_hw_programming, true);
- 	amdgpu_dm_replay_set_event(dm, stream, true,
- 		replay_event_hw_programming, true);
- 
- 	if (dm->dc->caps.ips_support && reallow_idle)
- 		dc_allow_idle_optimizations(dm->dc, true);
- 
- 	mutex_unlock(&dm->dc_lock);
- 
- 	if (rc)
- 		dm->actual_brightness[bl_idx] = user_brightness;
- }
- 
- static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
- {
- 	struct amdgpu_display_manager *dm = bl_get_data(bd);
- 	int i;
- 
- 	for (i = 0; i < dm->num_of_edps; i++) {
- 		if (bd == dm->backlight_dev[i])
- 			break;
- 	}
- 	if (i >= AMDGPU_DM_MAX_NUM_EDP)
- 		i = 0;
- 	amdgpu_dm_backlight_set_level(dm, i, bd->props.brightness);
- 
- 	return 0;
- }
- 
- static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm,
- 					 int bl_idx)
- {
- 	int ret;
- 	struct amdgpu_dm_backlight_caps caps;
- 	struct dc_link *link = (struct dc_link *)dm->backlight_link[bl_idx];
- 
- 	amdgpu_dm_update_backlight_caps(dm, bl_idx);
- 	caps = dm->backlight_caps[bl_idx];
- 
- 	if (caps.aux_support) {
- 		u32 avg, peak;
- 
- 		if (!dc_link_get_backlight_level_nits(link, &avg, &peak))
- 			return dm->brightness[bl_idx];
- 		return convert_brightness_to_user(&caps, avg);
- 	}
- 
- 	ret = dc_link_get_backlight_level(link);
- 
- 	if (ret == DC_ERROR_UNEXPECTED)
- 		return dm->brightness[bl_idx];
- 
- 	return convert_brightness_to_user(&caps, ret);
- }
- 
- static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
- {
- 	struct amdgpu_display_manager *dm = bl_get_data(bd);
- 	int i;
- 
- 	for (i = 0; i < dm->num_of_edps; i++) {
- 		if (bd == dm->backlight_dev[i])
- 			break;
- 	}
- 	if (i >= AMDGPU_DM_MAX_NUM_EDP)
- 		i = 0;
- 	return amdgpu_dm_backlight_get_level(dm, i);
- }
- 
- static const struct backlight_ops amdgpu_dm_backlight_ops = {
- 	.options = BL_CORE_SUSPENDRESUME,
- 	.get_brightness = amdgpu_dm_backlight_get_brightness,
- 	.update_status	= amdgpu_dm_backlight_update_status,
- };
- 
- static void
- amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_device *drm = aconnector->base.dev;
- 	struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
- 	struct backlight_properties props = { 0 };
- 	struct amdgpu_dm_backlight_caps *caps;
- 	char bl_name[16];
- 	int min, max;
- 	int real_brightness;
- 	int init_brightness;
- 
- 	if (aconnector->bl_idx == -1)
- 		return;
- 
- 	if (!acpi_video_backlight_use_native()) {
- 		drm_info(drm, "Skipping amdgpu DM backlight registration\n");
- 		/* Try registering an ACPI video backlight device instead. */
- 		acpi_video_register_backlight();
- 		return;
- 	}
- 
- 	caps = &dm->backlight_caps[aconnector->bl_idx];
- 	if (get_brightness_range(caps, &min, &max)) {
- 		if (power_supply_is_system_supplied() > 0)
- 			props.brightness = DIV_ROUND_CLOSEST(max * caps->ac_level, 100);
- 		else
- 			props.brightness = DIV_ROUND_CLOSEST(max * caps->dc_level, 100);
- 		/* min is zero, so max needs to be adjusted */
- 		props.max_brightness = max;
- 		drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
- 			caps->ac_level, caps->dc_level);
- 	} else
- 		props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL;
- 
- 	init_brightness = props.brightness;
- 
- 	if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) {
- 		drm_info(drm, "Using custom brightness curve\n");
- 		props.scale = BACKLIGHT_SCALE_NON_LINEAR;
- 	} else
- 		props.scale = BACKLIGHT_SCALE_LINEAR;
- 	props.type = BACKLIGHT_RAW;
- 
- 	snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
- 		 drm->primary->index + aconnector->bl_idx);
- 
- 	dm->backlight_dev[aconnector->bl_idx] =
- 		backlight_device_register(bl_name, aconnector->base.kdev, dm,
- 					  &amdgpu_dm_backlight_ops, &props);
- 	dm->brightness[aconnector->bl_idx] = props.brightness;
- 
- 	if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) {
- 		drm_err(drm, "DM: Backlight registration failed!\n");
- 		dm->backlight_dev[aconnector->bl_idx] = NULL;
- 	} else {
- 		/*
- 		 * dm->brightness[x] can be inconsistent just after startup until
- 		 * ops.get_brightness is called.
- 		 */
- 		real_brightness =
- 			amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]);
- 
- 		if (real_brightness != init_brightness) {
- 			dm->actual_brightness[aconnector->bl_idx] = real_brightness;
- 			dm->brightness[aconnector->bl_idx] = real_brightness;
- 		}
- 		drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name);
- 	}
- }
- 
  static int initialize_plane(struct amdgpu_display_manager *dm,
  			    struct amdgpu_mode_info *mode_info, int plane_id,
  			    enum drm_plane_type plane_type,
@@@ -5651,42 -2442,6 +2442,6 @@@
  }
  
  
- static void setup_backlight_device(struct amdgpu_display_manager *dm,
- 				   struct amdgpu_dm_connector *aconnector)
- {
- 	struct amdgpu_dm_backlight_caps *caps;
- 	struct dc_link *link = aconnector->dc_link;
- 	int bl_idx = dm->num_of_edps;
- 
- 	if (!(link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) ||
- 	    link->type == dc_connection_none)
- 		return;
- 
- 	if (dm->num_of_edps >= AMDGPU_DM_MAX_NUM_EDP) {
- 		drm_warn(adev_to_drm(dm->adev), "Too much eDP connections, skipping backlight setup for additional eDPs\n");
- 		return;
- 	}
- 
- 	aconnector->bl_idx = bl_idx;
- 
- 	amdgpu_dm_update_backlight_caps(dm, bl_idx);
- 	dm->backlight_link[bl_idx] = link;
- 	dm->num_of_edps++;
- 
- 	update_connector_ext_caps(aconnector);
- 	caps = &dm->backlight_caps[aconnector->bl_idx];
- 
- 	/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */
- 	if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0)
- 		drm_object_attach_property(&aconnector->base.base,
- 					   dm->adev->mode_info.abm_level_property,
- 					   ABM_SYSFS_CONTROL);
- }
- 
- static void amdgpu_set_panel_orientation(struct drm_connector *connector);
- 
- 
- 
  /*
   * In this architecture, the association
   * connector -> encoder -> crtc
@@@ -5798,7 -2553,7 +2553,7 @@@ static int amdgpu_dm_initialize_drm_dev
  	case IP_VERSION(4, 0, 1):
  	case IP_VERSION(4, 2, 0):
  	case IP_VERSION(4, 2, 1):
- 		if (register_outbox_irq_handlers(dm->adev)) {
+ 		if (amdgpu_dm_register_outbox_irq_handlers(dm->adev)) {
  			drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
  			goto fail;
  		}
@@@ -5911,7 -2666,7 +2666,7 @@@
  			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
  
  		if (aconnector->base.force && new_connection_type == dc_connection_none) {
- 			emulated_link_detect(link);
+ 			amdgpu_dm_emulated_link_detect(link);
  			amdgpu_dm_update_connector_after_detect(aconnector);
  		} else {
  			bool ret = false;
@@@ -5923,7 -2678,7 +2678,7 @@@
  
  			if (ret) {
  				amdgpu_dm_update_connector_after_detect(aconnector);
- 				setup_backlight_device(dm, aconnector);
+ 				amdgpu_dm_setup_backlight_device(dm, aconnector);
  
  				/* Disable PSR if Replay can be enabled */
  				if (replay_feature_enabled)
@@@ -5975,7 -2730,7 +2730,7 @@@
  	case CHIP_VEGA10:
  	case CHIP_VEGA12:
  	case CHIP_VEGA20:
- 		if (dce110_register_irq_handlers(dm->adev)) {
+ 		if (amdgpu_dm_dce110_register_irq_handlers(dm->adev)) {
  			drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
  			goto fail;
  		}
@@@ -6005,7 -2760,7 +2760,7 @@@
  		case IP_VERSION(4, 0, 1):
  		case IP_VERSION(4, 2, 0):
  		case IP_VERSION(4, 2, 1):
- 			if (dcn10_register_irq_handlers(dm->adev)) {
+ 			if (amdgpu_dm_dcn10_register_irq_handlers(dm->adev)) {
  				drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
  				goto fail;
  			}
@@@ -6096,78 -2851,6 +2851,6 @@@ DEVICE_ATTR_WO(s3_debug)
  
  #endif
  
- static int dm_init_microcode(struct amdgpu_device *adev)
- {
- 	char *fw_name_dmub;
- 	int r;
- 
- 	switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
- 	case IP_VERSION(2, 1, 0):
- 		fw_name_dmub = FIRMWARE_RENOIR_DMUB;
- 		if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id))
- 			fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 0):
- 		if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 0))
- 			fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB;
- 		else
- 			fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 1):
- 		fw_name_dmub = FIRMWARE_VANGOGH_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 2):
- 		fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB;
- 		break;
- 	case IP_VERSION(3, 0, 3):
- 		fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 2):
- 	case IP_VERSION(3, 1, 3):
- 		fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 4):
- 		fw_name_dmub = FIRMWARE_DCN_314_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 5):
- 		fw_name_dmub = FIRMWARE_DCN_315_DMUB;
- 		break;
- 	case IP_VERSION(3, 1, 6):
- 		fw_name_dmub = FIRMWARE_DCN316_DMUB;
- 		break;
- 	case IP_VERSION(3, 2, 0):
- 		fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB;
- 		break;
- 	case IP_VERSION(3, 2, 1):
- 		fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB;
- 		break;
- 	case IP_VERSION(3, 5, 0):
- 		fw_name_dmub = FIRMWARE_DCN_35_DMUB;
- 		break;
- 	case IP_VERSION(3, 5, 1):
- 		fw_name_dmub = FIRMWARE_DCN_351_DMUB;
- 		break;
- 	case IP_VERSION(3, 6, 0):
- 		fw_name_dmub = FIRMWARE_DCN_36_DMUB;
- 		break;
- 	case IP_VERSION(4, 0, 1):
- 		fw_name_dmub = FIRMWARE_DCN_401_DMUB;
- 		break;
- 	case IP_VERSION(4, 2, 0):
- 		fw_name_dmub = FIRMWARE_DCN_42_DMUB;
- 		break;
- 	case IP_VERSION(4, 2, 1):
- 		fw_name_dmub = FIRMWARE_DCN_42B_DMUB;
- 		break;
- 	default:
- 		/* ASIC doesn't support DMUB. */
- 		return 0;
- 	}
- 	r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, AMDGPU_UCODE_REQUIRED,
- 				 "%s", fw_name_dmub);
- 	return r;
- }
- 
  static int dm_early_init(struct amdgpu_ip_block *ip_block)
  {
  	struct amdgpu_device *adev = ip_block->adev;
@@@ -6318,22 -3001,13 +3001,13 @@@
  	return dm_init_microcode(adev);
  }
  
- static bool modereset_required(struct drm_crtc_state *crtc_state)
+ STATIC_IFN_KUNIT bool modereset_required(struct drm_crtc_state *crtc_state)
  {
  	return !crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
  }
+ EXPORT_IF_KUNIT(modereset_required);
  
- static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
- {
- 	drm_encoder_cleanup(encoder);
- 	kfree(encoder);
- }
- 
- static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
- 	.destroy = amdgpu_dm_encoder_destroy,
- };
- 
- static int
+ STATIC_IFN_KUNIT int
  fill_plane_color_attributes(const struct drm_plane_state *plane_state,
  			    const enum surface_pixel_format format,
  			    enum dc_color_space *color_space)
@@@ -6380,6 -3054,7 +3054,7 @@@
  
  	return 0;
  }
+ EXPORT_IF_KUNIT(fill_plane_color_attributes);
  
  static int
  fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
@@@ -6718,7 -3393,7 +3393,7 @@@ ffu
  			   &flip_addrs->dirty_rect_count, true);
  }
  
- static void update_stream_scaling_settings(struct drm_device *dev,
+ void amdgpu_dm_update_stream_scaling_settings(struct drm_device *dev,
  					   const struct drm_display_mode *mode,
  					   const struct dm_connector_state *dm_state,
  					   struct dc_stream_state *stream)
@@@ -6774,2063 -3449,6 +3449,6 @@@
  
  }
  
- static enum dc_color_depth
- convert_color_depth_from_display_info(const struct drm_connector *connector,
- 				      bool is_y420, int requested_bpc)
- {
- 	u8 bpc;
- 
- 	if (is_y420) {
- 		bpc = 8;
- 
- 		/* Cap display bpc based on HDMI 2.0 HF-VSDB */
- 		if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48)
- 			bpc = 16;
- 		else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36)
- 			bpc = 12;
- 		else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
- 			bpc = 10;
- 	} else {
- 		bpc = (uint8_t)connector->display_info.bpc;
- 		/* Assume 8 bpc by default if no bpc is specified. */
- 		bpc = bpc ? bpc : 8;
- 	}
- 
- 	if (requested_bpc > 0) {
- 		/*
- 		 * Cap display bpc based on the user requested value.
- 		 *
- 		 * The value for state->max_bpc may not correctly updated
- 		 * depending on when the connector gets added to the state
- 		 * or if this was called outside of atomic check, so it
- 		 * can't be used directly.
- 		 */
- 		bpc = min_t(u8, bpc, requested_bpc);
- 
- 		/* Round down to the nearest even number. */
- 		bpc = bpc - (bpc & 1);
- 	}
- 
- 	switch (bpc) {
- 	case 0:
- 		/*
- 		 * Temporary Work around, DRM doesn't parse color depth for
- 		 * EDID revision before 1.4
- 		 * TODO: Fix edid parsing
- 		 */
- 		return COLOR_DEPTH_888;
- 	case 6:
- 		return COLOR_DEPTH_666;
- 	case 8:
- 		return COLOR_DEPTH_888;
- 	case 10:
- 		return COLOR_DEPTH_101010;
- 	case 12:
- 		return COLOR_DEPTH_121212;
- 	case 14:
- 		return COLOR_DEPTH_141414;
- 	case 16:
- 		return COLOR_DEPTH_161616;
- 	default:
- 		return COLOR_DEPTH_UNDEFINED;
- 	}
- }
- 
- static enum dc_aspect_ratio
- get_aspect_ratio(const struct drm_display_mode *mode_in)
- {
- 	/* 1-1 mapping, since both enums follow the HDMI spec. */
- 	return (enum dc_aspect_ratio) mode_in->picture_aspect_ratio;
- }
- 
- static enum dc_color_space
- get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing,
- 		       const struct drm_connector_state *connector_state)
- {
- 	enum dc_color_space color_space = COLOR_SPACE_SRGB;
- 
- 	switch (connector_state->colorspace) {
- 	case DRM_MODE_COLORIMETRY_BT601_YCC:
- 		if (dc_crtc_timing->flags.Y_ONLY)
- 			color_space = COLOR_SPACE_YCBCR601_LIMITED;
- 		else
- 			color_space = COLOR_SPACE_YCBCR601;
- 		break;
- 	case DRM_MODE_COLORIMETRY_BT709_YCC:
- 		if (dc_crtc_timing->flags.Y_ONLY)
- 			color_space = COLOR_SPACE_YCBCR709_LIMITED;
- 		else
- 			color_space = COLOR_SPACE_YCBCR709;
- 		break;
- 	case DRM_MODE_COLORIMETRY_OPRGB:
- 		color_space = COLOR_SPACE_ADOBERGB;
- 		break;
- 	case DRM_MODE_COLORIMETRY_BT2020_RGB:
- 	case DRM_MODE_COLORIMETRY_BT2020_YCC:
- 		if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
- 			color_space = COLOR_SPACE_2020_RGB_FULLRANGE;
- 		else
- 			color_space = COLOR_SPACE_2020_YCBCR_LIMITED;
- 		break;
- 	case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601
- 	default:
- 		if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) {
- 			color_space = COLOR_SPACE_SRGB;
- 			if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
- 				color_space = COLOR_SPACE_SRGB_LIMITED;
- 		/*
- 		 * 27030khz is the separation point between HDTV and SDTV
- 		 * according to HDMI spec, we use YCbCr709 and YCbCr601
- 		 * respectively
- 		 */
- 		} else if (dc_crtc_timing->pix_clk_100hz > 270300) {
- 			if (dc_crtc_timing->flags.Y_ONLY)
- 				color_space =
- 					COLOR_SPACE_YCBCR709_LIMITED;
- 			else
- 				color_space = COLOR_SPACE_YCBCR709;
- 		} else {
- 			if (dc_crtc_timing->flags.Y_ONLY)
- 				color_space =
- 					COLOR_SPACE_YCBCR601_LIMITED;
- 			else
- 				color_space = COLOR_SPACE_YCBCR601;
- 		}
- 		break;
- 	}
- 
- 	return color_space;
- }
- 
- static enum display_content_type
- get_output_content_type(const struct drm_connector_state *connector_state)
- {
- 	switch (connector_state->content_type) {
- 	default:
- 	case DRM_MODE_CONTENT_TYPE_NO_DATA:
- 		return DISPLAY_CONTENT_TYPE_NO_DATA;
- 	case DRM_MODE_CONTENT_TYPE_GRAPHICS:
- 		return DISPLAY_CONTENT_TYPE_GRAPHICS;
- 	case DRM_MODE_CONTENT_TYPE_PHOTO:
- 		return DISPLAY_CONTENT_TYPE_PHOTO;
- 	case DRM_MODE_CONTENT_TYPE_CINEMA:
- 		return DISPLAY_CONTENT_TYPE_CINEMA;
- 	case DRM_MODE_CONTENT_TYPE_GAME:
- 		return DISPLAY_CONTENT_TYPE_GAME;
- 	}
- }
- 
- static bool adjust_colour_depth_from_display_info(
- 	struct dc_crtc_timing *timing_out,
- 	const struct drm_display_info *info)
- {
- 	enum dc_color_depth depth = timing_out->display_color_depth;
- 	int normalized_clk;
- 
- 	do {
- 		normalized_clk = timing_out->pix_clk_100hz / 10;
- 		/* YCbCr 4:2:0 requires additional adjustment of 1/2 */
- 		if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420)
- 			normalized_clk /= 2;
- 		/* Adjusting pix clock following on HDMI spec based on colour depth */
- 		switch (depth) {
- 		case COLOR_DEPTH_888:
- 			break;
- 		case COLOR_DEPTH_101010:
- 			normalized_clk = (normalized_clk * 30) / 24;
- 			break;
- 		case COLOR_DEPTH_121212:
- 			normalized_clk = (normalized_clk * 36) / 24;
- 			break;
- 		case COLOR_DEPTH_161616:
- 			normalized_clk = (normalized_clk * 48) / 24;
- 			break;
- 		default:
- 			/* The above depths are the only ones valid for HDMI. */
- 			return false;
- 		}
- 		if (normalized_clk <= info->max_tmds_clock) {
- 			timing_out->display_color_depth = depth;
- 			return true;
- 		}
- 	} while (--depth > COLOR_DEPTH_666);
- 	return false;
- }
- 
- static void fill_stream_properties_from_drm_display_mode(
- 	struct dc_stream_state *stream,
- 	const struct drm_display_mode *mode_in,
- 	const struct drm_connector *connector,
- 	const struct drm_connector_state *connector_state,
- 	const struct dc_stream_state *old_stream,
- 	int requested_bpc)
- {
- 	struct dc_crtc_timing *timing_out = &stream->timing;
- 	const struct drm_display_info *info = &connector->display_info;
- 	struct amdgpu_dm_connector *aconnector = NULL;
- 	struct hdmi_vendor_infoframe hv_frame;
- 	struct hdmi_avi_infoframe avi_frame;
- 	ssize_t err;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 	memset(&hv_frame, 0, sizeof(hv_frame));
- 	memset(&avi_frame, 0, sizeof(avi_frame));
- 
- 	timing_out->h_border_left = 0;
- 	timing_out->h_border_right = 0;
- 	timing_out->v_border_top = 0;
- 	timing_out->v_border_bottom = 0;
- 	/* TODO: un-hardcode */
- 	if (drm_mode_is_420_only(info, mode_in)
- 			&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 			    stream->signal == SIGNAL_TYPE_HDMI_FRL)
- 			&& aconnector
- 			&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420)
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- 	else if (drm_mode_is_420_also(info, mode_in)
- 			&& aconnector
- 			&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420
- 			|| aconnector->force_yuv420_output))
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- 	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
- 			&& aconnector
- 			&& (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422
- 			|| aconnector->force_yuv422_output))
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
- 	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
- 			&& (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 			    stream->signal == SIGNAL_TYPE_HDMI_FRL)
- 			&& aconnector
- 			&& aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR444)
- 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
- 	else
- 		timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
- 
- 	timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
- 	timing_out->display_color_depth = convert_color_depth_from_display_info(
- 		connector,
- 		(timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420),
- 		requested_bpc);
- 	timing_out->scan_type = SCANNING_TYPE_NODATA;
- 	timing_out->hdmi_vic = 0;
- 
- 	if (old_stream) {
- 		timing_out->vic = old_stream->timing.vic;
- 		timing_out->flags.HSYNC_POSITIVE_POLARITY = old_stream->timing.flags.HSYNC_POSITIVE_POLARITY;
- 		timing_out->flags.VSYNC_POSITIVE_POLARITY = old_stream->timing.flags.VSYNC_POSITIVE_POLARITY;
- 	} else {
- 		timing_out->vic = drm_match_cea_mode(mode_in);
- 		if (mode_in->flags & DRM_MODE_FLAG_PHSYNC)
- 			timing_out->flags.HSYNC_POSITIVE_POLARITY = 1;
- 		if (mode_in->flags & DRM_MODE_FLAG_PVSYNC)
- 			timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
- 	}
- 
- 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 		stream->signal == SIGNAL_TYPE_HDMI_FRL) {
- 		err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame,
- 							       (struct drm_connector *)connector,
- 							       mode_in);
- 		if (err < 0)
- 			drm_warn_once(connector->dev, "Failed to setup avi infoframe on connector %s: %zd\n",
- 				      connector->name, err);
- 		timing_out->vic = avi_frame.video_code;
- 		err = drm_hdmi_vendor_infoframe_from_display_mode(&hv_frame,
- 								  (struct drm_connector *)connector,
- 								  mode_in);
- 		if (err < 0)
- 			drm_warn_once(connector->dev, "Failed to setup vendor infoframe on connector %s: %zd\n",
- 				      connector->name, err);
- 		timing_out->hdmi_vic = hv_frame.vic;
- 	}
- 
- 	if (aconnector && is_freesync_video_mode(mode_in, aconnector)) {
- 		timing_out->h_addressable = mode_in->hdisplay;
- 		timing_out->h_total = mode_in->htotal;
- 		timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start;
- 		timing_out->h_front_porch = mode_in->hsync_start - mode_in->hdisplay;
- 		timing_out->v_total = mode_in->vtotal;
- 		timing_out->v_addressable = mode_in->vdisplay;
- 		timing_out->v_front_porch = mode_in->vsync_start - mode_in->vdisplay;
- 		timing_out->v_sync_width = mode_in->vsync_end - mode_in->vsync_start;
- 		timing_out->pix_clk_100hz = mode_in->clock * 10;
- 	} else {
- 		timing_out->h_addressable = mode_in->crtc_hdisplay;
- 		timing_out->h_total = mode_in->crtc_htotal;
- 		timing_out->h_sync_width = mode_in->crtc_hsync_end - mode_in->crtc_hsync_start;
- 		timing_out->h_front_porch = mode_in->crtc_hsync_start - mode_in->crtc_hdisplay;
- 		timing_out->v_total = mode_in->crtc_vtotal;
- 		timing_out->v_addressable = mode_in->crtc_vdisplay;
- 		timing_out->v_front_porch = mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
- 		timing_out->v_sync_width = mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
- 		timing_out->pix_clk_100hz = mode_in->crtc_clock * 10;
- 	}
- 
- 	timing_out->aspect_ratio = get_aspect_ratio(mode_in);
- 
- 	stream->out_transfer_func.type = TF_TYPE_PREDEFINED;
- 	stream->out_transfer_func.tf = TRANSFER_FUNCTION_SRGB;
- 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
- 		if (!adjust_colour_depth_from_display_info(timing_out, info) &&
- 		    drm_mode_is_420_also(info, mode_in) &&
- 		    timing_out->pixel_encoding != PIXEL_ENCODING_YCBCR420) {
- 			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- 			adjust_colour_depth_from_display_info(timing_out, info);
- 		}
- 	}
- 
- 	stream->output_color_space = get_output_color_space(timing_out, connector_state);
- 	stream->content_type = get_output_content_type(connector_state);
- }
- 
- static void fill_audio_info(struct audio_info *audio_info,
- 			    const struct drm_connector *drm_connector,
- 			    const struct dc_sink *dc_sink)
- {
- 	int i = 0;
- 	int cea_revision = 0;
- 	const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
- 
- 	audio_info->manufacture_id = edid_caps->manufacturer_id;
- 	audio_info->product_id = edid_caps->product_id;
- 
- 	cea_revision = drm_connector->display_info.cea_rev;
- 
- 	strscpy(audio_info->display_name,
- 		edid_caps->display_name,
- 		AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
- 
- 	if (cea_revision >= 3) {
- 		audio_info->mode_count = edid_caps->audio_mode_count;
- 
- 		for (i = 0; i < audio_info->mode_count; ++i) {
- 			audio_info->modes[i].format_code =
- 					(enum audio_format_code)
- 					(edid_caps->audio_modes[i].format_code);
- 			audio_info->modes[i].channel_count =
- 					edid_caps->audio_modes[i].channel_count;
- 			audio_info->modes[i].sample_rates.all =
- 					edid_caps->audio_modes[i].sample_rate;
- 			audio_info->modes[i].sample_size =
- 					edid_caps->audio_modes[i].sample_size;
- 		}
- 	}
- 
- 	audio_info->flags.all = edid_caps->speaker_flags;
- 
- 	/* TODO: We only check for the progressive mode, check for interlace mode too */
- 	if (drm_connector->latency_present[0]) {
- 		audio_info->video_latency = drm_connector->video_latency[0];
- 		audio_info->audio_latency = drm_connector->audio_latency[0];
- 	}
- 
- 	/* TODO: For DP, video and audio latency should be calculated from DPCD caps */
- 
- }
- 
- static void
- copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode,
- 				      struct drm_display_mode *dst_mode)
- {
- 	dst_mode->crtc_hdisplay = src_mode->crtc_hdisplay;
- 	dst_mode->crtc_vdisplay = src_mode->crtc_vdisplay;
- 	dst_mode->crtc_clock = src_mode->crtc_clock;
- 	dst_mode->crtc_hblank_start = src_mode->crtc_hblank_start;
- 	dst_mode->crtc_hblank_end = src_mode->crtc_hblank_end;
- 	dst_mode->crtc_hsync_start =  src_mode->crtc_hsync_start;
- 	dst_mode->crtc_hsync_end = src_mode->crtc_hsync_end;
- 	dst_mode->crtc_htotal = src_mode->crtc_htotal;
- 	dst_mode->crtc_hskew = src_mode->crtc_hskew;
- 	dst_mode->crtc_vblank_start = src_mode->crtc_vblank_start;
- 	dst_mode->crtc_vblank_end = src_mode->crtc_vblank_end;
- 	dst_mode->crtc_vsync_start = src_mode->crtc_vsync_start;
- 	dst_mode->crtc_vsync_end = src_mode->crtc_vsync_end;
- 	dst_mode->crtc_vtotal = src_mode->crtc_vtotal;
- }
- 
- static void
- decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
- 					const struct drm_display_mode *native_mode,
- 					bool scale_enabled)
- {
- 	if (scale_enabled || (
- 	    native_mode->clock == drm_mode->clock &&
- 	    native_mode->htotal == drm_mode->htotal &&
- 	    native_mode->vtotal == drm_mode->vtotal)) {
- 		if (native_mode->crtc_clock)
- 			copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
- 	} else {
- 		/* no scaling nor amdgpu inserted, no need to patch */
- 	}
- }
- 
- static struct dc_sink *
- create_fake_sink(struct drm_device *dev, struct dc_link *link)
- {
- 	struct dc_sink_init_data sink_init_data = { 0 };
- 	struct dc_sink *sink = NULL;
- 
- 	sink_init_data.link = link;
- 	sink_init_data.sink_signal = link->connector_signal;
- 
- 	sink = dc_sink_create(&sink_init_data);
- 	if (!sink) {
- 		drm_err(dev, "Failed to create sink!\n");
- 		return NULL;
- 	}
- 	sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
- 
- 	return sink;
- }
- 
- static void set_multisync_trigger_params(
- 		struct dc_stream_state *stream)
- {
- 	struct dc_stream_state *master = NULL;
- 
- 	if (stream->triggered_crtc_reset.enabled) {
- 		master = stream->triggered_crtc_reset.event_source;
- 		stream->triggered_crtc_reset.event =
- 			master->timing.flags.VSYNC_POSITIVE_POLARITY ?
- 			CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING;
- 		stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL;
- 	}
- }
- 
- static void set_master_stream(struct dc_stream_state *stream_set[],
- 			      int stream_count)
- {
- 	int j, highest_rfr = 0, master_stream = 0;
- 
- 	for (j = 0;  j < stream_count; j++) {
- 		if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
- 			int refresh_rate = 0;
- 
- 			refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/
- 				(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
- 			if (refresh_rate > highest_rfr) {
- 				highest_rfr = refresh_rate;
- 				master_stream = j;
- 			}
- 		}
- 	}
- 	for (j = 0;  j < stream_count; j++) {
- 		if (stream_set[j])
- 			stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream];
- 	}
- }
- 
- static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
- {
- 	int i = 0;
- 	struct dc_stream_state *stream;
- 
- 	if (context->stream_count < 2)
- 		return;
- 	for (i = 0; i < context->stream_count ; i++) {
- 		if (!context->streams[i])
- 			continue;
- 		/*
- 		 * TODO: add a function to read AMD VSDB bits and set
- 		 * crtc_sync_master.multi_sync_enabled flag
- 		 * For now it's set to false
- 		 */
- 	}
- 
- 	set_master_stream(context->streams, context->stream_count);
- 
- 	for (i = 0; i < context->stream_count ; i++) {
- 		stream = context->streams[i];
- 
- 		if (!stream)
- 			continue;
- 
- 		set_multisync_trigger_params(stream);
- 	}
- }
- 
- /**
-  * DOC: FreeSync Video
-  *
-  * When a userspace application wants to play a video, the content follows a
-  * standard format definition that usually specifies the FPS for that format.
-  * The below list illustrates some video format and the expected FPS,
-  * respectively:
-  *
-  * - TV/NTSC (23.976 FPS)
-  * - Cinema (24 FPS)
-  * - TV/PAL (25 FPS)
-  * - TV/NTSC (29.97 FPS)
-  * - TV/NTSC (30 FPS)
-  * - Cinema HFR (48 FPS)
-  * - TV/PAL (50 FPS)
-  * - Commonly used (60 FPS)
-  * - Multiples of 24 (48,72,96 FPS)
-  *
-  * The list of standards video format is not huge and can be added to the
-  * connector modeset list beforehand. With that, userspace can leverage
-  * FreeSync to extends the front porch in order to attain the target refresh
-  * rate. Such a switch will happen seamlessly, without screen blanking or
-  * reprogramming of the output in any other way. If the userspace requests a
-  * modesetting change compatible with FreeSync modes that only differ in the
-  * refresh rate, DC will skip the full update and avoid blink during the
-  * transition. For example, the video player can change the modesetting from
-  * 60Hz to 30Hz for playing TV/NTSC content when it goes full screen without
-  * causing any display blink. This same concept can be applied to a mode
-  * setting change.
-  */
- static struct drm_display_mode *
- get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector,
- 		bool use_probed_modes)
- {
- 	struct drm_display_mode *m, *m_pref = NULL;
- 	u16 current_refresh, highest_refresh;
- 	struct list_head *list_head = use_probed_modes ?
- 		&aconnector->base.probed_modes :
- 		&aconnector->base.modes;
- 
- 	if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 		return NULL;
- 
- 	if (aconnector->freesync_vid_base.clock != 0)
- 		return &aconnector->freesync_vid_base;
- 
- 	/* Find the preferred mode */
- 	list_for_each_entry(m, list_head, head) {
- 		if (m->type & DRM_MODE_TYPE_PREFERRED) {
- 			m_pref = m;
- 			break;
- 		}
- 	}
- 
- 	if (!m_pref) {
- 		/* Probably an EDID with no preferred mode. Fallback to first entry */
- 		m_pref = list_first_entry_or_null(
- 				&aconnector->base.modes, struct drm_display_mode, head);
- 		if (!m_pref) {
- 			drm_dbg_driver(aconnector->base.dev, "No preferred mode found in EDID\n");
- 			return NULL;
- 		}
- 	}
- 
- 	highest_refresh = drm_mode_vrefresh(m_pref);
- 
- 	/*
- 	 * Find the mode with highest refresh rate with same resolution.
- 	 * For some monitors, preferred mode is not the mode with highest
- 	 * supported refresh rate.
- 	 */
- 	list_for_each_entry(m, list_head, head) {
- 		current_refresh  = drm_mode_vrefresh(m);
- 
- 		if (m->hdisplay == m_pref->hdisplay &&
- 		    m->vdisplay == m_pref->vdisplay &&
- 		    highest_refresh < current_refresh) {
- 			highest_refresh = current_refresh;
- 			m_pref = m;
- 		}
- 	}
- 
- 	drm_mode_copy(&aconnector->freesync_vid_base, m_pref);
- 	return m_pref;
- }
- 
- static bool is_freesync_video_mode(const struct drm_display_mode *mode,
- 		struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_display_mode *high_mode;
- 	int timing_diff;
- 
- 	high_mode = get_highest_refresh_rate_mode(aconnector, false);
- 	if (!high_mode || !mode)
- 		return false;
- 
- 	timing_diff = high_mode->vtotal - mode->vtotal;
- 
- 	if (high_mode->clock == 0 || high_mode->clock != mode->clock ||
- 	    high_mode->hdisplay != mode->hdisplay ||
- 	    high_mode->vdisplay != mode->vdisplay ||
- 	    high_mode->hsync_start != mode->hsync_start ||
- 	    high_mode->hsync_end != mode->hsync_end ||
- 	    high_mode->htotal != mode->htotal ||
- 	    high_mode->hskew != mode->hskew ||
- 	    high_mode->vscan != mode->vscan ||
- 	    high_mode->vsync_start - mode->vsync_start != timing_diff ||
- 	    high_mode->vsync_end - mode->vsync_end != timing_diff)
- 		return false;
- 	else
- 		return true;
- }
- 
- #if defined(CONFIG_DRM_AMD_DC_FP)
- static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
- 			    struct dc_sink *sink, struct dc_stream_state *stream,
- 			    struct dsc_dec_dpcd_caps *dsc_caps)
- {
- 	stream->timing.flags.DSC = 0;
- 	dsc_caps->is_dsc_supported = false;
- 
- 	if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
- 	    sink->sink_signal == SIGNAL_TYPE_EDP)) {
- 		if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE)
- 			dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
- 				aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
- 				aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
- 				dsc_caps);
- 		else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
- 			if (aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT &&
- 					!aconnector->dsc_settings.dsc_force_disable_passthrough &&
- 					aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0 &&
- 					sink->edid_caps.frl_dsc_support &&
- 					sink->edid_caps.max_frl_rate > 0 &&
- 					sink->edid_caps.frl_dsc_max_frl_rate > 0)
- 				dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
- 			else
- 				dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
- 				      aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
- 				      aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
- 				      dsc_caps);
- 		}
- 	} else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) {
- 		if (sink->edid_caps.frl_dsc_support &&
- 				sink->edid_caps.max_frl_rate > 0 &&
- 				sink->edid_caps.frl_dsc_max_frl_rate > 0)
- 			dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps);
- 	}
- }
- 
- static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector,
- 				    struct dc_sink *sink, struct dc_stream_state *stream,
- 				    struct dsc_dec_dpcd_caps *dsc_caps,
- 				    uint32_t max_dsc_target_bpp_limit_override)
- {
- 	const struct dc_link_settings *verified_link_cap = NULL;
- 	u32 link_bw_in_kbps;
- 	u32 edp_min_bpp_x16, edp_max_bpp_x16;
- 	struct dc *dc = sink->ctx->dc;
- 	struct dc_dsc_bw_range bw_range = {0};
- 	struct dc_dsc_config dsc_cfg = {0};
- 	struct dc_dsc_config_options dsc_options = {0};
- 
- 	dc_dsc_get_default_config_option(dc, &dsc_options);
- 	dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16;
- 
- 	verified_link_cap = dc_link_get_link_cap(stream->link);
- 	link_bw_in_kbps = dc_link_bandwidth_kbps(stream->link, verified_link_cap);
- 	edp_min_bpp_x16 = 8 * 16;
- 	edp_max_bpp_x16 = 8 * 16;
- 
- 	if (edp_max_bpp_x16 > dsc_caps->edp_max_bits_per_pixel)
- 		edp_max_bpp_x16 = dsc_caps->edp_max_bits_per_pixel;
- 
- 	if (edp_max_bpp_x16 < edp_min_bpp_x16)
- 		edp_min_bpp_x16 = edp_max_bpp_x16;
- 
- 	if (dc_dsc_compute_bandwidth_range(dc->res_pool->dscs[0],
- 				dc->debug.dsc_min_slice_height_override,
- 				edp_min_bpp_x16, edp_max_bpp_x16,
- 				dsc_caps,
- 				&stream->timing,
- 				dc_link_get_highest_encoding_format(aconnector->dc_link),
- 				&bw_range)) {
- 
- 		if (bw_range.max_kbps < link_bw_in_kbps) {
- 			if (dc_dsc_compute_config(dc->res_pool->dscs[0],
- 					dsc_caps,
- 					&dsc_options,
- 					0,
- 					&stream->timing,
- 					dc_link_get_highest_encoding_format(aconnector->dc_link),
- 					&dsc_cfg)) {
- 				stream->timing.dsc_cfg = dsc_cfg;
- 				stream->timing.flags.DSC = 1;
- 				stream->timing.dsc_cfg.bits_per_pixel = edp_max_bpp_x16;
- 			}
- 			return;
- 		}
- 	}
- 
- 	if (dc_dsc_compute_config(dc->res_pool->dscs[0],
- 				dsc_caps,
- 				&dsc_options,
- 				link_bw_in_kbps,
- 				&stream->timing,
- 				dc_link_get_highest_encoding_format(aconnector->dc_link),
- 				&dsc_cfg)) {
- 		stream->timing.dsc_cfg = dsc_cfg;
- 		stream->timing.flags.DSC = 1;
- 	}
- }
- 
- static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
- 					struct dc_sink *sink, struct dc_stream_state *stream,
- 					struct dsc_dec_dpcd_caps *dsc_caps)
- {
- 	struct drm_connector *drm_connector = &aconnector->base;
- 	u32 link_bandwidth_kbps;
- 	struct dc *dc = sink->ctx->dc;
- 	const struct dc_hdmi_frl_link_settings *frl_verified_link_cap = NULL;
- 	u32 converter_bw_in_kbps;
- 	u32 sink_bw_in_kbps;
- 	u32 dsc_sink_bw_in_kbps;
- 	u32 max_supported_bw_in_kbps, timing_bw_in_kbps;
- 	u32 dsc_max_supported_bw_in_kbps;
- 	u32 max_dsc_target_bpp_limit_override =
- 		drm_connector->display_info.max_dsc_bpp;
- 	struct dc_dsc_config_options dsc_options = {0};
- 
- 	dc_dsc_get_default_config_option(dc, &dsc_options);
- 	dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16;
- 
- 	link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
- 							dc_link_get_link_cap(aconnector->dc_link));
- 
- 	/* Set DSC policy according to dsc_clock_en */
- 	dc_dsc_policy_set_enable_dsc_when_not_needed(
- 		aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE);
- 
- 	if (sink->sink_signal == SIGNAL_TYPE_EDP &&
- 	    !aconnector->dc_link->panel_config.dsc.disable_dsc_edp &&
- 	    dc->caps.edp_dsc_support && aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE) {
- 
- 		apply_dsc_policy_for_edp(aconnector, sink, stream, dsc_caps, max_dsc_target_bpp_limit_override);
- 
- 	} else if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) {
- 		if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) {
- 			if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
- 						dsc_caps,
- 						&dsc_options,
- 						link_bandwidth_kbps,
- 						&stream->timing,
- 						dc_link_get_highest_encoding_format(aconnector->dc_link),
- 						&stream->timing.dsc_cfg)) {
- 				stream->timing.flags.DSC = 1;
- 				drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from SST RX\n",
- 							__func__, drm_connector->name);
- 			}
- 		} else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
- 			timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing,
- 					dc_link_get_highest_encoding_format(aconnector->dc_link));
- 			converter_bw_in_kbps = aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps;
- 			sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.max_frl_rate);
- 			dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate);
- 
- 			if (dsc_caps->is_frl) {
- 				max_supported_bw_in_kbps = min(link_bandwidth_kbps, converter_bw_in_kbps);
- 				max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, sink_bw_in_kbps);
- 				dsc_max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, dsc_sink_bw_in_kbps);
- 			} else {
- 				max_supported_bw_in_kbps = link_bandwidth_kbps;
- 				dsc_max_supported_bw_in_kbps = link_bandwidth_kbps;
- 			}
- 
- 			if (timing_bw_in_kbps > max_supported_bw_in_kbps &&
- 					max_supported_bw_in_kbps > 0 &&
- 					dsc_max_supported_bw_in_kbps > 0)
- 				if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
- 						dsc_caps,
- 						&dsc_options,
- 						dsc_max_supported_bw_in_kbps,
- 						&stream->timing,
- 						dc_link_get_highest_encoding_format(aconnector->dc_link),
- 						&stream->timing.dsc_cfg)) {
- 					stream->timing.flags.DSC = 1;
- 					drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from %s\n",
- 							__func__, drm_connector->name,
- 							(dsc_caps->is_frl == 1) ? "HDMI FRL RX" : "DP-HDMI PCON");
- 				}
- 		}
- 	}
- 	else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) {
- 		struct dc_dsc_policy dsc_policy = {0};
- 
- 		frl_verified_link_cap = dc_link_get_frl_link_cap(stream->link);
- 		if (frl_verified_link_cap->frl_link_rate != HDMI_FRL_LINK_RATE_DISABLE &&
- 			aconnector->dc_link->frl_flags.force_frl_dsc) {
- 			dc_dsc_policy_set_enable_dsc_when_not_needed(true);
- 			dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
- 		}
- 
- 		timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, DC_LINK_ENCODING_HDMI_FRL);
- 		link_bandwidth_kbps = dc_link_frl_bandwidth_kbps(stream->link, frl_verified_link_cap->frl_link_rate);
- 		dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate);
- 
- 		if ((timing_bw_in_kbps > link_bandwidth_kbps && dsc_sink_bw_in_kbps > 0) ||
- 		    (dsc_policy.enable_dsc_when_not_needed || dsc_options.force_dsc_when_not_needed)) {
- 			if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
- 					dsc_caps,
- 					&dsc_options,
- 					dsc_sink_bw_in_kbps,
- 					&stream->timing,
- 					dc_link_get_highest_encoding_format(aconnector->dc_link),
- 					&stream->timing.dsc_cfg)) {
- 				stream->timing.flags.DSC = 1;
- 				drm_dbg_driver(drm_connector->dev, "%s: HDMI_FRL_DSC [%s] DSC is selected from HDMI FRL RX\n",
- 						__func__, drm_connector->name);
- 			}
- 		}
- 	}
- 
- 	/* Overwrite the stream flag if DSC is enabled through debugfs */
- 	if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE)
- 		stream->timing.flags.DSC = 1;
- 
- 	if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h)
- 		stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h;
- 
- 	if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v)
- 		stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v;
- 
- 	if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel)
- 		stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel;
- }
- #endif
- 
- static struct dc_stream_state *
- create_stream_for_sink(struct drm_connector *connector,
- 		       const struct drm_display_mode *drm_mode,
- 		       const struct dm_connector_state *dm_state,
- 		       const struct dc_stream_state *old_stream,
- 		       int requested_bpc)
- {
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_dm_connector *aconnector = NULL;
- 	struct drm_display_mode *preferred_mode = NULL;
- 	const struct drm_connector_state *con_state = &dm_state->base;
- 	struct dc_stream_state *stream = NULL;
- 	struct drm_display_mode mode;
- 	struct drm_display_mode saved_mode;
- 	struct drm_display_mode *freesync_mode = NULL;
- 	bool native_mode_found = false;
- 	bool recalculate_timing = false;
- 	bool scale = dm_state->scaling != RMX_OFF;
- 	int mode_refresh;
- 	int preferred_refresh = 0;
- 	enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN;
- #if defined(CONFIG_DRM_AMD_DC_FP)
- 	struct dsc_dec_dpcd_caps dsc_caps = {0};
- #endif
- 	struct dc_link *link = NULL;
- 	struct dc_sink *sink = NULL;
- 
- 	drm_mode_init(&mode, drm_mode);
- 	memset(&saved_mode, 0, sizeof(saved_mode));
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) {
- 		aconnector = NULL;
- 		aconnector = to_amdgpu_dm_connector(connector);
- 		link = aconnector->dc_link;
- 	} else {
- 		struct drm_writeback_connector *wbcon = NULL;
- 		struct amdgpu_dm_wb_connector *dm_wbcon = NULL;
- 
- 		wbcon = drm_connector_to_writeback(connector);
- 		dm_wbcon = to_amdgpu_dm_wb_connector(wbcon);
- 		link = dm_wbcon->link;
- 	}
- 
- 	if (!aconnector || !aconnector->dc_sink) {
- 		sink = create_fake_sink(dev, link);
- 		if (!sink)
- 			return stream;
- 
- 	} else {
- 		sink = aconnector->dc_sink;
- 		dc_sink_retain(sink);
- 	}
- 
- 	stream = dc_create_stream_for_sink(sink);
- 
- 	if (stream == NULL) {
- 		drm_err(dev, "Failed to create stream for sink!\n");
- 		goto finish;
- 	}
- 
- 	/* We leave this NULL for writeback connectors */
- 	stream->dm_stream_context = aconnector;
- 
- 	stream->timing.flags.LTE_340MCSC_SCRAMBLE =
- 		connector->display_info.hdmi.scdc.scrambling.low_rates;
- 
- 	list_for_each_entry(preferred_mode, &connector->modes, head) {
- 		/* Search for preferred mode */
- 		if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) {
- 			native_mode_found = true;
- 			break;
- 		}
- 	}
- 	if (!native_mode_found)
- 		preferred_mode = list_first_entry_or_null(
- 				&connector->modes,
- 				struct drm_display_mode,
- 				head);
- 
- 	mode_refresh = drm_mode_vrefresh(&mode);
- 
- 	if (preferred_mode == NULL) {
- 		/*
- 		 * This may not be an error, the use case is when we have no
- 		 * usermode calls to reset and set mode upon hotplug. In this
- 		 * case, we call set mode ourselves to restore the previous mode
- 		 * and the modelist may not be filled in time.
- 		 */
- 		drm_dbg_driver(dev, "No preferred mode found\n");
- 	} else if (aconnector) {
- 		recalculate_timing = amdgpu_freesync_vid_mode &&
- 				 is_freesync_video_mode(&mode, aconnector);
- 		if (recalculate_timing) {
- 			freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
- 			drm_mode_copy(&saved_mode, &mode);
- 			saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio;
- 			drm_mode_copy(&mode, freesync_mode);
- 			mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio;
- 		} else {
- 			decide_crtc_timing_for_drm_display_mode(
- 					&mode, preferred_mode, scale);
- 
- 			preferred_refresh = drm_mode_vrefresh(preferred_mode);
- 		}
- 	}
- 
- 	if (recalculate_timing)
- 		drm_mode_set_crtcinfo(&saved_mode, 0);
- 
- 	/*
- 	 * If scaling is enabled and refresh rate didn't change
- 	 * we copy the vic and polarities of the old timings
- 	 */
- 	if (!scale || mode_refresh != preferred_refresh)
- 		fill_stream_properties_from_drm_display_mode(
- 			stream, &mode, connector, con_state, NULL,
- 			requested_bpc);
- 	else
- 		fill_stream_properties_from_drm_display_mode(
- 			stream, &mode, connector, con_state, old_stream,
- 			requested_bpc);
- 
- 	/* The rest isn't needed for writeback connectors */
- 	if (!aconnector)
- 		goto finish;
- 
- 	if (aconnector->timing_changed) {
- 		drm_dbg(aconnector->base.dev,
- 			"overriding timing for automated test, bpc %d, changing to %d\n",
- 			stream->timing.display_color_depth,
- 			aconnector->timing_requested->display_color_depth);
- 		stream->timing = *aconnector->timing_requested;
- 	}
- 
- #if defined(CONFIG_DRM_AMD_DC_FP)
- 	/* SST DSC determination policy */
- 	update_dsc_caps(aconnector, sink, stream, &dsc_caps);
- 	if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported)
- 		apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps);
- #endif
- 
- 	update_stream_scaling_settings(dev, &mode, dm_state, stream);
- 
- 	fill_audio_info(
- 		&stream->audio_info,
- 		connector,
- 		sink);
- 
- 	update_stream_signal(stream, sink);
- 
- 	if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 	    stream->signal == SIGNAL_TYPE_HDMI_FRL)
- 		mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
- 
- 	if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
- 	    stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST ||
- 	    stream->signal == SIGNAL_TYPE_EDP) {
- 		const struct dc_edid_caps *edid_caps;
- 		unsigned int disable_colorimetry = 0;
- 
- 		if (aconnector->dc_sink) {
- 			edid_caps = &aconnector->dc_sink->edid_caps;
- 			disable_colorimetry = edid_caps->panel_patch.disable_colorimetry;
- 		}
- 
- 		//
- 		// should decide stream support vsc sdp colorimetry capability
- 		// before building vsc info packet
- 		//
- 		stream->use_vsc_sdp_for_colorimetry = stream->link->dpcd_caps.dpcd_rev.raw >= 0x14 &&
- 						      stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED &&
- 						      !disable_colorimetry;
- 
- 		if (stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22)
- 			tf = TRANSFER_FUNC_GAMMA_22;
- 		mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf);
- 		aconnector->sr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY;
- 
- 	}
- finish:
- 	dc_sink_release(sink);
- 
- 	return stream;
- }
- 
- /**
-  * amdgpu_dm_connector_poll - Poll a connector to see if it's connected to a display
-  * @aconnector: DM connector to poll (owns @base drm_connector and @dc_link)
-  * @force: if true, force polling even when DAC load detection was used
-  *
-  * Used for connectors that don't support HPD (hotplug detection) to
-  * periodically check whether the connector is connected to a display.
-  *
-  * When connection was determined via DAC load detection, we avoid
-  * re-running it on normal polls to prevent visible glitches, unless
-  * @force is set.
-  *
-  * Return: The probed connector status (connected/disconnected/unknown).
-  */
- static enum drm_connector_status
- amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dc_link *link = aconnector->dc_link;
- 	enum dc_connection_type conn_type = dc_connection_none;
- 	enum drm_connector_status status = connector_status_disconnected;
- 
- 	/* When we determined the connection using DAC load detection,
- 	 * do NOT poll the connector do detect disconnect because
- 	 * that would run DAC load detection again which can cause
- 	 * visible visual glitches.
- 	 *
- 	 * Only allow to poll such a connector again when forcing.
- 	 */
- 	if (!force && link->local_sink && link->type == dc_connection_analog_load)
- 		return connector->status;
- 
- 	mutex_lock(&aconnector->hpd_lock);
- 
- 	if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) &&
- 	    conn_type != dc_connection_none) {
- 		mutex_lock(&adev->dm.dc_lock);
- 
- 		/* Only call full link detection when a sink isn't created yet,
- 		 * ie. just when the display is plugged in, otherwise we risk flickering.
- 		 */
- 		if (link->local_sink ||
- 			dc_link_detect(link, DETECT_REASON_HPD))
- 			status = connector_status_connected;
- 
- 		mutex_unlock(&adev->dm.dc_lock);
- 	}
- 
- 	if (connector->status != status) {
- 		if (status == connector_status_disconnected) {
- 			if (link->local_sink)
- 				dc_sink_release(link->local_sink);
- 
- 			link->local_sink = NULL;
- 			link->dpcd_sink_count = 0;
- 			link->type = dc_connection_none;
- 		}
- 
- 		amdgpu_dm_update_connector_after_detect(aconnector);
- 	}
- 
- 	mutex_unlock(&aconnector->hpd_lock);
- 	return status;
- }
- 
- /**
-  * amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display
-  *
-  * A connector is considered connected when it has a sink that is not NULL.
-  * For connectors that support HPD (hotplug detection), the connection is
-  * handled in the HPD interrupt.
-  * For connectors that may not support HPD, such as analog connectors,
-  * DRM will call this function repeatedly to poll them.
-  *
-  * Notes:
-  * 1. This interface is NOT called in context of HPD irq.
-  * 2. This interface *is called* in context of user-mode ioctl. Which
-  *    makes it a bad place for *any* MST-related activity.
-  *
-  * @connector: The DRM connector we are checking. We convert it to
-  *             amdgpu_dm_connector so we can read the DC link and state.
-  * @force:     If true, do a full detect again. This is used even when
-  *             a lighter check would normally be used to avoid flicker.
-  *
-  * Return: The connector status (connected, disconnected, or unknown).
-  *
-  */
- static enum drm_connector_status
- amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
- {
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 
- 	update_subconnector_property(aconnector);
- 
- 	if (aconnector->base.force == DRM_FORCE_ON ||
- 		aconnector->base.force == DRM_FORCE_ON_DIGITAL)
- 		return connector_status_connected;
- 	else if (aconnector->base.force == DRM_FORCE_OFF)
- 		return connector_status_disconnected;
- 
- 	/* Poll analog connectors and only when either
- 	 * disconnected or connected to an analog display.
- 	 */
- 	if (drm_kms_helper_is_poll_worker() &&
- 		dc_connector_supports_analog(aconnector->dc_link->link_id.id) &&
- 		(!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog))
- 		return amdgpu_dm_connector_poll(aconnector, force);
- 
- 	return (aconnector->dc_sink ? connector_status_connected :
- 			connector_status_disconnected);
- }
- 
- int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
- 					    struct drm_connector_state *connector_state,
- 					    struct drm_property *property,
- 					    uint64_t val)
- {
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dm_connector_state *dm_old_state =
- 		to_dm_connector_state(connector->state);
- 	struct dm_connector_state *dm_new_state =
- 		to_dm_connector_state(connector_state);
- 
- 	int ret = -EINVAL;
- 
- 	if (property == dev->mode_config.scaling_mode_property) {
- 		enum amdgpu_rmx_type rmx_type;
- 
- 		switch (val) {
- 		case DRM_MODE_SCALE_CENTER:
- 			rmx_type = RMX_CENTER;
- 			break;
- 		case DRM_MODE_SCALE_ASPECT:
- 			rmx_type = RMX_ASPECT;
- 			break;
- 		case DRM_MODE_SCALE_FULLSCREEN:
- 			rmx_type = RMX_FULL;
- 			break;
- 		case DRM_MODE_SCALE_NONE:
- 		default:
- 			rmx_type = RMX_OFF;
- 			break;
- 		}
- 
- 		if (dm_old_state->scaling == rmx_type)
- 			return 0;
- 
- 		dm_new_state->scaling = rmx_type;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_hborder_property) {
- 		dm_new_state->underscan_hborder = val;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_vborder_property) {
- 		dm_new_state->underscan_vborder = val;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_property) {
- 		dm_new_state->underscan_enable = val;
- 		ret = 0;
- 	} else if (property == adev->mode_info.abm_level_property) {
- 		switch (val) {
- 		case ABM_SYSFS_CONTROL:
- 			dm_new_state->abm_sysfs_forbidden = false;
- 			break;
- 		case ABM_LEVEL_OFF:
- 			dm_new_state->abm_sysfs_forbidden = true;
- 			dm_new_state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
- 			break;
- 		default:
- 			dm_new_state->abm_sysfs_forbidden = true;
- 			dm_new_state->abm_level = val;
- 		}
- 		ret = 0;
- 	}
- 
- 	return ret;
- }
- 
- int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
- 					    const struct drm_connector_state *state,
- 					    struct drm_property *property,
- 					    uint64_t *val)
- {
- 	struct drm_device *dev = connector->dev;
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct dm_connector_state *dm_state =
- 		to_dm_connector_state(state);
- 	int ret = -EINVAL;
- 
- 	if (property == dev->mode_config.scaling_mode_property) {
- 		switch (dm_state->scaling) {
- 		case RMX_CENTER:
- 			*val = DRM_MODE_SCALE_CENTER;
- 			break;
- 		case RMX_ASPECT:
- 			*val = DRM_MODE_SCALE_ASPECT;
- 			break;
- 		case RMX_FULL:
- 			*val = DRM_MODE_SCALE_FULLSCREEN;
- 			break;
- 		case RMX_OFF:
- 		default:
- 			*val = DRM_MODE_SCALE_NONE;
- 			break;
- 		}
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_hborder_property) {
- 		*val = dm_state->underscan_hborder;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_vborder_property) {
- 		*val = dm_state->underscan_vborder;
- 		ret = 0;
- 	} else if (property == adev->mode_info.underscan_property) {
- 		*val = dm_state->underscan_enable;
- 		ret = 0;
- 	} else if (property == adev->mode_info.abm_level_property) {
- 		if (!dm_state->abm_sysfs_forbidden)
- 			*val = ABM_SYSFS_CONTROL;
- 		else
- 			*val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ?
- 				dm_state->abm_level : 0;
- 		ret = 0;
- 	}
- 
- 	return ret;
- }
- 
- /**
-  * DOC: panel power savings
-  *
-  * The display manager allows you to set your desired **panel power savings**
-  * level (between 0-4, with 0 representing off), e.g. using the following::
-  *
-  *   # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings
-  *
-  * Modifying this value can have implications on color accuracy, so tread
-  * carefully.
-  */
- 
- static ssize_t panel_power_savings_show(struct device *device,
- 					struct device_attribute *attr,
- 					char *buf)
- {
- 	struct drm_connector *connector = dev_get_drvdata(device);
- 	struct drm_device *dev = connector->dev;
- 	u8 val;
- 
- 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- 	val = to_dm_connector_state(connector->state)->abm_level ==
- 		ABM_LEVEL_IMMEDIATE_DISABLE ? 0 :
- 		to_dm_connector_state(connector->state)->abm_level;
- 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
- 
- 	return sysfs_emit(buf, "%u\n", val);
- }
- 
- static ssize_t panel_power_savings_store(struct device *device,
- 					 struct device_attribute *attr,
- 					 const char *buf, size_t count)
- {
- 	struct drm_connector *connector = dev_get_drvdata(device);
- 	struct drm_device *dev = connector->dev;
- 	long val;
- 	int ret;
- 
- 	ret = kstrtol(buf, 0, &val);
- 
- 	if (ret)
- 		return ret;
- 
- 	if (val < 0 || val > 4)
- 		return -EINVAL;
- 
- 	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- 	if (to_dm_connector_state(connector->state)->abm_sysfs_forbidden)
- 		ret = -EBUSY;
- 	else
- 		to_dm_connector_state(connector->state)->abm_level = val ?:
- 			ABM_LEVEL_IMMEDIATE_DISABLE;
- 	drm_modeset_unlock(&dev->mode_config.connection_mutex);
- 
- 	if (ret)
- 		return ret;
- 
- 	drm_kms_helper_hotplug_event(dev);
- 
- 	return count;
- }
- 
- static DEVICE_ATTR_RW(panel_power_savings);
- 
- static struct attribute *amdgpu_attrs[] = {
- 	&dev_attr_panel_power_savings.attr,
- 	NULL
- };
- 
- static const struct attribute_group amdgpu_group = {
- 	.name = "amdgpu",
- 	.attrs = amdgpu_attrs
- };
- 
- static bool
- amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector)
- {
- 	if (amdgpu_dm_abm_level >= 0)
- 		return false;
- 
- 	if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
- 		return false;
- 
- 	/* check for OLED panels */
- 	if (amdgpu_dm_connector->bl_idx >= 0) {
- 		struct drm_device *drm = amdgpu_dm_connector->base.dev;
- 		struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm;
- 		struct amdgpu_dm_backlight_caps *caps;
- 
- 		caps = &dm->backlight_caps[amdgpu_dm_connector->bl_idx];
- 		if (caps->aux_support)
- 			return false;
- 	}
- 
- 	return true;
- }
- 
- static void amdgpu_dm_connector_unregister(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
- 
- 	if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector))
- 		sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group);
- 
- 	cec_notifier_conn_unregister(amdgpu_dm_connector->notifier);
- 	drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux);
- }
- 
- static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct amdgpu_display_manager *dm = &adev->dm;
- 
- 	/*
- 	 * Call only if mst_mgr was initialized before since it's not done
- 	 * for all connector types.
- 	 */
- 	if (aconnector->mst_mgr.dev)
- 		drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
- 
- 	/* Cancel and flush any pending HDMI HPD debounce work */
- 	if (aconnector->hdmi_hpd_debounce_delay_ms) {
- 		cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
- 		if (aconnector->hdmi_prev_sink) {
- 			dc_sink_release(aconnector->hdmi_prev_sink);
- 			aconnector->hdmi_prev_sink = NULL;
- 		}
- 	}
- 
- 	if (aconnector->bl_idx != -1) {
- 		backlight_device_unregister(dm->backlight_dev[aconnector->bl_idx]);
- 		dm->backlight_dev[aconnector->bl_idx] = NULL;
- 	}
- 
- 	if (aconnector->dc_em_sink)
- 		dc_sink_release(aconnector->dc_em_sink);
- 	aconnector->dc_em_sink = NULL;
- 	if (aconnector->dc_sink)
- 		dc_sink_release(aconnector->dc_sink);
- 	aconnector->dc_sink = NULL;
- 
- 	drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux);
- 	drm_connector_unregister(connector);
- 	drm_connector_cleanup(connector);
- 	kfree(aconnector->dm_dp_aux.aux.name);
- 
- 	kfree(connector);
- }
- 
- void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
- {
- 	struct dm_connector_state *state =
- 		to_dm_connector_state(connector->state);
- 
- 	if (connector->state)
- 		__drm_atomic_helper_connector_destroy_state(connector->state);
- 
- 	kfree(state);
- 
- 	state = kzalloc_obj(*state);
- 
- 	if (state) {
- 		state->scaling = RMX_OFF;
- 		state->underscan_enable = false;
- 		state->underscan_hborder = 0;
- 		state->underscan_vborder = 0;
- 		state->base.max_requested_bpc = 8;
- 		state->vcpi_slots = 0;
- 		state->pbn = 0;
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
- 			if (amdgpu_dm_abm_level <= 0)
- 				state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE;
- 			else
- 				state->abm_level = amdgpu_dm_abm_level;
- 		}
- 
- 		__drm_atomic_helper_connector_reset(connector, &state->base);
- 	}
- }
- 
- struct drm_connector_state *
- amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
- {
- 	struct dm_connector_state *state =
- 		to_dm_connector_state(connector->state);
- 
- 	struct dm_connector_state *new_state =
- 			kmemdup(state, sizeof(*state), GFP_KERNEL);
- 
- 	if (!new_state)
- 		return NULL;
- 
- 	__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
- 
- 	new_state->freesync_capable = state->freesync_capable;
- 	new_state->abm_level = state->abm_level;
- 	new_state->scaling = state->scaling;
- 	new_state->underscan_enable = state->underscan_enable;
- 	new_state->underscan_hborder = state->underscan_hborder;
- 	new_state->underscan_vborder = state->underscan_vborder;
- 	new_state->vcpi_slots = state->vcpi_slots;
- 	new_state->pbn = state->pbn;
- 	return &new_state->base;
- }
- 
- static int
- amdgpu_dm_connector_late_register(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 		to_amdgpu_dm_connector(connector);
- 	int r;
- 
- 	if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) {
- 		r = sysfs_create_group(&connector->kdev->kobj,
- 				       &amdgpu_group);
- 		if (r)
- 			return r;
- 	}
- 
- 	amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
- 
- 	if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
- 	    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
- 		amdgpu_dm_connector->dm_dp_aux.aux.dev = connector->kdev;
- 		r = drm_dp_aux_register(&amdgpu_dm_connector->dm_dp_aux.aux);
- 		if (r)
- 			return r;
- 	}
- 
- #if defined(CONFIG_DEBUG_FS)
- 	connector_debugfs_init(amdgpu_dm_connector);
- #endif
- 
- 	return 0;
- }
- 
- static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 	struct dc_link *dc_link = aconnector->dc_link;
- 	struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
- 	const struct drm_edid *drm_edid;
- 	struct i2c_adapter *ddc;
- 	struct drm_device *dev = connector->dev;
- 
- 	if (dc_link && dc_link->aux_mode)
- 		ddc = &aconnector->dm_dp_aux.aux.ddc;
- 	else
- 		ddc = &aconnector->i2c->base;
- 
- 	drm_edid = drm_edid_read_ddc(connector, ddc);
- 	drm_edid_connector_update(connector, drm_edid);
- 	if (!drm_edid) {
- 		drm_err(dev, "No EDID found on connector: %s.\n", connector->name);
- 		return;
- 	}
- 
- 	aconnector->drm_edid = drm_edid;
- 	/* Update emulated (virtual) sink's EDID */
- 	if (dc_em_sink && dc_link) {
- 		// FIXME: Get rid of drm_edid_raw()
- 		const struct edid *edid = drm_edid_raw(drm_edid);
- 
- 		memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
- 		memmove(dc_em_sink->dc_edid.raw_edid, edid,
- 			(edid->extensions + 1) * EDID_LENGTH);
- 		dm_helpers_parse_edid_caps(
- 			dc_link,
- 			&dc_em_sink->dc_edid,
- 			&dc_em_sink->edid_caps);
- 	}
- }
- 
- static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
- 	.reset = amdgpu_dm_connector_funcs_reset,
- 	.detect = amdgpu_dm_connector_detect,
- 	.fill_modes = drm_helper_probe_single_connector_modes,
- 	.destroy = amdgpu_dm_connector_destroy,
- 	.atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state,
- 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
- 	.atomic_set_property = amdgpu_dm_connector_atomic_set_property,
- 	.atomic_get_property = amdgpu_dm_connector_atomic_get_property,
- 	.late_register = amdgpu_dm_connector_late_register,
- 	.early_unregister = amdgpu_dm_connector_unregister,
- 	.force = amdgpu_dm_connector_funcs_force
- };
- 
- static int get_modes(struct drm_connector *connector)
- {
- 	return amdgpu_dm_connector_get_modes(connector);
- }
- 
- static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 	struct dc_link *dc_link = aconnector->dc_link;
- 	struct dc_sink_init_data init_params = {
- 			.link = aconnector->dc_link,
- 			.sink_signal = SIGNAL_TYPE_VIRTUAL
- 	};
- 	const struct drm_edid *drm_edid;
- 	const struct edid *edid;
- 	struct i2c_adapter *ddc;
- 
- 	if (dc_link && dc_link->aux_mode)
- 		ddc = &aconnector->dm_dp_aux.aux.ddc;
- 	else
- 		ddc = &aconnector->i2c->base;
- 
- 	drm_edid = drm_edid_read_ddc(connector, ddc);
- 	drm_edid_connector_update(connector, drm_edid);
- 	if (!drm_edid) {
- 		drm_err(connector->dev, "No EDID found on connector: %s.\n", connector->name);
- 		return;
- 	}
- 
- 	if (connector->display_info.is_hdmi)
- 		init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
- 
- 	aconnector->drm_edid = drm_edid;
- 
- 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
- 	aconnector->dc_em_sink = dc_link_add_remote_sink(
- 		aconnector->dc_link,
- 		(uint8_t *)edid,
- 		(edid->extensions + 1) * EDID_LENGTH,
- 		&init_params);
- 
- 	if (aconnector->base.force == DRM_FORCE_ON) {
- 		aconnector->dc_sink = aconnector->dc_link->local_sink ?
- 		aconnector->dc_link->local_sink :
- 		aconnector->dc_em_sink;
- 		if (aconnector->dc_sink)
- 			dc_sink_retain(aconnector->dc_sink);
- 	}
- }
- 
- static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
- {
- 	struct dc_link *link = (struct dc_link *)aconnector->dc_link;
- 
- 	/*
- 	 * In case of headless boot with force on for DP managed connector
- 	 * Those settings have to be != 0 to get initial modeset
- 	 */
- 	if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) {
- 		link->verified_link_cap.lane_count = LANE_COUNT_FOUR;
- 		link->verified_link_cap.link_rate = LINK_RATE_HIGH2;
- 	}
- 
- 	create_eml_sink(aconnector);
- }
- 
- static enum dc_status dm_validate_stream_and_context(struct dc *dc,
- 						struct dc_stream_state *stream)
- {
- 	enum dc_status dc_result = DC_ERROR_UNEXPECTED;
- 	struct dc_plane_state *dc_plane_state = NULL;
- 	struct dc_state *dc_state = NULL;
- 
- 	if (!stream)
- 		goto cleanup;
- 
- 	dc_plane_state = dc_create_plane_state(dc);
- 	if (!dc_plane_state)
- 		goto cleanup;
- 
- 	dc_state = dc_state_create(dc, NULL);
- 	if (!dc_state)
- 		goto cleanup;
- 
- 	/* populate stream to plane */
- 	dc_plane_state->src_rect.height  = stream->src.height;
- 	dc_plane_state->src_rect.width   = stream->src.width;
- 	dc_plane_state->dst_rect.height  = stream->src.height;
- 	dc_plane_state->dst_rect.width   = stream->src.width;
- 	dc_plane_state->clip_rect.height = stream->src.height;
- 	dc_plane_state->clip_rect.width  = stream->src.width;
- 	dc_plane_state->plane_size.surface_pitch = ((stream->src.width + 255) / 256) * 256;
- 	dc_plane_state->plane_size.surface_size.height = stream->src.height;
- 	dc_plane_state->plane_size.surface_size.width  = stream->src.width;
- 	dc_plane_state->plane_size.chroma_size.height  = stream->src.height;
- 	dc_plane_state->plane_size.chroma_size.width   = stream->src.width;
- 	dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
- 	dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN;
- 	dc_plane_state->rotation = ROTATION_ANGLE_0;
- 	dc_plane_state->is_tiling_rotated = false;
- 	dc_plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL;
- 
- 	dc_result = dc_validate_stream(dc, stream);
- 	if (dc_result == DC_OK)
- 		dc_result = dc_validate_plane(dc, dc_plane_state);
- 
- 	if (dc_result == DC_OK)
- 		dc_result = dc_state_add_stream(dc, dc_state, stream);
- 
- 	if (dc_result == DC_OK && !dc_state_add_plane(
- 						dc,
- 						stream,
- 						dc_plane_state,
- 						dc_state))
- 		dc_result = DC_FAIL_ATTACH_SURFACES;
- 
- 	if (dc_result == DC_OK)
- 		dc_result = dc_validate_global_state(dc, dc_state, DC_VALIDATE_MODE_ONLY);
- 
- cleanup:
- 	if (dc_state)
- 		dc_state_release(dc_state);
- 
- 	if (dc_plane_state)
- 		dc_plane_state_release(dc_plane_state);
- 
- 	return dc_result;
- }
- 
- struct dc_stream_state *
- create_validate_stream_for_sink(struct drm_connector *connector,
- 				const struct drm_display_mode *drm_mode,
- 				const struct dm_connector_state *dm_state,
- 				const struct dc_stream_state *old_stream)
- {
- 	struct amdgpu_dm_connector *aconnector = NULL;
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct dc_stream_state *stream;
- 	const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL;
- 	int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8;
- 	enum dc_status dc_result = DC_OK;
- 	uint8_t bpc_limit = 6;
- 
- 	if (!dm_state)
- 		return NULL;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 	if (aconnector &&
- 	    (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
- 	     aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL ||
- 	     aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
- 		bpc_limit = 8;
- 
- 	do {
- 		drm_dbg_kms(connector->dev, "Trying with %d bpc\n", requested_bpc);
- 		stream = create_stream_for_sink(connector, drm_mode,
- 						dm_state, old_stream,
- 						requested_bpc);
- 		if (stream == NULL) {
- 			drm_err(adev_to_drm(adev), "Failed to create stream for sink!\n");
- 			break;
- 		}
- 
- 		dc_result = dc_validate_stream(adev->dm.dc, stream);
- 
- 		if (!aconnector) /* writeback connector */
- 			return stream;
- 
- 		if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
- 			dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
- 
- 		if (dc_result == DC_OK)
- 			dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
- 
- 		if (dc_result != DC_OK) {
- 			drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n",
- 				      drm_mode->hdisplay,
- 				      drm_mode->vdisplay,
- 				      drm_mode->clock,
- 				      dc_pixel_encoding_to_str(stream->timing.pixel_encoding),
- 				      dc_color_depth_to_str(stream->timing.display_color_depth),
- 				      dc_status_to_str(dc_result));
- 
- 			dc_stream_release(stream);
- 			stream = NULL;
- 			requested_bpc -= 2; /* lower bpc to retry validation */
- 		}
- 
- 	} while (stream == NULL && requested_bpc >= bpc_limit);
- 
- 	switch (dc_result) {
- 	/*
- 	 * If we failed to validate DP bandwidth stream with the requested RGB color depth,
- 	 * we try to fallback and configure in order:
- 	 * YUV422 (8bpc, 6bpc)
- 	 * YUV420 (8bpc, 6bpc)
- 	 */
- 	case DC_FAIL_ENC_VALIDATE:
- 	case DC_EXCEED_DONGLE_CAP:
- 	case DC_NO_DP_LINK_BANDWIDTH:
- 		/* recursively entered twice and already tried both YUV422 and YUV420 */
- 		if (aconnector->force_yuv422_output && aconnector->force_yuv420_output)
- 			break;
- 		/* first failure; try YUV422 */
- 		if (!aconnector->force_yuv422_output) {
- 			drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV422\n",
- 				    __func__, __LINE__, dc_result);
- 			aconnector->force_yuv422_output = true;
- 		/* recursively entered and YUV422 failed, try YUV420 */
- 		} else if (!aconnector->force_yuv420_output) {
- 			drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV420\n",
- 				    __func__, __LINE__, dc_result);
- 			aconnector->force_yuv420_output = true;
- 		}
- 		stream = create_validate_stream_for_sink(connector, drm_mode,
- 							 dm_state, old_stream);
- 		aconnector->force_yuv422_output = false;
- 		aconnector->force_yuv420_output = false;
- 		break;
- 	case DC_OK:
- 		break;
- 	default:
- 		drm_dbg_kms(connector->dev, "%s:%d Unhandled validation failure %d\n",
- 			    __func__, __LINE__, dc_result);
- 		break;
- 	}
- 
- 	return stream;
- }
- 
- enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
- 				   const struct drm_display_mode *mode)
- {
- 	int result = MODE_ERROR;
- 	struct dc_sink *dc_sink;
- 	struct drm_display_mode *test_mode;
- 	/* TODO: Unhardcode stream count */
- 	struct dc_stream_state *stream;
- 	/* we always have an amdgpu_dm_connector here since we got
- 	 * here via the amdgpu_dm_connector_helper_funcs
- 	 */
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 
- 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
- 			(mode->flags & DRM_MODE_FLAG_DBLSCAN))
- 		return result;
- 
- 	/*
- 	 * Only run this the first time mode_valid is called to initilialize
- 	 * EDID mgmt
- 	 */
- 	if (aconnector->base.force != DRM_FORCE_UNSPECIFIED &&
- 		!aconnector->dc_em_sink)
- 		handle_edid_mgmt(aconnector);
- 
- 	dc_sink = to_amdgpu_dm_connector(connector)->dc_sink;
- 
- 	if (dc_sink == NULL && aconnector->base.force != DRM_FORCE_ON_DIGITAL &&
- 				aconnector->base.force != DRM_FORCE_ON) {
- 		drm_err(connector->dev, "dc_sink is NULL!\n");
- 		goto fail;
- 	}
- 
- 	test_mode = drm_mode_duplicate(connector->dev, mode);
- 	if (!test_mode)
- 		goto fail;
- 
- 	drm_mode_set_crtcinfo(test_mode, 0);
- 
- 	stream = create_validate_stream_for_sink(connector, test_mode,
- 						 to_dm_connector_state(connector->state),
- 						 NULL);
- 	drm_mode_destroy(connector->dev, test_mode);
- 	if (stream) {
- 		dc_stream_release(stream);
- 		result = MODE_OK;
- 	}
- 
- fail:
- 	/* TODO: error handling*/
- 	return result;
- }
- 
- static int fill_hdr_info_packet(const struct drm_connector_state *state,
- 				struct dc_info_packet *out)
- {
- 	struct hdmi_drm_infoframe frame;
- 	unsigned char buf[30]; /* 26 + 4 */
- 	ssize_t len;
- 	int ret, i;
- 
- 	memset(out, 0, sizeof(*out));
- 
- 	if (!state->hdr_output_metadata)
- 		return 0;
- 
- 	ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, state);
- 	if (ret)
- 		return ret;
- 
- 	len = hdmi_drm_infoframe_pack_only(&frame, buf, sizeof(buf));
- 	if (len < 0)
- 		return (int)len;
- 
- 	/* Static metadata is a fixed 26 bytes + 4 byte header. */
- 	if (len != 30)
- 		return -EINVAL;
- 
- 	/* Prepare the infopacket for DC. */
- 	switch (state->connector->connector_type) {
- 	case DRM_MODE_CONNECTOR_HDMIA:
- 		out->hb0 = 0x87; /* type */
- 		out->hb1 = 0x01; /* version */
- 		out->hb2 = 0x1A; /* length */
- 		out->sb[0] = buf[3]; /* checksum */
- 		i = 1;
- 		break;
- 
- 	case DRM_MODE_CONNECTOR_DisplayPort:
- 	case DRM_MODE_CONNECTOR_eDP:
- 		out->hb0 = 0x00; /* sdp id, zero */
- 		out->hb1 = 0x87; /* type */
- 		out->hb2 = 0x1D; /* payload len - 1 */
- 		out->hb3 = (0x13 << 2); /* sdp version */
- 		out->sb[0] = 0x01; /* version */
- 		out->sb[1] = 0x1A; /* length */
- 		i = 2;
- 		break;
- 
- 	default:
- 		return -EINVAL;
- 	}
- 
- 	memcpy(&out->sb[i], &buf[4], 26);
- 	out->valid = true;
- 
- 	print_hex_dump(KERN_DEBUG, "HDR SB:", DUMP_PREFIX_NONE, 16, 1, out->sb,
- 		       sizeof(out->sb), false);
- 
- 	return 0;
- }
- 
- static int
- amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
- 				 struct drm_atomic_commit *state)
- {
- 	struct drm_connector_state *new_con_state =
- 		drm_atomic_get_new_connector_state(state, conn);
- 	struct drm_connector_state *old_con_state =
- 		drm_atomic_get_old_connector_state(state, conn);
- 	struct drm_crtc *crtc = new_con_state->crtc;
- 	struct drm_crtc_state *new_crtc_state;
- 	struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn);
- 	int ret;
- 
- 	if (WARN_ON(unlikely(!old_con_state || !new_con_state)))
- 		return -EINVAL;
- 
- 	trace_amdgpu_dm_connector_atomic_check(new_con_state);
- 
- 	if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
- 		ret = drm_dp_mst_root_conn_atomic_check(new_con_state, &aconn->mst_mgr);
- 		if (ret < 0)
- 			return ret;
- 	}
- 
- 	if (!crtc)
- 		return 0;
- 
- 	if (new_con_state->privacy_screen_sw_state != old_con_state->privacy_screen_sw_state) {
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		new_crtc_state->mode_changed = true;
- 	}
- 
- 	if (new_con_state->colorspace != old_con_state->colorspace) {
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		new_crtc_state->mode_changed = true;
- 	}
- 
- 	if (new_con_state->content_type != old_con_state->content_type) {
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		new_crtc_state->mode_changed = true;
- 	}
- 
- 	if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) {
- 		struct dc_info_packet hdr_infopacket;
- 
- 		ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket);
- 		if (ret)
- 			return ret;
- 
- 		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
- 		if (IS_ERR(new_crtc_state))
- 			return PTR_ERR(new_crtc_state);
- 
- 		/*
- 		 * DC considers the stream backends changed if the
- 		 * static metadata changes. Forcing the modeset also
- 		 * gives a simple way for userspace to switch from
- 		 * 8bpc to 10bpc when setting the metadata to enter
- 		 * or exit HDR.
- 		 *
- 		 * Changing the static metadata after it's been
- 		 * set is permissible, however. So only force a
- 		 * modeset if we're entering or exiting HDR.
- 		 */
- 		new_crtc_state->mode_changed = new_crtc_state->mode_changed ||
- 			!old_con_state->hdr_output_metadata ||
- 			!new_con_state->hdr_output_metadata;
- 	}
- 
- 	return 0;
- }
- 
- static const struct drm_connector_helper_funcs
- amdgpu_dm_connector_helper_funcs = {
- 	/*
- 	 * If hotplugging a second bigger display in FB Con mode, bigger resolution
- 	 * modes will be filtered by drm_mode_validate_size(), and those modes
- 	 * are missing after user start lightdm. So we need to renew modes list.
- 	 * in get_modes call back, not just return the modes count
- 	 */
- 	.get_modes = get_modes,
- 	.mode_valid = amdgpu_dm_connector_mode_valid,
- 	.atomic_check = amdgpu_dm_connector_atomic_check,
- };
- 
- static void dm_encoder_helper_disable(struct drm_encoder *encoder)
- {
- 
- }
- 
- int convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth)
- {
- 	switch (display_color_depth) {
- 	case COLOR_DEPTH_666:
- 		return 6;
- 	case COLOR_DEPTH_888:
- 		return 8;
- 	case COLOR_DEPTH_101010:
- 		return 10;
- 	case COLOR_DEPTH_121212:
- 		return 12;
- 	case COLOR_DEPTH_141414:
- 		return 14;
- 	case COLOR_DEPTH_161616:
- 		return 16;
- 	default:
- 		break;
- 	}
- 	return 0;
- }
- 
- static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
- 					  struct drm_crtc_state *crtc_state,
- 					  struct drm_connector_state *conn_state)
- {
- 	struct drm_atomic_commit *state = crtc_state->state;
- 	struct drm_connector *connector = conn_state->connector;
- 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
- 	struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state);
- 	const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
- 	struct drm_dp_mst_topology_mgr *mst_mgr;
- 	struct drm_dp_mst_port *mst_port;
- 	struct drm_dp_mst_topology_state *mst_state;
- 	enum dc_color_depth color_depth;
- 	int clock, bpp = 0;
- 	bool is_y420 = false;
- 
- 	if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) ||
- 	    (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
- 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
- 		struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
- 		enum drm_mode_status result;
- 
- 		result = drm_crtc_helper_mode_valid_fixed(encoder->crtc, adjusted_mode, native_mode);
- 		if (result != MODE_OK && dm_new_connector_state->scaling == RMX_OFF) {
- 			drm_dbg_driver(encoder->dev,
- 				       "mode %dx%d@%dHz is not native, enabling scaling\n",
- 				       adjusted_mode->hdisplay, adjusted_mode->vdisplay,
- 				       drm_mode_vrefresh(adjusted_mode));
- 			dm_new_connector_state->scaling = RMX_ASPECT;
- 		}
- 		return 0;
- 	}
- 
- 	if (!aconnector->mst_output_port)
- 		return 0;
- 
- 	mst_port = aconnector->mst_output_port;
- 	mst_mgr = &aconnector->mst_root->mst_mgr;
- 
- 	if (!crtc_state->connectors_changed && !crtc_state->mode_changed)
- 		return 0;
- 
- 	mst_state = drm_atomic_get_mst_topology_state(state, mst_mgr);
- 	if (IS_ERR(mst_state))
- 		return PTR_ERR(mst_state);
- 
- 	mst_state->pbn_div.full = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link);
- 
- 	if (!state->duplicated) {
- 		int max_bpc = conn_state->max_requested_bpc;
- 
- 		is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
- 			  aconnector->force_yuv420_output;
- 		color_depth = convert_color_depth_from_display_info(connector,
- 								    is_y420,
- 								    max_bpc);
- 		bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
- 		clock = adjusted_mode->clock;
- 		dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4);
- 	}
- 
- 	dm_new_connector_state->vcpi_slots =
- 		drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port,
- 					      dm_new_connector_state->pbn);
- 	if (dm_new_connector_state->vcpi_slots < 0) {
- 		drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots);
- 		return dm_new_connector_state->vcpi_slots;
- 	}
- 	return 0;
- }
- 
- const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
- 	.disable = dm_encoder_helper_disable,
- 	.atomic_check = dm_encoder_helper_atomic_check
- };
- 
  static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state,
  					    struct dc_state *dc_state,
  					    struct dsc_mst_fairness_vars *vars)
@@@ -8908,753 -3526,6 +3526,6 @@@
  	return 0;
  }
  
- static int to_drm_connector_type(enum signal_type st, uint32_t connector_id)
- {
- 	switch (st) {
- 	case SIGNAL_TYPE_HDMI_TYPE_A:
- 		return DRM_MODE_CONNECTOR_HDMIA;
- 	case SIGNAL_TYPE_EDP:
- 		return DRM_MODE_CONNECTOR_eDP;
- 	case SIGNAL_TYPE_LVDS:
- 		return DRM_MODE_CONNECTOR_LVDS;
- 	case SIGNAL_TYPE_RGB:
- 		return DRM_MODE_CONNECTOR_VGA;
- 	case SIGNAL_TYPE_DISPLAY_PORT:
- 	case SIGNAL_TYPE_DISPLAY_PORT_MST:
- 		/* External DP bridges have a different connector type. */
- 		if (connector_id == CONNECTOR_ID_VGA)
- 			return DRM_MODE_CONNECTOR_VGA;
- 		else if (connector_id == CONNECTOR_ID_LVDS)
- 			return DRM_MODE_CONNECTOR_LVDS;
- 
- 		return DRM_MODE_CONNECTOR_DisplayPort;
- 	case SIGNAL_TYPE_DVI_DUAL_LINK:
- 	case SIGNAL_TYPE_DVI_SINGLE_LINK:
- 		if (connector_id == CONNECTOR_ID_SINGLE_LINK_DVII ||
- 			connector_id == CONNECTOR_ID_DUAL_LINK_DVII)
- 			return DRM_MODE_CONNECTOR_DVII;
- 
- 		return DRM_MODE_CONNECTOR_DVID;
- 	case SIGNAL_TYPE_VIRTUAL:
- 		return DRM_MODE_CONNECTOR_VIRTUAL;
- 
- 	default:
- 		return DRM_MODE_CONNECTOR_Unknown;
- 	}
- }
- 
- static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector)
- {
- 	struct drm_encoder *encoder;
- 
- 	/* There is only one encoder per connector */
- 	drm_connector_for_each_possible_encoder(connector, encoder)
- 		return encoder;
- 
- 	return NULL;
- }
- 
- static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
- {
- 	struct drm_encoder *encoder;
- 	struct amdgpu_encoder *amdgpu_encoder;
- 
- 	encoder = amdgpu_dm_connector_to_encoder(connector);
- 
- 	if (encoder == NULL)
- 		return;
- 
- 	amdgpu_encoder = to_amdgpu_encoder(encoder);
- 
- 	amdgpu_encoder->native_mode.clock = 0;
- 
- 	if (!list_empty(&connector->probed_modes)) {
- 		struct drm_display_mode *preferred_mode = NULL;
- 
- 		list_for_each_entry(preferred_mode,
- 				    &connector->probed_modes,
- 				    head) {
- 			if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED)
- 				amdgpu_encoder->native_mode = *preferred_mode;
- 
- 			break;
- 		}
- 
- 	}
- }
- 
- static struct drm_display_mode *
- amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
- 			     const char *name,
- 			     int hdisplay, int vdisplay)
- {
- 	struct drm_device *dev = encoder->dev;
- 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
- 	struct drm_display_mode *mode = NULL;
- 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
- 
- 	mode = drm_mode_duplicate(dev, native_mode);
- 
- 	if (mode == NULL)
- 		return NULL;
- 
- 	mode->hdisplay = hdisplay;
- 	mode->vdisplay = vdisplay;
- 	mode->type &= ~DRM_MODE_TYPE_PREFERRED;
- 	strscpy(mode->name, name, DRM_DISPLAY_MODE_LEN);
- 
- 	return mode;
- 
- }
- 
- static const struct amdgpu_dm_mode_size {
- 	char name[DRM_DISPLAY_MODE_LEN];
- 	int w;
- 	int h;
- } common_modes[] = {
- 	{  "640x480",  640,  480},
- 	{  "800x600",  800,  600},
- 	{ "1024x768", 1024,  768},
- 	{ "1280x720", 1280,  720},
- 	{ "1280x800", 1280,  800},
- 	{"1280x1024", 1280, 1024},
- 	{ "1440x900", 1440,  900},
- 	{"1680x1050", 1680, 1050},
- 	{"1600x1200", 1600, 1200},
- 	{"1920x1080", 1920, 1080},
- 	{"1920x1200", 1920, 1200}
- };
- 
- static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
- 						 struct drm_connector *connector)
- {
- 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
- 	struct drm_display_mode *mode = NULL;
- 	struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 				to_amdgpu_dm_connector(connector);
- 	int i;
- 	int n;
- 
- 	if ((connector->connector_type != DRM_MODE_CONNECTOR_eDP) &&
- 	    (connector->connector_type != DRM_MODE_CONNECTOR_LVDS))
- 		return;
- 
- 	n = ARRAY_SIZE(common_modes);
- 
- 	for (i = 0; i < n; i++) {
- 		struct drm_display_mode *curmode = NULL;
- 		bool mode_existed = false;
- 
- 		if (common_modes[i].w > native_mode->hdisplay ||
- 		    common_modes[i].h > native_mode->vdisplay ||
- 		   (common_modes[i].w == native_mode->hdisplay &&
- 		    common_modes[i].h == native_mode->vdisplay))
- 			continue;
- 
- 		list_for_each_entry(curmode, &connector->probed_modes, head) {
- 			if (common_modes[i].w == curmode->hdisplay &&
- 			    common_modes[i].h == curmode->vdisplay) {
- 				mode_existed = true;
- 				break;
- 			}
- 		}
- 
- 		if (mode_existed)
- 			continue;
- 
- 		mode = amdgpu_dm_create_common_mode(encoder,
- 				common_modes[i].name, common_modes[i].w,
- 				common_modes[i].h);
- 		if (!mode)
- 			continue;
- 
- 		drm_mode_probed_add(connector, mode);
- 		amdgpu_dm_connector->num_modes++;
- 	}
- }
- 
- static void amdgpu_set_panel_orientation(struct drm_connector *connector)
- {
- 	struct drm_encoder *encoder;
- 	struct amdgpu_encoder *amdgpu_encoder;
- 	const struct drm_display_mode *native_mode;
- 
- 	if (connector->connector_type != DRM_MODE_CONNECTOR_eDP &&
- 	    connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
- 		return;
- 
- 	mutex_lock(&connector->dev->mode_config.mutex);
- 	amdgpu_dm_connector_get_modes(connector);
- 	mutex_unlock(&connector->dev->mode_config.mutex);
- 
- 	encoder = amdgpu_dm_connector_to_encoder(connector);
- 	if (!encoder)
- 		return;
- 
- 	amdgpu_encoder = to_amdgpu_encoder(encoder);
- 
- 	native_mode = &amdgpu_encoder->native_mode;
- 	if (native_mode->hdisplay == 0 || native_mode->vdisplay == 0)
- 		return;
- 
- 	drm_connector_set_panel_orientation_with_quirk(connector,
- 						       DRM_MODE_PANEL_ORIENTATION_UNKNOWN,
- 						       native_mode->hdisplay,
- 						       native_mode->vdisplay);
- }
- 
- static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
- 					      const struct drm_edid *drm_edid)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 			to_amdgpu_dm_connector(connector);
- 
- 	if (drm_edid) {
- 		/* empty probed_modes */
- 		INIT_LIST_HEAD(&connector->probed_modes);
- 		amdgpu_dm_connector->num_modes =
- 				drm_edid_connector_add_modes(connector);
- 
- 		/* sorting the probed modes before calling function
- 		 * amdgpu_dm_get_native_mode() since EDID can have
- 		 * more than one preferred mode. The modes that are
- 		 * later in the probed mode list could be of higher
- 		 * and preferred resolution. For example, 3840x2160
- 		 * resolution in base EDID preferred timing and 4096x2160
- 		 * preferred resolution in DID extension block later.
- 		 */
- 		drm_mode_sort(&connector->probed_modes);
- 		amdgpu_dm_get_native_mode(connector);
- 
- 		/* Freesync capabilities are reset by calling
- 		 * drm_edid_connector_add_modes() and need to be
- 		 * restored here.
- 		 */
- 		amdgpu_dm_update_freesync_caps(connector, drm_edid, false);
- 	} else {
- 		amdgpu_dm_connector->num_modes = 0;
- 	}
- }
- 
- static bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector,
- 			      struct drm_display_mode *mode)
- {
- 	struct drm_display_mode *m;
- 
- 	list_for_each_entry(m, &aconnector->base.probed_modes, head) {
- 		if (drm_mode_equal(m, mode))
- 			return true;
- 	}
- 
- 	return false;
- }
- 
- static uint add_fs_modes(struct amdgpu_dm_connector *aconnector)
- {
- 	const struct drm_display_mode *m;
- 	struct drm_display_mode *new_mode;
- 	uint i;
- 	u32 new_modes_count = 0;
- 
- 	/* Standard FPS values
- 	 *
- 	 * 23.976       - TV/NTSC
- 	 * 24           - Cinema
- 	 * 25           - TV/PAL
- 	 * 29.97        - TV/NTSC
- 	 * 30           - TV/NTSC
- 	 * 48           - Cinema HFR
- 	 * 50           - TV/PAL
- 	 * 60           - Commonly used
- 	 * 48,72,96,120 - Multiples of 24
- 	 */
- 	static const u32 common_rates[] = {
- 		23976, 24000, 25000, 29970, 30000,
- 		48000, 50000, 60000, 72000, 96000, 120000
- 	};
- 
- 	/*
- 	 * Find mode with highest refresh rate with the same resolution
- 	 * as the preferred mode. Some monitors report a preferred mode
- 	 * with lower resolution than the highest refresh rate supported.
- 	 */
- 
- 	m = get_highest_refresh_rate_mode(aconnector, true);
- 	if (!m)
- 		return 0;
- 
- 	for (i = 0; i < ARRAY_SIZE(common_rates); i++) {
- 		u64 target_vtotal, target_vtotal_diff;
- 		u64 num, den;
- 
- 		if (drm_mode_vrefresh(m) * 1000 < common_rates[i])
- 			continue;
- 
- 		if (common_rates[i] < aconnector->min_vfreq * 1000 ||
- 		    common_rates[i] > aconnector->max_vfreq * 1000)
- 			continue;
- 
- 		num = (unsigned long long)m->clock * 1000 * 1000;
- 		den = common_rates[i] * (unsigned long long)m->htotal;
- 		target_vtotal = div_u64(num, den);
- 		target_vtotal_diff = target_vtotal - m->vtotal;
- 
- 		/* Check for illegal modes */
- 		if (m->vsync_start + target_vtotal_diff < m->vdisplay ||
- 		    m->vsync_end + target_vtotal_diff < m->vsync_start ||
- 		    m->vtotal + target_vtotal_diff < m->vsync_end)
- 			continue;
- 
- 		new_mode = drm_mode_duplicate(aconnector->base.dev, m);
- 		if (!new_mode)
- 			goto out;
- 
- 		new_mode->vtotal += (u16)target_vtotal_diff;
- 		new_mode->vsync_start += (u16)target_vtotal_diff;
- 		new_mode->vsync_end += (u16)target_vtotal_diff;
- 		new_mode->type &= ~DRM_MODE_TYPE_PREFERRED;
- 		new_mode->type |= DRM_MODE_TYPE_DRIVER;
- 
- 		if (!is_duplicate_mode(aconnector, new_mode)) {
- 			drm_mode_probed_add(&aconnector->base, new_mode);
- 			new_modes_count += 1;
- 		} else
- 			drm_mode_destroy(aconnector->base.dev, new_mode);
- 	}
-  out:
- 	return new_modes_count;
- }
- 
- static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
- 						   const struct drm_edid *drm_edid)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 		to_amdgpu_dm_connector(connector);
- 
- 	if (!(amdgpu_freesync_vid_mode && drm_edid))
- 		return;
- 
- 	if (!amdgpu_dm_connector->dc_sink || !amdgpu_dm_connector->dc_link)
- 		return;
- 
- 	if (!dc_supports_vrr(amdgpu_dm_connector->dc_sink->ctx->dce_version))
- 		return;
- 
- 	if (dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id) &&
- 	    amdgpu_dm_connector->dc_sink->edid_caps.analog)
- 		return;
- 
- 	if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 		amdgpu_dm_connector->num_modes +=
- 			add_fs_modes(amdgpu_dm_connector);
- }
- 
- static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 			to_amdgpu_dm_connector(connector);
- 	struct dc_link *dc_link = amdgpu_dm_connector->dc_link;
- 	struct drm_encoder *encoder;
- 	const struct drm_edid *drm_edid = amdgpu_dm_connector->drm_edid;
- 	struct dc_link_settings *verified_link_cap = &dc_link->verified_link_cap;
- 	const struct dc *dc = dc_link->dc;
- 
- 	encoder = amdgpu_dm_connector_to_encoder(connector);
- 
- 	if (!drm_edid) {
- 		amdgpu_dm_connector->num_modes =
- 				drm_add_modes_noedid(connector, 640, 480);
- 		if (dc->link_srv->dp_get_encoding_format(verified_link_cap) == DP_128b_132b_ENCODING)
- 			amdgpu_dm_connector->num_modes +=
- 				drm_add_modes_noedid(connector, 1920, 1080);
- 
- 		if (amdgpu_dm_connector->dc_sink &&
- 		    amdgpu_dm_connector->dc_sink->edid_caps.analog &&
- 		    dc_connector_supports_analog(dc_link->link_id.id)) {
- 			/* Analog monitor connected by DAC load detection.
- 			 * Add common modes. It will be up to the user to select one that works.
- 			 */
- 			for (int i = 0; i < ARRAY_SIZE(common_modes); i++)
- 				amdgpu_dm_connector->num_modes += drm_add_modes_noedid(
- 					connector, common_modes[i].w, common_modes[i].h);
- 		}
- 	} else {
- 		amdgpu_dm_connector_ddc_get_modes(connector, drm_edid);
- 		if (encoder)
- 			amdgpu_dm_connector_add_common_modes(encoder, connector);
- 		amdgpu_dm_connector_add_freesync_modes(connector, drm_edid);
- 	}
- 	amdgpu_dm_fbc_init(connector);
- 
- 	return amdgpu_dm_connector->num_modes;
- }
- 
- static const u32 supported_colorspaces =
- 	BIT(DRM_MODE_COLORIMETRY_BT709_YCC) |
- 	BIT(DRM_MODE_COLORIMETRY_OPRGB) |
- 	BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) |
- 	BIT(DRM_MODE_COLORIMETRY_BT2020_YCC);
- 
- void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
- 				     struct amdgpu_dm_connector *aconnector,
- 				     int connector_type,
- 				     struct dc_link *link,
- 				     int link_index)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dm->ddev);
- 
- 	/*
- 	 * Some of the properties below require access to state, like bpc.
- 	 * Allocate some default initial connector state with our reset helper.
- 	 */
- 	if (aconnector->base.funcs->reset)
- 		aconnector->base.funcs->reset(&aconnector->base);
- 
- 	aconnector->connector_id = link_index;
- 	aconnector->bl_idx = -1;
- 	aconnector->dc_link = link;
- 	aconnector->base.interlace_allowed = false;
- 	aconnector->base.doublescan_allowed = false;
- 	aconnector->base.stereo_allowed = false;
- 	aconnector->base.dpms = DRM_MODE_DPMS_OFF;
- 	aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
- 	aconnector->audio_inst = -1;
- 	aconnector->pack_sdp_v1_3 = false;
- 	aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE;
- 	memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info));
- 	mutex_init(&aconnector->hpd_lock);
- 	mutex_init(&aconnector->handle_mst_msg_ready);
- 
- 	/*
- 	 * If HDMI HPD debounce delay is set, use the minimum between selected
- 	 * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS
- 	 */
- 	if (amdgpu_hdmi_hpd_debounce_delay_ms) {
- 		aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms,
- 							     AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS);
- 		INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work);
- 		aconnector->hdmi_prev_sink = NULL;
- 	} else {
- 		aconnector->hdmi_hpd_debounce_delay_ms = 0;
- 	}
- 
- 	/*
- 	 * configure support HPD hot plug connector_>polled default value is 0
- 	 * which means HPD hot plug not supported
- 	 */
- 	switch (connector_type) {
- 	case DRM_MODE_CONNECTOR_HDMIA:
- 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- 		aconnector->base.ycbcr_420_allowed =
- 			link->link_enc->features.hdmi_ycbcr420_supported ? true : false;
- 		break;
- 	case DRM_MODE_CONNECTOR_DisplayPort:
- 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- 		link->link_enc = link_enc_cfg_get_link_enc(link);
- 		ASSERT(link->link_enc);
- 		if (link->link_enc)
- 			aconnector->base.ycbcr_420_allowed =
- 			link->link_enc->features.dp_ycbcr420_supported ? true : false;
- 		break;
- 	case DRM_MODE_CONNECTOR_DVID:
- 		aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- 		break;
- 	case DRM_MODE_CONNECTOR_DVII:
- 	case DRM_MODE_CONNECTOR_VGA:
- 		aconnector->base.polled =
- 			DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
- 		break;
- 	default:
- 		break;
- 	}
- 
- 	drm_object_attach_property(&aconnector->base.base,
- 				dm->ddev->mode_config.scaling_mode_property,
- 				DRM_MODE_SCALE_NONE);
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA
- 		|| (connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root))
- 		drm_connector_attach_broadcast_rgb_property(&aconnector->base);
- 
- 	drm_object_attach_property(&aconnector->base.base,
- 				adev->mode_info.underscan_property,
- 				UNDERSCAN_OFF);
- 	drm_object_attach_property(&aconnector->base.base,
- 				adev->mode_info.underscan_hborder_property,
- 				0);
- 	drm_object_attach_property(&aconnector->base.base,
- 				adev->mode_info.underscan_vborder_property,
- 				0);
- 
- 	if (!aconnector->mst_root)
- 		drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16);
- 
- 	aconnector->base.state->max_bpc = 16;
- 	aconnector->base.state->max_requested_bpc = aconnector->base.state->max_bpc;
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
- 		/* Content Type is currently only implemented for HDMI. */
- 		drm_connector_attach_content_type_property(&aconnector->base);
- 	}
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA) {
- 		if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces))
- 			drm_connector_attach_colorspace_property(&aconnector->base);
- 	} else if ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root) ||
- 		   connector_type == DRM_MODE_CONNECTOR_eDP) {
- 		if (!drm_mode_create_dp_colorspace_property(&aconnector->base, supported_colorspaces))
- 			drm_connector_attach_colorspace_property(&aconnector->base);
- 	}
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- 	    connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
- 	    connector_type == DRM_MODE_CONNECTOR_eDP) {
- 		drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
- 
- 		if (!aconnector->mst_root)
- 			drm_connector_attach_vrr_capable_property(&aconnector->base);
- 
- 		if (adev->dm.hdcp_workqueue)
- 			drm_connector_attach_content_protection_property(&aconnector->base, true);
- 	}
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_eDP) {
- 		struct drm_privacy_screen *privacy_screen;
- 
- 		drm_connector_attach_panel_type_property(&aconnector->base);
- 
- 		privacy_screen = drm_privacy_screen_get(adev_to_drm(adev)->dev, NULL);
- 		if (!IS_ERR(privacy_screen)) {
- 			drm_connector_attach_privacy_screen_provider(&aconnector->base,
- 								     privacy_screen);
- 		} else if (PTR_ERR(privacy_screen) != -ENODEV) {
- 			drm_warn(adev_to_drm(adev), "Error getting privacy-screen\n");
- 		}
- 	}
- }
- 
- static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
- 			      struct i2c_msg *msgs, int num)
- {
- 	struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
- 	struct ddc_service *ddc_service = i2c->ddc_service;
- 	struct i2c_command cmd;
- 	int i;
- 	int result = -EIO;
- 
- 	if (!ddc_service->ddc_pin)
- 		return result;
- 
- 	cmd.payloads = kzalloc_objs(struct i2c_payload, num);
- 
- 	if (!cmd.payloads)
- 		return result;
- 
- 	cmd.number_of_payloads = num;
- 	cmd.engine = I2C_COMMAND_ENGINE_DEFAULT;
- 	cmd.speed = 100;
- 
- 	for (i = 0; i < num; i++) {
- 		cmd.payloads[i].write = !(msgs[i].flags & I2C_M_RD);
- 		cmd.payloads[i].address = msgs[i].addr;
- 		cmd.payloads[i].length = msgs[i].len;
- 		cmd.payloads[i].data = msgs[i].buf;
- 	}
- 
- 	if (i2c->oem) {
- 		if (dc_submit_i2c_oem(
- 			    ddc_service->ctx->dc,
- 			    &cmd))
- 			result = num;
- 	} else {
- 		if (dc_submit_i2c(
- 			    ddc_service->ctx->dc,
- 			    ddc_service->link->link_index,
- 			    &cmd))
- 			result = num;
- 	}
- 
- 	kfree(cmd.payloads);
- 	return result;
- }
- 
- static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap)
- {
- 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
- }
- 
- static const struct i2c_algorithm amdgpu_dm_i2c_algo = {
- 	.master_xfer = amdgpu_dm_i2c_xfer,
- 	.functionality = amdgpu_dm_i2c_func,
- };
- 
- static struct amdgpu_i2c_adapter *
- create_i2c(struct ddc_service *ddc_service, bool oem)
- {
- 	struct amdgpu_device *adev = ddc_service->ctx->driver_context;
- 	struct amdgpu_i2c_adapter *i2c;
- 
- 	i2c = kzalloc_obj(struct amdgpu_i2c_adapter);
- 	if (!i2c)
- 		return NULL;
- 	i2c->base.owner = THIS_MODULE;
- 	i2c->base.dev.parent = &adev->pdev->dev;
- 	i2c->base.algo = &amdgpu_dm_i2c_algo;
- 	if (oem)
- 		snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c OEM bus");
- 	else
- 		snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d",
- 			 ddc_service->link->link_index);
- 	i2c_set_adapdata(&i2c->base, i2c);
- 	i2c->ddc_service = ddc_service;
- 	i2c->oem = oem;
- 
- 	return i2c;
- }
- 
- int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector)
- {
- 	struct cec_connector_info conn_info;
- 	struct drm_device *ddev = aconnector->base.dev;
- 	struct device *hdmi_dev = ddev->dev;
- 
- 	if (amdgpu_dc_debug_mask & DC_DISABLE_HDMI_CEC) {
- 		drm_info(ddev, "HDMI-CEC feature masked\n");
- 		return -EINVAL;
- 	}
- 
- 	cec_fill_conn_info_from_drm(&conn_info, &aconnector->base);
- 	aconnector->notifier =
- 		cec_notifier_conn_register(hdmi_dev, NULL, &conn_info);
- 	if (!aconnector->notifier) {
- 		drm_err(ddev, "Failed to create cec notifier\n");
- 		return -ENOMEM;
- 	}
- 
- 	return 0;
- }
- 
- /*
-  * Note: this function assumes that dc_link_detect() was called for the
-  * dc_link which will be represented by this aconnector.
-  */
- static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
- 				    struct amdgpu_dm_connector *aconnector,
- 				    u32 link_index,
- 				    struct amdgpu_encoder *aencoder)
- {
- 	int res = 0;
- 	int connector_type;
- 	struct dc *dc = dm->dc;
- 	struct dc_link *link = dc_get_link_at_index(dc, link_index);
- 	struct amdgpu_i2c_adapter *i2c;
- 
- 	/* Not needed for writeback connector */
- 	link->priv = aconnector;
- 
- 
- 	i2c = create_i2c(link->ddc, false);
- 	if (!i2c) {
- 		drm_err(adev_to_drm(dm->adev), "Failed to create i2c adapter data\n");
- 		return -ENOMEM;
- 	}
- 
- 	aconnector->i2c = i2c;
- 	res = devm_i2c_add_adapter(dm->adev->dev, &i2c->base);
- 
- 	if (res) {
- 		drm_err(adev_to_drm(dm->adev), "Failed to register hw i2c %d\n", link->link_index);
- 		goto out_free;
- 	}
- 
- 	connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id);
- 
- 	res = drm_connector_init_with_ddc(
- 			dm->ddev,
- 			&aconnector->base,
- 			&amdgpu_dm_connector_funcs,
- 			connector_type,
- 			&i2c->base);
- 
- 	if (res) {
- 		drm_err(adev_to_drm(dm->adev), "connector_init failed\n");
- 		aconnector->connector_id = -1;
- 		goto out_free;
- 	}
- 
- 	drm_connector_helper_add(
- 			&aconnector->base,
- 			&amdgpu_dm_connector_helper_funcs);
- 
- 	amdgpu_dm_connector_init_helper(
- 		dm,
- 		aconnector,
- 		connector_type,
- 		link,
- 		link_index);
- 
- 	drm_connector_attach_encoder(
- 		&aconnector->base, &aencoder->base);
- 
- 	if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
- 	    connector_type == DRM_MODE_CONNECTOR_HDMIB)
- 		amdgpu_dm_initialize_hdmi_connector(aconnector);
- 
- 	if (dc_is_dp_signal(link->connector_signal))
- 		amdgpu_dm_initialize_dp_connector(dm, aconnector, link->link_index);
- 
- out_free:
- 	if (res) {
- 		kfree(i2c);
- 		aconnector->i2c = NULL;
- 	}
- 	return res;
- }
- 
- int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev)
- {
- 	switch (adev->mode_info.num_crtc) {
- 	case 1:
- 		return 0x1;
- 	case 2:
- 		return 0x3;
- 	case 3:
- 		return 0x7;
- 	case 4:
- 		return 0xf;
- 	case 5:
- 		return 0x1f;
- 	case 6:
- 	default:
- 		return 0x3f;
- 	}
- }
- 
- static int amdgpu_dm_encoder_init(struct drm_device *dev,
- 				  struct amdgpu_encoder *aencoder,
- 				  uint32_t link_index)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 
- 	int res = drm_encoder_init(dev,
- 				   &aencoder->base,
- 				   &amdgpu_dm_encoder_funcs,
- 				   DRM_MODE_ENCODER_TMDS,
- 				   NULL);
- 
- 	aencoder->base.possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev);
- 
- 	if (!res)
- 		aencoder->encoder_id = link_index;
- 	else
- 		aencoder->encoder_id = -1;
- 
- 	drm_encoder_helper_add(&aencoder->base, &amdgpu_dm_encoder_helper_funcs);
- 
- 	return res;
- }
- 
  static void manage_dm_interrupts(struct amdgpu_device *adev,
  				 struct amdgpu_crtc *acrtc,
  				 struct dm_crtc_state *acrtc_state)
@@@ -9754,7 -3625,7 +3625,7 @@@ static void dm_update_pflip_irq_state(s
  	amdgpu_irq_update(adev, &adev->pageflip_irq, irq_type);
  }
  
- static bool
+ STATIC_IFN_KUNIT bool
  is_scaling_state_different(const struct dm_connector_state *dm_state,
  			   const struct dm_connector_state *old_dm_state)
  {
@@@ -9771,6 -3642,7 +3642,7 @@@
  		return true;
  	return false;
  }
+ EXPORT_IF_KUNIT(is_scaling_state_different);
  
  static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
  					    struct drm_crtc_state *old_crtc_state,
@@@ -10079,7 -3951,7 +3951,7 @@@ static void amdgpu_dm_handle_vrr_transi
  					    struct dm_crtc_state *old_state,
  					    struct dm_crtc_state *new_state)
  {
- 	struct amdgpu_device *adev = drm_to_adev(new_state->base.crtc->dev);
+ 	struct amdgpu_device *adev = dm->adev;
  	bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state);
  	bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state);
  
@@@ -10384,14 -4256,12 +4256,12 @@@ static void amdgpu_dm_commit_planes(str
  			continue;
  
  		bundle->surface_updates[planes_count].surface = dc_plane;
- 		if (new_pcrtc_state->color_mgmt_changed || new_plane_state->color_mgmt_changed) {
+ 		if (new_pcrtc_state->color_mgmt_changed) {
  			bundle->surface_updates[planes_count].gamma = &dc_plane->gamma_correction;
  			bundle->surface_updates[planes_count].in_transfer_func = &dc_plane->in_transfer_func;
  			bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
  			bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult;
- 			bundle->surface_updates[planes_count].func_shaper = &dc_plane->in_shaper_func;
- 			bundle->surface_updates[planes_count].lut3d_func = &dc_plane->lut3d_func;
- 			bundle->surface_updates[planes_count].blend_tf = &dc_plane->blend_tf;
+ 			bundle->surface_updates[planes_count].cm = &dc_plane->cm;
  		}
  
  		amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
@@@ -10764,87 -4634,6 +4634,6 @@@ cleanup
  	kfree(bundle);
  }
  
- static void amdgpu_dm_commit_audio(struct drm_device *dev,
- 				   struct drm_atomic_commit *state)
- {
- 	struct amdgpu_device *adev = drm_to_adev(dev);
- 	struct amdgpu_dm_connector *aconnector;
- 	struct drm_connector *connector;
- 	struct drm_connector_state *old_con_state, *new_con_state;
- 	struct drm_crtc_state *new_crtc_state;
- 	struct dm_crtc_state *new_dm_crtc_state;
- 	const struct dc_stream_status *status;
- 	int i, inst;
- 
- 	/* Notify device removals. */
- 	for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
- 		if (old_con_state->crtc != new_con_state->crtc) {
- 			/* CRTC changes require notification. */
- 			goto notify;
- 		}
- 
- 		if (!new_con_state->crtc)
- 			continue;
- 
- 		new_crtc_state = drm_atomic_get_new_crtc_state(
- 			state, new_con_state->crtc);
- 
- 		if (!new_crtc_state)
- 			continue;
- 
- 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
- 			continue;
- 
- notify:
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 		mutex_lock(&adev->dm.audio_lock);
- 		inst = aconnector->audio_inst;
- 		aconnector->audio_inst = -1;
- 		mutex_unlock(&adev->dm.audio_lock);
- 
- 		amdgpu_dm_audio_eld_notify(adev, inst);
- 	}
- 
- 	/* Notify audio device additions. */
- 	for_each_new_connector_in_state(state, connector, new_con_state, i) {
- 		if (!new_con_state->crtc)
- 			continue;
- 
- 		new_crtc_state = drm_atomic_get_new_crtc_state(
- 			state, new_con_state->crtc);
- 
- 		if (!new_crtc_state)
- 			continue;
- 
- 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
- 			continue;
- 
- 		new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
- 		if (!new_dm_crtc_state->stream)
- 			continue;
- 
- 		status = dc_stream_get_status(new_dm_crtc_state->stream);
- 		if (!status)
- 			continue;
- 
- 		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 			continue;
- 
- 		aconnector = to_amdgpu_dm_connector(connector);
- 
- 		mutex_lock(&adev->dm.audio_lock);
- 		inst = status->audio_inst;
- 		aconnector->audio_inst = inst;
- 		mutex_unlock(&adev->dm.audio_lock);
- 
- 		amdgpu_dm_audio_eld_notify(adev, inst);
- 	}
- }
- 
  /*
   * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC
   * @crtc_state: the DRM CRTC state
@@@ -10859,10 -4648,55 +4648,55 @@@ static void amdgpu_dm_crtc_copy_transie
  	stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state);
  }
  
+ /**
+  * amdgpu_dm_crtc_complete_writeback - finish a pending writeback job
+  * @acrtc: the CRTC whose pending writeback should be completed
+  *
+  * Clears the pending state, signals the writeback out fence and releases the
+  * vblank reference taken in dm_set_writeback() while the writeback was armed.
+  * The pending flag is tested and cleared under the writeback job lock, so this
+  * is safe to call concurrently from the completion vblank IRQ
+  * (dm_crtc_high_irq()) and from the writeback teardown path
+  * (dm_clear_writeback()); only the caller that observes the pending job
+  * performs the completion.
+  *
+  * Return: true if a pending writeback job was completed by this call.
+  */
+ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc)
+ {
+ 	unsigned long flags;
+ 	bool pending;
+ 
+ 	if (!acrtc->wb_conn)
+ 		return false;
+ 
+ 	spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
+ 	pending = acrtc->wb_pending;
+ 	acrtc->wb_pending = false;
+ 	spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
+ 
+ 	if (!pending)
+ 		return false;
+ 
+ 	drm_writeback_signal_completion(acrtc->wb_conn, 0);
+ 	drm_crtc_vblank_put(&acrtc->base);
+ 
+ 	return true;
+ }
+ 
  static void dm_clear_writeback(struct amdgpu_display_manager *dm,
+ 			      struct amdgpu_crtc *acrtc,
  			      struct dm_crtc_state *crtc_state)
  {
  	dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
+ 
+ 	/*
+ 	 * If the writeback is still pending when it is torn down (its
+ 	 * completion vblank IRQ never fired), signal the out fence so a
+ 	 * waiting client does not stall and release the vblank reference
+ 	 * taken in dm_set_writeback().
+ 	 */
+ 	amdgpu_dm_crtc_complete_writeback(acrtc);
  }
  
  /**
@@@ -11015,7 -4849,7 +4849,7 @@@ static void amdgpu_dm_commit_streams(st
  
  		dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
  
- 		dm_clear_writeback(dm, dm_old_crtc_state);
+ 		dm_clear_writeback(dm, acrtc, dm_old_crtc_state);
  		acrtc->wb_enabled = false;
  	}
  
@@@ -11289,9 -5123,24 +5123,24 @@@ static void dm_set_writeback(struct amd
  
  	dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info);
  
- 	acrtc->wb_pending = true;
  	acrtc->wb_conn = wb_conn;
  	drm_writeback_queue_job(wb_conn, new_con_state);
+ 
+ 	/*
+ 	 * Writeback completion is detected in the CRTC vblank IRQ
+ 	 * (dm_crtc_high_irq()). Take a vblank reference so the vblank interrupt
+ 	 * stays enabled while the writeback is pending; otherwise a
+ 	 * writeback-only commit right after drm_crtc_vblank_on() (e.g.
+ 	 * re-enabling a CRTC that was disabled) has no other vblank reference,
+ 	 * the IRQ never fires and the out fence times out. The matching put
+ 	 * happens once completion is signalled in dm_crtc_high_irq(), or when
+ 	 * the writeback is torn down in dm_clear_writeback().
+ 	 *
+ 	 * Arm wb_pending only after the reference is held so the completion IRQ
+ 	 * cannot run its matching vblank_put before this get.
+ 	 */
+ 	WARN_ON(drm_crtc_vblank_get(&acrtc->base));
+ 	acrtc->wb_pending = true;
  }
  
  static void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
@@@ -11442,6 -5291,74 +5291,74 @@@ static int amdgpu_dm_atomic_setup_commi
  	return 0;
  }
  
+ STATIC_IFN_KUNIT void set_multisync_trigger_params(
+ 		struct dc_stream_state *stream)
+ {
+ 	struct dc_stream_state *master = NULL;
+ 
+ 	if (stream->triggered_crtc_reset.enabled) {
+ 		master = stream->triggered_crtc_reset.event_source;
+ 		stream->triggered_crtc_reset.event =
+ 			master->timing.flags.VSYNC_POSITIVE_POLARITY ?
+ 			CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING;
+ 		stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL;
+ 	}
+ }
+ EXPORT_IF_KUNIT(set_multisync_trigger_params);
+ 
+ STATIC_IFN_KUNIT void set_master_stream(struct dc_stream_state *stream_set[],
+ 					int stream_count)
+ {
+ 	int j, highest_rfr = 0, master_stream = 0;
+ 
+ 	for (j = 0;  j < stream_count; j++) {
+ 		if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) {
+ 			int refresh_rate = 0;
+ 
+ 			refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/
+ 				(stream_set[j]->timing.h_total*stream_set[j]->timing.v_total);
+ 			if (refresh_rate > highest_rfr) {
+ 				highest_rfr = refresh_rate;
+ 				master_stream = j;
+ 			}
+ 		}
+ 	}
+ 	for (j = 0;  j < stream_count; j++) {
+ 		if (stream_set[j])
+ 			stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream];
+ 	}
+ }
+ EXPORT_IF_KUNIT(set_master_stream);
+ 
+ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
+ {
+ 	int i = 0;
+ 	struct dc_stream_state *stream;
+ 
+ 	if (context->stream_count < 2)
+ 		return;
+ 	for (i = 0; i < context->stream_count ; i++) {
+ 		if (!context->streams[i])
+ 			continue;
+ 		/*
+ 		 * TODO: add a function to read AMD VSDB bits and set
+ 		 * crtc_sync_master.multi_sync_enabled flag
+ 		 * For now it's set to false
+ 		 */
+ 	}
+ 
+ 	set_master_stream(context->streams, context->stream_count);
+ 
+ 	for (i = 0; i < context->stream_count ; i++) {
+ 		stream = context->streams[i];
+ 
+ 		if (!stream)
+ 			continue;
+ 
+ 		set_multisync_trigger_params(stream);
+ 	}
+ }
+ 
  /**
   * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
   * @state: The atomic state to commit
@@@ -11510,7 -5427,7 +5427,7 @@@ static void amdgpu_dm_atomic_commit_tai
  
  		if ((new_con_state->hdmi.broadcast_rgb != old_con_state->hdmi.broadcast_rgb) &&
  			(dm_old_crtc_state->stream->output_color_space !=
- 				get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state)))
+ 				amdgpu_dm_get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state)))
  			output_color_space_changed = true;
  
  		abm_changed = dm_new_crtc_state->abm_level !=
@@@ -11524,7 -5441,7 +5441,7 @@@
  
  		stream_update.stream = dm_new_crtc_state->stream;
  		if (scaling_changed) {
- 			update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode,
+ 			amdgpu_dm_update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode,
  					dm_new_con_state, dm_new_crtc_state->stream);
  
  			stream_update.src = dm_new_crtc_state->stream->src;
@@@ -11533,7 -5450,7 +5450,7 @@@
  
  		if (output_color_space_changed) {
  			dm_new_crtc_state->stream->output_color_space
- 				= get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state);
+ 				= amdgpu_dm_get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state);
  
  			stream_update.output_color_space = &dm_new_crtc_state->stream->output_color_space;
  		}
@@@ -11545,7 -5462,7 +5462,7 @@@
  		}
  
  		if (hdr_changed) {
- 			fill_hdr_info_packet(new_con_state, &hdr_packet);
+ 			amdgpu_dm_fill_hdr_info_packet(new_con_state, &hdr_packet);
  			stream_update.hdr_static_metadata = &hdr_packet;
  		}
  
@@@ -11753,104 -5670,6 +5670,6 @@@
  	trace_amdgpu_dm_atomic_commit_tail_finish(state);
  }
  
- static int dm_force_atomic_commit(struct drm_connector *connector)
- {
- 	int ret = 0;
- 	struct drm_device *ddev = connector->dev;
- 	struct drm_atomic_commit *state = drm_atomic_commit_alloc(ddev);
- 	struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
- 	struct drm_plane *plane = disconnected_acrtc->base.primary;
- 	struct drm_connector_state *conn_state;
- 	struct drm_crtc_state *crtc_state;
- 	struct drm_plane_state *plane_state;
- 
- 	if (!state)
- 		return -ENOMEM;
- 
- 	state->acquire_ctx = ddev->mode_config.acquire_ctx;
- 
- 	/* Construct an atomic state to restore previous display setting */
- 
- 	/*
- 	 * Attach connectors to drm_atomic_commit
- 	 */
- 	conn_state = drm_atomic_get_connector_state(state, connector);
- 
- 	/* Check for error in getting connector state */
- 	if (IS_ERR(conn_state)) {
- 		ret = PTR_ERR(conn_state);
- 		goto out;
- 	}
- 
- 	/* Attach crtc to drm_atomic_commit*/
- 	crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
- 
- 	/* Check for error in getting crtc state */
- 	if (IS_ERR(crtc_state)) {
- 		ret = PTR_ERR(crtc_state);
- 		goto out;
- 	}
- 
- 	/* force a restore */
- 	crtc_state->mode_changed = true;
- 
- 	/* Attach plane to drm_atomic_commit */
- 	plane_state = drm_atomic_get_plane_state(state, plane);
- 
- 	/* Check for error in getting plane state */
- 	if (IS_ERR(plane_state)) {
- 		ret = PTR_ERR(plane_state);
- 		goto out;
- 	}
- 
- 	/* Call commit internally with the state we just constructed */
- 	ret = drm_atomic_commit(state);
- 
- out:
- 	drm_atomic_commit_put(state);
- 	if (ret)
- 		drm_err(ddev, "Restoring old state failed with %i\n", ret);
- 
- 	return ret;
- }
- 
- /*
-  * This function handles all cases when set mode does not come upon hotplug.
-  * This includes when a display is unplugged then plugged back into the
-  * same port and when running without usermode desktop manager supprot
-  */
- void dm_restore_drm_connector_state(struct drm_device *dev,
- 				    struct drm_connector *connector)
- {
- 	struct amdgpu_dm_connector *aconnector;
- 	struct amdgpu_crtc *disconnected_acrtc;
- 	struct dm_crtc_state *acrtc_state;
- 
- 	if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
- 		return;
- 
- 	aconnector = to_amdgpu_dm_connector(connector);
- 
- 	if (!aconnector->dc_sink || !connector->state || !connector->encoder)
- 		return;
- 
- 	disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
- 	if (!disconnected_acrtc)
- 		return;
- 
- 	acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state);
- 	if (!acrtc_state->stream)
- 		return;
- 
- 	/*
- 	 * If the previous sink is not released and different from the current,
- 	 * we deduce we are in a state where we can not rely on usermode call
- 	 * to turn on the display, so we do it here
- 	 */
- 	if (acrtc_state->stream->sink != aconnector->dc_sink)
- 		dm_force_atomic_commit(&aconnector->base);
- }
- 
  /*
   * Grabs all modesetting locks to serialize against any blocking commits,
   * Waits for completion of all non blocking commits.
@@@ -11955,7 -5774,7 +5774,7 @@@ static void reset_freesync_config_for_c
  	       sizeof(new_crtc_state->vrr_infopacket));
  }
  
- static bool
+ STATIC_IFN_KUNIT bool
  is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
  				 struct drm_crtc_state *new_crtc_state)
  {
@@@ -11984,8 -5803,9 +5803,9 @@@
  
  	return false;
  }
+ EXPORT_IF_KUNIT(is_timing_unchanged_for_freesync);
  
- static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
+ STATIC_IFN_KUNIT void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
  {
  	u64 num, den, res;
  	struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
@@@ -11999,6 -5819,7 +5819,7 @@@
  	res = div_u64(num, den);
  	dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res;
  }
+ EXPORT_IF_KUNIT(set_freesync_fixed_config);
  
  static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
  			 struct drm_atomic_commit *state,
@@@ -12052,7 -5873,7 +5873,7 @@@
  		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
  			goto skip_modeset;
  
- 		new_stream = create_validate_stream_for_sink(connector,
+ 		new_stream = amdgpu_dm_create_validate_stream_for_sink(connector,
  							     &new_crtc_state->mode,
  							     dm_new_conn_state,
  							     dm_old_crtc_state->stream);
@@@ -12080,7 -5901,7 +5901,7 @@@
  
  		dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
  
- 		ret = fill_hdr_info_packet(drm_new_conn_state,
+ 		ret = amdgpu_dm_fill_hdr_info_packet(drm_new_conn_state,
  					   &new_stream->hdr_static_metadata);
  		if (ret)
  			goto fail;
@@@ -12149,11 -5970,11 +5970,11 @@@
  
  			goto skip_modeset;
  		} else if (amdgpu_freesync_vid_mode && aconnector &&
- 			   is_freesync_video_mode(&new_crtc_state->mode,
+ 			   amdgpu_dm_is_freesync_video_mode(&new_crtc_state->mode,
  						  aconnector)) {
  			struct drm_display_mode *high_mode;
  
- 			high_mode = get_highest_refresh_rate_mode(aconnector, false);
+ 			high_mode = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false);
  			if (!drm_mode_equal(&new_crtc_state->mode, high_mode))
  				set_freesync_fixed_config(dm_new_crtc_state);
  		}
@@@ -12246,7 -6067,7 +6067,7 @@@ skip_modeset
  	/* Scaling or underscan settings */
  	if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) ||
  				drm_atomic_crtc_needs_modeset(new_crtc_state))
- 		update_stream_scaling_settings(adev_to_drm(adev),
+ 		amdgpu_dm_update_stream_scaling_settings(adev_to_drm(adev),
  			&new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream);
  
  	/* ABM settings */
@@@ -12342,10 -6163,6 +6163,6 @@@ static bool should_reset_plane(struct d
  	if (new_crtc_state->color_mgmt_changed)
  		return true;
  
- 	/* Plane color pipeline or its colorop changes. */
- 	if (new_plane_state->color_mgmt_changed)
- 		return true;
- 
  	/*
  	 * On zpos change, planes need to be reordered by removing and re-adding
  	 * them one by one to the dc state, in order of descending zpos.
@@@ -12720,7 -6537,7 +6537,7 @@@ static int dm_update_plane_state(struc
  		/* Tell DC to do a full surface update every time there
  		 * is a plane change. Inefficient, but works for now.
  		 */
- 		dm_new_plane_state->dc_state->update_flags.bits.full_update = 1;
+ 		dm_new_plane_state->dc_state->update_bits.full_update = 1;
  
  		*lock_and_validation_needed = true;
  	}
@@@ -12739,8 -6556,8 +6556,8 @@@ out
  	return ret;
  }
  
- static void dm_get_oriented_plane_size(struct drm_plane_state *plane_state,
- 				       int *src_w, int *src_h)
+ STATIC_IFN_KUNIT void dm_get_oriented_plane_size(struct drm_plane_state *plane_state,
+ 					 int *src_w, int *src_h)
  {
  	switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
  	case DRM_MODE_ROTATE_90:
@@@ -12756,8 -6573,9 +6573,9 @@@
  		break;
  	}
  }
+ EXPORT_IF_KUNIT(dm_get_oriented_plane_size);
  
- static void
+ STATIC_IFN_KUNIT void
  dm_get_plane_scale(struct drm_plane_state *plane_state,
  		   int *out_plane_scale_w, int *out_plane_scale_h)
  {
@@@ -12767,6 -6585,7 +6585,7 @@@
  	*out_plane_scale_w = plane_src_w ? plane_state->crtc_w * 1000 / plane_src_w : 0;
  	*out_plane_scale_h = plane_src_h ? plane_state->crtc_h * 1000 / plane_src_h : 0;
  }
+ EXPORT_IF_KUNIT(dm_get_plane_scale);
  
  /*
   * The normalized_zpos value cannot be used by this iterator directly. It's only
@@@ -12986,6 -6805,31 +6805,31 @@@ static int dm_crtc_get_cursor_mode(stru
  			break;
  		}
  
+ 		/*
+ 		 * A non-cursor plane moving or resizing (without a scale change)
+ 		 * changes how much of the CRTC it covers. This can create or
+ 		 * remove a hole under the cursor and thus flip the required
+ 		 * cursor mode (native vs overlay), so its destination rect must
+ 		 * be re-evaluated too.
+ 		 *
+ 		 * The cursor plane itself is deliberately excluded: the cursor
+ 		 * mode depends on the underlying planes' coverage, not on the
+ 		 * cursor's position (see the entire_crtc_covered logic below).
+ 		 * Triggering on cursor movement would force every legacy cursor
+ 		 * update off its fast path, and in a cursor-only commit - where
+ 		 * the underlying planes are not part of the state - the coverage
+ 		 * loop would see no covering plane and misevaluate the mode as
+ 		 * overlay, regressing flip-vs-cursor-legacy.
+ 		 */
+ 		if (plane->type != DRM_PLANE_TYPE_CURSOR &&
+ 		    (old_plane_state->crtc_x != plane_state->crtc_x ||
+ 		     old_plane_state->crtc_y != plane_state->crtc_y ||
+ 		     old_plane_state->crtc_w != plane_state->crtc_w ||
+ 		     old_plane_state->crtc_h != plane_state->crtc_h)) {
+ 			consider_mode_change = true;
+ 			break;
+ 		}
+ 
  		if (dm_plane_color_pipeline_active(state, plane, true) !=
  		    dm_plane_color_pipeline_active(state, plane, false)) {
  			consider_mode_change = true;
@@@ -13141,7 -6985,7 +6985,7 @@@ static int amdgpu_dm_atomic_check(struc
  
  	ret = drm_atomic_helper_check_modeset(dev, state);
  	if (ret) {
- 		drm_dbg_atomic(dev, "drm_atomic_helper_check_modeset() failed\n");
+ 		drm_dbg_atomic(dev, "drm_atomic_helper_check_modeset() failed: %pe\n", ERR_PTR(ret));
  		goto fail;
  	}
  
@@@ -13156,7 -7000,7 +7000,7 @@@
  
  		new_crtc_state = drm_atomic_get_crtc_state(state, new_con_state->crtc);
  		if (IS_ERR(new_crtc_state)) {
- 			drm_dbg_atomic(dev, "drm_atomic_get_crtc_state() failed\n");
+ 			drm_dbg_atomic(dev, "drm_atomic_get_crtc_state() failed: %pe\n", new_crtc_state);
  			ret = PTR_ERR(new_crtc_state);
  			goto fail;
  		}
@@@ -13176,7 -7020,7 +7020,7 @@@
  			if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
  				ret = add_affected_mst_dsc_crtcs(state, crtc);
  				if (ret) {
- 					drm_dbg_atomic(dev, "add_affected_mst_dsc_crtcs() failed\n");
+ 					drm_dbg_atomic(dev, "add_affected_mst_dsc_crtcs() failed: %pe\n", ERR_PTR(ret));
  					goto fail;
  				}
  			}
@@@ -13193,7 -7037,7 +7037,7 @@@
  
  		ret = amdgpu_dm_verify_lut_sizes(new_crtc_state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "amdgpu_dm_verify_lut_sizes() failed\n");
+ 			drm_dbg_atomic(dev, "amdgpu_dm_verify_lut_sizes() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13202,13 -7046,13 +7046,13 @@@
  
  		ret = drm_atomic_add_affected_connectors(state, crtc);
  		if (ret) {
- 			drm_dbg_atomic(dev, "drm_atomic_add_affected_connectors() failed\n");
+ 			drm_dbg_atomic(dev, "drm_atomic_add_affected_connectors() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
  		ret = drm_atomic_add_affected_planes(state, crtc);
  		if (ret) {
- 			drm_dbg_atomic(dev, "drm_atomic_add_affected_planes() failed\n");
+ 			drm_dbg_atomic(dev, "drm_atomic_add_affected_planes() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13247,7 -7091,7 +7091,7 @@@
  
  			if (IS_ERR(new_plane_state)) {
  				ret = PTR_ERR(new_plane_state);
- 				drm_dbg_atomic(dev, "new_plane_state is BAD\n");
+ 				drm_dbg_atomic(dev, "new_plane_state is BAD: %pe\n", new_plane_state);
  				goto fail;
  			}
  		}
@@@ -13261,7 -7105,7 +7105,7 @@@
  	 */
  	ret = drm_atomic_normalize_zpos(dev, state);
  	if (ret) {
- 		drm_dbg(dev, "drm_atomic_normalize_zpos() failed\n");
+ 		drm_dbg(dev, "drm_atomic_normalize_zpos() failed: %pe\n", ERR_PTR(ret));
  		goto fail;
  	}
  
@@@ -13275,7 -7119,7 +7119,7 @@@
  		ret = dm_crtc_get_cursor_mode(adev, state, dm_new_crtc_state,
  					      &dm_new_crtc_state->cursor_mode);
  		if (ret) {
- 			drm_dbg(dev, "Failed to determine cursor mode\n");
+ 			drm_dbg(dev, "Failed to determine cursor mode: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13307,7 -7151,7 +7151,7 @@@
  					    &lock_and_validation_needed,
  					    &is_top_most_overlay);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_update_plane_state() failed\n");
+ 			drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13320,7 -7164,7 +7164,7 @@@
  					   false,
  					   &lock_and_validation_needed);
  		if (ret) {
- 			drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed\n");
+ 			drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13333,7 -7177,7 +7177,7 @@@
  					   true,
  					   &lock_and_validation_needed);
  		if (ret) {
- 			drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed\n");
+ 			drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13347,7 -7191,7 +7191,7 @@@
  					    &lock_and_validation_needed,
  					    &is_top_most_overlay);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_update_plane_state() failed\n");
+ 			drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  	}
@@@ -13363,7 -7207,7 +7207,7 @@@
  	/* Run this here since we want to validate the streams we created */
  	ret = drm_atomic_helper_check_planes(dev, state);
  	if (ret) {
- 		drm_dbg_atomic(dev, "drm_atomic_helper_check_planes() failed\n");
+ 		drm_dbg_atomic(dev, "drm_atomic_helper_check_planes() failed: %pe\n", ERR_PTR(ret));
  		goto fail;
  	}
  
@@@ -13501,13 -7345,13 +7345,13 @@@
  	if (lock_and_validation_needed) {
  		ret = dm_atomic_get_state(state, &dm_state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_atomic_get_state() failed\n");
+ 			drm_dbg_atomic(dev, "dm_atomic_get_state() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
  		ret = do_aquire_global_lock(dev, state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "do_aquire_global_lock() failed\n");
+ 			drm_dbg_atomic(dev, "do_aquire_global_lock() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13515,7 -7359,7 +7359,7 @@@
  		if (dc_resource_is_dsc_encoding_supported(dc)) {
  			ret = compute_mst_dsc_configs_for_state(state, dm_state->context, vars);
  			if (ret) {
- 				drm_dbg_atomic(dev, "MST_DSC compute_mst_dsc_configs_for_state() failed\n");
+ 				drm_dbg_atomic(dev, "MST_DSC compute_mst_dsc_configs_for_state() failed: %pe\n", ERR_PTR(ret));
  				ret = -EINVAL;
  				goto fail;
  			}
@@@ -13524,7 -7368,7 +7368,7 @@@
  
  		ret = dm_update_mst_vcpi_slots_for_dsc(state, dm_state->context, vars);
  		if (ret) {
- 			drm_dbg_atomic(dev, "dm_update_mst_vcpi_slots_for_dsc() failed\n");
+ 			drm_dbg_atomic(dev, "dm_update_mst_vcpi_slots_for_dsc() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  
@@@ -13536,7 -7380,7 +7380,7 @@@
  		 */
  		ret = drm_dp_mst_atomic_check(state);
  		if (ret) {
- 			drm_dbg_atomic(dev, "MST drm_dp_mst_atomic_check() failed\n");
+ 			drm_dbg_atomic(dev, "MST drm_dp_mst_atomic_check() failed: %pe\n", ERR_PTR(ret));
  			goto fail;
  		}
  		status = dc_validate_global_state(dc, dm_state->context, DC_VALIDATE_MODE_ONLY);
@@@ -13625,380 -7469,13 +7469,13 @@@ fail
  	else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
  		drm_dbg_atomic(dev, "Atomic check stopped due to signal.\n");
  	else
- 		drm_dbg_atomic(dev, "Atomic check failed with err: %d\n", ret);
+ 		drm_dbg_atomic(dev, "Atomic check failed: %pe\n", ERR_PTR(ret));
  
  	trace_amdgpu_dm_atomic_check_finish(state, ret);
  
  	return ret;
  }
  
- static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
- 		unsigned int offset,
- 		unsigned int total_length,
- 		u8 *data,
- 		unsigned int length,
- 		struct amdgpu_hdmi_vsdb_info *vsdb)
- {
- 	bool res;
- 	union dmub_rb_cmd cmd;
- 	struct dmub_cmd_send_edid_cea *input;
- 	struct dmub_cmd_edid_cea_output *output;
- 
- 	if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES)
- 		return false;
- 
- 	memset(&cmd, 0, sizeof(cmd));
- 
- 	input = &cmd.edid_cea.data.input;
- 
- 	cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA;
- 	cmd.edid_cea.header.sub_type = 0;
- 	cmd.edid_cea.header.payload_bytes =
- 		sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header);
- 	input->offset = offset;
- 	input->length = length;
- 	input->cea_total_length = total_length;
- 	memcpy(input->payload, data, length);
- 
- 	res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
- 	if (!res) {
- 		drm_err(adev_to_drm(dm->adev), "EDID CEA parser failed\n");
- 		return false;
- 	}
- 
- 	output = &cmd.edid_cea.data.output;
- 
- 	if (output->type == DMUB_CMD__EDID_CEA_ACK) {
- 		if (!output->ack.success) {
- 			drm_err(adev_to_drm(dm->adev), "EDID CEA ack failed at offset %d\n",
- 					output->ack.offset);
- 		}
- 	} else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) {
- 		if (!output->amd_vsdb.vsdb_found)
- 			return false;
- 
- 		vsdb->freesync_supported = output->amd_vsdb.freesync_supported;
- 		vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version;
- 		vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate;
- 		vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate;
- 		vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code;
- 	} else {
- 		drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n");
- 		return false;
- 	}
- 
- 	return true;
- }
- 
- static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
- 		u8 *edid_ext, int len,
- 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	int i;
- 
- 	/* send extension block to DMCU for parsing */
- 	for (i = 0; i < len; i += 8) {
- 		bool res;
- 		int offset;
- 
- 		/* send 8 bytes a time */
- 		if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8))
- 			return false;
- 
- 		if (i+8 == len) {
- 			/* EDID block sent completed, expect result */
- 			int version, min_rate, max_rate;
- 
- 			res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate);
- 			if (res) {
- 				/* amd vsdb found */
- 				vsdb_info->freesync_supported = 1;
- 				vsdb_info->amd_vsdb_version = version;
- 				vsdb_info->min_refresh_rate_hz = min_rate;
- 				vsdb_info->max_refresh_rate_hz = max_rate;
- 				/* Not enabled on DMCU*/
- 				vsdb_info->freesync_mccs_vcp_code = 0;
- 				return true;
- 			}
- 			/* not amd vsdb */
- 			return false;
- 		}
- 
- 		/* check for ack*/
- 		res = dc_edid_parser_recv_cea_ack(dm->dc, &offset);
- 		if (!res)
- 			return false;
- 	}
- 
- 	return false;
- }
- 
- static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
- 		u8 *edid_ext, int len,
- 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	int i;
- 
- 	/* send extension block to DMCU for parsing */
- 	for (i = 0; i < len; i += 8) {
- 		/* send 8 bytes a time */
- 		if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info))
- 			return false;
- 	}
- 
- 	return vsdb_info->freesync_supported;
- }
- 
- static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
- 		u8 *edid_ext, int len,
- 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
- 	bool ret;
- 
- 	mutex_lock(&adev->dm.dc_lock);
- 	if (adev->dm.dmub_srv)
- 		ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info);
- 	else
- 		ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info);
- 	mutex_unlock(&adev->dm.dc_lock);
- 	return ret;
- }
- 
- static void parse_edid_displayid_vrr(struct drm_connector *connector,
- 				     const struct edid *edid)
- {
- 	u8 *edid_ext = NULL;
- 	int i;
- 	int j = 0;
- 	u16 min_vfreq;
- 	u16 max_vfreq;
- 
- 	if (!edid || !edid->extensions)
- 		return;
- 
- 	/* Find DisplayID extension */
- 	for (i = 0; i < edid->extensions; i++) {
- 		edid_ext = (void *)(edid + (i + 1));
- 		if (edid_ext[0] == DISPLAYID_EXT)
- 			break;
- 	}
- 
- 	if (i == edid->extensions)
- 		return;
- 
- 	while (j < EDID_LENGTH) {
- 		/* Get dynamic video timing range from DisplayID if available */
- 		if (EDID_LENGTH - j > 13 && edid_ext[j] == 0x25	&&
- 		    (edid_ext[j+1] & 0xFE) == 0 && (edid_ext[j+2] == 9)) {
- 			min_vfreq = edid_ext[j+9];
- 			if (edid_ext[j+1] & 7)
- 				max_vfreq = edid_ext[j+10] + ((edid_ext[j+11] & 3) << 8);
- 			else
- 				max_vfreq = edid_ext[j+10];
- 
- 			if (max_vfreq && min_vfreq) {
- 				connector->display_info.monitor_range.max_vfreq = max_vfreq;
- 				connector->display_info.monitor_range.min_vfreq = min_vfreq;
- 
- 				return;
- 			}
- 		}
- 		j++;
- 	}
- }
- 
- static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
- 			struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	struct drm_connector *connector = &aconnector->base;
- 
- 	vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode;
- 	vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version;
- 
- 	return connector->display_info.amd_vsdb.version != 0;
- }
- 
- static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
- 			       const struct edid *edid,
- 			       struct amdgpu_hdmi_vsdb_info *vsdb_info)
- {
- 	u8 *edid_ext = NULL;
- 	int i;
- 	bool valid_vsdb_found = false;
- 
- 	/*----- drm_find_cea_extension() -----*/
- 	/* No EDID or EDID extensions */
- 	if (edid == NULL || edid->extensions == 0)
- 		return -ENODEV;
- 
- 	/* Find CEA extension */
- 	for (i = 0; i < edid->extensions; i++) {
- 		edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1);
- 		if (edid_ext[0] == CEA_EXT)
- 			break;
- 	}
- 
- 	if (i == edid->extensions)
- 		return -ENODEV;
- 
- 	/*----- cea_db_offsets() -----*/
- 	if (edid_ext[0] != CEA_EXT)
- 		return -ENODEV;
- 
- 	valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info);
- 
- 	return valid_vsdb_found ? i : -ENODEV;
- }
- 
- /**
-  * amdgpu_dm_update_freesync_caps - Update Freesync capabilities
-  *
-  * @connector: Connector to query.
-  * @drm_edid: DRM EDID from monitor
-  * @do_mccs: Controls whether MCCS (Monitor Control Command Set) over
-  *	      DDC (Display Data Channel) transactions are performed. When true,
-  *	      the driver queries the monitor to get or update additional FreeSync
-  *	      capability information. When false, these transactions are skipped.
-  *
-  * Amdgpu supports Freesync in DP and HDMI displays, and it is required to keep
-  * track of some of the display information in the internal data struct used by
-  * amdgpu_dm. This function checks which type of connector we need to set the
-  * FreeSync parameters.
-  */
- void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
- 				    const struct drm_edid *drm_edid, bool do_mccs)
- {
- 	int i = 0;
- 	struct amdgpu_dm_connector *amdgpu_dm_connector =
- 			to_amdgpu_dm_connector(connector);
- 	struct dm_connector_state *dm_con_state = NULL;
- 	struct dc_sink *sink;
- 	struct amdgpu_device *adev = drm_to_adev(connector->dev);
- 	struct amdgpu_hdmi_vsdb_info vsdb_info = {0};
- 	const struct edid *edid;
- 	bool freesync_capable = false;
- 	enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE;
- 
- 	if (!connector->state) {
- 		drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__);
- 		goto update;
- 	}
- 
- 	sink = amdgpu_dm_connector->dc_sink ?
- 		amdgpu_dm_connector->dc_sink :
- 		amdgpu_dm_connector->dc_em_sink;
- 
- 	drm_edid_connector_update(connector, drm_edid);
- 
- 	if (!drm_edid || !sink) {
- 		dm_con_state = to_dm_connector_state(connector->state);
- 
- 		amdgpu_dm_connector->min_vfreq = 0;
- 		amdgpu_dm_connector->max_vfreq = 0;
- 		freesync_capable = false;
- 
- 		goto update;
- 	}
- 
- 	dm_con_state = to_dm_connector_state(connector->state);
- 
- 	if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version))
- 		goto update;
- 
- 	edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw()
- 
- 	/* Some eDP panels only have the refresh rate range info in DisplayID */
- 	if ((connector->display_info.monitor_range.min_vfreq == 0 ||
- 	     connector->display_info.monitor_range.max_vfreq == 0))
- 		parse_edid_displayid_vrr(connector, edid);
- 
- 	if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
- 		     sink->sink_signal == SIGNAL_TYPE_EDP)) {
- 		if (amdgpu_dm_connector->dc_link &&
- 		    amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) {
- 			amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
- 			amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
- 			if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 				freesync_capable = true;
- 		}
- 
- 		get_amd_vsdb(amdgpu_dm_connector, &vsdb_info);
- 
- 		if (vsdb_info.replay_mode) {
- 			amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode;
- 			amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version;
- 			amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP;
- 		}
- 
- 	} else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) {
- 		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
- 		if (i >= 0) {
- 			amdgpu_dm_connector->vsdb_info = vsdb_info;
- 			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
- 
- 			if (vsdb_info.freesync_supported) {
- 				amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
- 				if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 					freesync_capable = true;
- 
- 				connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
- 			}
- 		}
- 	}
- 
- 	if (amdgpu_dm_connector->dc_link)
- 		as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link);
- 
- 	if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) {
- 		i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info);
- 		if (i >= 0) {
- 			amdgpu_dm_connector->vsdb_info = vsdb_info;
- 			sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code;
- 
- 			if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) {
- 				amdgpu_dm_connector->pack_sdp_v1_3 = true;
- 				amdgpu_dm_connector->as_type = as_type;
- 
- 				amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz;
- 				if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
- 					freesync_capable = true;
- 
- 				connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz;
- 				connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz;
- 			}
- 		}
- 	}
- 
- 	/* Handle MCCS */
- 	if (do_mccs) {
- 		dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
- 
- 		if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported)
- 			freesync_capable = false;
- 
- 		if (sink->mccs_caps.freesync_supported && freesync_capable)
- 			dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink);
- 	}
- 
- update:
- 	if (dm_con_state)
- 		dm_con_state->freesync_capable = freesync_capable;
- 
- 	if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable &&
- 	    amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) {
- 		amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false;
- 		amdgpu_dm_connector->dc_link->replay_settings.replay_feature_enabled = false;
- 	}
- 
- 	if (connector->vrr_capable_property)
- 		drm_connector_set_vrr_capable_property(connector,
- 						       freesync_capable);
- }
- 
  void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
  {
  	struct amdgpu_device *adev = drm_to_adev(dev);
@@@ -14018,12 -7495,6 +7495,6 @@@
  	mutex_unlock(&adev->dm.dc_lock);
  }
  
- static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
- {
- 	if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter)
- 		dc_exit_ips_for_hw_access(dc);
- }
- 
  void dm_write_reg_func(const struct dc_context *ctx, uint32_t address,
  		       u32 value, const char *func_name)
  {
@@@ -14052,13 -7523,6 +7523,6 @@@ uint32_t dm_read_reg_func(const struct 
  	}
  #endif
  
- 	if (ctx->dmub_srv &&
- 	    ctx->dmub_srv->reg_helper_offload.gather_in_progress &&
- 	    !ctx->dmub_srv->reg_helper_offload.should_burst_write) {
- 		ASSERT(false);
- 		return 0;
- 	}
- 
  	amdgpu_dm_exit_ips_for_hw_access(ctx->dc);
  
  	value = cgs_read_register(ctx->cgs_device, address);
@@@ -14068,179 -7532,6 +7532,6 @@@
  	return value;
  }
  
- int amdgpu_dm_process_dmub_aux_transfer_sync(
- 		struct dc_context *ctx,
- 		unsigned int link_index,
- 		struct aux_payload *payload,
- 		enum aux_return_code_type *operation_result)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 	struct dmub_notification *p_notify = adev->dm.dmub_notify;
- 	int ret = -1;
- 
- 	mutex_lock(&adev->dm.dpia_aux_lock);
- 	if (!dc_process_dmub_aux_transfer_async(ctx->dc, link_index, payload)) {
- 		*operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE;
- 		goto out;
- 	}
- 
- 	if (!wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
- 		drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!");
- 		*operation_result = AUX_RET_ERROR_TIMEOUT;
- 		goto out;
- 	}
- 
- 	if (p_notify->result != AUX_RET_SUCCESS) {
- 		/*
- 		 * Transient states before tunneling is enabled could
- 		 * lead to this error. We can ignore this for now.
- 		 */
- 		if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) {
- 			drm_warn(adev_to_drm(adev), "DPIA AUX failed on 0x%x(%d), error %d\n",
- 					payload->address, payload->length,
- 					p_notify->result);
- 		}
- 		*operation_result = p_notify->result;
- 		goto out;
- 	}
- 
- 	payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF;
- 	if (adev->dm.dmub_notify->aux_reply.command & 0xF0)
- 		/* The reply is stored in the top nibble of the command. */
- 		payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF;
- 
- 	/*write req may receive a byte indicating partially written number as well*/
- 	if (p_notify->aux_reply.length)
- 		memcpy(payload->data, p_notify->aux_reply.data,
- 				p_notify->aux_reply.length);
- 
- 	/* success */
- 	ret = p_notify->aux_reply.length;
- 	*operation_result = p_notify->result;
- out:
- 	reinit_completion(&adev->dm.dmub_aux_transfer_done);
- 	mutex_unlock(&adev->dm.dpia_aux_lock);
- 	return ret;
- }
- 
- static void abort_fused_io(
- 		struct dc_context *ctx,
- 		const struct dmub_cmd_fused_request *request
- )
- {
- 	union dmub_rb_cmd command = { 0 };
- 	struct dmub_rb_cmd_fused_io *io = &command.fused_io;
- 
- 	io->header.type = DMUB_CMD__FUSED_IO;
- 	io->header.sub_type = DMUB_CMD__FUSED_IO_ABORT;
- 	io->header.payload_bytes = sizeof(*io) - sizeof(io->header);
- 	io->request = *request;
- 	dm_execute_dmub_cmd(ctx, &command, DM_DMUB_WAIT_TYPE_NO_WAIT);
- }
- 
- static bool execute_fused_io(
- 		struct amdgpu_device *dev,
- 		struct dc_context *ctx,
- 		union dmub_rb_cmd *commands,
- 		uint8_t count,
- 		uint32_t timeout_us
- )
- {
- 	const uint8_t ddc_line = commands[0].fused_io.request.u.aux.ddc_line;
- 
- 	if (ddc_line >= ARRAY_SIZE(dev->dm.fused_io))
- 		return false;
- 
- 	struct fused_io_sync *sync = &dev->dm.fused_io[ddc_line];
- 	struct dmub_rb_cmd_fused_io *first = &commands[0].fused_io;
- 	const bool result = dm_execute_dmub_cmd_list(ctx, count, commands, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
- 			&& first->header.ret_status
- 			&& first->request.status == FUSED_REQUEST_STATUS_SUCCESS;
- 
- 	if (!result)
- 		return false;
- 
- 	while (wait_for_completion_timeout(&sync->replied, usecs_to_jiffies(timeout_us))) {
- 		reinit_completion(&sync->replied);
- 
- 		struct dmub_cmd_fused_request *reply = (struct dmub_cmd_fused_request *) sync->reply_data;
- 
- 		static_assert(sizeof(*reply) <= sizeof(sync->reply_data), "Size mismatch");
- 
- 		if (reply->identifier == first->request.identifier) {
- 			first->request = *reply;
- 			return true;
- 		}
- 	}
- 
- 	reinit_completion(&sync->replied);
- 	first->request.status = FUSED_REQUEST_STATUS_TIMEOUT;
- 	abort_fused_io(ctx, &first->request);
- 	return false;
- }
- 
- bool amdgpu_dm_execute_fused_io(
- 		struct amdgpu_device *dev,
- 		struct dc_link *link,
- 		union dmub_rb_cmd *commands,
- 		uint8_t count,
- 		uint32_t timeout_us)
- {
- 	struct amdgpu_display_manager *dm = &dev->dm;
- 
- 	mutex_lock(&dm->dpia_aux_lock);
- 
- 	const bool result = execute_fused_io(dev, link->ctx, commands, count, timeout_us);
- 
- 	mutex_unlock(&dm->dpia_aux_lock);
- 	return result;
- }
- 
- int amdgpu_dm_process_dmub_set_config_sync(
- 		struct dc_context *ctx,
- 		unsigned int link_index,
- 		struct set_config_cmd_payload *payload,
- 		enum set_config_status *operation_result)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 	bool is_cmd_complete;
- 	int ret;
- 
- 	mutex_lock(&adev->dm.dpia_aux_lock);
- 	is_cmd_complete = dc_process_dmub_set_config_async(ctx->dc,
- 			link_index, payload, adev->dm.dmub_notify);
- 
- 	if (is_cmd_complete || wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) {
- 		ret = 0;
- 		*operation_result = adev->dm.dmub_notify->sc_status;
- 	} else {
- 		drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!");
- 		ret = -1;
- 		*operation_result = SET_CONFIG_UNKNOWN_ERROR;
- 	}
- 
- 	if (!is_cmd_complete)
- 		reinit_completion(&adev->dm.dmub_aux_transfer_done);
- 	mutex_unlock(&adev->dm.dpia_aux_lock);
- 	return ret;
- }
- 
- bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 
- 	guard(spinlock_irqsave)(&adev->dm.dmub_lock);
- 	return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type);
- }
- 
- bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
- {
- 	struct amdgpu_device *adev = ctx->driver_context;
- 
- 	guard(spinlock_irqsave)(&adev->dm.dmub_lock);
- 	return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type);
- }
- 
  void dm_acpi_process_phy_transition_interlock(
  	const struct dc_context *ctx,
  	struct dm_process_phy_transition_init_params process_phy_transition_init_params)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the drm tree with the drm-fixes tree
From: Mark Brown @ 2026-07-17 14:40 UTC (permalink / raw)
  To: Dave Airlie, DRI
  Cc: Alex Deucher, Chenyu Chen, Dmytro Laktyushkin, Gabe Teeger,
	George Zhang, Linux Kernel Mailing List, Linux Next Mailing List,
	Matthew Stewart, Peichen Huang, Pengpeng Hou

[-- Attachment #1: Type: text/plain, Size: 6755 bytes --]

Hi all,

Today's linux-next merge of the drm tree got a conflict in:

  drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c

between commits:

  6351003b1f4ec ("drm/amd/display: wire DCN42B mcache programming callback")
  57cf172be2827 ("drm/amd/display: fix dcn42b det allocation order")
  c4bc7ffb91586 ("drm/amd/display: Fix DCN42B null registers & register masks")

from the drm-fixes tree and commits:

  85453fb4ff726 ("drm/amd/display: wire DCN42B mcache programming callback")
  183bbded999a7 ("drm/amd/display: fix dcn42b det allocation order")
  fd651b9a3be9e ("drm/amd/display: Add DCN42B VID_CRC_CONTROL and HBLANK_CONTROL registers")
  219fb1f4c5b91 ("drm/amd/display: Enable zstate support and fix seamless boot")
  b7d69145907cd ("drm/amd/display: Fix DCN42B null registers & register masks")
  6cefc59d36667 ("drm/amd/display: Enable IPS support for DCN4 Variant")
  329baa1c5f62b ("drm/amd/display: Enable PSR and Replay on DCN4 variant [Part 2]")
  e14fcf9e5d2b5 ("drm/amd/display: correct encoder minimal creation")
  d2184b1ba1be2 ("drm/amd/display: Enable pstate for DCN4 non-emulation builds")

from the drm tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index 94e166c0a9b0b,2334bc5b75b8f..0000000000000
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@@ -134,6 -134,19 +134,6 @@@
  #define regHUBP3_HUBPREQ_DEBUG                0x088d
  #define regHUBP3_HUBPREQ_DEBUG_BASE_IDX       2
  
 -#define regDP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL                                                   0x3687
 -#define regDP_SYM32_ENC0_DP_SYM32_ENC_VID_CRC_CONTROL_BASE_IDX                                          2
 -#define regDP_SYM32_ENC1_DP_SYM32_ENC_VID_CRC_CONTROL                                                   0x375b
 -#define regDP_SYM32_ENC1_DP_SYM32_ENC_VID_CRC_CONTROL_BASE_IDX                                          2
 -#define regDP_SYM32_ENC2_DP_SYM32_ENC_VID_CRC_CONTROL                                                   0x382f
 -#define regDP_SYM32_ENC2_DP_SYM32_ENC_VID_CRC_CONTROL_BASE_IDX                                          2
 -#define regDP_SYM32_ENC0_DP_SYM32_ENC_HBLANK_CONTROL                                                    0x366b
 -#define regDP_SYM32_ENC0_DP_SYM32_ENC_HBLANK_CONTROL_BASE_IDX                                           2
 -#define regDP_SYM32_ENC1_DP_SYM32_ENC_HBLANK_CONTROL                                                    0x373f
 -#define regDP_SYM32_ENC1_DP_SYM32_ENC_HBLANK_CONTROL_BASE_IDX                                           2
 -#define regDP_SYM32_ENC2_DP_SYM32_ENC_HBLANK_CONTROL                                                    0x3813
 -#define regDP_SYM32_ENC2_DP_SYM32_ENC_HBLANK_CONTROL_BASE_IDX                                           2
 -
  enum dcn401_clk_src_array_id {
  	DCN401_CLK_SRC_PLL0,
  	DCN401_CLK_SRC_PLL1,
@@@ -253,10 -266,10 +253,10 @@@ static struct bios_registers bios_regs
  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_2(__SHIFT)
+ 	CS_COMMON_MASK_SH_LIST_DCN4_0_1(__SHIFT)
  };
  static const struct dce110_clk_src_mask cs_mask = {
- 	CS_COMMON_MASK_SH_LIST_DCN3_2(_MASK)
+ 	CS_COMMON_MASK_SH_LIST_DCN4_0_1(_MASK)
  };
  #define abm_regs_init(id) \
  	ABM_DCN42B_REG_LIST_RI(id)
@@@ -351,7 -364,7 +351,7 @@@ static const struct dcn10_link_enc_mas
  	LINK_ENCODER_MASK_SH_LIST_DCN42B(_MASK)};
  
  #define hpo_dp_stream_encoder_reg_init(id) \
- 	DCN42B_HPO_DP_STREAM_ENC_REG_LIST_RI(id)
+ 	DCN42_HPO_DP_STREAM_ENC_REG_LIST_RI(id)
  
  static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4];
  
@@@ -775,7 -788,7 +775,7 @@@ static const struct dc_debug_options de
  	.underflow_assert_delay_us = 0xFFFFFFFF,
  	.dwb_fi_phase = -1, // -1 = disable,
  	.dmub_command_table = true,
- 	.pstate_enabled = false,
+ 	.pstate_enabled = true,
  	.enable_mem_low_power = {
  		.bits = {
  			.vga = false,
@@@ -801,7 -814,7 +801,7 @@@
  		}
  	},
  	.seamless_boot_odm_combine = DML_FAIL_SOURCE_PIXEL_FORMAT,
- 	.enable_z9_disable_interface = false, /* Allow support for the PMFW interface for disable Z9*/
+ 	.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,
@@@ -823,7 -836,7 +823,7 @@@
  	.disable_timeout = true,
  	.min_disp_clk_khz = 50000,
  	.static_screen_wait_frames = 2,
- 	.disable_z10 = true,
+ 	.disable_z10 = false,
  	.ignore_pg = true,
  	.disable_stutter_for_wm_program = true,
  	.min_deep_sleep_dcfclk_khz = 8000,
@@@ -1034,9 -1047,9 +1034,9 @@@ static struct hubp *dcn42b_hubp_create
  }
  static const struct dc_panel_config dcn42b_panel_config_defaults = {
  	.psr = {
- 		.disable_psr = true,
+ 		.disable_psr = false,
  		.disallow_psrsu = true,
- 		.disallow_replay = true,
+ 		.disallow_replay = false,
  	},
  	.ilr = {
  		.optimize_edp_link_rate = true,
@@@ -1842,7 -1855,7 +1842,7 @@@ static struct link_encoder *dcn42b_link
  {
  	struct dcn20_link_encoder *enc20;
  
- 	if ((unsigned int)(eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc)
+ 	if ((unsigned int)(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);
@@@ -1854,6 -1867,8 +1854,8 @@@
  			ctx,
  			&link_enc_feature,
  			&link_enc_regs[eng_id - ENGINE_ID_DIGA],
+ 			&le_shift,
+ 			&le_mask,
  			eng_id);
  
  	return &enc20->enc10.base;
@@@ -2002,11 -2017,10 +2004,10 @@@ static bool dcn42b_resource_construct
  	dc->caps.dmcub_support = true;
  	dc->caps.is_apu = true;
  	dc->caps.seamless_odm = true;
- 	dc->caps.zstate_support = false;
- 	dc->caps.ips_support = false;
+ 	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->config.disable_ips = DMUB_IPS_DISABLE_ALL;
  
  	/* Color pipeline capabilities */
  	dc->caps.color.dpp.dcn_arch = 1;

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: manual merge of the bluetooth tree with the origin tree
From: Mark Brown @ 2026-07-17 14:37 UTC (permalink / raw)
  To: Marcel Holtmann, Johan Hedberg
  Cc: Kiran K, Linux Kernel Mailing List, Linux Next Mailing List,
	Luiz Augusto von Dentz

[-- Attachment #1: Type: text/plain, Size: 17803 bytes --]

Hi all,

Today's linux-next merge of the bluetooth tree got a conflict in:

  drivers/bluetooth/btintel_pcie.c

between commit:

  9c36951474d8e ("Bluetooth: btintel_pcie: Refactor FLR to use device_reprobe()")

from the origin tree and commit:

  603b91aeb20a2 ("Bluetooth: btintel_pcie: Refactor FLR to use device_reprobe()")
  ca75417ab1793 ("Bluetooth: btintel_pcie: split coredump worker into per-trigger works")

from the bluetooth tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --combined drivers/bluetooth/btintel_pcie.c
index 2b7231be5973d,2e28847263ab0..0000000000000
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@@ -1446,72 -1446,134 +1446,134 @@@ exit_on_error
  	return err;
  }
  
+ /* Queue a coredump dump_traces() pass.
+  *
+  * Returns true if a new coredump was queued, false if one was already
+  * in-flight (the BTINTEL_PCIE_COREDUMP_INPROGRESS bit serves as the
+  * single-writer guard for the @coredump_work item) or the workqueue is
+  * disabled (reset / remove in progress).
+  *
+  * Always queue this AFTER any companion event-reader work (hwexp /
+  * fwtrigger) so that, on the ordered @dump_workqueue, the event reader
+  * runs first and populates dmp_hdr.event_type / event_id before
+  * dump_traces consumes them.
+  */
+ static bool btintel_pcie_queue_coredump(struct btintel_pcie_data *data,
+ 					u16 trigger_reason)
+ {
+ 	if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
+ 		return false;
+ 
+ 	data->dmp_hdr.trigger_reason = trigger_reason;
+ 
+ 	if (queue_work(data->dump_workqueue, &data->coredump_work))
+ 		return true;
+ 
+ 	/* Workqueue is disabled (reset/remove drained it). Release the
+ 	 * guard so a later trigger, after re-probe, can succeed.
+ 	 */
+ 	clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+ 	return false;
+ }
+ 
  static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data)
  {
  	bt_dev_dbg(data->hdev, "Received firmware smart trigger cause");
  
- 	if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags))
+ 	/* Per-work guard: deduplicate concurrent FW-trigger interrupts.
+ 	 * Cleared at the tail of btintel_pcie_fwtrigger_worker().
+ 	 */
+ 	if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
+ 			     &data->flags))
  		return;
  
- 	/* Trigger device core dump when there is FW assert */
- 	if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
- 		data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
+ 	if (!queue_work(data->dump_workqueue, &data->fwtrigger_work)) {
+ 		clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
+ 		return;
+ 	}
  
- 	queue_work(data->coredump_workqueue, &data->coredump_work);
+ 	/* Queue coredump after the fwtrigger event reader so dmp_hdr.event_*
+ 	 * is populated before dump_traces consumes it.
+ 	 */
+ 	btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
  }
  
  static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data)
  {
  	bt_dev_err(data->hdev, "Received hw exception interrupt");
  
+ 	/* CORE_HALTED is the single-writer guard for this handler. It is
+ 	 * set once on first HW exception and cleared only by re-probe
+ 	 * (data is reallocated), so it also serializes hwexp_work
+ 	 * scheduling without needing a separate bit.
+ 	 */
  	if (test_and_set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags))
  		return;
  
- 	if (test_and_set_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags))
- 		return;
+ 	/* Queue companion coredump first so it is appended after hwexp_work
+ 	 * on the ordered @dump_workqueue (preserves the original
+ 	 * coredump-then-hwexp ordering).
+ 	 */
+ 	btintel_pcie_queue_coredump(data, BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
  
- 	/* Trigger device core dump when there is HW  exception */
- 	if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
- 		data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
- 
- 	queue_work(data->coredump_workqueue, &data->coredump_work);
+ 	queue_work(data->dump_workqueue, &data->hwexp_work);
  }
  
  static void btintel_pcie_coredump_worker(struct work_struct *work)
  {
  	struct btintel_pcie_data *data = container_of(work,
  					struct btintel_pcie_data, coredump_work);
- 	int err;
  
  	/* hdev is NULL until setup_hdev() succeeds, and is cleared on
  	 * teardown after disable_work_sync() drains us; bail in that case.
  	 */
+ 	if (!data->hdev)
+ 		goto out;
+ 
+ 	btintel_pcie_dump_traces(data->hdev);
+ out:
+ 	/* Release guard last so a new trigger can run only after this
+ 	 * pass has fully completed (including dev_coredumpv()).
+ 	 */
+ 	clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+ }
+ 
+ static void btintel_pcie_hwexp_worker(struct work_struct *work)
+ {
+ 	struct btintel_pcie_data *data = container_of(work,
+ 					struct btintel_pcie_data, hwexp_work);
+ 
  	if (!data->hdev)
  		return;
  
- 	if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) {
- 		err = btintel_pcie_dump_fwtrigger_event(data);
- 		if (err)
- 			bt_dev_warn(data->hdev, "failed to log fwtrigger event");
- 		clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
- 	}
+ 	/* Unlike usb products, controller will not send hardware exception
+ 	 * event on exception. Instead controller writes the hardware event
+ 	 * to device memory along with optional debug events, raises MSIX
+ 	 * and halts. Driver shall read the exception event from device
+ 	 * memory and passes it to the stack for further processing.
+ 	 *
+ 	 * Re-entry is gated by BTINTEL_PCIE_CORE_HALTED in the IRQ
+ 	 * handler, which is only cleared by re-probe; no per-work bit
+ 	 * is needed here.
+ 	 */
+ 	btintel_pcie_read_hwexp(data);
+ }
  
- 	if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
- 		btintel_pcie_dump_traces(data->hdev);
- 		clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
- 	}
+ static void btintel_pcie_fwtrigger_worker(struct work_struct *work)
+ {
+ 	struct btintel_pcie_data *data = container_of(work,
+ 					struct btintel_pcie_data, fwtrigger_work);
+ 	int err;
  
- 	if (test_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags)) {
- 		/* Unlike usb products, controller will not send hardware
- 		 * exception event on exception. Instead controller writes the
- 		 * hardware event to device memory along with optional debug
- 		 * events, raises MSIX and halts. Driver shall read the
- 		 * exception event from device memory and passes it stack for
- 		 * further processing.
- 		 */
- 		btintel_pcie_read_hwexp(data);
- 		clear_bit(BTINTEL_PCIE_HWEXP_INPROGRESS, &data->flags);
- 	}
+ 	if (!data->hdev)
+ 		goto out;
+ 
+ 	err = btintel_pcie_dump_fwtrigger_event(data);
+ 	if (err)
+ 		bt_dev_warn(data->hdev, "failed to log fwtrigger event");
+ out:
+ 	/* Release guard last; matches set in fw_trigger handler. */
+ 	clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
  }
  
  static void btintel_pcie_rx_work(struct work_struct *work)
@@@ -2488,8 -2550,6 +2550,6 @@@ static void btintel_pcie_inc_recovery_c
  	}
  }
  
- static void btintel_pcie_reset(struct hci_dev *hdev);
- 
  static int btintel_pcie_acpi_reset_method(struct btintel_pcie_data *data)
  {
  	union acpi_object *obj, argv4;
@@@ -2650,20 -2710,22 +2710,22 @@@ static void btintel_pcie_reset_work(str
  	btintel_pcie_synchronize_irqs(data);
  
  	flush_work(&data->rx_work);
- 	/* Drain any in-flight coredump and block new ones across reset.
- 	 * Safe from self-deadlock: coredump_work runs on a separate wq.
+ 	/* Drain any in-flight dump workers and block new ones across reset.
+ 	 * Safe from self-deadlock: they all run on a separate wq.
  	 */
  	disable_work_sync(&data->coredump_work);
+ 	disable_work_sync(&data->hwexp_work);
+ 	disable_work_sync(&data->fwtrigger_work);
  
  	bt_dev_dbg(data->hdev, "Release bluetooth interface");
  
  	/* Both reset paths follow the same contract: on success they
  	 * destroy 'data' via device_reprobe() (a fresh probe re-INIT_WORKs
- 	 * the coredump_work with disable count 0), so enable_work() must
+ 	 * the dump workers with disable count 0), so enable_work() must
  	 * NOT be called on the success path. Only the FLR path can fail
  	 * with 'data' still alive, in which case we balance the
- 	 * disable_work_sync() above so a later successful reset is not
- 	 * permanently blocked.
+ 	 * disable_work_sync() calls above so a later successful reset is
+ 	 * not permanently blocked.
  	 *
  	 * pci_lock_rescan_remove() (held above) serializes against PCI
  	 * device addition/removal (hotplug), so no device can be added to
@@@ -2674,64 -2736,97 +2736,97 @@@
  		goto out;
  	}
  
- 	if (btintel_pcie_perform_flr(data))
+ 	if (btintel_pcie_perform_flr(data)) {
  		enable_work(&data->coredump_work);
+ 		enable_work(&data->hwexp_work);
+ 		enable_work(&data->fwtrigger_work);
+ 	}
  
  out:
  	pci_dev_put(pdev);
  	pci_unlock_rescan_remove();
  }
  
- static void btintel_pcie_reset(struct hci_dev *hdev)
+ /* Schedule a device reset of the requested type.
+  *
+  * BTINTEL_PCIE_RECOVERY_IN_PROGRESS serializes all reset requesters
+  * (sysfs reset attribute, hci_cmd_timeout(), hw_error, resume error
+  * path, etc.) so that:
+  *
+  *   - dev_data->reset_type is written by exactly one caller (the
+  *     thread that wins test_and_set_bit), eliminating the race where
+  *     a second hw_error could clobber an already-scheduled reset's
+  *     type;
+  *   - the write happens AFTER the bit is set, so reset_work observes
+  *     it through schedule_work()'s memory ordering;
+  *   - losers return without touching reset_type or scheduling the
+  *     work, so concurrent triggers are silently coalesced into the
+  *     in-flight one (whose recovery will reinitialize the device
+  *     regardless of the dropped trigger's variant).
+  *
+  * The bit is cleared only by .remove() / re-probe via fresh devm
+  * allocation, which is the intended one-shot semantics: a reset
+  * tears down and re-probes 'data', so there is no "in-flight"
+  * reset to follow up after device_reprobe() succeeds.
+  */
+ static void btintel_pcie_request_reset(struct btintel_pcie_data *data,
+ 				       enum btintel_pcie_reset_type type)
  {
- 	struct btintel_pcie_data *data;
- 
- 	data = hci_get_drvdata(hdev);
- 
  	if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags))
  		return;
  
  	if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
  		return;
  
+ 	data->reset_type = type;
+ 
  	pci_dev_get(data->pdev);
  	schedule_work(&data->reset_work);
  }
  
+ static void btintel_pcie_hci_reset(struct hci_dev *hdev)
+ {
+ 	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+ 
+ 	btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
+ }
+ 
  static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code)
  {
- 	struct btintel_pcie_dev_recovery *data;
+ 	struct btintel_pcie_dev_recovery *rec;
  	struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev);
  	struct pci_dev *pdev = dev_data->pdev;
+ 	enum btintel_pcie_reset_type type;
  	time64_t retry_window;
  
+ 	if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &dev_data->flags))
+ 		return;
+ 
  	btintel_pcie_dump_debug_registers(hdev);
  
- 	data = btintel_pcie_get_recovery(pdev, &hdev->dev);
- 	if (!data)
+ 	rec = btintel_pcie_get_recovery(pdev, &hdev->dev);
+ 	if (!rec)
  		return;
  
- 	if (code == 0x13)
- 		dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_PLDR;
- 	else
- 		dev_data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
+ 	type = (code == 0x13) ? BTINTEL_PCIE_IOSF_PRR_PLDR
+ 			      : BTINTEL_PCIE_IOSF_PRR_FLR;
  
  	bt_dev_err(hdev, "Encountered exception err:0x%x triggering: %s", code,
- 		   dev_data->reset_type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
- 	retry_window = ktime_get_boottime_seconds() - data->last_error;
+ 		   type == BTINTEL_PCIE_IOSF_PRR_PLDR ? "PLDR" : "FLR");
+ 	retry_window = ktime_get_boottime_seconds() - rec->last_error;
  
  	if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
- 	    data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
+ 	    rec->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
  		bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d",
- 			   BTINTEL_PCIE_FLR_MAX_RETRY, data->count);
+ 			   BTINTEL_PCIE_FLR_MAX_RETRY, rec->count);
  		bt_dev_dbg(hdev, "Boot time: %lld seconds",
  			   ktime_get_boottime_seconds());
  		bt_dev_dbg(hdev, "last error at: %lld seconds",
- 			   data->last_error);
+ 			   rec->last_error);
  		return;
  	}
  	btintel_pcie_inc_recovery_count(pdev, &hdev->dev);
- 	btintel_pcie_reset(hdev);
+ 	btintel_pcie_request_reset(dev_data, type);
  }
  
  static bool btintel_pcie_wakeup(struct hci_dev *hdev)
@@@ -2821,7 -2916,7 +2916,7 @@@ static int btintel_pcie_setup_hdev(stru
  	hdev->hw_error = btintel_pcie_hw_error;
  	hdev->set_diag = btintel_set_diag;
  	hdev->set_bdaddr = btintel_set_bdaddr;
- 	hdev->reset = btintel_pcie_reset;
+ 	hdev->reset = btintel_pcie_hci_reset;
  	hdev->wakeup = btintel_pcie_wakeup;
  	hdev->hci_drv = &btintel_pcie_hci_drv;
  
@@@ -2869,8 -2964,8 +2964,8 @@@ static int btintel_pcie_probe(struct pc
  	if (!data->workqueue)
  		return -ENOMEM;
  
- 	data->coredump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
- 	if (!data->coredump_workqueue) {
+ 	data->dump_workqueue = alloc_ordered_workqueue(KBUILD_MODNAME "_cd", 0);
+ 	if (!data->dump_workqueue) {
  		destroy_workqueue(data->workqueue);
  		return -ENOMEM;
  	}
@@@ -2879,6 -2974,8 +2974,8 @@@
  	INIT_WORK(&data->rx_work, btintel_pcie_rx_work);
  	INIT_WORK(&data->reset_work, btintel_pcie_reset_work);
  	INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker);
+ 	INIT_WORK(&data->hwexp_work, btintel_pcie_hwexp_worker);
+ 	INIT_WORK(&data->fwtrigger_work, btintel_pcie_fwtrigger_worker);
  
  	data->boot_stage_cache = 0x00;
  	data->img_resp_cache = 0x00;
@@@ -2921,7 -3018,7 +3018,7 @@@ exit_error
  	/* reset device before exit */
  	btintel_pcie_reset_bt(data);
  
- 	destroy_workqueue(data->coredump_workqueue);
+ 	destroy_workqueue(data->dump_workqueue);
  
  	pci_clear_master(pdev);
  
@@@ -2940,12 -3037,14 +3037,14 @@@ static void btintel_pcie_remove(struct 
  		return;
  	}
  
- 	/* Permanently block coredump triggers and drain the worker before
- 	 * tearing down. Must run before cancel_work_sync(&reset_work) so
- 	 * the disable counter stays >= 1 even after reset_work()'s
+ 	/* Permanently block all dump triggers and drain the workers before
+ 	 * tearing down. Must run before disable_work_sync(&reset_work) so
+ 	 * the disable counters stay >= 1 even after reset_work()'s
  	 * balanced enable_work() (counter 2 -> 1, never reaching 0).
  	 */
  	disable_work_sync(&data->coredump_work);
+ 	disable_work_sync(&data->hwexp_work);
+ 	disable_work_sync(&data->fwtrigger_work);
  
  	/* Cancel pending reset work. Skip only when remove() is called from
  	 * within the reset work itself (PLDR device_reprobe path) to avoid
@@@ -2973,7 -3072,7 +3072,7 @@@
  
  	btintel_pcie_release_hdev(data);
  
- 	destroy_workqueue(data->coredump_workqueue);
+ 	destroy_workqueue(data->dump_workqueue);
  	destroy_workqueue(data->workqueue);
  
  	btintel_pcie_free(data);
@@@ -2992,16 -3091,8 +3091,8 @@@ static void btintel_pcie_coredump(struc
  	if (!data)
  		return;
  
- 	if (test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
- 		return;
- 
- 	data->dmp_hdr.trigger_reason  = BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER;
- 	/* queue_work() returns false if the work is disabled (reset or
- 	 * remove in progress); clear the in-progress bit so a later
- 	 * trigger can succeed once the work is re-enabled.
- 	 */
- 	if (!queue_work(data->coredump_workqueue, &data->coredump_work))
- 		clear_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags);
+ 	btintel_pcie_queue_coredump(data,
+ 				    BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER);
  }
  #endif
  
@@@ -3113,8 -3204,7 +3204,7 @@@ static int btintel_pcie_resume(struct d
  	if (data->pm_sx_event == PM_EVENT_FREEZE ||
  	    data->pm_sx_event == PM_EVENT_HIBERNATE) {
  		set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
- 		data->reset_type = BTINTEL_PCIE_IOSF_PRR_FLR;
- 		btintel_pcie_reset(data->hdev);
+ 		btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
  		return 0;
  	}
  
@@@ -3138,14 -3228,10 +3228,10 @@@
  	if (btintel_pcie_in_error(data) ||
  			btintel_pcie_in_device_halt(data)) {
  		bt_dev_err(data->hdev, "Controller in error state for D0 entry");
- 		if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS,
- 				      &data->flags)) {
- 			data->dmp_hdr.trigger_reason =
- 				BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
- 			queue_work(data->coredump_workqueue, &data->coredump_work);
- 		}
+ 		btintel_pcie_queue_coredump(data,
+ 					    BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT);
  		set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
- 		btintel_pcie_reset(data->hdev);
+ 		btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
  	}
  	return err;
  }

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: linux-next: build failure in the final build
From: Greg Kroah-Hartman @ 2026-07-17 14:35 UTC (permalink / raw)
  To: Manuel Ebner
  Cc: Mark Brown, Johan Hovold, Linux Kernel Mailing List,
	Linux Next Mailing List
In-Reply-To: <c2fe4a81c639cddb65116d9b3526e82206927c0d.camel@mailbox.org>

On Fri, Jul 17, 2026 at 03:47:55PM +0200, Manuel Ebner wrote:
> Hi Mark, 
> 
> On Wed, 2026-07-15 at 16:37 +0100, Mark Brown wrote:
> > On Mon, Jul 13, 2026 at 06:48:32PM +0100, Mark Brown wrote:
> > > Hi all,
> > > 
> > > In the final builds, today's linux-next build (arm64 allyesconfig)
> > > failed like this:
> > 
> > This error is due to a71f5aef1be98 (USB: gadget: fsl-udc: enable compile
> > testing) from the usb tree, a dependency change as expected.  I'll do
> > something about this tomorrow.
> 
> I stumbled across the same build errors. Are you still on this?

Should I revert that commit to resolve this?

thanks,

greg k-h

^ permalink raw reply

* linux-next: duplicate patch in the bluetooth tree
From: Mark Brown @ 2026-07-17 14:28 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, Marcel Holtmann, Johan Hedberg
  Cc: Linux Kernel Mailing List, Linux Next Mailing List

[-- Attachment #1: Type: text/plain, Size: 188 bytes --]

Hi all,

The following commit is also in Linus Torvalds' tree as a different commit
(but the same patch):

   603b91aeb20a2 (Bluetooth: btintel_pcie: Refactor FLR to use device_reprobe())

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Re: linux-next: build failure after merge of the qcom tree
From: Konrad Dybcio @ 2026-07-17 14:03 UTC (permalink / raw)
  To: Mark Brown, Konrad Dybcio, Bjorn Andersson, Andy Gross,
	Wangao Wang, Dikshita Agarwal, Dmitry Baryshkov
  Cc: Linux Kernel Mailing List, Linux Next Mailing List
In-Reply-To: <aloumm-rrofkrmxT@sirena.org.uk>

On 7/17/26 3:31 PM, Mark Brown wrote:
> Hi all,
> 
> After merging the qcom tree, today's linux-next build (arm64 defconfig)
> failed like this:
> 
> Lexical error: /tmp/next/build/arch/arm64/boot/dts/qcom/purwa.dtsi:169.14-35 Unexpected 'VIDEO_CC_MVS0_BSE_CLK' 
> 
> Caused by commit
> 
>   43899c55d79ba (arm64: dts: qcom: purwa: Override Iris clocks and operating points)
> 
> possibly interacting with something else that changes implicit includes
> or something.  I have used the tree from next-20260716 instead.

Rebase mess. for-next is missing:

+#include <dt-bindings/clock/qcom,x1p42100-videocc.h> in purwa.dtsi

which was previously mistakengly squashed into:

	arm64: dts: qcom: x1e80100: Add CAMCC block definition

which added the nodes for *CAM*CC..

Konrad

^ permalink raw reply

* Re: linux-next: build failure in the final build
From: Manuel Ebner @ 2026-07-17 13:47 UTC (permalink / raw)
  To: Mark Brown, Greg Kroah-Hartman, Johan Hovold
  Cc: Linux Kernel Mailing List, Linux Next Mailing List
In-Reply-To: <4f9f5ff9-8eaa-4bd5-9331-37119f78e13f@sirena.org.uk>

Hi Mark, 

On Wed, 2026-07-15 at 16:37 +0100, Mark Brown wrote:
> On Mon, Jul 13, 2026 at 06:48:32PM +0100, Mark Brown wrote:
> > Hi all,
> > 
> > In the final builds, today's linux-next build (arm64 allyesconfig)
> > failed like this:
> 
> This error is due to a71f5aef1be98 (USB: gadget: fsl-udc: enable compile
> testing) from the usb tree, a dependency change as expected.  I'll do
> something about this tomorrow.

I stumbled across the same build errors. Are you still on this?

best regarsds
 Manuel Ebner

> 
> > 
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:105:5: error: no previous
> > prototype for 'write_ulpi' [-Werror=missing-prototypes]
> >   105 | int write_ulpi(u8 addr, u8 data)
> >       |     ^~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:118:6: error: no previous
> > prototype for 'fsl_otg_chrg_vbus' [-Werror=missing-prototypes]
> >   118 | void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)
> >       |      ^~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:136:6: error: no previous
> > prototype for 'fsl_otg_dischrg_vbus' [-Werror=missing-prototypes]
> >   136 | void fsl_otg_dischrg_vbus(int on)
> >       |      ^~~~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:154:6: error: no previous
> > prototype for 'fsl_otg_drv_vbus' [-Werror=missing-prototypes]
> >   154 | void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)
> >       |      ^~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:172:6: error: no previous
> > prototype for 'fsl_otg_loc_conn' [-Werror=missing-prototypes]
> >   172 | void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)
> >       |      ^~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:191:6: error: no previous
> > prototype for 'fsl_otg_loc_sof' [-Werror=missing-prototypes]
> >   191 | void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)
> >       |      ^~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:206:6: error: no previous
> > prototype for 'fsl_otg_start_pulse' [-Werror=missing-prototypes]
> >   206 | void fsl_otg_start_pulse(struct otg_fsm *fsm)
> >       |      ^~~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:222:6: error: no previous
> > prototype for 'b_data_pulse_end' [-Werror=missing-prototypes]
> >   222 | void b_data_pulse_end(unsigned long foo)
> >       |      ^~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:241:6: error: no previous
> > prototype for 'b_vbus_pulse_end' [-Werror=missing-prototypes]
> >   241 | void b_vbus_pulse_end(unsigned long foo)
> >       |      ^~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:254:6: error: no previous
> > prototype for 'b_srp_end' [-Werror=missing-prototypes]
> >   254 | void b_srp_end(unsigned long foo)
> >       |      ^~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:269:6: error: no previous
> > prototype for 'a_wait_enum' [-Werror=missing-prototypes]
> >   269 | void a_wait_enum(unsigned long foo)
> >       |      ^~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:279:6: error: no previous
> > prototype for 'set_tmout' [-Werror=missing-prototypes]
> >   279 | void set_tmout(unsigned long indicator)
> >       |      ^~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:285:5: error: no previous
> > prototype for 'fsl_otg_init_timers' [-Werror=missing-prototypes]
> >   285 | int fsl_otg_init_timers(struct otg_fsm *fsm)
> >       |     ^~~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:342:6: error: no previous
> > prototype for 'fsl_otg_uninit_timers' [-Werror=missing-prototypes]
> >   342 | void fsl_otg_uninit_timers(void)
> >       |      ^~~~~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:446:6: error: no previous
> > prototype for 'otg_reset_controller' [-Werror=missing-prototypes]
> >   446 | void otg_reset_controller(void)
> >       |      ^~~~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:458:5: error: no previous
> > prototype for 'fsl_otg_start_host' [-Werror=missing-prototypes]
> >   458 | int fsl_otg_start_host(struct otg_fsm *fsm, int on)
> >       |     ^~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:525:5: error: no previous
> > prototype for 'fsl_otg_start_gadget' [-Werror=missing-prototypes]
> >   525 | int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
> >       |     ^~~~~~~~~~~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:707:13: error: no previous
> > prototype for 'fsl_otg_isr' [-Werror=missing-prototypes]
> >   707 | irqreturn_t fsl_otg_isr(int irq, void *dev_id)
> >       |             ^~~~~~~~~~~
> > /tmp/next/build/drivers/usb/phy/phy-fsl-usb.c:833:5: error: no previous
> > prototype for 'usb_otg_start' [-Werror=missing-prototypes]
> >   833 | int usb_otg_start(struct platform_device *pdev)
> >       |     ^~~~~~~~~~~~~
> > cc1: all warnings being treated as errors make[6]:
> > 
> > It looks like this is a change in dependencies which has allowed this to
> > be built from today, I didn't isolate exactly what - it looks like the
> > issue is missing statics on all these function definitions, making them
> > global.  I have ignored this for today.
> 

^ permalink raw reply

* linux-next: build failure after merge of the qcom tree
From: Mark Brown @ 2026-07-17 13:31 UTC (permalink / raw)
  To: Konrad Dybcio, Bjorn Andersson, Andy Gross, Wangao Wang,
	Dikshita Agarwal, Dmitry Baryshkov
  Cc: Linux Kernel Mailing List, Linux Next Mailing List

Hi all,

After merging the qcom tree, today's linux-next build (arm64 defconfig)
failed like this:

Lexical error: /tmp/next/build/arch/arm64/boot/dts/qcom/purwa.dtsi:169.14-35 Unexpected 'VIDEO_CC_MVS0_BSE_CLK' 

Caused by commit

  43899c55d79ba (arm64: dts: qcom: purwa: Override Iris clocks and operating points)

possibly interacting with something else that changes implicit includes
or something.  I have used the tree from next-20260716 instead.

^ permalink raw reply

* Fixes tags need work in the drm-msm tree
From: Mark Brown @ 2026-07-17 13:30 UTC (permalink / raw)
  To: Rob Clark, Sean Paul; +Cc: linux-kernel, linux-next

[-- Attachment #1: Type: text/plain, Size: 308 bytes --]

In commit

  6cd33b6f4155e ("drm/msm/dsi: round 6G byte clock rate to the PLL-achievable value")

Fixes tag

  Fixes: 6b16f05aa39f ("drm/msm/dsi: Split clk rate setting and enable")

has these problem(s):

  - Subject does not match target commit subject
    Just use
	git log -1 --format='Fixes: %h ("%s")'

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* Missing signoff in the drm-fixes tree
From: Mark Brown @ 2026-07-17 13:30 UTC (permalink / raw)
  To: Dave Airlie, DRI; +Cc: linux-kernel, linux-next

[-- Attachment #1: Type: text/plain, Size: 621 bytes --]

Commits

  c9ab9622f5b27 ("Revert "drm/amd/display: Restore 5s vbl offdelay for NV3x+ DGPUs"")
  d73f4e118dc4c ("drm/amd/display: check GRPH_FLIP status before sending event")
  d094bc1f17783 ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
  2979ff0595f84 ("drm/amdgpu: fix bo->pin leaking in amdgpu_bo_create_reserved")
  cee666427f280 ("drm/amdgpu/userq: fix indefinite fence wait during GPU reset")
  57cf172be2827 ("drm/amd/display: fix dcn42b det allocation order")
  bdd22e186a959 ("drm/amd/display: fix dcn42 det allocation order")

are missing a Signed-off-by from their committers

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* linux-next: Tree for Jul 16
From: Mark Brown @ 2026-07-17 13:30 UTC (permalink / raw)
  To: Linux Next Mailing List; +Cc: Linux Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 1598 bytes --]

Hi all,

Changes since 20260715:

None.

Non-merge commits (relative to Linus' tree): 6313
 6142 files changed, 255877 insertions(+), 101466 deletions(-)

----------------------------------------------------------------------------

I have created today's linux-next tree at
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
(patches at https://www.kernel.org/pub/linux/kernel/next/ ).  If you
are tracking the linux-next tree using git, you should not use "git pull"
to do so as that will try to merge the new linux-next release with the
old one.  You should use "git fetch" and checkout or reset to the new
master.

You can see which trees have been included by looking in the Next/Trees
file in the source.  There is also the merge.log file in the Next
directory.  Between each merge, the tree was built with a defconfig
for arm64, an allmodconfig for x86_64, a multi_v7_defconfig for arm,
an arm64 build of various kselftests, a KUnit build and run on arm64,
and a native build of tools/perf.  After the final fixups (if any), I do
an x86_64 modules_install followed by builds for x86_64 allnoconfig,
arm64 allyesconfig, powerpc allnoconfig (32 and 64 bit),
ppc44x_defconfig and pseries_le_defconfig and i386, s390, sparc and
sparc64 defconfig and htmldocs.

Below is a summary of the state of the merge.

I am currently merging 429 trees (counting Linus' and 133 trees of bug
fix patches pending for the current release).

Stats about the size of the tree over time can be seen at
http://neuling.org/linux-next-size.html .

Thanks to Paul Gortmaker for triage and bug fixes.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ 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