amd-gfx.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/31] DC Patches July 15, 2022
@ 2022-07-15 18:16 Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 01/31] drm/amd/display: Support vertical interrupt 0 for all dcn ASIC Rodrigo Siqueira
                   ` (31 more replies)
  0 siblings, 32 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Daniel Wheeler,
	Aurabindo.Pillai, wayne.lin, Bhawanpreet.Lakha,
	agustin.gutierrez, pavle.kotarac

This DC patchset brings improvements in multiple areas. In summary, we
highlight:

- Isolate FPU operation for DCN32/321 under the DML folder
- Create a specific file for CRTC and plane based on amdgpu_dm
- Fix DSC issues
- Updates tp DML logic

Cc: Daniel Wheeler <daniel.wheeler@amd.com>

Thanks
Siqueira

Alvin Lee (2):
  drm/amd/display: Update in dml
  drm/amd/display: Don't set dram clock change requirement for SubVP

Aric Cyr (1):
  drm/amd/display: 3.2.195

Chris Park (1):
  drm/amd/display: Update Cursor Attribute MALL cache

Jun Lei (2):
  drm/amd/display: Remove unused variable
  drm/amd/display: Update DML logic for unbounded req handling

Rodrigo Siqueira (16):
  drm/amd/display: Create a file dedicated to planes
  drm/amd/display: Create a file dedicated for CRTC
  drm/amd/display: Fix hard hang if DSC is disabled
  drm/amd/display: Drop FPU flags from dcn32_clk_mgr
  drm/amd/display: Move populate phaton function to dml
  drm/amd/display: Move predict pipe to dml fpu folder
  drm/amd/display: Move insert entry table to the FPU code
  drm/amd/display: Move phanton stream to FPU code
  drm/amd/display: Move SubVP functions to dcn32_fpu
  drm/amd/display: Move wm and dlg calculation to FPU code
  drm/amd/display: Move dlg params calculation
  drm/amd/display: Move ntuple to insert entry
  drm/amd/display: Move bounding box to FPU folder
  drm/amd/display: Drop FPU flags from dcn32 Makefile
  drm/amd/display: Create dcn321_fpu file
  drm/amd/display: Drop FPU code from dcn321 resource

Taimur Hassan (2):
  drm/amd/display: Update de-tile override to anticipate pipe splitting
  drm/amd/display: Loop through all pipes for DET allocation

Vladimir Stempen (1):
  drm/amd/display: Disable GPUVM in IP resource configuration

Wayne Lin (5):
  drm/amd/display: Support vertical interrupt 0 for all dcn ASIC
  drm/amd/display: Expose function reset_cur_dp_mst_topology
  drm/amd/display: fix trigger_hotplug to support mst case
  drm/amd/display: Add is_mst_connector debugfs entry
  drm/amd/display: Add tags for indicating mst progress status

Wenjing Liu (1):
  drm/amd/display: remove number of DSC slices override in DML

 .../gpu/drm/amd/display/amdgpu_dm/Makefile    |    8 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2557 +++--------------
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   20 +
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |  463 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.h    |   51 +
 .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c |  114 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   18 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |   13 +
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 1637 +++++++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.h   |   73 +
 .../gpu/drm/amd/display/dc/clk_mgr/Makefile   |   25 -
 .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c  |   81 +-
 drivers/gpu/drm/amd/display/dc/core/dc_link.c |    2 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |    3 +-
 drivers/gpu/drm/amd/display/dc/dc_link.h      |    3 +
 drivers/gpu/drm/amd/display/dc/dcn32/Makefile |   28 -
 .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c |   40 +-
 .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h |    3 +
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 2039 +------------
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |   15 +-
 .../display/dc/dcn32/dcn32_resource_helpers.c |  130 +-
 .../gpu/drm/amd/display/dc/dcn321/Makefile    |   25 -
 .../amd/display/dc/dcn321/dcn321_resource.c   |  649 +----
 .../amd/display/dc/dcn321/dcn321_resource.h   |    3 +
 drivers/gpu/drm/amd/display/dc/dml/Makefile   |    4 +
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 2244 +++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |   74 +
 .../dc/dml/dcn32/display_mode_vba_32.c        |   64 +-
 .../dc/dml/dcn32/display_mode_vba_util_32.c   |   70 +-
 .../dc/dml/dcn32/display_mode_vba_util_32.h   |   10 +-
 .../amd/display/dc/dml/dcn321/dcn321_fpu.c    |  684 +++++
 .../amd/display/dc/dml/dcn321/dcn321_fpu.h    |   38 +
 .../amd/display/dc/dml/display_mode_structs.h |    1 +
 .../drm/amd/display/dc/dml/display_mode_vba.c |    2 +
 .../display/dc/irq/dcn30/irq_service_dcn30.c  |   14 +-
 .../dc/irq/dcn303/irq_service_dcn303.c        |   19 +
 36 files changed, 6035 insertions(+), 5189 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h

-- 
2.37.0


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/31] drm/amd/display: Support vertical interrupt 0 for all dcn ASIC
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 02/31] drm/amd/display: Remove unused variable Rodrigo Siqueira
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	Wayne Lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

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

[Why]
When CONFIG_DRM_AMD_SECURE_DISPLAY is enabled, it will try
to register vertical interrupt 0 for specific task.

Currently, only dcn10 have defined relevant info for vertical interrupt
0. If we enable CONFIG_DRM_AMD_SECURE_DISPLAY for other dcn ASIC, will
get DC_IRQ_SOURCE_INVALID while calling dc_interrupt_to_irq_source() and
cause pointer errors.

[How]
Add support of vertical interrupt 0 for all dcn ASIC.

Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
 .../display/dc/irq/dcn30/irq_service_dcn30.c  | 14 +++++++-------
 .../dc/irq/dcn303/irq_service_dcn303.c        | 19 +++++++++++++++++++
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
index 146cd1819912..2aa74ee1502a 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
@@ -289,6 +289,13 @@ static const struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vblank_irq_info_funcs\
 	}
 
+#define dmub_trace_int_entry()\
+	[DC_IRQ_SOURCE_DMCUB_OUTBOX0] = {\
+		IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX0_READY_INT_EN,\
+			DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX0_READY_INT_ACK),\
+		.funcs = &dmub_trace_irq_info_funcs\
+	}
+
 #define vline0_int_entry(reg_num)\
 	[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\
 		IRQ_REG_ENTRY(OTG, reg_num,\
@@ -297,13 +304,6 @@ static const struct irq_source_info_funcs vline0_irq_info_funcs = {
 		.funcs = &vline0_irq_info_funcs\
 	}
 
-#define dmub_trace_int_entry()\
-	[DC_IRQ_SOURCE_DMCUB_OUTBOX0] = {\
-		IRQ_REG_ENTRY_DMUB(DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX0_READY_INT_EN,\
-			DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX0_READY_INT_ACK),\
-		.funcs = &dmub_trace_irq_info_funcs\
-	}
-
 #define dummy_irq_entry() \
 	{\
 		.funcs = &dummy_irq_info_funcs\
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
index 66e60762388e..1d149d290147 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
@@ -24,6 +24,10 @@ static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_servi
 		return DC_IRQ_SOURCE_VBLANK1;
 	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
 		return DC_IRQ_SOURCE_VBLANK2;
+	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
+		return DC_IRQ_SOURCE_DC1_VLINE0;
+	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
+		return DC_IRQ_SOURCE_DC2_VLINE0;
 	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 		return DC_IRQ_SOURCE_PFLIP1;
 	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
@@ -96,6 +100,11 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = {
 		.ack = NULL
 };
 
+static const struct irq_source_info_funcs vline0_irq_info_funcs = {
+	.set = NULL,
+	.ack = NULL
+};
+
 #undef BASE_INNER
 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 
@@ -164,6 +173,14 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = {
 		.funcs = &vblank_irq_info_funcs\
 	}
 
+#define vline0_int_entry(reg_num)\
+	[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\
+		IRQ_REG_ENTRY(OTG, reg_num,\
+			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE,\
+			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
+		.funcs = &vline0_irq_info_funcs\
+	}
+
 #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
 
 #define i2c_int_entry(reg_num) \
@@ -236,6 +253,8 @@ static const struct irq_source_info irq_source_info_dcn303[DAL_IRQ_SOURCES_NUMBE
 		vupdate_no_lock_int_entry(1),
 		vblank_int_entry(0),
 		vblank_int_entry(1),
+		vline0_int_entry(0),
+		vline0_int_entry(1),
 };
 
 static const struct irq_service_funcs irq_service_funcs_dcn303 = {
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 02/31] drm/amd/display: Remove unused variable
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 01/31] drm/amd/display: Support vertical interrupt 0 for all dcn ASIC Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 03/31] drm/amd/display: Update in dml Rodrigo Siqueira
                   ` (29 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Jun Lei, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

From: Jun Lei <Jun.Lei@amd.com>

Remove an unused variable "remove_disconnect_edp" which was a workaround
bit.

Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Jun Lei <Jun.Lei@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dc.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 7c42377f0aae..be41f9fcf1dd 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -683,7 +683,6 @@ struct dc_debug_options {
 	bool hdmi20_disable;
 	bool skip_detection_link_training;
 	uint32_t edid_read_retry_times;
-	bool remove_disconnect_edp;
 	unsigned int force_odm_combine; //bit vector based on otg inst
 	unsigned int seamless_boot_odm_combine;
 	unsigned int force_odm_combine_4to1; //bit vector based on otg inst
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 03/31] drm/amd/display: Update in dml
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 01/31] drm/amd/display: Support vertical interrupt 0 for all dcn ASIC Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 02/31] drm/amd/display: Remove unused variable Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 04/31] drm/amd/display: Expose function reset_cur_dp_mst_topology Rodrigo Siqueira
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Dmytro Laktyushkin, Sunpeng.Li,
	Harry.Wentland, qingqing.zhuo, Rodrigo.Siqueira, roman.li,
	solomon.chiu, Aurabindo.Pillai, Alvin Lee, wayne.lin,
	Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

From: Alvin Lee <Alvin.Lee2@amd.com>

Update DML to configure drr_display in vba struct.

Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h | 1 +
 drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c     | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
index 87c9b9f9976e..e8b094006d95 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
@@ -499,6 +499,7 @@ struct _vcs_dpi_display_pipe_dest_params_st {
 	unsigned int refresh_rate;
 	bool synchronize_timings;
 	unsigned int odm_combine_policy;
+	bool drr_display;
 };
 
 struct _vcs_dpi_display_pipe_params_st {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
index 39f93072b5e0..083f89e276d6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
@@ -697,6 +697,7 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib)
 		mode_lib->vba.PixelClock[mode_lib->vba.NumberOfActivePlanes] = dst->pixel_rate_mhz;
 		mode_lib->vba.PixelClockBackEnd[mode_lib->vba.NumberOfActivePlanes] = dst->pixel_rate_mhz;
 		mode_lib->vba.DPPCLK[mode_lib->vba.NumberOfActivePlanes] = clks->dppclk_mhz;
+		mode_lib->vba.DRRDisplay[mode_lib->vba.NumberOfActiveSurfaces] = dst->drr_display;
 		if (ip->is_line_buffer_bpp_fixed)
 			mode_lib->vba.LBBitPerPixel[mode_lib->vba.NumberOfActivePlanes] =
 					ip->line_buffer_fixed_bpp;
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 04/31] drm/amd/display: Expose function reset_cur_dp_mst_topology
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (2 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 03/31] drm/amd/display: Update in dml Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 05/31] drm/amd/display: fix trigger_hotplug to support mst case Rodrigo Siqueira
                   ` (27 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	Hersen Wu, Wayne Lin, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

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

[Why & How]
Need to leverage this function out of dc_link.c. Change it to public.

Reviewed-by: Hersen Wu <hersenxs.wu@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc_link.c | 2 +-
 drivers/gpu/drm/amd/display/dc/dc_link.h      | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index 858ee51f930a..ef54b96affa8 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -845,7 +845,7 @@ static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason
 	return link->type == dc_connection_mst_branch;
 }
 
-static bool reset_cur_dp_mst_topology(struct dc_link *link)
+bool reset_cur_dp_mst_topology(struct dc_link *link)
 {
 	bool result = false;
 	DC_LOGGER_INIT(link->ctx->logger);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index 023774b94da3..a0af0f6afeef 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -514,4 +514,7 @@ bool dc_dp_trace_is_logged(struct dc_link *link,
 struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
 		bool in_detection);
 unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
+
+/* Destruct the mst topology of the link and reset the allocated payload table */
+bool reset_cur_dp_mst_topology(struct dc_link *link);
 #endif /* DC_LINK_H_ */
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 05/31] drm/amd/display: fix trigger_hotplug to support mst case
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (3 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 04/31] drm/amd/display: Expose function reset_cur_dp_mst_topology Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 06/31] drm/amd/display: Add is_mst_connector debugfs entry Rodrigo Siqueira
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	Hersen Wu, Wayne Lin, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

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

[Why & How]
Correct few problems below to have debugfs trigger_hotplug entry
supports mst case

* Adjust the place for acquiring the hpd_lock. We'll also access
  dc_link when simulate unplug
* When detect the connector is a mst root, call
  reset_cur_dp_mst_topology() to simulate unplug
* Don't support hotplug caused by CSN message since we can't change
  mst topology info directly. We can't simulate that
* Clean up redundant code

Reviewed-by: Hersen Wu <hersenxs.wu@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c   | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index e0646db6fdbf..b764198eca5c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -1273,14 +1273,22 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
 		return -EINVAL;
 	}
 
+	kfree(wr_buf);
+
 	if (param_nums <= 0) {
 		DRM_DEBUG_DRIVER("user data not be read\n");
-		kfree(wr_buf);
+		return -EINVAL;
+	}
+
+	mutex_lock(&aconnector->hpd_lock);
+
+	/* Don't support for mst end device*/
+	if (aconnector->mst_port) {
+		mutex_unlock(&aconnector->hpd_lock);
 		return -EINVAL;
 	}
 
 	if (param[0] == 1) {
-		mutex_lock(&aconnector->hpd_lock);
 
 		if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type) &&
 			new_connection_type != dc_connection_none)
@@ -1317,6 +1325,10 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
 
 		amdgpu_dm_update_connector_after_detect(aconnector);
 
+		/* If the aconnector is the root node in mst topology */
+		if (aconnector->mst_mgr.mst_state == true)
+			reset_cur_dp_mst_topology(link);
+
 		drm_modeset_lock_all(dev);
 		dm_restore_drm_connector_state(dev, connector);
 		drm_modeset_unlock_all(dev);
@@ -1327,7 +1339,6 @@ static ssize_t trigger_hotplug(struct file *f, const char __user *buf,
 unlock:
 	mutex_unlock(&aconnector->hpd_lock);
 
-	kfree(wr_buf);
 	return size;
 }
 
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 06/31] drm/amd/display: Add is_mst_connector debugfs entry
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (4 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 05/31] drm/amd/display: fix trigger_hotplug to support mst case Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 07/31] drm/amd/display: Add tags for indicating mst progress status Rodrigo Siqueira
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	Hersen Wu, Wayne Lin, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

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

[Why & How]
Add "is_mst_connector" debugfs entry to help distinguish whether
a connector is in a mst topology or not.

Access it with the following command:
    cat /sys/kernel/debug/dri/0/DP-X/is_mst_connector

Result:
- "root" stands for the root connector of the topology
- "branch" stands for branch device of the topology
- "end" stands for leaf node connector of the topology
- "no" stands for the connector is not a device of a mst topology

Reviewed-by: Hersen Wu <hersenxs.wu@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 53 +++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index b764198eca5c..991e58a3a78c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -2557,6 +2557,57 @@ static int target_backlight_show(struct seq_file *m, void *unused)
 	return 0;
 }
 
+/*
+ * function description: Determine if the connector is mst connector
+ *
+ * This function helps to determine whether a connector is a mst connector.
+ * - "root" stands for the root connector of the topology
+ * - "branch" stands for branch device of the topology
+ * - "end" stands for leaf node connector of the topology
+ * - "no" stands for the connector is not a device of a mst topology
+ * Access it with the following command:
+ *
+ *	cat /sys/kernel/debug/dri/0/DP-X/is_mst_connector
+ *
+ */
+static int dp_is_mst_connector_show(struct seq_file *m, void *unused)
+{
+	struct drm_connector *connector = m->private;
+	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+	struct drm_dp_mst_topology_mgr *mgr = NULL;
+	struct drm_dp_mst_port *port = NULL;
+	char *role = NULL;
+
+	mutex_lock(&aconnector->hpd_lock);
+
+	if (aconnector->mst_mgr.mst_state) {
+		role = "root";
+	} else if (aconnector->mst_port &&
+		aconnector->mst_port->mst_mgr.mst_state) {
+
+		role = "end";
+
+		mgr = &aconnector->mst_port->mst_mgr;
+		port = aconnector->port;
+
+		drm_modeset_lock(&mgr->base.lock, NULL);
+		if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
+			port->mcs)
+			role = "branch";
+		drm_modeset_unlock(&mgr->base.lock);
+
+	} else {
+		role = "no";
+	}
+
+	seq_printf(m, "%s\n", role);
+
+	mutex_unlock(&aconnector->hpd_lock);
+
+	return 0;
+}
+
+
 DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support);
 DEFINE_SHOW_ATTRIBUTE(dmub_fw_state);
 DEFINE_SHOW_ATTRIBUTE(dmub_tracebuffer);
@@ -2567,6 +2618,7 @@ DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability);
 #endif
 DEFINE_SHOW_ATTRIBUTE(internal_display);
 DEFINE_SHOW_ATTRIBUTE(psr_capability);
+DEFINE_SHOW_ATTRIBUTE(dp_is_mst_connector);
 
 static const struct file_operations dp_dsc_clock_en_debugfs_fops = {
 	.owner = THIS_MODULE,
@@ -2710,6 +2762,7 @@ static const struct {
 		{"dp_dsc_fec_support", &dp_dsc_fec_support_fops},
 		{"max_bpc", &dp_max_bpc_debugfs_fops},
 		{"dsc_disable_passthrough", &dp_dsc_disable_passthrough_debugfs_fops},
+		{"is_mst_connector", &dp_is_mst_connector_fops}
 };
 
 #ifdef CONFIG_DRM_AMD_DC_HDCP
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 07/31] drm/amd/display: Add tags for indicating mst progress status
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (5 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 06/31] drm/amd/display: Add is_mst_connector debugfs entry Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 08/31] drm/amd/display: Create a file dedicated to planes Rodrigo Siqueira
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	Hersen Wu, Wayne Lin, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

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

[Why & How]
In order to leverage igt tool to maintain mst feature, expose new
debugfs entry "mst_progress_status".

In our dm flow, record down the result of each phase of mst and user
can examine the mst result by checking whether each phase get completed
successfully.

Reviewed-by: Hersen Wu <hersenxs.wu@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 20 ++++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c | 46 ++++++++++++++++++-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 18 +++++++-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 13 ++++++
 4 files changed, 94 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 33d66d4897dc..cdfd32c4128c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -571,6 +571,14 @@ struct dsc_preferred_settings {
 	bool dsc_force_disable_passthrough;
 };
 
+enum mst_progress_status {
+	MST_STATUS_DEFAULT = 0,
+	MST_PROBE = BIT(0),
+	MST_REMOTE_EDID = BIT(1),
+	MST_ALLOCATE_NEW_PAYLOAD = BIT(2),
+	MST_CLEAR_ALLOCATED_PAYLOAD = BIT(3),
+};
+
 struct amdgpu_dm_connector {
 
 	struct drm_connector base;
@@ -623,8 +631,20 @@ struct amdgpu_dm_connector {
 	struct drm_display_mode freesync_vid_base;
 
 	int psr_skip_count;
+
+	/* Record progress status of mst*/
+	uint8_t mst_status;
 };
 
+static inline void amdgpu_dm_set_mst_status(uint8_t *status,
+		uint8_t flags, bool set)
+{
+	if (set)
+		*status |= flags;
+	else
+		*status &= ~flags;
+}
+
 #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base)
 
 extern const struct amdgpu_ip_block_version dm_ip_block;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 991e58a3a78c..cd8db385eda0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -49,6 +49,13 @@ struct dmub_debugfs_trace_entry {
 	uint32_t param1;
 };
 
+static const char *const mst_progress_status[] = {
+	"probe",
+	"remote_edid",
+	"allocate_new_payload",
+	"clear_allocated_payload",
+};
+
 static inline const char *yesno(bool v)
 {
 	return v ? "yes" : "no";
@@ -2607,6 +2614,41 @@ static int dp_is_mst_connector_show(struct seq_file *m, void *unused)
 	return 0;
 }
 
+/*
+ * function description: Read out the mst progress status
+ *
+ * This function helps to determine the mst progress status of
+ * a mst connector.
+ *
+ * Access it with the following command:
+ *
+ *	cat /sys/kernel/debug/dri/0/DP-X/mst_progress_status
+ *
+ */
+static int dp_mst_progress_status_show(struct seq_file *m, void *unused)
+{
+	struct drm_connector *connector = m->private;
+	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+	struct amdgpu_device *adev = drm_to_adev(connector->dev);
+	int i;
+
+	mutex_lock(&aconnector->hpd_lock);
+	mutex_lock(&adev->dm.dc_lock);
+
+	if (aconnector->mst_status == MST_STATUS_DEFAULT) {
+		seq_puts(m, "disabled\n");
+	} else {
+		for (i = 0; i < sizeof(mst_progress_status)/sizeof(char *); i++)
+			seq_printf(m, "%s:%s\n",
+				mst_progress_status[i],
+				aconnector->mst_status & BIT(i) ? "done" : "not_done");
+	}
+
+	mutex_unlock(&adev->dm.dc_lock);
+	mutex_unlock(&aconnector->hpd_lock);
+
+	return 0;
+}
 
 DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support);
 DEFINE_SHOW_ATTRIBUTE(dmub_fw_state);
@@ -2619,6 +2661,7 @@ DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability);
 DEFINE_SHOW_ATTRIBUTE(internal_display);
 DEFINE_SHOW_ATTRIBUTE(psr_capability);
 DEFINE_SHOW_ATTRIBUTE(dp_is_mst_connector);
+DEFINE_SHOW_ATTRIBUTE(dp_mst_progress_status);
 
 static const struct file_operations dp_dsc_clock_en_debugfs_fops = {
 	.owner = THIS_MODULE,
@@ -2762,7 +2805,8 @@ static const struct {
 		{"dp_dsc_fec_support", &dp_dsc_fec_support_fops},
 		{"max_bpc", &dp_max_bpc_debugfs_fops},
 		{"dsc_disable_passthrough", &dp_dsc_disable_passthrough_debugfs_fops},
-		{"is_mst_connector", &dp_is_mst_connector_fops}
+		{"is_mst_connector", &dp_is_mst_connector_fops},
+		{"mst_progress_status", &dp_mst_progress_status_fops}
 };
 
 #ifdef CONFIG_DRM_AMD_DC_HDCP
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 137645d40b72..d66e3cd64ebd 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -312,6 +312,8 @@ bool dm_helpers_dp_mst_send_payload_allocation(
 	struct amdgpu_dm_connector *aconnector;
 	struct drm_dp_mst_topology_mgr *mst_mgr;
 	struct drm_dp_mst_port *mst_port;
+	enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD;
+	enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
 
 	aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
 
@@ -325,8 +327,20 @@ bool dm_helpers_dp_mst_send_payload_allocation(
 	if (!mst_mgr->mst_state)
 		return false;
 
-	/* It's OK for this to fail */
-	drm_dp_update_payload_part2(mst_mgr);
+	if (!enable) {
+		set_flag = MST_CLEAR_ALLOCATED_PAYLOAD;
+		clr_flag = MST_ALLOCATE_NEW_PAYLOAD;
+	}
+
+	if (drm_dp_update_payload_part2(mst_mgr)) {
+		amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			set_flag, false);
+	} else {
+		amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			set_flag, true);
+		amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			clr_flag, false);
+	}
 
 	if (!enable)
 		drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 168d5676b657..c69c1086b35c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -179,6 +179,8 @@ amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector)
 		aconnector->dc_sink = NULL;
 		aconnector->edid = NULL;
 	}
+
+	aconnector->mst_status = MST_STATUS_DEFAULT;
 	drm_modeset_unlock(&root->mst_mgr.base.lock);
 }
 
@@ -279,6 +281,9 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
 		edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
 
 		if (!edid) {
+			amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			MST_REMOTE_EDID, false);
+
 			drm_connector_update_edid_property(
 				&aconnector->base,
 				NULL);
@@ -309,6 +314,8 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
 		}
 
 		aconnector->edid = edid;
+		amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			MST_REMOTE_EDID, true);
 	}
 
 	if (aconnector->dc_sink && aconnector->dc_sink->sink_signal == SIGNAL_TYPE_VIRTUAL) {
@@ -430,6 +437,10 @@ dm_dp_mst_detect(struct drm_connector *connector,
 		dc_sink_release(aconnector->dc_sink);
 		aconnector->dc_sink = NULL;
 		aconnector->edid = NULL;
+
+		amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			MST_REMOTE_EDID | MST_ALLOCATE_NEW_PAYLOAD | MST_CLEAR_ALLOCATED_PAYLOAD,
+			false);
 	}
 
 	return connection_status;
@@ -526,6 +537,8 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
 	connector = &aconnector->base;
 	aconnector->port = port;
 	aconnector->mst_port = master;
+	amdgpu_dm_set_mst_status(&aconnector->mst_status,
+			MST_PROBE, true);
 
 	if (drm_connector_init(
 		dev,
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 08/31] drm/amd/display: Create a file dedicated to planes
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (6 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 07/31] drm/amd/display: Add tags for indicating mst progress status Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-18 14:29   ` Alex Deucher
  2022-07-15 18:16 ` [PATCH 09/31] drm/amd/display: Create a file dedicated for CRTC Rodrigo Siqueira
                   ` (23 subsequent siblings)
  31 siblings, 1 reply; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

[Why]
The amdgpu_dm file contains most of the code that works as an interface
between DRM API and DC. As a result, this file becomes very large since
it comprises multiple abstractions such as plane manipulation.

[How]
This commit extracts the plane code to its specific file named
amdgpu_dm_plane. This change does not change anything inside the
functions; the only exception is converting some static functions to a
global function.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/Makefile    |    7 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2135 +++--------------
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 1637 +++++++++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.h   |   73 +
 4 files changed, 2057 insertions(+), 1795 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
index 718e123a3230..ec559ea902a3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
@@ -25,7 +25,12 @@
 
 
 
-AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o
+AMDGPUDM = \
+	amdgpu_dm.o \
+	amdgpu_dm_plane.o \
+	amdgpu_dm_irq.o \
+	amdgpu_dm_mst_types.o \
+	amdgpu_dm_color.o
 
 ifdef CONFIG_DRM_AMD_DC_DCN
 AMDGPUDM += dc_fpu.o
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index dae998e014b0..ceac70e93ece 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -46,6 +46,7 @@
 #include "amdgpu_ucode.h"
 #include "atom.h"
 #include "amdgpu_dm.h"
+#include "amdgpu_dm_plane.h"
 #ifdef CONFIG_DRM_AMD_DC_HDCP
 #include "amdgpu_dm_hdcp.h"
 #include <drm/drm_hdcp.h>
@@ -203,10 +204,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev);
 /* 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_plane_init(struct amdgpu_display_manager *dm,
-				struct drm_plane *plane,
-				unsigned long possible_crtcs,
-				const struct dc_plane_cap *plane_cap);
 static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
 			       struct drm_plane *plane,
 			       uint32_t link_index);
@@ -225,12 +222,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
 static int amdgpu_dm_atomic_check(struct drm_device *dev,
 				  struct drm_atomic_state *state);
 
-static void handle_cursor_update(struct drm_plane *plane,
-				 struct drm_plane_state *old_plane_state);
-
-static const struct drm_format_info *
-amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
-
 static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector);
 static void handle_hpd_rx_irq(void *param);
 
@@ -4315,11 +4306,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
 	case IP_VERSION(3, 0, 0):
 	case IP_VERSION(3, 1, 2):
 	case IP_VERSION(3, 1, 3):
-	case IP_VERSION(3, 1, 4):
 	case IP_VERSION(3, 1, 5):
 	case IP_VERSION(3, 1, 6):
 	case IP_VERSION(3, 2, 0):
 	case IP_VERSION(3, 2, 1):
+	case IP_VERSION(3, 1, 4):
 	case IP_VERSION(2, 1, 0):
 		if (register_outbox_irq_handlers(dm->adev)) {
 			DRM_ERROR("DM: Failed to initialize IRQ\n");
@@ -4707,1104 +4698,222 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
 	.destroy = amdgpu_dm_encoder_destroy,
 };
 
-
-static void get_min_max_dc_plane_scaling(struct drm_device *dev,
-					 struct drm_framebuffer *fb,
-					 int *min_downscale, int *max_upscale)
-{
-	struct amdgpu_device *adev = drm_to_adev(dev);
-	struct dc *dc = adev->dm.dc;
-	/* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
-	struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
-
-	switch (fb->format->format) {
-	case DRM_FORMAT_P010:
-	case DRM_FORMAT_NV12:
-	case DRM_FORMAT_NV21:
-		*max_upscale = plane_cap->max_upscale_factor.nv12;
-		*min_downscale = plane_cap->max_downscale_factor.nv12;
-		break;
-
-	case DRM_FORMAT_XRGB16161616F:
-	case DRM_FORMAT_ARGB16161616F:
-	case DRM_FORMAT_XBGR16161616F:
-	case DRM_FORMAT_ABGR16161616F:
-		*max_upscale = plane_cap->max_upscale_factor.fp16;
-		*min_downscale = plane_cap->max_downscale_factor.fp16;
-		break;
-
-	default:
-		*max_upscale = plane_cap->max_upscale_factor.argb8888;
-		*min_downscale = plane_cap->max_downscale_factor.argb8888;
-		break;
-	}
-
-	/*
-	 * A factor of 1 in the plane_cap means to not allow scaling, ie. use a
-	 * scaling factor of 1.0 == 1000 units.
-	 */
-	if (*max_upscale == 1)
-		*max_upscale = 1000;
-
-	if (*min_downscale == 1)
-		*min_downscale = 1000;
-}
-
-
-static int fill_dc_scaling_info(struct amdgpu_device *adev,
-				const struct drm_plane_state *state,
-				struct dc_scaling_info *scaling_info)
+static int
+fill_plane_color_attributes(const struct drm_plane_state *plane_state,
+			    const enum surface_pixel_format format,
+			    enum dc_color_space *color_space)
 {
-	int scale_w, scale_h, min_downscale, max_upscale;
-
-	memset(scaling_info, 0, sizeof(*scaling_info));
-
-	/* Source is fixed 16.16 but we ignore mantissa for now... */
-	scaling_info->src_rect.x = state->src_x >> 16;
-	scaling_info->src_rect.y = state->src_y >> 16;
+	bool full_range;
 
-	/*
-	 * For reasons we don't (yet) fully understand a non-zero
-	 * src_y coordinate into an NV12 buffer can cause a
-	 * system hang on DCN1x.
-	 * To avoid hangs (and maybe be overly cautious)
-	 * let's reject both non-zero src_x and src_y.
-	 *
-	 * We currently know of only one use-case to reproduce a
-	 * scenario with non-zero src_x and src_y for NV12, which
-	 * is to gesture the YouTube Android app into full screen
-	 * on ChromeOS.
-	 */
-	if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) ||
-	    (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) &&
-	    (state->fb && state->fb->format->format == DRM_FORMAT_NV12 &&
-	    (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0)))
-		return -EINVAL;
+	*color_space = COLOR_SPACE_SRGB;
 
-	scaling_info->src_rect.width = state->src_w >> 16;
-	if (scaling_info->src_rect.width == 0)
-		return -EINVAL;
+	/* DRM color properties only affect non-RGB formats. */
+	if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
+		return 0;
 
-	scaling_info->src_rect.height = state->src_h >> 16;
-	if (scaling_info->src_rect.height == 0)
-		return -EINVAL;
+	full_range = (plane_state->color_range == DRM_COLOR_YCBCR_FULL_RANGE);
 
-	scaling_info->dst_rect.x = state->crtc_x;
-	scaling_info->dst_rect.y = state->crtc_y;
+	switch (plane_state->color_encoding) {
+	case DRM_COLOR_YCBCR_BT601:
+		if (full_range)
+			*color_space = COLOR_SPACE_YCBCR601;
+		else
+			*color_space = COLOR_SPACE_YCBCR601_LIMITED;
+		break;
 
-	if (state->crtc_w == 0)
-		return -EINVAL;
+	case DRM_COLOR_YCBCR_BT709:
+		if (full_range)
+			*color_space = COLOR_SPACE_YCBCR709;
+		else
+			*color_space = COLOR_SPACE_YCBCR709_LIMITED;
+		break;
 
-	scaling_info->dst_rect.width = state->crtc_w;
+	case DRM_COLOR_YCBCR_BT2020:
+		if (full_range)
+			*color_space = COLOR_SPACE_2020_YCBCR;
+		else
+			return -EINVAL;
+		break;
 
-	if (state->crtc_h == 0)
+	default:
 		return -EINVAL;
-
-	scaling_info->dst_rect.height = state->crtc_h;
-
-	/* DRM doesn't specify clipping on destination output. */
-	scaling_info->clip_rect = scaling_info->dst_rect;
-
-	/* Validate scaling per-format with DC plane caps */
-	if (state->plane && state->plane->dev && state->fb) {
-		get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
-					     &min_downscale, &max_upscale);
-	} else {
-		min_downscale = 250;
-		max_upscale = 16000;
 	}
 
-	scale_w = scaling_info->dst_rect.width * 1000 /
-		  scaling_info->src_rect.width;
-
-	if (scale_w < min_downscale || scale_w > max_upscale)
-		return -EINVAL;
-
-	scale_h = scaling_info->dst_rect.height * 1000 /
-		  scaling_info->src_rect.height;
-
-	if (scale_h < min_downscale || scale_h > max_upscale)
-		return -EINVAL;
-
-	/*
-	 * The "scaling_quality" can be ignored for now, quality = 0 has DC
-	 * assume reasonable defaults based on the format.
-	 */
-
 	return 0;
 }
 
-static void
-fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info,
-				 uint64_t tiling_flags)
-{
-	/* Fill GFX8 params */
-	if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
-		unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
-
-		bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
-		bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
-		mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
-		tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
-		num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
-
-		/* XXX fix me for VI */
-		tiling_info->gfx8.num_banks = num_banks;
-		tiling_info->gfx8.array_mode =
-				DC_ARRAY_2D_TILED_THIN1;
-		tiling_info->gfx8.tile_split = tile_split;
-		tiling_info->gfx8.bank_width = bankw;
-		tiling_info->gfx8.bank_height = bankh;
-		tiling_info->gfx8.tile_aspect = mtaspect;
-		tiling_info->gfx8.tile_mode =
-				DC_ADDR_SURF_MICRO_TILING_DISPLAY;
-	} else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
-			== DC_ARRAY_1D_TILED_THIN1) {
-		tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
-	}
-
-	tiling_info->gfx8.pipe_config =
-			AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
-}
-
-static void
-fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev,
-				  union dc_tiling_info *tiling_info)
-{
-	tiling_info->gfx9.num_pipes =
-		adev->gfx.config.gb_addr_config_fields.num_pipes;
-	tiling_info->gfx9.num_banks =
-		adev->gfx.config.gb_addr_config_fields.num_banks;
-	tiling_info->gfx9.pipe_interleave =
-		adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
-	tiling_info->gfx9.num_shader_engines =
-		adev->gfx.config.gb_addr_config_fields.num_se;
-	tiling_info->gfx9.max_compressed_frags =
-		adev->gfx.config.gb_addr_config_fields.max_compress_frags;
-	tiling_info->gfx9.num_rb_per_se =
-		adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
-	tiling_info->gfx9.shaderEnable = 1;
-	if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
-		tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;
-}
-
 static int
-validate_dcc(struct amdgpu_device *adev,
-	     const enum surface_pixel_format format,
-	     const enum dc_rotation_angle rotation,
-	     const union dc_tiling_info *tiling_info,
-	     const struct dc_plane_dcc_param *dcc,
-	     const struct dc_plane_address *address,
-	     const struct plane_size *plane_size)
+fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
+			    const struct drm_plane_state *plane_state,
+			    const uint64_t tiling_flags,
+			    struct dc_plane_info *plane_info,
+			    struct dc_plane_address *address,
+			    bool tmz_surface,
+			    bool force_disable_dcc)
 {
-	struct dc *dc = adev->dm.dc;
-	struct dc_dcc_surface_param input;
-	struct dc_surface_dcc_cap output;
-
-	memset(&input, 0, sizeof(input));
-	memset(&output, 0, sizeof(output));
+	const struct drm_framebuffer *fb = plane_state->fb;
+	const struct amdgpu_framebuffer *afb =
+		to_amdgpu_framebuffer(plane_state->fb);
+	int ret;
 
-	if (!dcc->enable)
-		return 0;
+	memset(plane_info, 0, sizeof(*plane_info));
 
-	if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
-	    !dc->cap_funcs.get_dcc_compression_cap)
+	switch (fb->format->format) {
+	case DRM_FORMAT_C8:
+		plane_info->format =
+			SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
+		break;
+	case DRM_FORMAT_RGB565:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
+		break;
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ARGB2101010:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
+		break;
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_ABGR2101010:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
+		break;
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR8888;
+		break;
+	case DRM_FORMAT_NV21:
+		plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
+		break;
+	case DRM_FORMAT_NV12:
+		plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
+		break;
+	case DRM_FORMAT_P010:
+		plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
+		break;
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
+		break;
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
+		break;
+	case DRM_FORMAT_XRGB16161616:
+	case DRM_FORMAT_ARGB16161616:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616;
+		break;
+	case DRM_FORMAT_XBGR16161616:
+	case DRM_FORMAT_ABGR16161616:
+		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616;
+		break;
+	default:
+		DRM_ERROR(
+			"Unsupported screen format %p4cc\n",
+			&fb->format->format);
 		return -EINVAL;
+	}
 
-	input.format = format;
-	input.surface_size.width = plane_size->surface_size.width;
-	input.surface_size.height = plane_size->surface_size.height;
-	input.swizzle_mode = tiling_info->gfx9.swizzle;
-
-	if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180)
-		input.scan = SCAN_DIRECTION_HORIZONTAL;
-	else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270)
-		input.scan = SCAN_DIRECTION_VERTICAL;
+	switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
+	case DRM_MODE_ROTATE_0:
+		plane_info->rotation = ROTATION_ANGLE_0;
+		break;
+	case DRM_MODE_ROTATE_90:
+		plane_info->rotation = ROTATION_ANGLE_90;
+		break;
+	case DRM_MODE_ROTATE_180:
+		plane_info->rotation = ROTATION_ANGLE_180;
+		break;
+	case DRM_MODE_ROTATE_270:
+		plane_info->rotation = ROTATION_ANGLE_270;
+		break;
+	default:
+		plane_info->rotation = ROTATION_ANGLE_0;
+		break;
+	}
 
-	if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
-		return -EINVAL;
 
-	if (!output.capable)
-		return -EINVAL;
+	plane_info->visible = true;
+	plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE;
 
-	if (dcc->independent_64b_blks == 0 &&
-	    output.grph.rgb.independent_64b_blks != 0)
-		return -EINVAL;
+	plane_info->layer_index = 0;
 
-	return 0;
-}
+	ret = fill_plane_color_attributes(plane_state, plane_info->format,
+					  &plane_info->color_space);
+	if (ret)
+		return ret;
 
-static bool
-modifier_has_dcc(uint64_t modifier)
-{
-	return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
-}
+	ret = fill_plane_buffer_attributes(adev, afb, plane_info->format,
+					   plane_info->rotation, tiling_flags,
+					   &plane_info->tiling_info,
+					   &plane_info->plane_size,
+					   &plane_info->dcc, address,
+					   tmz_surface, force_disable_dcc);
+	if (ret)
+		return ret;
 
-static unsigned
-modifier_gfx9_swizzle_mode(uint64_t modifier)
-{
-	if (modifier == DRM_FORMAT_MOD_LINEAR)
-		return 0;
+	fill_blending_from_plane_state(
+		plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
+		&plane_info->global_alpha, &plane_info->global_alpha_value);
 
-	return AMD_FMT_MOD_GET(TILE, modifier);
+	return 0;
 }
 
-static const struct drm_format_info *
-amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
+static int fill_dc_plane_attributes(struct amdgpu_device *adev,
+				    struct dc_plane_state *dc_plane_state,
+				    struct drm_plane_state *plane_state,
+				    struct drm_crtc_state *crtc_state)
 {
-	return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]);
-}
+	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
+	struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb;
+	struct dc_scaling_info scaling_info;
+	struct dc_plane_info plane_info;
+	int ret;
+	bool force_disable_dcc = false;
 
-static void
-fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev,
-				    union dc_tiling_info *tiling_info,
-				    uint64_t modifier)
-{
-	unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
-	unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
-	unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier);
-	unsigned int pipes_log2;
+	ret = fill_dc_scaling_info(adev, plane_state, &scaling_info);
+	if (ret)
+		return ret;
 
-	pipes_log2 = min(5u, mod_pipe_xor_bits);
+	dc_plane_state->src_rect = scaling_info.src_rect;
+	dc_plane_state->dst_rect = scaling_info.dst_rect;
+	dc_plane_state->clip_rect = scaling_info.clip_rect;
+	dc_plane_state->scaling_quality = scaling_info.scaling_quality;
 
-	fill_gfx9_tiling_info_from_device(adev, tiling_info);
+	force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
+	ret = fill_dc_plane_info_and_addr(adev, plane_state,
+					  afb->tiling_flags,
+					  &plane_info,
+					  &dc_plane_state->address,
+					  afb->tmz_surface,
+					  force_disable_dcc);
+	if (ret)
+		return ret;
 
-	if (!IS_AMD_FMT_MOD(modifier))
-		return;
+	dc_plane_state->format = plane_info.format;
+	dc_plane_state->color_space = plane_info.color_space;
+	dc_plane_state->format = plane_info.format;
+	dc_plane_state->plane_size = plane_info.plane_size;
+	dc_plane_state->rotation = plane_info.rotation;
+	dc_plane_state->horizontal_mirror = plane_info.horizontal_mirror;
+	dc_plane_state->stereo_format = plane_info.stereo_format;
+	dc_plane_state->tiling_info = plane_info.tiling_info;
+	dc_plane_state->visible = plane_info.visible;
+	dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
+	dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
+	dc_plane_state->global_alpha = plane_info.global_alpha;
+	dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
+	dc_plane_state->dcc = plane_info.dcc;
+	dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
+	dc_plane_state->flip_int_enabled = true;
 
-	tiling_info->gfx9.num_pipes = 1u << pipes_log2;
-	tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2);
-
-	if (adev->family >= AMDGPU_FAMILY_NV) {
-		tiling_info->gfx9.num_pkrs = 1u << pkrs_log2;
-	} else {
-		tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits;
-
-		/* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */
-	}
-}
-
-enum dm_micro_swizzle {
-	MICRO_SWIZZLE_Z = 0,
-	MICRO_SWIZZLE_S = 1,
-	MICRO_SWIZZLE_D = 2,
-	MICRO_SWIZZLE_R = 3
-};
-
-static bool dm_plane_format_mod_supported(struct drm_plane *plane,
-					  uint32_t format,
-					  uint64_t modifier)
-{
-	struct amdgpu_device *adev = drm_to_adev(plane->dev);
-	const struct drm_format_info *info = drm_format_info(format);
-	int i;
-
-	enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3;
-
-	if (!info)
-		return false;
-
-	/*
-	 * We always have to allow these modifiers:
-	 * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
-	 * 2. Not passing any modifiers is the same as explicitly passing INVALID.
-	 */
-	if (modifier == DRM_FORMAT_MOD_LINEAR ||
-	    modifier == DRM_FORMAT_MOD_INVALID) {
-		return true;
-	}
-
-	/* Check that the modifier is on the list of the plane's supported modifiers. */
-	for (i = 0; i < plane->modifier_count; i++) {
-		if (modifier == plane->modifiers[i])
-			break;
-	}
-	if (i == plane->modifier_count)
-		return false;
-
-	/*
-	 * For D swizzle the canonical modifier depends on the bpp, so check
-	 * it here.
-	 */
-	if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 &&
-	    adev->family >= AMDGPU_FAMILY_NV) {
-		if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4)
-			return false;
-	}
-
-	if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D &&
-	    info->cpp[0] < 8)
-		return false;
-
-	if (modifier_has_dcc(modifier)) {
-		/* Per radeonsi comments 16/64 bpp are more complicated. */
-		if (info->cpp[0] != 4)
-			return false;
-		/* We support multi-planar formats, but not when combined with
-		 * additional DCC metadata planes. */
-		if (info->num_planes > 1)
-			return false;
-	}
-
-	return true;
-}
-
-static void
-add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod)
-{
-	if (!*mods)
-		return;
-
-	if (*cap - *size < 1) {
-		uint64_t new_cap = *cap * 2;
-		uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL);
-
-		if (!new_mods) {
-			kfree(*mods);
-			*mods = NULL;
-			return;
-		}
-
-		memcpy(new_mods, *mods, sizeof(uint64_t) * *size);
-		kfree(*mods);
-		*mods = new_mods;
-		*cap = new_cap;
-	}
-
-	(*mods)[*size] = mod;
-	*size += 1;
-}
-
-static void
-add_gfx9_modifiers(const struct amdgpu_device *adev,
-		   uint64_t **mods, uint64_t *size, uint64_t *capacity)
-{
-	int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
-	int pipe_xor_bits = min(8, pipes +
-				ilog2(adev->gfx.config.gb_addr_config_fields.num_se));
-	int bank_xor_bits = min(8 - pipe_xor_bits,
-				ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));
-	int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +
-		 ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);
-
-
-	if (adev->family == AMDGPU_FAMILY_RV) {
-		/* Raven2 and later */
-		bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81;
-
-		/*
-		 * No _D DCC swizzles yet because we only allow 32bpp, which
-		 * doesn't support _D on DCN
-		 */
-
-		if (has_constant_encode) {
-			add_modifier(mods, size, capacity, AMD_FMT_MOD |
-				    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-				    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
-				    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-				    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
-				    AMD_FMT_MOD_SET(DCC, 1) |
-				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-				    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
-				    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));
-		}
-
-		add_modifier(mods, size, capacity, AMD_FMT_MOD |
-			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
-			    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-			    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
-			    AMD_FMT_MOD_SET(DCC, 1) |
-			    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-			    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
-			    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0));
-
-		if (has_constant_encode) {
-			add_modifier(mods, size, capacity, AMD_FMT_MOD |
-				    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-				    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
-				    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-				    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
-				    AMD_FMT_MOD_SET(DCC, 1) |
-				    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
-				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-				    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
-
-				    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-				    AMD_FMT_MOD_SET(RB, rb) |
-				    AMD_FMT_MOD_SET(PIPE, pipes));
-		}
-
-		add_modifier(mods, size, capacity, AMD_FMT_MOD |
-			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
-			    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-			    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
-			    AMD_FMT_MOD_SET(DCC, 1) |
-			    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
-			    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-			    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
-			    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) |
-			    AMD_FMT_MOD_SET(RB, rb) |
-			    AMD_FMT_MOD_SET(PIPE, pipes));
-	}
-
-	/*
-	 * Only supported for 64bpp on Raven, will be filtered on format in
-	 * dm_plane_format_mod_supported.
-	 */
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
-
-	if (adev->family == AMDGPU_FAMILY_RV) {
-		add_modifier(mods, size, capacity, AMD_FMT_MOD |
-			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
-			    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-			    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
-	}
-
-	/*
-	 * Only supported for 64bpp on Raven, will be filtered on format in
-	 * dm_plane_format_mod_supported.
-	 */
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
-
-	if (adev->family == AMDGPU_FAMILY_RV) {
-		add_modifier(mods, size, capacity, AMD_FMT_MOD |
-			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
-			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
-	}
-}
-
-static void
-add_gfx10_1_modifiers(const struct amdgpu_device *adev,
-		      uint64_t **mods, uint64_t *size, uint64_t *capacity)
-{
-	int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(DCC, 1) |
-		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(DCC, 1) |
-		    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
-		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
-
-
-	/* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
-}
-
-static void
-add_gfx10_3_modifiers(const struct amdgpu_device *adev,
-		      uint64_t **mods, uint64_t *size, uint64_t *capacity)
-{
-	int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
-	int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs);
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
-		    AMD_FMT_MOD_SET(DCC, 1) |
-		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
-		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
-		    AMD_FMT_MOD_SET(DCC, 1) |
-		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
-		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
-		    AMD_FMT_MOD_SET(DCC, 1) |
-		    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
-		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
-		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
-		    AMD_FMT_MOD_SET(DCC, 1) |
-		    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
-		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
-		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
-		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(PACKERS, pkrs));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
-		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-		    AMD_FMT_MOD_SET(PACKERS, pkrs));
-
-	/* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
-		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
-}
-
-static void
-add_gfx11_modifiers(struct amdgpu_device *adev,
-		      uint64_t **mods, uint64_t *size, uint64_t *capacity)
-{
-	int num_pipes = 0;
-	int pipe_xor_bits = 0;
-	int num_pkrs = 0;
-	int pkrs = 0;
-	u32 gb_addr_config;
-	u8 i = 0;
-	unsigned swizzle_r_x;
-	uint64_t modifier_r_x;
-	uint64_t modifier_dcc_best;
-	uint64_t modifier_dcc_4k;
-
-	/* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from
-	 * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes} */
-	gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG);
-	ASSERT(gb_addr_config != 0);
-
-	num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS);
-	pkrs = ilog2(num_pkrs);
-	num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES);
-	pipe_xor_bits = ilog2(num_pipes);
-
-	for (i = 0; i < 2; i++) {
-		/* Insert the best one first. */
-		/* R_X swizzle modes are the best for rendering and DCC requires them. */
-		if (num_pipes > 16)
-			swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : AMD_FMT_MOD_TILE_GFX9_64K_R_X;
-		else
-			swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX9_64K_R_X : AMD_FMT_MOD_TILE_GFX11_256K_R_X;
-
-		modifier_r_x = AMD_FMT_MOD |
-			       AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
-			       AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
-			       AMD_FMT_MOD_SET(TILE, swizzle_r_x) |
-			       AMD_FMT_MOD_SET(PACKERS, pkrs);
-
-		/* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */
-		modifier_dcc_best = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
-				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) |
-				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
-				    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B);
-
-		/* DCC settings for 4K and greater resolutions. (required by display hw) */
-		modifier_dcc_4k = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
-				  AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
-				  AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
-				  AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B);
-
-		add_modifier(mods, size, capacity, modifier_dcc_best);
-		add_modifier(mods, size, capacity, modifier_dcc_4k);
-
-		add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1));
-		add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1));
-
-		add_modifier(mods, size, capacity, modifier_r_x);
-	}
-
-	add_modifier(mods, size, capacity, AMD_FMT_MOD |
-             AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
-			 AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D));
-}
-
-static int
-get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods)
-{
-	uint64_t size = 0, capacity = 128;
-	*mods = NULL;
-
-	/* We have not hooked up any pre-GFX9 modifiers. */
-	if (adev->family < AMDGPU_FAMILY_AI)
-		return 0;
-
-	*mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL);
-
-	if (plane_type == DRM_PLANE_TYPE_CURSOR) {
-		add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
-		add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
-		return *mods ? 0 : -ENOMEM;
-	}
-
-	switch (adev->family) {
-	case AMDGPU_FAMILY_AI:
-	case AMDGPU_FAMILY_RV:
-		add_gfx9_modifiers(adev, mods, &size, &capacity);
-		break;
-	case AMDGPU_FAMILY_NV:
-	case AMDGPU_FAMILY_VGH:
-	case AMDGPU_FAMILY_YC:
-	case AMDGPU_FAMILY_GC_10_3_6:
-	case AMDGPU_FAMILY_GC_10_3_7:
-		if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
-			add_gfx10_3_modifiers(adev, mods, &size, &capacity);
-		else
-			add_gfx10_1_modifiers(adev, mods, &size, &capacity);
-		break;
-	case AMDGPU_FAMILY_GC_11_0_0:
-	case AMDGPU_FAMILY_GC_11_0_2:
-		add_gfx11_modifiers(adev, mods, &size, &capacity);
-		break;
-	}
-
-	add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
-
-	/* INVALID marks the end of the list. */
-	add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
-
-	if (!*mods)
-		return -ENOMEM;
-
-	return 0;
-}
-
-static int
-fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
-					  const struct amdgpu_framebuffer *afb,
-					  const enum surface_pixel_format format,
-					  const enum dc_rotation_angle rotation,
-					  const struct plane_size *plane_size,
-					  union dc_tiling_info *tiling_info,
-					  struct dc_plane_dcc_param *dcc,
-					  struct dc_plane_address *address,
-					  const bool force_disable_dcc)
-{
-	const uint64_t modifier = afb->base.modifier;
-	int ret = 0;
-
-	fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
-	tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
-
-	if (modifier_has_dcc(modifier) && !force_disable_dcc) {
-		uint64_t dcc_address = afb->address + afb->base.offsets[1];
-		bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
-		bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
-
-		dcc->enable = 1;
-		dcc->meta_pitch = afb->base.pitches[1];
-		dcc->independent_64b_blks = independent_64b_blks;
-		if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
-			if (independent_64b_blks && independent_128b_blks)
-				dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl;
-			else if (independent_128b_blks)
-				dcc->dcc_ind_blk = hubp_ind_block_128b;
-			else if (independent_64b_blks && !independent_128b_blks)
-				dcc->dcc_ind_blk = hubp_ind_block_64b;
-			else
-				dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
-		} else {
-			if (independent_64b_blks)
-				dcc->dcc_ind_blk = hubp_ind_block_64b;
-			else
-				dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
-		}
-
-		address->grph.meta_addr.low_part = lower_32_bits(dcc_address);
-		address->grph.meta_addr.high_part = upper_32_bits(dcc_address);
-	}
-
-	ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
-	if (ret)
-		drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
-
-	return ret;
-}
-
-static int
-fill_plane_buffer_attributes(struct amdgpu_device *adev,
-			     const struct amdgpu_framebuffer *afb,
-			     const enum surface_pixel_format format,
-			     const enum dc_rotation_angle rotation,
-			     const uint64_t tiling_flags,
-			     union dc_tiling_info *tiling_info,
-			     struct plane_size *plane_size,
-			     struct dc_plane_dcc_param *dcc,
-			     struct dc_plane_address *address,
-			     bool tmz_surface,
-			     bool force_disable_dcc)
-{
-	const struct drm_framebuffer *fb = &afb->base;
-	int ret;
-
-	memset(tiling_info, 0, sizeof(*tiling_info));
-	memset(plane_size, 0, sizeof(*plane_size));
-	memset(dcc, 0, sizeof(*dcc));
-	memset(address, 0, sizeof(*address));
-
-	address->tmz_surface = tmz_surface;
-
-	if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
-		uint64_t addr = afb->address + fb->offsets[0];
-
-		plane_size->surface_size.x = 0;
-		plane_size->surface_size.y = 0;
-		plane_size->surface_size.width = fb->width;
-		plane_size->surface_size.height = fb->height;
-		plane_size->surface_pitch =
-			fb->pitches[0] / fb->format->cpp[0];
-
-		address->type = PLN_ADDR_TYPE_GRAPHICS;
-		address->grph.addr.low_part = lower_32_bits(addr);
-		address->grph.addr.high_part = upper_32_bits(addr);
-	} else if (format < SURFACE_PIXEL_FORMAT_INVALID) {
-		uint64_t luma_addr = afb->address + fb->offsets[0];
-		uint64_t chroma_addr = afb->address + fb->offsets[1];
-
-		plane_size->surface_size.x = 0;
-		plane_size->surface_size.y = 0;
-		plane_size->surface_size.width = fb->width;
-		plane_size->surface_size.height = fb->height;
-		plane_size->surface_pitch =
-			fb->pitches[0] / fb->format->cpp[0];
-
-		plane_size->chroma_size.x = 0;
-		plane_size->chroma_size.y = 0;
-		/* TODO: set these based on surface format */
-		plane_size->chroma_size.width = fb->width / 2;
-		plane_size->chroma_size.height = fb->height / 2;
-
-		plane_size->chroma_pitch =
-			fb->pitches[1] / fb->format->cpp[1];
-
-		address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
-		address->video_progressive.luma_addr.low_part =
-			lower_32_bits(luma_addr);
-		address->video_progressive.luma_addr.high_part =
-			upper_32_bits(luma_addr);
-		address->video_progressive.chroma_addr.low_part =
-			lower_32_bits(chroma_addr);
-		address->video_progressive.chroma_addr.high_part =
-			upper_32_bits(chroma_addr);
-	}
-
-	if (adev->family >= AMDGPU_FAMILY_AI) {
-		ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format,
-								rotation, plane_size,
-								tiling_info, dcc,
-								address,
-								force_disable_dcc);
-		if (ret)
-			return ret;
-	} else {
-		fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags);
-	}
-
-	return 0;
-}
-
-static void
-fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
-			       bool *per_pixel_alpha, bool *pre_multiplied_alpha,
-			       bool *global_alpha, int *global_alpha_value)
-{
-	*per_pixel_alpha = false;
-	*pre_multiplied_alpha = true;
-	*global_alpha = false;
-	*global_alpha_value = 0xff;
-
-	if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
-		return;
-
-	if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
-		plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
-		static const uint32_t alpha_formats[] = {
-			DRM_FORMAT_ARGB8888,
-			DRM_FORMAT_RGBA8888,
-			DRM_FORMAT_ABGR8888,
-		};
-		uint32_t format = plane_state->fb->format->format;
-		unsigned int i;
-
-		for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
-			if (format == alpha_formats[i]) {
-				*per_pixel_alpha = true;
-				break;
-			}
-		}
-
-		if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
-			*pre_multiplied_alpha = false;
-	}
-
-	if (plane_state->alpha < 0xffff) {
-		*global_alpha = true;
-		*global_alpha_value = plane_state->alpha >> 8;
-	}
-}
-
-static int
-fill_plane_color_attributes(const struct drm_plane_state *plane_state,
-			    const enum surface_pixel_format format,
-			    enum dc_color_space *color_space)
-{
-	bool full_range;
-
-	*color_space = COLOR_SPACE_SRGB;
-
-	/* DRM color properties only affect non-RGB formats. */
-	if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
-		return 0;
-
-	full_range = (plane_state->color_range == DRM_COLOR_YCBCR_FULL_RANGE);
-
-	switch (plane_state->color_encoding) {
-	case DRM_COLOR_YCBCR_BT601:
-		if (full_range)
-			*color_space = COLOR_SPACE_YCBCR601;
-		else
-			*color_space = COLOR_SPACE_YCBCR601_LIMITED;
-		break;
-
-	case DRM_COLOR_YCBCR_BT709:
-		if (full_range)
-			*color_space = COLOR_SPACE_YCBCR709;
-		else
-			*color_space = COLOR_SPACE_YCBCR709_LIMITED;
-		break;
-
-	case DRM_COLOR_YCBCR_BT2020:
-		if (full_range)
-			*color_space = COLOR_SPACE_2020_YCBCR;
-		else
-			return -EINVAL;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
-			    const struct drm_plane_state *plane_state,
-			    const uint64_t tiling_flags,
-			    struct dc_plane_info *plane_info,
-			    struct dc_plane_address *address,
-			    bool tmz_surface,
-			    bool force_disable_dcc)
-{
-	const struct drm_framebuffer *fb = plane_state->fb;
-	const struct amdgpu_framebuffer *afb =
-		to_amdgpu_framebuffer(plane_state->fb);
-	int ret;
-
-	memset(plane_info, 0, sizeof(*plane_info));
-
-	switch (fb->format->format) {
-	case DRM_FORMAT_C8:
-		plane_info->format =
-			SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
-		break;
-	case DRM_FORMAT_RGB565:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
-		break;
-	case DRM_FORMAT_XRGB8888:
-	case DRM_FORMAT_ARGB8888:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
-		break;
-	case DRM_FORMAT_XRGB2101010:
-	case DRM_FORMAT_ARGB2101010:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
-		break;
-	case DRM_FORMAT_XBGR2101010:
-	case DRM_FORMAT_ABGR2101010:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
-		break;
-	case DRM_FORMAT_XBGR8888:
-	case DRM_FORMAT_ABGR8888:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR8888;
-		break;
-	case DRM_FORMAT_NV21:
-		plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
-		break;
-	case DRM_FORMAT_NV12:
-		plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
-		break;
-	case DRM_FORMAT_P010:
-		plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
-		break;
-	case DRM_FORMAT_XRGB16161616F:
-	case DRM_FORMAT_ARGB16161616F:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
-		break;
-	case DRM_FORMAT_XBGR16161616F:
-	case DRM_FORMAT_ABGR16161616F:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
-		break;
-	case DRM_FORMAT_XRGB16161616:
-	case DRM_FORMAT_ARGB16161616:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616;
-		break;
-	case DRM_FORMAT_XBGR16161616:
-	case DRM_FORMAT_ABGR16161616:
-		plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616;
-		break;
-	default:
-		DRM_ERROR(
-			"Unsupported screen format %p4cc\n",
-			&fb->format->format);
-		return -EINVAL;
-	}
-
-	switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
-	case DRM_MODE_ROTATE_0:
-		plane_info->rotation = ROTATION_ANGLE_0;
-		break;
-	case DRM_MODE_ROTATE_90:
-		plane_info->rotation = ROTATION_ANGLE_90;
-		break;
-	case DRM_MODE_ROTATE_180:
-		plane_info->rotation = ROTATION_ANGLE_180;
-		break;
-	case DRM_MODE_ROTATE_270:
-		plane_info->rotation = ROTATION_ANGLE_270;
-		break;
-	default:
-		plane_info->rotation = ROTATION_ANGLE_0;
-		break;
-	}
-
-	plane_info->visible = true;
-	plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE;
-
-	plane_info->layer_index = 0;
-
-	ret = fill_plane_color_attributes(plane_state, plane_info->format,
-					  &plane_info->color_space);
-	if (ret)
-		return ret;
-
-	ret = fill_plane_buffer_attributes(adev, afb, plane_info->format,
-					   plane_info->rotation, tiling_flags,
-					   &plane_info->tiling_info,
-					   &plane_info->plane_size,
-					   &plane_info->dcc, address, tmz_surface,
-					   force_disable_dcc);
-	if (ret)
-		return ret;
-
-	fill_blending_from_plane_state(
-		plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
-		&plane_info->global_alpha, &plane_info->global_alpha_value);
-
-	return 0;
-}
-
-static int fill_dc_plane_attributes(struct amdgpu_device *adev,
-				    struct dc_plane_state *dc_plane_state,
-				    struct drm_plane_state *plane_state,
-				    struct drm_crtc_state *crtc_state)
-{
-	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
-	struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb;
-	struct dc_scaling_info scaling_info;
-	struct dc_plane_info plane_info;
-	int ret;
-	bool force_disable_dcc = false;
-
-	ret = fill_dc_scaling_info(adev, plane_state, &scaling_info);
-	if (ret)
-		return ret;
-
-	dc_plane_state->src_rect = scaling_info.src_rect;
-	dc_plane_state->dst_rect = scaling_info.dst_rect;
-	dc_plane_state->clip_rect = scaling_info.clip_rect;
-	dc_plane_state->scaling_quality = scaling_info.scaling_quality;
-
-	force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
-	ret = fill_dc_plane_info_and_addr(adev, plane_state,
-					  afb->tiling_flags,
-					  &plane_info,
-					  &dc_plane_state->address,
-					  afb->tmz_surface,
-					  force_disable_dcc);
-	if (ret)
-		return ret;
-
-	dc_plane_state->format = plane_info.format;
-	dc_plane_state->color_space = plane_info.color_space;
-	dc_plane_state->format = plane_info.format;
-	dc_plane_state->plane_size = plane_info.plane_size;
-	dc_plane_state->rotation = plane_info.rotation;
-	dc_plane_state->horizontal_mirror = plane_info.horizontal_mirror;
-	dc_plane_state->stereo_format = plane_info.stereo_format;
-	dc_plane_state->tiling_info = plane_info.tiling_info;
-	dc_plane_state->visible = plane_info.visible;
-	dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
-	dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
-	dc_plane_state->global_alpha = plane_info.global_alpha;
-	dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
-	dc_plane_state->dcc = plane_info.dcc;
-	dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
-	dc_plane_state->flip_int_enabled = true;
-
-	/*
-	 * Always set input transfer function, since plane state is refreshed
-	 * every time.
-	 */
-	ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
-	if (ret)
-		return ret;
+	/*
+	 * Always set input transfer function, since plane state is refreshed
+	 * every time.
+	 */
+	ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
+	if (ret)
+		return ret;
 
 	return 0;
 }
@@ -6165,7 +5274,7 @@ static void fill_stream_properties_from_drm_display_mode(
 	timing_out->scan_type = SCANNING_TYPE_NODATA;
 	timing_out->hdmi_vic = 0;
 
-	if(old_stream) {
+	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;
@@ -6387,16 +5496,126 @@ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
 	}
 }
 
+/**
+ * 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->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_DEBUG_DRIVER("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_DCN)
 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)
+			    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)) {
+	    sink->sink_signal == SIGNAL_TYPE_EDP)) {
 		if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE ||
 			sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
 			dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
@@ -6406,6 +5625,7 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
 	}
 }
 
+
 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,
@@ -6464,9 +5684,10 @@ static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector,
 	}
 }
 
+
 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 dc_sink *sink, struct dc_stream_state *stream,
+					struct dsc_dec_dpcd_caps *dsc_caps)
 {
 	struct drm_connector *drm_connector = &aconnector->base;
 	uint32_t link_bandwidth_kbps;
@@ -6477,7 +5698,6 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
 
 	link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
 							dc_link_get_link_cap(aconnector->dc_link));
-
 	if (stream->link && stream->link->local_sink)
 		max_dsc_target_bpp_limit_override =
 			stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit;
@@ -6501,8 +5721,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
 						&stream->timing,
 						&stream->timing.dsc_cfg)) {
 				stream->timing.flags.DSC = 1;
-				DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from SST RX\n",
-								 __func__, drm_connector->name);
+				DRM_DEBUG_DRIVER("%s: [%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);
@@ -6530,126 +5749,16 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
 	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 /* CONFIG_DRM_AMD_DC_DCN */
-
-/**
- * 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,120 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->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_DEBUG_DRIVER("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 (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 (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 (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 /* CONFIG_DRM_AMD_DC_DCN */
 
 static struct dc_stream_state *
 create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
@@ -6674,6 +5783,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 #if defined(CONFIG_DRM_AMD_DC_DCN)
 	struct dsc_dec_dpcd_caps dsc_caps;
 #endif
+
 	struct dc_sink *sink = NULL;
 
 	memset(&saved_mode, 0, sizeof(saved_mode));
@@ -6737,7 +5847,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 			drm_mode_copy(&mode, freesync_mode);
 		} else {
 			decide_crtc_timing_for_drm_display_mode(
-				&mode, preferred_mode, scale);
+					&mode, preferred_mode, scale);
 
 			preferred_refresh = drm_mode_vrefresh(preferred_mode);
 		}
@@ -6748,7 +5858,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 	else if (!dm_state)
 		drm_mode_set_crtcinfo(&mode, 0);
 
-       /*
+	/*
 	* If scaling is enabled and refresh rate didn't change
 	* we copy the vic and polarities of the old timings
 	*/
@@ -6996,7 +6106,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
 	    !aconnector->fake_enable)
 		connected = (aconnector->dc_sink != NULL);
 	else
-		connected = (aconnector->base.force == DRM_FORCE_ON);
+		connected = (aconnector->base.force == DRM_FORCE_ON ||
+				aconnector->base.force == DRM_FORCE_ON_DIGITAL);
 
 	update_subconnector_property(aconnector);
 
@@ -7120,18 +6231,21 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
 	int i;
 
 	/*
-	 * Call only if mst_mgr was iniitalized before since it's not done
+	 * 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);
 
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
+	defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
 	for (i = 0; i < dm->num_of_edps; i++) {
 		if ((link == dm->backlight_link[i]) && dm->backlight_dev[i]) {
 			backlight_device_unregister(dm->backlight_dev[i]);
 			dm->backlight_dev[i] = NULL;
 		}
 	}
+#endif
 
 	if (aconnector->dc_em_sink)
 		dc_sink_release(aconnector->dc_em_sink);
@@ -7172,6 +6286,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
 		state->base.max_requested_bpc = 8;
 		state->vcpi_slots = 0;
 		state->pbn = 0;
+
 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
 			state->abm_level = amdgpu_dm_abm_level;
 
@@ -7561,10 +6676,10 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc,
 }
 
 static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
-				       struct drm_atomic_state *state)
+				      struct drm_atomic_state *state)
 {
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
-									  crtc);
+										crtc);
 	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
 	struct dc *dc = adev->dm.dc;
 	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
@@ -7575,7 +6690,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
 	dm_update_crtc_active_planes(crtc, crtc_state);
 
 	if (WARN_ON(unlikely(!dm_crtc_state->stream &&
-		     modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
+			modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
 		return ret;
 	}
 
@@ -7586,7 +6701,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
 	 * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
 	 */
 	if (crtc_state->enable &&
-	    !(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
+		!(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
 		DRM_DEBUG_ATOMIC("Can't enable a CRTC without enabling the primary plane\n");
 		return -EINVAL;
 	}
@@ -7624,21 +6739,21 @@ 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;
-		}
+	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;
 }
 
@@ -7669,7 +6784,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
 	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;
+			  aconnector->force_yuv420_output;
 		color_depth = convert_color_depth_from_display_info(connector,
 								    is_y420,
 								    max_bpc);
@@ -7724,7 +6839,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
 			if (!stream)
 				continue;
 
-			if ((struct amdgpu_dm_connector*)stream->dm_stream_context == aconnector)
+			if ((struct amdgpu_dm_connector *)stream->dm_stream_context == aconnector)
 				break;
 
 			stream = NULL;
@@ -7773,466 +6888,6 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
 }
 #endif
 
-static void dm_drm_plane_reset(struct drm_plane *plane)
-{
-	struct dm_plane_state *amdgpu_state = NULL;
-
-	if (plane->state)
-		plane->funcs->atomic_destroy_state(plane, plane->state);
-
-	amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
-	WARN_ON(amdgpu_state == NULL);
-
-	if (amdgpu_state)
-		__drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
-}
-
-static struct drm_plane_state *
-dm_drm_plane_duplicate_state(struct drm_plane *plane)
-{
-	struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
-
-	old_dm_plane_state = to_dm_plane_state(plane->state);
-	dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
-	if (!dm_plane_state)
-		return NULL;
-
-	__drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
-
-	if (old_dm_plane_state->dc_state) {
-		dm_plane_state->dc_state = old_dm_plane_state->dc_state;
-		dc_plane_state_retain(dm_plane_state->dc_state);
-	}
-
-	return &dm_plane_state->base;
-}
-
-static void dm_drm_plane_destroy_state(struct drm_plane *plane,
-				struct drm_plane_state *state)
-{
-	struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
-
-	if (dm_plane_state->dc_state)
-		dc_plane_state_release(dm_plane_state->dc_state);
-
-	drm_atomic_helper_plane_destroy_state(plane, state);
-}
-
-static const struct drm_plane_funcs dm_plane_funcs = {
-	.update_plane	= drm_atomic_helper_update_plane,
-	.disable_plane	= drm_atomic_helper_disable_plane,
-	.destroy	= drm_primary_helper_destroy,
-	.reset = dm_drm_plane_reset,
-	.atomic_duplicate_state = dm_drm_plane_duplicate_state,
-	.atomic_destroy_state = dm_drm_plane_destroy_state,
-	.format_mod_supported = dm_plane_format_mod_supported,
-};
-
-static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
-				      struct drm_plane_state *new_state)
-{
-	struct amdgpu_framebuffer *afb;
-	struct drm_gem_object *obj;
-	struct amdgpu_device *adev;
-	struct amdgpu_bo *rbo;
-	struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
-	struct list_head list;
-	struct ttm_validate_buffer tv;
-	struct ww_acquire_ctx ticket;
-	uint32_t domain;
-	int r;
-
-	if (!new_state->fb) {
-		DRM_DEBUG_KMS("No FB bound\n");
-		return 0;
-	}
-
-	afb = to_amdgpu_framebuffer(new_state->fb);
-	obj = new_state->fb->obj[0];
-	rbo = gem_to_amdgpu_bo(obj);
-	adev = amdgpu_ttm_adev(rbo->tbo.bdev);
-	INIT_LIST_HEAD(&list);
-
-	tv.bo = &rbo->tbo;
-	tv.num_shared = 1;
-	list_add(&tv.head, &list);
-
-	r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
-	if (r) {
-		dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
-		return r;
-	}
-
-	if (plane->type != DRM_PLANE_TYPE_CURSOR)
-		domain = amdgpu_display_supported_domains(adev, rbo->flags);
-	else
-		domain = AMDGPU_GEM_DOMAIN_VRAM;
-
-	r = amdgpu_bo_pin(rbo, domain);
-	if (unlikely(r != 0)) {
-		if (r != -ERESTARTSYS)
-			DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
-		ttm_eu_backoff_reservation(&ticket, &list);
-		return r;
-	}
-
-	r = amdgpu_ttm_alloc_gart(&rbo->tbo);
-	if (unlikely(r != 0)) {
-		amdgpu_bo_unpin(rbo);
-		ttm_eu_backoff_reservation(&ticket, &list);
-		DRM_ERROR("%p bind failed\n", rbo);
-		return r;
-	}
-
-	ttm_eu_backoff_reservation(&ticket, &list);
-
-	afb->address = amdgpu_bo_gpu_offset(rbo);
-
-	amdgpu_bo_ref(rbo);
-
-	/**
-	 * We don't do surface updates on planes that have been newly created,
-	 * but we also don't have the afb->address during atomic check.
-	 *
-	 * Fill in buffer attributes depending on the address here, but only on
-	 * newly created planes since they're not being used by DC yet and this
-	 * won't modify global state.
-	 */
-	dm_plane_state_old = to_dm_plane_state(plane->state);
-	dm_plane_state_new = to_dm_plane_state(new_state);
-
-	if (dm_plane_state_new->dc_state &&
-	    dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
-		struct dc_plane_state *plane_state =
-			dm_plane_state_new->dc_state;
-		bool force_disable_dcc = !plane_state->dcc.enable;
-
-		fill_plane_buffer_attributes(
-			adev, afb, plane_state->format, plane_state->rotation,
-			afb->tiling_flags,
-			&plane_state->tiling_info, &plane_state->plane_size,
-			&plane_state->dcc, &plane_state->address,
-			afb->tmz_surface, force_disable_dcc);
-	}
-
-	return 0;
-}
-
-static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
-				       struct drm_plane_state *old_state)
-{
-	struct amdgpu_bo *rbo;
-	int r;
-
-	if (!old_state->fb)
-		return;
-
-	rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
-	r = amdgpu_bo_reserve(rbo, false);
-	if (unlikely(r)) {
-		DRM_ERROR("failed to reserve rbo before unpin\n");
-		return;
-	}
-
-	amdgpu_bo_unpin(rbo);
-	amdgpu_bo_unreserve(rbo);
-	amdgpu_bo_unref(&rbo);
-}
-
-static int dm_plane_helper_check_state(struct drm_plane_state *state,
-				       struct drm_crtc_state *new_crtc_state)
-{
-	struct drm_framebuffer *fb = state->fb;
-	int min_downscale, max_upscale;
-	int min_scale = 0;
-	int max_scale = INT_MAX;
-
-	/* Plane enabled? Validate viewport and get scaling factors from plane caps. */
-	if (fb && state->crtc) {
-		/* Validate viewport to cover the case when only the position changes */
-		if (state->plane->type != DRM_PLANE_TYPE_CURSOR) {
-			int viewport_width = state->crtc_w;
-			int viewport_height = state->crtc_h;
-
-			if (state->crtc_x < 0)
-				viewport_width += state->crtc_x;
-			else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay)
-				viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x;
-
-			if (state->crtc_y < 0)
-				viewport_height += state->crtc_y;
-			else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
-				viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
-
-			if (viewport_width < 0 || viewport_height < 0) {
-				DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
-				return -EINVAL;
-			} else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
-				DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
-				return -EINVAL;
-			} else if (viewport_height < MIN_VIEWPORT_SIZE) {
-				DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
-				return -EINVAL;
-			}
-
-		}
-
-		/* Get min/max allowed scaling factors from plane caps. */
-		get_min_max_dc_plane_scaling(state->crtc->dev, fb,
-					     &min_downscale, &max_upscale);
-		/*
-		 * Convert to drm convention: 16.16 fixed point, instead of dc's
-		 * 1.0 == 1000. Also drm scaling is src/dst instead of dc's
-		 * dst/src, so min_scale = 1.0 / max_upscale, etc.
-		 */
-		min_scale = (1000 << 16) / max_upscale;
-		max_scale = (1000 << 16) / min_downscale;
-	}
-
-	return drm_atomic_helper_check_plane_state(
-		state, new_crtc_state, min_scale, max_scale, true, true);
-}
-
-static int dm_plane_atomic_check(struct drm_plane *plane,
-				 struct drm_atomic_state *state)
-{
-	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
-										 plane);
-	struct amdgpu_device *adev = drm_to_adev(plane->dev);
-	struct dc *dc = adev->dm.dc;
-	struct dm_plane_state *dm_plane_state;
-	struct dc_scaling_info scaling_info;
-	struct drm_crtc_state *new_crtc_state;
-	int ret;
-
-	trace_amdgpu_dm_plane_atomic_check(new_plane_state);
-
-	dm_plane_state = to_dm_plane_state(new_plane_state);
-
-	if (!dm_plane_state->dc_state)
-		return 0;
-
-	new_crtc_state =
-		drm_atomic_get_new_crtc_state(state,
-					      new_plane_state->crtc);
-	if (!new_crtc_state)
-		return -EINVAL;
-
-	ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
-	if (ret)
-		return ret;
-
-	ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
-	if (ret)
-		return ret;
-
-	if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
-		return 0;
-
-	return -EINVAL;
-}
-
-static int dm_plane_atomic_async_check(struct drm_plane *plane,
-				       struct drm_atomic_state *state)
-{
-	/* Only support async updates on cursor planes. */
-	if (plane->type != DRM_PLANE_TYPE_CURSOR)
-		return -EINVAL;
-
-	return 0;
-}
-
-static void dm_plane_atomic_async_update(struct drm_plane *plane,
-					 struct drm_atomic_state *state)
-{
-	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
-									   plane);
-	struct drm_plane_state *old_state =
-		drm_atomic_get_old_plane_state(state, plane);
-
-	trace_amdgpu_dm_atomic_update_cursor(new_state);
-
-	swap(plane->state->fb, new_state->fb);
-
-	plane->state->src_x = new_state->src_x;
-	plane->state->src_y = new_state->src_y;
-	plane->state->src_w = new_state->src_w;
-	plane->state->src_h = new_state->src_h;
-	plane->state->crtc_x = new_state->crtc_x;
-	plane->state->crtc_y = new_state->crtc_y;
-	plane->state->crtc_w = new_state->crtc_w;
-	plane->state->crtc_h = new_state->crtc_h;
-
-	handle_cursor_update(plane, old_state);
-}
-
-static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
-	.prepare_fb = dm_plane_helper_prepare_fb,
-	.cleanup_fb = dm_plane_helper_cleanup_fb,
-	.atomic_check = dm_plane_atomic_check,
-	.atomic_async_check = dm_plane_atomic_async_check,
-	.atomic_async_update = dm_plane_atomic_async_update
-};
-
-/*
- * TODO: these are currently initialized to rgb formats only.
- * For future use cases we should either initialize them dynamically based on
- * plane capabilities, or initialize this array to all formats, so internal drm
- * check will succeed, and let DC implement proper check
- */
-static const uint32_t rgb_formats[] = {
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_ARGB8888,
-	DRM_FORMAT_RGBA8888,
-	DRM_FORMAT_XRGB2101010,
-	DRM_FORMAT_XBGR2101010,
-	DRM_FORMAT_ARGB2101010,
-	DRM_FORMAT_ABGR2101010,
-	DRM_FORMAT_XRGB16161616,
-	DRM_FORMAT_XBGR16161616,
-	DRM_FORMAT_ARGB16161616,
-	DRM_FORMAT_ABGR16161616,
-	DRM_FORMAT_XBGR8888,
-	DRM_FORMAT_ABGR8888,
-	DRM_FORMAT_RGB565,
-};
-
-static const uint32_t overlay_formats[] = {
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_ARGB8888,
-	DRM_FORMAT_RGBA8888,
-	DRM_FORMAT_XBGR8888,
-	DRM_FORMAT_ABGR8888,
-	DRM_FORMAT_RGB565
-};
-
-static const u32 cursor_formats[] = {
-	DRM_FORMAT_ARGB8888
-};
-
-static int get_plane_formats(const struct drm_plane *plane,
-			     const struct dc_plane_cap *plane_cap,
-			     uint32_t *formats, int max_formats)
-{
-	int i, num_formats = 0;
-
-	/*
-	 * TODO: Query support for each group of formats directly from
-	 * DC plane caps. This will require adding more formats to the
-	 * caps list.
-	 */
-
-	switch (plane->type) {
-	case DRM_PLANE_TYPE_PRIMARY:
-		for (i = 0; i < ARRAY_SIZE(rgb_formats); ++i) {
-			if (num_formats >= max_formats)
-				break;
-
-			formats[num_formats++] = rgb_formats[i];
-		}
-
-		if (plane_cap && plane_cap->pixel_format_support.nv12)
-			formats[num_formats++] = DRM_FORMAT_NV12;
-		if (plane_cap && plane_cap->pixel_format_support.p010)
-			formats[num_formats++] = DRM_FORMAT_P010;
-		if (plane_cap && plane_cap->pixel_format_support.fp16) {
-			formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
-			formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
-			formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
-			formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
-		}
-		break;
-
-	case DRM_PLANE_TYPE_OVERLAY:
-		for (i = 0; i < ARRAY_SIZE(overlay_formats); ++i) {
-			if (num_formats >= max_formats)
-				break;
-
-			formats[num_formats++] = overlay_formats[i];
-		}
-		break;
-
-	case DRM_PLANE_TYPE_CURSOR:
-		for (i = 0; i < ARRAY_SIZE(cursor_formats); ++i) {
-			if (num_formats >= max_formats)
-				break;
-
-			formats[num_formats++] = cursor_formats[i];
-		}
-		break;
-	}
-
-	return num_formats;
-}
-
-static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
-				struct drm_plane *plane,
-				unsigned long possible_crtcs,
-				const struct dc_plane_cap *plane_cap)
-{
-	uint32_t formats[32];
-	int num_formats;
-	int res = -EPERM;
-	unsigned int supported_rotations;
-	uint64_t *modifiers = NULL;
-
-	num_formats = get_plane_formats(plane, plane_cap, formats,
-					ARRAY_SIZE(formats));
-
-	res = get_plane_modifiers(dm->adev, plane->type, &modifiers);
-	if (res)
-		return res;
-
-	res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
-				       &dm_plane_funcs, formats, num_formats,
-				       modifiers, plane->type, NULL);
-	kfree(modifiers);
-	if (res)
-		return res;
-
-	if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
-	    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);
-
-		drm_plane_create_alpha_property(plane);
-		drm_plane_create_blend_mode_property(plane, blend_caps);
-	}
-
-	if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
-	    plane_cap &&
-	    (plane_cap->pixel_format_support.nv12 ||
-	     plane_cap->pixel_format_support.p010)) {
-		/* This only affects YUV formats. */
-		drm_plane_create_color_properties(
-			plane,
-			BIT(DRM_COLOR_YCBCR_BT601) |
-			BIT(DRM_COLOR_YCBCR_BT709) |
-			BIT(DRM_COLOR_YCBCR_BT2020),
-			BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
-			BIT(DRM_COLOR_YCBCR_FULL_RANGE),
-			DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
-	}
-
-	supported_rotations =
-		DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
-		DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
-
-	if (dm->adev->asic_type >= CHIP_BONAIRE &&
-	    plane->type != DRM_PLANE_TYPE_CURSOR)
-		drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
-						   supported_rotations);
-
-	drm_plane_helper_add(plane, &dm_plane_helper_funcs);
-
-	/* Create (reset) the plane state */
-	if (plane->funcs->reset)
-		plane->funcs->reset(plane);
-
-	return 0;
-}
-
 static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
 			       struct drm_plane *plane,
 			       uint32_t crtc_index)
@@ -9072,114 +7727,6 @@ static void remove_stream(struct amdgpu_device *adev,
 	acrtc->enabled = false;
 }
 
-static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
-			       struct dc_cursor_position *position)
-{
-	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-	int x, y;
-	int xorigin = 0, yorigin = 0;
-
-	if (!crtc || !plane->state->fb)
-		return 0;
-
-	if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
-	    (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
-		DRM_ERROR("%s: bad cursor width or height %d x %d\n",
-			  __func__,
-			  plane->state->crtc_w,
-			  plane->state->crtc_h);
-		return -EINVAL;
-	}
-
-	x = plane->state->crtc_x;
-	y = plane->state->crtc_y;
-
-	if (x <= -amdgpu_crtc->max_cursor_width ||
-	    y <= -amdgpu_crtc->max_cursor_height)
-		return 0;
-
-	if (x < 0) {
-		xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
-		x = 0;
-	}
-	if (y < 0) {
-		yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
-		y = 0;
-	}
-	position->enable = true;
-	position->translate_by_source = true;
-	position->x = x;
-	position->y = y;
-	position->x_hotspot = xorigin;
-	position->y_hotspot = yorigin;
-
-	return 0;
-}
-
-static void handle_cursor_update(struct drm_plane *plane,
-				 struct drm_plane_state *old_plane_state)
-{
-	struct amdgpu_device *adev = drm_to_adev(plane->dev);
-	struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
-	struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
-	struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
-	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
-	uint64_t address = afb ? afb->address : 0;
-	struct dc_cursor_position position = {0};
-	struct dc_cursor_attributes attributes;
-	int ret;
-
-	if (!plane->state->fb && !old_plane_state->fb)
-		return;
-
-	DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
-		      __func__,
-		      amdgpu_crtc->crtc_id,
-		      plane->state->crtc_w,
-		      plane->state->crtc_h);
-
-	ret = get_cursor_position(plane, crtc, &position);
-	if (ret)
-		return;
-
-	if (!position.enable) {
-		/* turn off cursor */
-		if (crtc_state && crtc_state->stream) {
-			mutex_lock(&adev->dm.dc_lock);
-			dc_stream_set_cursor_position(crtc_state->stream,
-						      &position);
-			mutex_unlock(&adev->dm.dc_lock);
-		}
-		return;
-	}
-
-	amdgpu_crtc->cursor_width = plane->state->crtc_w;
-	amdgpu_crtc->cursor_height = plane->state->crtc_h;
-
-	memset(&attributes, 0, sizeof(attributes));
-	attributes.address.high_part = upper_32_bits(address);
-	attributes.address.low_part  = lower_32_bits(address);
-	attributes.width             = plane->state->crtc_w;
-	attributes.height            = plane->state->crtc_h;
-	attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
-	attributes.rotation_angle    = 0;
-	attributes.attribute_flags.value = 0;
-
-	attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
-
-	if (crtc_state->stream) {
-		mutex_lock(&adev->dm.dc_lock);
-		if (!dc_stream_set_cursor_attributes(crtc_state->stream,
-							 &attributes))
-			DRM_ERROR("DC failed to set cursor attributes\n");
-
-		if (!dc_stream_set_cursor_position(crtc_state->stream,
-						   &position))
-			DRM_ERROR("DC failed to set cursor position\n");
-		mutex_unlock(&adev->dm.dc_lock);
-	}
-}
-
 static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
 {
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
new file mode 100644
index 000000000000..e27621e11947
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -0,0 +1,1637 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_fourcc.h>
+
+#include "amdgpu.h"
+#include "dal_asic_id.h"
+#include "amdgpu_display.h"
+#include "amdgpu_dm_trace.h"
+#include "gc/gc_11_0_0_offset.h"
+#include "gc/gc_11_0_0_sh_mask.h"
+
+/*
+ * TODO: these are currently initialized to rgb formats only.
+ * For future use cases we should either initialize them dynamically based on
+ * plane capabilities, or initialize this array to all formats, so internal drm
+ * check will succeed, and let DC implement proper check
+ */
+static const uint32_t rgb_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_XRGB16161616,
+	DRM_FORMAT_XBGR16161616,
+	DRM_FORMAT_ARGB16161616,
+	DRM_FORMAT_ABGR16161616,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB565,
+};
+
+static const uint32_t overlay_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_RGB565
+};
+
+static const u32 cursor_formats[] = {
+	DRM_FORMAT_ARGB8888
+};
+
+enum dm_micro_swizzle {
+	MICRO_SWIZZLE_Z = 0,
+	MICRO_SWIZZLE_S = 1,
+	MICRO_SWIZZLE_D = 2,
+	MICRO_SWIZZLE_R = 3
+};
+
+const struct drm_format_info *amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
+{
+	return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]);
+}
+
+void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
+			       bool *per_pixel_alpha, bool *pre_multiplied_alpha,
+			       bool *global_alpha, int *global_alpha_value)
+{
+	*per_pixel_alpha = false;
+	*pre_multiplied_alpha = true;
+	*global_alpha = false;
+	*global_alpha_value = 0xff;
+
+	if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
+		return;
+
+	if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
+		plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
+		static const uint32_t alpha_formats[] = {
+			DRM_FORMAT_ARGB8888,
+			DRM_FORMAT_RGBA8888,
+			DRM_FORMAT_ABGR8888,
+		};
+		uint32_t format = plane_state->fb->format->format;
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
+			if (format == alpha_formats[i]) {
+				*per_pixel_alpha = true;
+				break;
+			}
+		}
+
+		if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
+			*pre_multiplied_alpha = false;
+	}
+
+	if (plane_state->alpha < 0xffff) {
+		*global_alpha = true;
+		*global_alpha_value = plane_state->alpha >> 8;
+	}
+}
+
+static void add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod)
+{
+	if (!*mods)
+		return;
+
+	if (*cap - *size < 1) {
+		uint64_t new_cap = *cap * 2;
+		uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL);
+
+		if (!new_mods) {
+			kfree(*mods);
+			*mods = NULL;
+			return;
+		}
+
+		memcpy(new_mods, *mods, sizeof(uint64_t) * *size);
+		kfree(*mods);
+		*mods = new_mods;
+		*cap = new_cap;
+	}
+
+	(*mods)[*size] = mod;
+	*size += 1;
+}
+
+bool modifier_has_dcc(uint64_t modifier)
+{
+	return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
+}
+
+unsigned modifier_gfx9_swizzle_mode(uint64_t modifier)
+{
+	if (modifier == DRM_FORMAT_MOD_LINEAR)
+		return 0;
+
+	return AMD_FMT_MOD_GET(TILE, modifier);
+}
+
+static void fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info,
+				 uint64_t tiling_flags)
+{
+	/* Fill GFX8 params */
+	if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
+		unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
+
+		bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
+		bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
+		mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
+		tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
+		num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
+
+		/* XXX fix me for VI */
+		tiling_info->gfx8.num_banks = num_banks;
+		tiling_info->gfx8.array_mode =
+				DC_ARRAY_2D_TILED_THIN1;
+		tiling_info->gfx8.tile_split = tile_split;
+		tiling_info->gfx8.bank_width = bankw;
+		tiling_info->gfx8.bank_height = bankh;
+		tiling_info->gfx8.tile_aspect = mtaspect;
+		tiling_info->gfx8.tile_mode =
+				DC_ADDR_SURF_MICRO_TILING_DISPLAY;
+	} else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
+			== DC_ARRAY_1D_TILED_THIN1) {
+		tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
+	}
+
+	tiling_info->gfx8.pipe_config =
+			AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
+}
+
+static void fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev,
+				  union dc_tiling_info *tiling_info)
+{
+	/* Fill GFX9 params */
+	tiling_info->gfx9.num_pipes =
+		adev->gfx.config.gb_addr_config_fields.num_pipes;
+	tiling_info->gfx9.num_banks =
+		adev->gfx.config.gb_addr_config_fields.num_banks;
+	tiling_info->gfx9.pipe_interleave =
+		adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
+	tiling_info->gfx9.num_shader_engines =
+		adev->gfx.config.gb_addr_config_fields.num_se;
+	tiling_info->gfx9.max_compressed_frags =
+		adev->gfx.config.gb_addr_config_fields.max_compress_frags;
+	tiling_info->gfx9.num_rb_per_se =
+		adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
+	tiling_info->gfx9.shaderEnable = 1;
+	if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
+		tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;
+}
+
+static void fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev,
+				    union dc_tiling_info *tiling_info,
+				    uint64_t modifier)
+{
+	unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
+	unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
+	unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier);
+	unsigned int pipes_log2;
+
+	pipes_log2 = min(5u, mod_pipe_xor_bits);
+
+	fill_gfx9_tiling_info_from_device(adev, tiling_info);
+
+	if (!IS_AMD_FMT_MOD(modifier))
+		return;
+
+	tiling_info->gfx9.num_pipes = 1u << pipes_log2;
+	tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2);
+
+	if (adev->family >= AMDGPU_FAMILY_NV) {
+		tiling_info->gfx9.num_pkrs = 1u << pkrs_log2;
+	} else {
+		tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits;
+
+		/* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */
+	}
+}
+
+static int validate_dcc(struct amdgpu_device *adev,
+	     const enum surface_pixel_format format,
+	     const enum dc_rotation_angle rotation,
+	     const union dc_tiling_info *tiling_info,
+	     const struct dc_plane_dcc_param *dcc,
+	     const struct dc_plane_address *address,
+	     const struct plane_size *plane_size)
+{
+	struct dc *dc = adev->dm.dc;
+	struct dc_dcc_surface_param input;
+	struct dc_surface_dcc_cap output;
+
+	memset(&input, 0, sizeof(input));
+	memset(&output, 0, sizeof(output));
+
+	if (!dcc->enable)
+		return 0;
+
+	if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
+	    !dc->cap_funcs.get_dcc_compression_cap)
+		return -EINVAL;
+
+	input.format = format;
+	input.surface_size.width = plane_size->surface_size.width;
+	input.surface_size.height = plane_size->surface_size.height;
+	input.swizzle_mode = tiling_info->gfx9.swizzle;
+
+	if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180)
+		input.scan = SCAN_DIRECTION_HORIZONTAL;
+	else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270)
+		input.scan = SCAN_DIRECTION_VERTICAL;
+
+	if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
+		return -EINVAL;
+
+	if (!output.capable)
+		return -EINVAL;
+
+	if (dcc->independent_64b_blks == 0 &&
+	    output.grph.rgb.independent_64b_blks != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
+					  const struct amdgpu_framebuffer *afb,
+					  const enum surface_pixel_format format,
+					  const enum dc_rotation_angle rotation,
+					  const struct plane_size *plane_size,
+					  union dc_tiling_info *tiling_info,
+					  struct dc_plane_dcc_param *dcc,
+					  struct dc_plane_address *address,
+					  const bool force_disable_dcc)
+{
+	const uint64_t modifier = afb->base.modifier;
+	int ret = 0;
+
+	fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
+	tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
+
+	if (modifier_has_dcc(modifier) && !force_disable_dcc) {
+		uint64_t dcc_address = afb->address + afb->base.offsets[1];
+		bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
+		bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
+
+		dcc->enable = 1;
+		dcc->meta_pitch = afb->base.pitches[1];
+		dcc->independent_64b_blks = independent_64b_blks;
+		if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
+			if (independent_64b_blks && independent_128b_blks)
+				dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl;
+			else if (independent_128b_blks)
+				dcc->dcc_ind_blk = hubp_ind_block_128b;
+			else if (independent_64b_blks && !independent_128b_blks)
+				dcc->dcc_ind_blk = hubp_ind_block_64b;
+			else
+				dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
+		} else {
+			if (independent_64b_blks)
+				dcc->dcc_ind_blk = hubp_ind_block_64b;
+			else
+				dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
+		}
+
+		address->grph.meta_addr.low_part = lower_32_bits(dcc_address);
+		address->grph.meta_addr.high_part = upper_32_bits(dcc_address);
+	}
+
+	ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
+	if (ret)
+		drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
+
+	return ret;
+}
+
+static void add_gfx10_1_modifiers(const struct amdgpu_device *adev,
+		      uint64_t **mods, uint64_t *size, uint64_t *capacity)
+{
+	int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(DCC, 1) |
+		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(DCC, 1) |
+		    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
+
+
+	/* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+}
+
+static void add_gfx9_modifiers(const struct amdgpu_device *adev,
+		   uint64_t **mods, uint64_t *size, uint64_t *capacity)
+{
+	int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
+	int pipe_xor_bits = min(8, pipes +
+				ilog2(adev->gfx.config.gb_addr_config_fields.num_se));
+	int bank_xor_bits = min(8 - pipe_xor_bits,
+				ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));
+	int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +
+		 ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);
+
+
+	if (adev->family == AMDGPU_FAMILY_RV) {
+		/* Raven2 and later */
+		bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81;
+
+		/*
+		 * No _D DCC swizzles yet because we only allow 32bpp, which
+		 * doesn't support _D on DCN
+		 */
+
+		if (has_constant_encode) {
+			add_modifier(mods, size, capacity, AMD_FMT_MOD |
+				    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+				    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+				    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+				    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
+				    AMD_FMT_MOD_SET(DCC, 1) |
+				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+				    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
+				    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));
+		}
+
+		add_modifier(mods, size, capacity, AMD_FMT_MOD |
+			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+			    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+			    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
+			    AMD_FMT_MOD_SET(DCC, 1) |
+			    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+			    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
+			    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0));
+
+		if (has_constant_encode) {
+			add_modifier(mods, size, capacity, AMD_FMT_MOD |
+				    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+				    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+				    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+				    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
+				    AMD_FMT_MOD_SET(DCC, 1) |
+				    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+				    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
+
+				    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+				    AMD_FMT_MOD_SET(RB, rb) |
+				    AMD_FMT_MOD_SET(PIPE, pipes));
+		}
+
+		add_modifier(mods, size, capacity, AMD_FMT_MOD |
+			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+			    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+			    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
+			    AMD_FMT_MOD_SET(DCC, 1) |
+			    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+			    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+			    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
+			    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) |
+			    AMD_FMT_MOD_SET(RB, rb) |
+			    AMD_FMT_MOD_SET(PIPE, pipes));
+	}
+
+	/*
+	 * Only supported for 64bpp on Raven, will be filtered on format in
+	 * dm_plane_format_mod_supported.
+	 */
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
+
+	if (adev->family == AMDGPU_FAMILY_RV) {
+		add_modifier(mods, size, capacity, AMD_FMT_MOD |
+			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
+			    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+			    AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
+	}
+
+	/*
+	 * Only supported for 64bpp on Raven, will be filtered on format in
+	 * dm_plane_format_mod_supported.
+	 */
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+
+	if (adev->family == AMDGPU_FAMILY_RV) {
+		add_modifier(mods, size, capacity, AMD_FMT_MOD |
+			    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
+			    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+	}
+}
+
+static void add_gfx10_3_modifiers(const struct amdgpu_device *adev,
+		      uint64_t **mods, uint64_t *size, uint64_t *capacity)
+{
+	int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
+	int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs);
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
+		    AMD_FMT_MOD_SET(DCC, 1) |
+		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
+		    AMD_FMT_MOD_SET(DCC, 1) |
+		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
+		    AMD_FMT_MOD_SET(DCC, 1) |
+		    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(PACKERS, pkrs) |
+		    AMD_FMT_MOD_SET(DCC, 1) |
+		    AMD_FMT_MOD_SET(DCC_RETILE, 1) |
+		    AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
+		    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+		    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(PACKERS, pkrs));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
+		    AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+		    AMD_FMT_MOD_SET(PACKERS, pkrs));
+
+	/* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+		    AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
+		    AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
+}
+
+static void add_gfx11_modifiers(struct amdgpu_device *adev,
+		      uint64_t **mods, uint64_t *size, uint64_t *capacity)
+{
+	int num_pipes = 0;
+	int pipe_xor_bits = 0;
+	int num_pkrs = 0;
+	int pkrs = 0;
+	u32 gb_addr_config;
+	u8 i = 0;
+	unsigned swizzle_r_x;
+	uint64_t modifier_r_x;
+	uint64_t modifier_dcc_best;
+	uint64_t modifier_dcc_4k;
+
+	/* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from
+	 * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes}
+	 */
+	gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG);
+	ASSERT(gb_addr_config != 0);
+
+	num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS);
+	pkrs = ilog2(num_pkrs);
+	num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES);
+	pipe_xor_bits = ilog2(num_pipes);
+
+	for (i = 0; i < 2; i++) {
+		/* Insert the best one first. */
+		/* R_X swizzle modes are the best for rendering and DCC requires them. */
+		if (num_pipes > 16)
+			swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : AMD_FMT_MOD_TILE_GFX9_64K_R_X;
+		else
+			swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX9_64K_R_X : AMD_FMT_MOD_TILE_GFX11_256K_R_X;
+
+		modifier_r_x = AMD_FMT_MOD |
+			       AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
+			       AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
+			       AMD_FMT_MOD_SET(TILE, swizzle_r_x) |
+			       AMD_FMT_MOD_SET(PACKERS, pkrs);
+
+		/* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */
+		modifier_dcc_best = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
+				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) |
+				    AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+				    AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B);
+
+		/* DCC settings for 4K and greater resolutions. (required by display hw) */
+		modifier_dcc_4k = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
+				  AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
+				  AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
+				  AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B);
+
+		add_modifier(mods, size, capacity, modifier_dcc_best);
+		add_modifier(mods, size, capacity, modifier_dcc_4k);
+
+		add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1));
+		add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1));
+
+		add_modifier(mods, size, capacity, modifier_r_x);
+	}
+
+	add_modifier(mods, size, capacity, AMD_FMT_MOD |
+			AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
+			AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D));
+}
+
+static int get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods)
+{
+	uint64_t size = 0, capacity = 128;
+	*mods = NULL;
+
+	/* We have not hooked up any pre-GFX9 modifiers. */
+	if (adev->family < AMDGPU_FAMILY_AI)
+		return 0;
+
+	*mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL);
+
+	if (plane_type == DRM_PLANE_TYPE_CURSOR) {
+		add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
+		add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
+		return *mods ? 0 : -ENOMEM;
+	}
+
+	switch (adev->family) {
+	case AMDGPU_FAMILY_AI:
+	case AMDGPU_FAMILY_RV:
+		add_gfx9_modifiers(adev, mods, &size, &capacity);
+		break;
+	case AMDGPU_FAMILY_NV:
+	case AMDGPU_FAMILY_VGH:
+	case AMDGPU_FAMILY_YC:
+	case AMDGPU_FAMILY_GC_10_3_6:
+	case AMDGPU_FAMILY_GC_10_3_7:
+		if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
+			add_gfx10_3_modifiers(adev, mods, &size, &capacity);
+		else
+			add_gfx10_1_modifiers(adev, mods, &size, &capacity);
+		break;
+	case AMDGPU_FAMILY_GC_11_0_0:
+	case AMDGPU_FAMILY_GC_11_0_2:
+		add_gfx11_modifiers(adev, mods, &size, &capacity);
+		break;
+	}
+
+	add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
+
+	/* INVALID marks the end of the list. */
+	add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
+
+	if (!*mods)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int get_plane_formats(const struct drm_plane *plane,
+			     const struct dc_plane_cap *plane_cap,
+			     uint32_t *formats, int max_formats)
+{
+	int i, num_formats = 0;
+
+	/*
+	 * TODO: Query support for each group of formats directly from
+	 * DC plane caps. This will require adding more formats to the
+	 * caps list.
+	 */
+
+	switch (plane->type) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		for (i = 0; i < ARRAY_SIZE(rgb_formats); ++i) {
+			if (num_formats >= max_formats)
+				break;
+
+			formats[num_formats++] = rgb_formats[i];
+		}
+
+		if (plane_cap && plane_cap->pixel_format_support.nv12)
+			formats[num_formats++] = DRM_FORMAT_NV12;
+		if (plane_cap && plane_cap->pixel_format_support.p010)
+			formats[num_formats++] = DRM_FORMAT_P010;
+		if (plane_cap && plane_cap->pixel_format_support.fp16) {
+			formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
+			formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
+			formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
+			formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
+		}
+		break;
+
+	case DRM_PLANE_TYPE_OVERLAY:
+		for (i = 0; i < ARRAY_SIZE(overlay_formats); ++i) {
+			if (num_formats >= max_formats)
+				break;
+
+			formats[num_formats++] = overlay_formats[i];
+		}
+		break;
+
+	case DRM_PLANE_TYPE_CURSOR:
+		for (i = 0; i < ARRAY_SIZE(cursor_formats); ++i) {
+			if (num_formats >= max_formats)
+				break;
+
+			formats[num_formats++] = cursor_formats[i];
+		}
+		break;
+	}
+
+	return num_formats;
+}
+
+#ifdef CONFIG_DRM_AMD_DC_HDR
+static int attach_color_mgmt_properties(struct amdgpu_display_manager *dm, struct drm_plane *plane)
+{
+	drm_object_attach_property(&plane->base,
+				   dm->degamma_lut_property,
+				   0);
+	drm_object_attach_property(&plane->base,
+				   dm->degamma_lut_size_property,
+				   MAX_COLOR_LUT_ENTRIES);
+	drm_object_attach_property(&plane->base, dm->ctm_property,
+				   0);
+	drm_object_attach_property(&plane->base, dm->sdr_boost_property,
+				   DEFAULT_SDR_BOOST);
+
+	return 0;
+}
+#endif
+
+int fill_plane_buffer_attributes(struct amdgpu_device *adev,
+			     const struct amdgpu_framebuffer *afb,
+			     const enum surface_pixel_format format,
+			     const enum dc_rotation_angle rotation,
+			     const uint64_t tiling_flags,
+			     union dc_tiling_info *tiling_info,
+			     struct plane_size *plane_size,
+			     struct dc_plane_dcc_param *dcc,
+			     struct dc_plane_address *address,
+			     bool tmz_surface,
+			     bool force_disable_dcc)
+{
+	const struct drm_framebuffer *fb = &afb->base;
+	int ret;
+
+	memset(tiling_info, 0, sizeof(*tiling_info));
+	memset(plane_size, 0, sizeof(*plane_size));
+	memset(dcc, 0, sizeof(*dcc));
+	memset(address, 0, sizeof(*address));
+
+	address->tmz_surface = tmz_surface;
+
+	if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+		uint64_t addr = afb->address + fb->offsets[0];
+
+		plane_size->surface_size.x = 0;
+		plane_size->surface_size.y = 0;
+		plane_size->surface_size.width = fb->width;
+		plane_size->surface_size.height = fb->height;
+		plane_size->surface_pitch =
+			fb->pitches[0] / fb->format->cpp[0];
+
+		address->type = PLN_ADDR_TYPE_GRAPHICS;
+		address->grph.addr.low_part = lower_32_bits(addr);
+		address->grph.addr.high_part = upper_32_bits(addr);
+	} else if (format < SURFACE_PIXEL_FORMAT_INVALID) {
+		uint64_t luma_addr = afb->address + fb->offsets[0];
+		uint64_t chroma_addr = afb->address + fb->offsets[1];
+
+		plane_size->surface_size.x = 0;
+		plane_size->surface_size.y = 0;
+		plane_size->surface_size.width = fb->width;
+		plane_size->surface_size.height = fb->height;
+		plane_size->surface_pitch =
+			fb->pitches[0] / fb->format->cpp[0];
+
+		plane_size->chroma_size.x = 0;
+		plane_size->chroma_size.y = 0;
+		/* TODO: set these based on surface format */
+		plane_size->chroma_size.width = fb->width / 2;
+		plane_size->chroma_size.height = fb->height / 2;
+
+		plane_size->chroma_pitch =
+			fb->pitches[1] / fb->format->cpp[1];
+
+		address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
+		address->video_progressive.luma_addr.low_part =
+			lower_32_bits(luma_addr);
+		address->video_progressive.luma_addr.high_part =
+			upper_32_bits(luma_addr);
+		address->video_progressive.chroma_addr.low_part =
+			lower_32_bits(chroma_addr);
+		address->video_progressive.chroma_addr.high_part =
+			upper_32_bits(chroma_addr);
+	}
+
+	if (adev->family >= AMDGPU_FAMILY_AI) {
+		ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format,
+								rotation, plane_size,
+								tiling_info, dcc,
+								address,
+								force_disable_dcc);
+		if (ret)
+			return ret;
+	} else {
+		fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags);
+	}
+
+	return 0;
+}
+
+static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
+				      struct drm_plane_state *new_state)
+{
+	struct amdgpu_framebuffer *afb;
+	struct drm_gem_object *obj;
+	struct amdgpu_device *adev;
+	struct amdgpu_bo *rbo;
+	struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
+	struct list_head list;
+	struct ttm_validate_buffer tv;
+	struct ww_acquire_ctx ticket;
+	uint32_t domain;
+	int r;
+
+	if (!new_state->fb) {
+		DRM_DEBUG_KMS("No FB bound\n");
+		return 0;
+	}
+
+	afb = to_amdgpu_framebuffer(new_state->fb);
+	obj = new_state->fb->obj[0];
+	rbo = gem_to_amdgpu_bo(obj);
+	adev = amdgpu_ttm_adev(rbo->tbo.bdev);
+	INIT_LIST_HEAD(&list);
+
+	tv.bo = &rbo->tbo;
+	tv.num_shared = 1;
+	list_add(&tv.head, &list);
+
+	r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
+	if (r) {
+		dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
+		return r;
+	}
+
+	if (plane->type != DRM_PLANE_TYPE_CURSOR)
+		domain = amdgpu_display_supported_domains(adev, rbo->flags);
+	else
+		domain = AMDGPU_GEM_DOMAIN_VRAM;
+
+	r = amdgpu_bo_pin(rbo, domain);
+	if (unlikely(r != 0)) {
+		if (r != -ERESTARTSYS)
+			DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
+		ttm_eu_backoff_reservation(&ticket, &list);
+		return r;
+	}
+
+	r = amdgpu_ttm_alloc_gart(&rbo->tbo);
+	if (unlikely(r != 0)) {
+		amdgpu_bo_unpin(rbo);
+		ttm_eu_backoff_reservation(&ticket, &list);
+		DRM_ERROR("%p bind failed\n", rbo);
+		return r;
+	}
+
+	ttm_eu_backoff_reservation(&ticket, &list);
+
+	afb->address = amdgpu_bo_gpu_offset(rbo);
+
+	amdgpu_bo_ref(rbo);
+
+	/**
+	 * We don't do surface updates on planes that have been newly created,
+	 * but we also don't have the afb->address during atomic check.
+	 *
+	 * Fill in buffer attributes depending on the address here, but only on
+	 * newly created planes since they're not being used by DC yet and this
+	 * won't modify global state.
+	 */
+	dm_plane_state_old = to_dm_plane_state(plane->state);
+	dm_plane_state_new = to_dm_plane_state(new_state);
+
+	if (dm_plane_state_new->dc_state &&
+	    dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
+		struct dc_plane_state *plane_state =
+			dm_plane_state_new->dc_state;
+		bool force_disable_dcc = !plane_state->dcc.enable;
+
+		fill_plane_buffer_attributes(
+			adev, afb, plane_state->format, plane_state->rotation,
+			afb->tiling_flags,
+			&plane_state->tiling_info, &plane_state->plane_size,
+			&plane_state->dcc, &plane_state->address,
+			afb->tmz_surface, force_disable_dcc);
+	}
+
+	return 0;
+}
+
+static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+	struct amdgpu_bo *rbo;
+	int r;
+
+	if (!old_state->fb)
+		return;
+
+	rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
+	r = amdgpu_bo_reserve(rbo, false);
+	if (unlikely(r)) {
+		DRM_ERROR("failed to reserve rbo before unpin\n");
+		return;
+	}
+
+	amdgpu_bo_unpin(rbo);
+	amdgpu_bo_unreserve(rbo);
+	amdgpu_bo_unref(&rbo);
+}
+
+static void get_min_max_dc_plane_scaling(struct drm_device *dev,
+					 struct drm_framebuffer *fb,
+					 int *min_downscale, int *max_upscale)
+{
+	struct amdgpu_device *adev = drm_to_adev(dev);
+	struct dc *dc = adev->dm.dc;
+	/* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
+	struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_P010:
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		*max_upscale = plane_cap->max_upscale_factor.nv12;
+		*min_downscale = plane_cap->max_downscale_factor.nv12;
+		break;
+
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		*max_upscale = plane_cap->max_upscale_factor.fp16;
+		*min_downscale = plane_cap->max_downscale_factor.fp16;
+		break;
+
+	default:
+		*max_upscale = plane_cap->max_upscale_factor.argb8888;
+		*min_downscale = plane_cap->max_downscale_factor.argb8888;
+		break;
+	}
+
+	/*
+	 * A factor of 1 in the plane_cap means to not allow scaling, ie. use a
+	 * scaling factor of 1.0 == 1000 units.
+	 */
+	if (*max_upscale == 1)
+		*max_upscale = 1000;
+
+	if (*min_downscale == 1)
+		*min_downscale = 1000;
+}
+
+int dm_plane_helper_check_state(struct drm_plane_state *state,
+				       struct drm_crtc_state *new_crtc_state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	int min_downscale, max_upscale;
+	int min_scale = 0;
+	int max_scale = INT_MAX;
+
+	/* Plane enabled? Validate viewport and get scaling factors from plane caps. */
+	if (fb && state->crtc) {
+		/* Validate viewport to cover the case when only the position changes */
+		if (state->plane->type != DRM_PLANE_TYPE_CURSOR) {
+			int viewport_width = state->crtc_w;
+			int viewport_height = state->crtc_h;
+
+			if (state->crtc_x < 0)
+				viewport_width += state->crtc_x;
+			else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay)
+				viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x;
+
+			if (state->crtc_y < 0)
+				viewport_height += state->crtc_y;
+			else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
+				viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
+
+			if (viewport_width < 0 || viewport_height < 0) {
+				DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
+				return -EINVAL;
+			} else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
+				DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
+				return -EINVAL;
+			} else if (viewport_height < MIN_VIEWPORT_SIZE) {
+				DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
+				return -EINVAL;
+			}
+
+		}
+
+		/* Get min/max allowed scaling factors from plane caps. */
+		get_min_max_dc_plane_scaling(state->crtc->dev, fb,
+					     &min_downscale, &max_upscale);
+		/*
+		 * Convert to drm convention: 16.16 fixed point, instead of dc's
+		 * 1.0 == 1000. Also drm scaling is src/dst instead of dc's
+		 * dst/src, so min_scale = 1.0 / max_upscale, etc.
+		 */
+		min_scale = (1000 << 16) / max_upscale;
+		max_scale = (1000 << 16) / min_downscale;
+	}
+
+	return drm_atomic_helper_check_plane_state(
+		state, new_crtc_state, min_scale, max_scale, true, true);
+}
+
+int fill_dc_scaling_info(struct amdgpu_device *adev,
+				const struct drm_plane_state *state,
+				struct dc_scaling_info *scaling_info)
+{
+	int scale_w, scale_h, min_downscale, max_upscale;
+
+	memset(scaling_info, 0, sizeof(*scaling_info));
+
+	/* Source is fixed 16.16 but we ignore mantissa for now... */
+	scaling_info->src_rect.x = state->src_x >> 16;
+	scaling_info->src_rect.y = state->src_y >> 16;
+
+	/*
+	 * For reasons we don't (yet) fully understand a non-zero
+	 * src_y coordinate into an NV12 buffer can cause a
+	 * system hang on DCN1x.
+	 * To avoid hangs (and maybe be overly cautious)
+	 * let's reject both non-zero src_x and src_y.
+	 *
+	 * We currently know of only one use-case to reproduce a
+	 * scenario with non-zero src_x and src_y for NV12, which
+	 * is to gesture the YouTube Android app into full screen
+	 * on ChromeOS.
+	 */
+	if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) ||
+	    (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) &&
+	    (state->fb && state->fb->format->format == DRM_FORMAT_NV12 &&
+	    (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0)))
+		return -EINVAL;
+
+	scaling_info->src_rect.width = state->src_w >> 16;
+	if (scaling_info->src_rect.width == 0)
+		return -EINVAL;
+
+	scaling_info->src_rect.height = state->src_h >> 16;
+	if (scaling_info->src_rect.height == 0)
+		return -EINVAL;
+
+	scaling_info->dst_rect.x = state->crtc_x;
+	scaling_info->dst_rect.y = state->crtc_y;
+
+	if (state->crtc_w == 0)
+		return -EINVAL;
+
+	scaling_info->dst_rect.width = state->crtc_w;
+
+	if (state->crtc_h == 0)
+		return -EINVAL;
+
+	scaling_info->dst_rect.height = state->crtc_h;
+
+	/* DRM doesn't specify clipping on destination output. */
+	scaling_info->clip_rect = scaling_info->dst_rect;
+
+	/* Validate scaling per-format with DC plane caps */
+	if (state->plane && state->plane->dev && state->fb) {
+		get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
+					     &min_downscale, &max_upscale);
+	} else {
+		min_downscale = 250;
+		max_upscale = 16000;
+	}
+
+	scale_w = scaling_info->dst_rect.width * 1000 /
+		  scaling_info->src_rect.width;
+
+	if (scale_w < min_downscale || scale_w > max_upscale)
+		return -EINVAL;
+
+	scale_h = scaling_info->dst_rect.height * 1000 /
+		  scaling_info->src_rect.height;
+
+	if (scale_h < min_downscale || scale_h > max_upscale)
+		return -EINVAL;
+
+	/*
+	 * The "scaling_quality" can be ignored for now, quality = 0 has DC
+	 * assume reasonable defaults based on the format.
+	 */
+
+	return 0;
+}
+
+static int dm_plane_atomic_check(struct drm_plane *plane,
+				 struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
+										 plane);
+	struct amdgpu_device *adev = drm_to_adev(plane->dev);
+	struct dc *dc = adev->dm.dc;
+	struct dm_plane_state *dm_plane_state;
+	struct dc_scaling_info scaling_info;
+	struct drm_crtc_state *new_crtc_state;
+	int ret;
+
+	trace_amdgpu_dm_plane_atomic_check(new_plane_state);
+
+	dm_plane_state = to_dm_plane_state(new_plane_state);
+
+	if (!dm_plane_state->dc_state)
+		return 0;
+
+	new_crtc_state =
+		drm_atomic_get_new_crtc_state(state,
+					      new_plane_state->crtc);
+	if (!new_crtc_state)
+		return -EINVAL;
+
+	ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
+	if (ret)
+		return ret;
+
+	ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
+	if (ret)
+		return ret;
+
+	if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
+		return 0;
+
+	return -EINVAL;
+}
+
+static int dm_plane_atomic_async_check(struct drm_plane *plane,
+				       struct drm_atomic_state *state)
+{
+	/* Only support async updates on cursor planes. */
+	if (plane->type != DRM_PLANE_TYPE_CURSOR)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
+			       struct dc_cursor_position *position)
+{
+	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	int x, y;
+	int xorigin = 0, yorigin = 0;
+
+	if (!crtc || !plane->state->fb)
+		return 0;
+
+	if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
+	    (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
+		DRM_ERROR("%s: bad cursor width or height %d x %d\n",
+			  __func__,
+			  plane->state->crtc_w,
+			  plane->state->crtc_h);
+		return -EINVAL;
+	}
+
+	x = plane->state->crtc_x;
+	y = plane->state->crtc_y;
+
+	if (x <= -amdgpu_crtc->max_cursor_width ||
+	    y <= -amdgpu_crtc->max_cursor_height)
+		return 0;
+
+	if (x < 0) {
+		xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
+		x = 0;
+	}
+	if (y < 0) {
+		yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
+		y = 0;
+	}
+	position->enable = true;
+	position->translate_by_source = true;
+	position->x = x;
+	position->y = y;
+	position->x_hotspot = xorigin;
+	position->y_hotspot = yorigin;
+
+	return 0;
+}
+
+void handle_cursor_update(struct drm_plane *plane,
+				 struct drm_plane_state *old_plane_state)
+{
+	struct amdgpu_device *adev = drm_to_adev(plane->dev);
+	struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
+	struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
+	struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
+	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+	uint64_t address = afb ? afb->address : 0;
+	struct dc_cursor_position position = {0};
+	struct dc_cursor_attributes attributes;
+	int ret;
+
+	if (!plane->state->fb && !old_plane_state->fb)
+		return;
+
+	DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
+		      __func__,
+		      amdgpu_crtc->crtc_id,
+		      plane->state->crtc_w,
+		      plane->state->crtc_h);
+
+	ret = get_cursor_position(plane, crtc, &position);
+	if (ret)
+		return;
+
+	if (!position.enable) {
+		/* turn off cursor */
+		if (crtc_state && crtc_state->stream) {
+			mutex_lock(&adev->dm.dc_lock);
+			dc_stream_set_cursor_position(crtc_state->stream,
+						      &position);
+			mutex_unlock(&adev->dm.dc_lock);
+		}
+		return;
+	}
+
+	amdgpu_crtc->cursor_width = plane->state->crtc_w;
+	amdgpu_crtc->cursor_height = plane->state->crtc_h;
+
+	memset(&attributes, 0, sizeof(attributes));
+	attributes.address.high_part = upper_32_bits(address);
+	attributes.address.low_part  = lower_32_bits(address);
+	attributes.width             = plane->state->crtc_w;
+	attributes.height            = plane->state->crtc_h;
+	attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
+	attributes.rotation_angle    = 0;
+	attributes.attribute_flags.value = 0;
+
+	attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
+
+	if (crtc_state->stream) {
+		mutex_lock(&adev->dm.dc_lock);
+		if (!dc_stream_set_cursor_attributes(crtc_state->stream,
+							 &attributes))
+			DRM_ERROR("DC failed to set cursor attributes\n");
+
+		if (!dc_stream_set_cursor_position(crtc_state->stream,
+						   &position))
+			DRM_ERROR("DC failed to set cursor position\n");
+		mutex_unlock(&adev->dm.dc_lock);
+	}
+}
+
+static void dm_plane_atomic_async_update(struct drm_plane *plane,
+					 struct drm_atomic_state *state)
+{
+	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
+									   plane);
+	struct drm_plane_state *old_state =
+		drm_atomic_get_old_plane_state(state, plane);
+
+	trace_amdgpu_dm_atomic_update_cursor(new_state);
+
+	swap(plane->state->fb, new_state->fb);
+
+	plane->state->src_x = new_state->src_x;
+	plane->state->src_y = new_state->src_y;
+	plane->state->src_w = new_state->src_w;
+	plane->state->src_h = new_state->src_h;
+	plane->state->crtc_x = new_state->crtc_x;
+	plane->state->crtc_y = new_state->crtc_y;
+	plane->state->crtc_w = new_state->crtc_w;
+	plane->state->crtc_h = new_state->crtc_h;
+
+	handle_cursor_update(plane, old_state);
+}
+
+static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
+	.prepare_fb = dm_plane_helper_prepare_fb,
+	.cleanup_fb = dm_plane_helper_cleanup_fb,
+	.atomic_check = dm_plane_atomic_check,
+	.atomic_async_check = dm_plane_atomic_async_check,
+	.atomic_async_update = dm_plane_atomic_async_update
+};
+
+static void dm_drm_plane_reset(struct drm_plane *plane)
+{
+	struct dm_plane_state *amdgpu_state = NULL;
+
+	if (plane->state)
+		plane->funcs->atomic_destroy_state(plane, plane->state);
+
+	amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
+	WARN_ON(amdgpu_state == NULL);
+
+	if (amdgpu_state)
+		__drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
+#ifdef CONFIG_DRM_AMD_DC_HDR
+	if (amdgpu_state)
+		amdgpu_state->sdr_boost = DEFAULT_SDR_BOOST;
+#endif
+}
+
+static struct drm_plane_state *
+dm_drm_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
+
+	old_dm_plane_state = to_dm_plane_state(plane->state);
+	dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
+	if (!dm_plane_state)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
+
+	if (old_dm_plane_state->dc_state) {
+		dm_plane_state->dc_state = old_dm_plane_state->dc_state;
+		dc_plane_state_retain(dm_plane_state->dc_state);
+	}
+
+#ifdef CONFIG_DRM_AMD_DC_HDR
+	if (dm_plane_state->degamma_lut)
+		drm_property_blob_get(dm_plane_state->degamma_lut);
+	if (dm_plane_state->ctm)
+		drm_property_blob_get(dm_plane_state->ctm);
+
+	dm_plane_state->sdr_boost = old_dm_plane_state->sdr_boost;
+#endif
+
+	return &dm_plane_state->base;
+}
+
+static bool dm_plane_format_mod_supported(struct drm_plane *plane,
+					  uint32_t format,
+					  uint64_t modifier)
+{
+	struct amdgpu_device *adev = drm_to_adev(plane->dev);
+	const struct drm_format_info *info = drm_format_info(format);
+	struct hw_asic_id asic_id = adev->dm.dc->ctx->asic_id;
+
+	enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3;
+
+	if (!info)
+		return false;
+
+	/*
+	 * We always have to allow these modifiers:
+	 * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
+	 * 2. Not passing any modifiers is the same as explicitly passing INVALID.
+	 */
+	if (modifier == DRM_FORMAT_MOD_LINEAR ||
+	    modifier == DRM_FORMAT_MOD_INVALID) {
+		return true;
+	}
+
+	/* check if swizzle mode is supported by this version of DCN */
+	switch (asic_id.chip_family) {
+	case FAMILY_SI:
+	case FAMILY_CI:
+	case FAMILY_KV:
+	case FAMILY_CZ:
+	case FAMILY_VI:
+		/* asics before AI does not have modifier support */
+		return false;
+	case FAMILY_AI:
+	case FAMILY_RV:
+	case FAMILY_NV:
+	case FAMILY_VGH:
+	case FAMILY_YELLOW_CARP:
+	case AMDGPU_FAMILY_GC_10_3_6:
+	case AMDGPU_FAMILY_GC_10_3_7:
+		switch (AMD_FMT_MOD_GET(TILE, modifier)) {
+		case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_D:
+			return true;
+		default:
+			return false;
+		}
+		break;
+	case AMDGPU_FAMILY_GC_11_0_0:
+		switch (AMD_FMT_MOD_GET(TILE, modifier)) {
+		case AMD_FMT_MOD_TILE_GFX11_256K_R_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
+		case AMD_FMT_MOD_TILE_GFX9_64K_D:
+			return true;
+		default:
+			return false;
+		}
+		break;
+	default:
+		ASSERT(0); /* Unknown asic */
+		break;
+	}
+
+	/*
+	 * For D swizzle the canonical modifier depends on the bpp, so check
+	 * it here.
+	 */
+	if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 &&
+	    adev->family >= AMDGPU_FAMILY_NV) {
+		if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4)
+			return false;
+	}
+
+	if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D &&
+	    info->cpp[0] < 8)
+		return false;
+
+	if (modifier_has_dcc(modifier)) {
+		/* Per radeonsi comments 16/64 bpp are more complicated. */
+		if (info->cpp[0] != 4)
+			return false;
+		/* We support multi-planar formats, but not when combined with
+		 * additional DCC metadata planes.
+		 */
+		if (info->num_planes > 1)
+			return false;
+	}
+
+	return true;
+}
+
+static void dm_drm_plane_destroy_state(struct drm_plane *plane,
+				struct drm_plane_state *state)
+{
+	struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+
+#ifdef CONFIG_DRM_AMD_DC_HDR
+	drm_property_blob_put(dm_plane_state->degamma_lut);
+	drm_property_blob_put(dm_plane_state->ctm);
+#endif
+	if (dm_plane_state->dc_state)
+		dc_plane_state_release(dm_plane_state->dc_state);
+
+	drm_atomic_helper_plane_destroy_state(plane, state);
+}
+
+#ifdef CONFIG_DRM_AMD_DC_HDR
+/* copied from drm_atomic_uapi.c */
+static int atomic_replace_property_blob_from_id(struct drm_device *dev,
+					 struct drm_property_blob **blob,
+					 uint64_t blob_id,
+					 ssize_t expected_size,
+					 ssize_t expected_elem_size,
+					 bool *replaced)
+{
+	struct drm_property_blob *new_blob = NULL;
+
+	if (blob_id != 0) {
+		new_blob = drm_property_lookup_blob(dev, blob_id);
+		if (new_blob == NULL)
+			return -EINVAL;
+
+		if (expected_size > 0 &&
+		    new_blob->length != expected_size) {
+			drm_property_blob_put(new_blob);
+			return -EINVAL;
+		}
+		if (expected_elem_size > 0 &&
+		    new_blob->length % expected_elem_size != 0) {
+			drm_property_blob_put(new_blob);
+			return -EINVAL;
+		}
+	}
+
+	*replaced |= drm_property_replace_blob(blob, new_blob);
+	drm_property_blob_put(new_blob);
+
+	return 0;
+}
+
+int dm_drm_plane_set_property(struct drm_plane *plane,
+			      struct drm_plane_state *state,
+			      struct drm_property *property,
+			      uint64_t val)
+{
+	struct amdgpu_device *adev = drm_to_adev(plane->dev);
+	struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+	int ret = 0;
+	bool replaced;
+
+	if (property == adev->dm.degamma_lut_property) {
+		ret = atomic_replace_property_blob_from_id(adev_to_drm(adev),
+				&dm_plane_state->degamma_lut,
+				val, -1, sizeof(struct drm_color_lut),
+				&replaced);
+	} else if (property == adev->dm.ctm_property) {
+		ret = atomic_replace_property_blob_from_id(adev_to_drm(adev),
+				&dm_plane_state->ctm,
+				val,
+				sizeof(struct drm_color_ctm), -1,
+				&replaced);
+	} else if (property == adev->dm.sdr_boost_property) {
+		dm_plane_state->sdr_boost = val;
+	} else {
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int dm_drm_plane_get_property(struct drm_plane *plane,
+			      const struct drm_plane_state *state,
+			      struct drm_property *property,
+			      uint64_t *val)
+{
+	struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+	struct amdgpu_device *adev = drm_to_adev(plane->dev);
+
+	if (property == adev->dm.degamma_lut_property) {
+		*val = (dm_plane_state->degamma_lut) ?
+			dm_plane_state->degamma_lut->base.id : 0;
+	} else if (property == adev->dm.ctm_property) {
+		*val = (dm_plane_state->ctm) ? dm_plane_state->ctm->base.id : 0;
+	} else if (property == adev->dm.sdr_boost_property) {
+		*val = dm_plane_state->sdr_boost;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+static const struct drm_plane_funcs dm_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.destroy	= drm_primary_helper_destroy,
+	.reset = dm_drm_plane_reset,
+	.atomic_duplicate_state = dm_drm_plane_duplicate_state,
+	.atomic_destroy_state = dm_drm_plane_destroy_state,
+	.format_mod_supported = dm_plane_format_mod_supported,
+#ifdef CONFIG_DRM_AMD_DC_HDR
+	.atomic_set_property = dm_drm_plane_set_property,
+	.atomic_get_property = dm_drm_plane_get_property,
+#endif
+};
+
+int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
+				struct drm_plane *plane,
+				unsigned long possible_crtcs,
+				const struct dc_plane_cap *plane_cap)
+{
+	uint32_t formats[32];
+	int num_formats;
+	int res = -EPERM;
+	unsigned int supported_rotations;
+	uint64_t *modifiers = NULL;
+
+	num_formats = get_plane_formats(plane, plane_cap, formats,
+					ARRAY_SIZE(formats));
+
+	res = get_plane_modifiers(dm->adev, plane->type, &modifiers);
+	if (res)
+		return res;
+
+	res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
+				       &dm_plane_funcs, formats, num_formats,
+				       modifiers, plane->type, NULL);
+	kfree(modifiers);
+	if (res)
+		return res;
+
+	if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
+	    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);
+
+		drm_plane_create_alpha_property(plane);
+		drm_plane_create_blend_mode_property(plane, blend_caps);
+	}
+
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
+	    plane_cap &&
+	    (plane_cap->pixel_format_support.nv12 ||
+	     plane_cap->pixel_format_support.p010)) {
+		/* This only affects YUV formats. */
+		drm_plane_create_color_properties(
+			plane,
+			BIT(DRM_COLOR_YCBCR_BT601) |
+			BIT(DRM_COLOR_YCBCR_BT709) |
+			BIT(DRM_COLOR_YCBCR_BT2020),
+			BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+			BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+			DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
+	}
+
+	supported_rotations =
+		DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
+		DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
+
+	if (dm->adev->asic_type >= CHIP_BONAIRE &&
+	    plane->type != DRM_PLANE_TYPE_CURSOR)
+		drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
+						   supported_rotations);
+
+	drm_plane_helper_add(plane, &dm_plane_helper_funcs);
+
+#ifdef CONFIG_DRM_AMD_DC_HDR
+	attach_color_mgmt_properties(dm, plane);
+#endif
+	/* Create (reset) the plane state */
+	if (plane->funcs->reset)
+		plane->funcs->reset(plane);
+
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
new file mode 100644
index 000000000000..95168c2cfa6f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __AMDGPU_DM_PLANE_H__
+#define __AMDGPU_DM_PLANE_H__
+
+#include "dc.h"
+
+void handle_cursor_update(struct drm_plane *plane,
+			  struct drm_plane_state *old_plane_state);
+
+int fill_dc_scaling_info(struct amdgpu_device *adev,
+			 const struct drm_plane_state *state,
+			 struct dc_scaling_info *scaling_info);
+
+void get_min_max_dc_plane_scaling(struct drm_device *dev,
+				  struct drm_framebuffer *fb,
+				  int *min_downscale, int *max_upscale);
+
+int dm_plane_helper_check_state(struct drm_plane_state *state,
+				struct drm_crtc_state *new_crtc_state);
+
+bool modifier_has_dcc(uint64_t modifier);
+
+unsigned int modifier_gfx9_swizzle_mode(uint64_t modifier);
+
+int fill_plane_buffer_attributes(struct amdgpu_device *adev,
+				 const struct amdgpu_framebuffer *afb,
+				 const enum surface_pixel_format format,
+				 const enum dc_rotation_angle rotation,
+				 const uint64_t tiling_flags,
+				 union dc_tiling_info *tiling_info,
+				 struct plane_size *plane_size,
+				 struct dc_plane_dcc_param *dcc,
+				 struct dc_plane_address *address,
+				 bool tmz_surface,
+				 bool force_disable_dcc);
+
+int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
+			 struct drm_plane *plane,
+			 unsigned long possible_crtcs,
+			 const struct dc_plane_cap *plane_cap);
+
+const struct drm_format_info *amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
+
+void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
+				    bool *per_pixel_alpha, bool *pre_multiplied_alpha,
+				    bool *global_alpha, int *global_alpha_value);
+
+#endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 09/31] drm/amd/display: Create a file dedicated for CRTC
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (7 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 08/31] drm/amd/display: Create a file dedicated to planes Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-20 17:36   ` André Almeida
  2022-07-15 18:16 ` [PATCH 10/31] drm/amd/display: remove number of DSC slices override in DML Rodrigo Siqueira
                   ` (22 subsequent siblings)
  31 siblings, 1 reply; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

[Why]
The amdgpu_dm file contains most of the code that works as an interface
between DRM API and DC. As a result, this file becomes very large since
it comprises multiple abstractions such as CRTC manipulation.

[How]
This commit extracts the CRTC code to its specific file named
amdgpu_dm_crtc. This change does not change anything inside the
functions; the only exception is converting some static functions to a
global function.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/Makefile    |   1 +
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 434 +---------------
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    | 463 ++++++++++++++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.h    |  51 ++
 4 files changed, 516 insertions(+), 433 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
index ec559ea902a3..90fb0f3cdb6f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
@@ -28,6 +28,7 @@
 AMDGPUDM = \
 	amdgpu_dm.o \
 	amdgpu_dm_plane.o \
+	amdgpu_dm_crtc.o \
 	amdgpu_dm_irq.o \
 	amdgpu_dm_mst_types.o \
 	amdgpu_dm_color.o
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ceac70e93ece..bf01ed340ec3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -47,6 +47,7 @@
 #include "atom.h"
 #include "amdgpu_dm.h"
 #include "amdgpu_dm_plane.h"
+#include "amdgpu_dm_crtc.h"
 #ifdef CONFIG_DRM_AMD_DC_HDCP
 #include "amdgpu_dm_hdcp.h"
 #include <drm/drm_hdcp.h>
@@ -204,9 +205,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev);
 /* 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_crtc_init(struct amdgpu_display_manager *dm,
-			       struct drm_plane *plane,
-			       uint32_t link_index);
 static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
 				    struct amdgpu_dm_connector *amdgpu_dm_connector,
 				    uint32_t link_index,
@@ -335,20 +333,6 @@ get_crtc_by_otg_inst(struct amdgpu_device *adev,
 	return NULL;
 }
 
-static inline bool amdgpu_dm_vrr_active_irq(struct amdgpu_crtc *acrtc)
-{
-	return acrtc->dm_irq_params.freesync_config.state ==
-		       VRR_STATE_ACTIVE_VARIABLE ||
-	       acrtc->dm_irq_params.freesync_config.state ==
-		       VRR_STATE_ACTIVE_FIXED;
-}
-
-static inline bool amdgpu_dm_vrr_active(struct dm_crtc_state *dm_state)
-{
-	return dm_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE ||
-	       dm_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
-}
-
 static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
 					      struct dm_crtc_state *new_state)
 {
@@ -464,26 +448,6 @@ static void dm_pflip_high_irq(void *interrupt_params)
 		     vrr_active, (int) !e);
 }
 
-static void dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
-{
-	struct drm_crtc *crtc = &acrtc->base;
-	struct drm_device *dev = crtc->dev;
-	unsigned long flags;
-
-	drm_crtc_handle_vblank(crtc);
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-
-	/* Send completion event for cursor-only commits */
-	if (acrtc->event && acrtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
-		drm_crtc_send_vblank_event(crtc, acrtc->event);
-		drm_crtc_vblank_put(crtc);
-		acrtc->event = NULL;
-	}
-
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
 static void dm_vupdate_high_irq(void *interrupt_params)
 {
 	struct common_irq_params *irq_params = interrupt_params;
@@ -1261,52 +1225,6 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
 
 }
 
-static void vblank_control_worker(struct work_struct *work)
-{
-	struct vblank_control_work *vblank_work =
-		container_of(work, struct vblank_control_work, work);
-	struct amdgpu_display_manager *dm = vblank_work->dm;
-
-	mutex_lock(&dm->dc_lock);
-
-	if (vblank_work->enable)
-		dm->active_vblank_irq_count++;
-	else if(dm->active_vblank_irq_count)
-		dm->active_vblank_irq_count--;
-
-	dc_allow_idle_optimizations(dm->dc, dm->active_vblank_irq_count == 0);
-
-	DRM_DEBUG_KMS("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0);
-
-	/*
-	 * Control PSR based on vblank requirements from OS
-	 *
-	 * If panel supports PSR SU, there's no need to disable PSR when OS is
-	 * submitting fast atomic commits (we infer this by whether the OS
-	 * requests vblank events). Fast atomic commits will simply trigger a
-	 * full-frame-update (FFU); a specific case of selective-update (SU)
-	 * where the SU region is the full hactive*vactive region. See
-	 * fill_dc_dirty_rects().
-	 */
-	if (vblank_work->stream && vblank_work->stream->link) {
-		if (vblank_work->enable) {
-			if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 &&
-			    vblank_work->stream->link->psr_settings.psr_allow_active)
-				amdgpu_dm_psr_disable(vblank_work->stream);
-		} else if (vblank_work->stream->link->psr_settings.psr_feature_enabled &&
-			   !vblank_work->stream->link->psr_settings.psr_allow_active &&
-			   vblank_work->acrtc->dm_irq_params.allow_psr_entry) {
-			amdgpu_dm_psr_enable(vblank_work->stream);
-		}
-	}
-
-	mutex_unlock(&dm->dc_lock);
-
-	dc_stream_release(vblank_work->stream);
-
-	kfree(vblank_work);
-}
-
 static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
 {
 	struct hpd_rx_irq_offload_work *offload_work;
@@ -2382,9 +2300,6 @@ static int dm_hw_fini(void *handle)
 }
 
 
-static int dm_enable_vblank(struct drm_crtc *crtc);
-static void dm_disable_vblank(struct drm_crtc *crtc);
-
 static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
 				 struct dc_state *state, bool enable)
 {
@@ -4676,13 +4591,6 @@ static int dm_early_init(void *handle)
 	return 0;
 }
 
-static bool modeset_required(struct drm_crtc_state *crtc_state,
-			     struct dc_stream_state *new_stream,
-			     struct dc_stream_state *old_stream)
-{
-	return crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
-}
-
 static bool modereset_required(struct drm_crtc_state *crtc_state)
 {
 	return !crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
@@ -5913,182 +5821,6 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 	return stream;
 }
 
-static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
-{
-	drm_crtc_cleanup(crtc);
-	kfree(crtc);
-}
-
-static void dm_crtc_destroy_state(struct drm_crtc *crtc,
-				  struct drm_crtc_state *state)
-{
-	struct dm_crtc_state *cur = to_dm_crtc_state(state);
-
-	/* TODO Destroy dc_stream objects are stream object is flattened */
-	if (cur->stream)
-		dc_stream_release(cur->stream);
-
-
-	__drm_atomic_helper_crtc_destroy_state(state);
-
-
-	kfree(state);
-}
-
-static void dm_crtc_reset_state(struct drm_crtc *crtc)
-{
-	struct dm_crtc_state *state;
-
-	if (crtc->state)
-		dm_crtc_destroy_state(crtc, crtc->state);
-
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (WARN_ON(!state))
-		return;
-
-	__drm_atomic_helper_crtc_reset(crtc, &state->base);
-}
-
-static struct drm_crtc_state *
-dm_crtc_duplicate_state(struct drm_crtc *crtc)
-{
-	struct dm_crtc_state *state, *cur;
-
-	cur = to_dm_crtc_state(crtc->state);
-
-	if (WARN_ON(!crtc->state))
-		return NULL;
-
-	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (!state)
-		return NULL;
-
-	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
-
-	if (cur->stream) {
-		state->stream = cur->stream;
-		dc_stream_retain(state->stream);
-	}
-
-	state->active_planes = cur->active_planes;
-	state->vrr_infopacket = cur->vrr_infopacket;
-	state->abm_level = cur->abm_level;
-	state->vrr_supported = cur->vrr_supported;
-	state->freesync_config = cur->freesync_config;
-	state->cm_has_degamma = cur->cm_has_degamma;
-	state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
-	state->mpo_requested = cur->mpo_requested;
-	/* TODO Duplicate dc_stream after objects are stream object is flattened */
-
-	return &state->base;
-}
-
-#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
-static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc)
-{
-	crtc_debugfs_init(crtc);
-
-	return 0;
-}
-#endif
-
-static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
-{
-	enum dc_irq_source irq_source;
-	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
-	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
-	int rc;
-
-	irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
-
-	rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
-
-	DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
-		      acrtc->crtc_id, enable ? "en" : "dis", rc);
-	return rc;
-}
-
-static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
-{
-	enum dc_irq_source irq_source;
-	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
-	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
-	struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
-	struct amdgpu_display_manager *dm = &adev->dm;
-	struct vblank_control_work *work;
-	int rc = 0;
-
-	if (enable) {
-		/* vblank irq on -> Only need vupdate irq in vrr mode */
-		if (amdgpu_dm_vrr_active(acrtc_state))
-			rc = dm_set_vupdate_irq(crtc, true);
-	} else {
-		/* vblank irq off -> vupdate irq off */
-		rc = dm_set_vupdate_irq(crtc, false);
-	}
-
-	if (rc)
-		return rc;
-
-	irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
-
-	if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
-		return -EBUSY;
-
-	if (amdgpu_in_reset(adev))
-		return 0;
-
-	if (dm->vblank_control_workqueue) {
-		work = kzalloc(sizeof(*work), GFP_ATOMIC);
-		if (!work)
-			return -ENOMEM;
-
-		INIT_WORK(&work->work, vblank_control_worker);
-		work->dm = dm;
-		work->acrtc = acrtc;
-		work->enable = enable;
-
-		if (acrtc_state->stream) {
-			dc_stream_retain(acrtc_state->stream);
-			work->stream = acrtc_state->stream;
-		}
-
-		queue_work(dm->vblank_control_workqueue, &work->work);
-	}
-
-	return 0;
-}
-
-static int dm_enable_vblank(struct drm_crtc *crtc)
-{
-	return dm_set_vblank(crtc, true);
-}
-
-static void dm_disable_vblank(struct drm_crtc *crtc)
-{
-	dm_set_vblank(crtc, false);
-}
-
-/* Implemented only the options currently available for the driver */
-static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
-	.reset = dm_crtc_reset_state,
-	.destroy = amdgpu_dm_crtc_destroy,
-	.set_config = drm_atomic_helper_set_config,
-	.page_flip = drm_atomic_helper_page_flip,
-	.atomic_duplicate_state = dm_crtc_duplicate_state,
-	.atomic_destroy_state = dm_crtc_destroy_state,
-	.set_crc_source = amdgpu_dm_crtc_set_crc_source,
-	.verify_crc_source = amdgpu_dm_crtc_verify_crc_source,
-	.get_crc_sources = amdgpu_dm_crtc_get_crc_sources,
-	.get_vblank_counter = amdgpu_get_vblank_counter_kms,
-	.enable_vblank = dm_enable_vblank,
-	.disable_vblank = dm_disable_vblank,
-	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
-#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
-	.late_register = amdgpu_dm_crtc_late_register,
-#endif
-};
-
 static enum drm_connector_status
 amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -6624,113 +6356,6 @@ amdgpu_dm_connector_helper_funcs = {
 	.atomic_check = amdgpu_dm_connector_atomic_check,
 };
 
-static void dm_crtc_helper_disable(struct drm_crtc *crtc)
-{
-}
-
-static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
-{
-	struct drm_atomic_state *state = new_crtc_state->state;
-	struct drm_plane *plane;
-	int num_active = 0;
-
-	drm_for_each_plane_mask(plane, state->dev, new_crtc_state->plane_mask) {
-		struct drm_plane_state *new_plane_state;
-
-		/* Cursor planes are "fake". */
-		if (plane->type == DRM_PLANE_TYPE_CURSOR)
-			continue;
-
-		new_plane_state = drm_atomic_get_new_plane_state(state, plane);
-
-		if (!new_plane_state) {
-			/*
-			 * The plane is enable on the CRTC and hasn't changed
-			 * state. This means that it previously passed
-			 * validation and is therefore enabled.
-			 */
-			num_active += 1;
-			continue;
-		}
-
-		/* We need a framebuffer to be considered enabled. */
-		num_active += (new_plane_state->fb != NULL);
-	}
-
-	return num_active;
-}
-
-static void dm_update_crtc_active_planes(struct drm_crtc *crtc,
-					 struct drm_crtc_state *new_crtc_state)
-{
-	struct dm_crtc_state *dm_new_crtc_state =
-		to_dm_crtc_state(new_crtc_state);
-
-	dm_new_crtc_state->active_planes = 0;
-
-	if (!dm_new_crtc_state->stream)
-		return;
-
-	dm_new_crtc_state->active_planes =
-		count_crtc_active_planes(new_crtc_state);
-}
-
-static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
-				      struct drm_atomic_state *state)
-{
-	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
-										crtc);
-	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
-	struct dc *dc = adev->dm.dc;
-	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
-	int ret = -EINVAL;
-
-	trace_amdgpu_dm_crtc_atomic_check(crtc_state);
-
-	dm_update_crtc_active_planes(crtc, crtc_state);
-
-	if (WARN_ON(unlikely(!dm_crtc_state->stream &&
-			modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
-		return ret;
-	}
-
-	/*
-	 * We require the primary plane to be enabled whenever the CRTC is, otherwise
-	 * drm_mode_cursor_universal may end up trying to enable the cursor plane while all other
-	 * planes are disabled, which is not supported by the hardware. And there is legacy
-	 * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
-	 */
-	if (crtc_state->enable &&
-		!(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
-		DRM_DEBUG_ATOMIC("Can't enable a CRTC without enabling the primary plane\n");
-		return -EINVAL;
-	}
-
-	/* In some use cases, like reset, no stream is attached */
-	if (!dm_crtc_state->stream)
-		return 0;
-
-	if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
-		return 0;
-
-	DRM_DEBUG_ATOMIC("Failed DC stream validation\n");
-	return ret;
-}
-
-static bool dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
-				      const struct drm_display_mode *mode,
-				      struct drm_display_mode *adjusted_mode)
-{
-	return true;
-}
-
-static const struct drm_crtc_helper_funcs amdgpu_dm_crtc_helper_funcs = {
-	.disable = dm_crtc_helper_disable,
-	.atomic_check = dm_crtc_helper_atomic_check,
-	.mode_fixup = dm_crtc_helper_mode_fixup,
-	.get_scanout_position = amdgpu_crtc_get_scanout_position,
-};
-
 static void dm_encoder_helper_disable(struct drm_encoder *encoder)
 {
 
@@ -6888,63 +6513,6 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
 }
 #endif
 
-static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
-			       struct drm_plane *plane,
-			       uint32_t crtc_index)
-{
-	struct amdgpu_crtc *acrtc = NULL;
-	struct drm_plane *cursor_plane;
-
-	int res = -ENOMEM;
-
-	cursor_plane = kzalloc(sizeof(*cursor_plane), GFP_KERNEL);
-	if (!cursor_plane)
-		goto fail;
-
-	cursor_plane->type = DRM_PLANE_TYPE_CURSOR;
-	res = amdgpu_dm_plane_init(dm, cursor_plane, 0, NULL);
-
-	acrtc = kzalloc(sizeof(struct amdgpu_crtc), GFP_KERNEL);
-	if (!acrtc)
-		goto fail;
-
-	res = drm_crtc_init_with_planes(
-			dm->ddev,
-			&acrtc->base,
-			plane,
-			cursor_plane,
-			&amdgpu_dm_crtc_funcs, NULL);
-
-	if (res)
-		goto fail;
-
-	drm_crtc_helper_add(&acrtc->base, &amdgpu_dm_crtc_helper_funcs);
-
-	/* Create (reset) the plane state */
-	if (acrtc->base.funcs->reset)
-		acrtc->base.funcs->reset(&acrtc->base);
-
-	acrtc->max_cursor_width = dm->adev->dm.dc->caps.max_cursor_size;
-	acrtc->max_cursor_height = dm->adev->dm.dc->caps.max_cursor_size;
-
-	acrtc->crtc_id = crtc_index;
-	acrtc->base.enabled = false;
-	acrtc->otg_inst = -1;
-
-	dm->adev->mode_info.crtcs[crtc_index] = acrtc;
-	drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
-				   true, MAX_COLOR_LUT_ENTRIES);
-	drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
-
-	return 0;
-
-fail:
-	kfree(acrtc);
-	kfree(cursor_plane);
-	return res;
-}
-
-
 static int to_drm_connector_type(enum signal_type st)
 {
 	switch (st) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
new file mode 100644
index 000000000000..a9413acfe4dc
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include <drm/drm_vblank.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "dc.h"
+#include "amdgpu.h"
+#include "amdgpu_dm_psr.h"
+#include "amdgpu_dm_crtc.h"
+#include "amdgpu_dm_plane.h"
+#include "amdgpu_dm_trace.h"
+#include "amdgpu_dm_debugfs.h"
+
+void dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
+{
+	struct drm_crtc *crtc = &acrtc->base;
+	struct drm_device *dev = crtc->dev;
+	unsigned long flags;
+
+	drm_crtc_handle_vblank(crtc);
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	/* Send completion event for cursor-only commits */
+	if (acrtc->event && acrtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
+		drm_crtc_send_vblank_event(crtc, acrtc->event);
+		drm_crtc_vblank_put(crtc);
+		acrtc->event = NULL;
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+bool modeset_required(struct drm_crtc_state *crtc_state,
+			     struct dc_stream_state *new_stream,
+			     struct dc_stream_state *old_stream)
+{
+	return crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state);
+}
+
+bool amdgpu_dm_vrr_active_irq(struct amdgpu_crtc *acrtc)
+
+{
+	return acrtc->dm_irq_params.freesync_config.state ==
+		       VRR_STATE_ACTIVE_VARIABLE ||
+	       acrtc->dm_irq_params.freesync_config.state ==
+		       VRR_STATE_ACTIVE_FIXED;
+}
+
+int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
+{
+	enum dc_irq_source irq_source;
+	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
+	int rc;
+
+	irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
+
+	rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+
+	DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
+		      acrtc->crtc_id, enable ? "en" : "dis", rc);
+	return rc;
+}
+
+bool amdgpu_dm_vrr_active(struct dm_crtc_state *dm_state)
+{
+	return dm_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE ||
+	       dm_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
+}
+
+static void vblank_control_worker(struct work_struct *work)
+{
+	struct vblank_control_work *vblank_work =
+		container_of(work, struct vblank_control_work, work);
+	struct amdgpu_display_manager *dm = vblank_work->dm;
+
+	mutex_lock(&dm->dc_lock);
+
+	if (vblank_work->enable)
+		dm->active_vblank_irq_count++;
+	else if (dm->active_vblank_irq_count)
+		dm->active_vblank_irq_count--;
+
+	dc_allow_idle_optimizations(
+		dm->dc, dm->active_vblank_irq_count == 0 ? true : false);
+
+	DRM_DEBUG_KMS("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0);
+
+	/*
+	 * Control PSR based on vblank requirements from OS
+	 *
+	 * If panel supports PSR SU, there's no need to disable PSR when OS is
+	 * submitting fast atomic commits (we infer this by whether the OS
+	 * requests vblank events). Fast atomic commits will simply trigger a
+	 * full-frame-update (FFU); a specific case of selective-update (SU)
+	 * where the SU region is the full hactive*vactive region. See
+	 * fill_dc_dirty_rects().
+	 */
+	if (vblank_work->stream && vblank_work->stream->link) {
+		if (vblank_work->enable) {
+			if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 &&
+			    vblank_work->stream->link->psr_settings.psr_allow_active)
+				amdgpu_dm_psr_disable(vblank_work->stream);
+		} else if (vblank_work->stream->link->psr_settings.psr_feature_enabled &&
+			   !vblank_work->stream->link->psr_settings.psr_allow_active &&
+			   vblank_work->acrtc->dm_irq_params.allow_psr_entry) {
+			amdgpu_dm_psr_enable(vblank_work->stream);
+		}
+	}
+
+	mutex_unlock(&dm->dc_lock);
+
+	dc_stream_release(vblank_work->stream);
+
+	kfree(vblank_work);
+}
+
+static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
+{
+	enum dc_irq_source irq_source;
+	struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
+	struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
+	struct amdgpu_display_manager *dm = &adev->dm;
+	struct vblank_control_work *work;
+	int rc = 0;
+
+	if (enable) {
+		/* vblank irq on -> Only need vupdate irq in vrr mode */
+		if (amdgpu_dm_vrr_active(acrtc_state))
+			rc = dm_set_vupdate_irq(crtc, true);
+	} else {
+		/* vblank irq off -> vupdate irq off */
+		rc = dm_set_vupdate_irq(crtc, false);
+	}
+
+	if (rc)
+		return rc;
+
+	irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
+
+	if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
+		return -EBUSY;
+
+	if (amdgpu_in_reset(adev))
+		return 0;
+
+	if (dm->vblank_control_workqueue) {
+		work = kzalloc(sizeof(*work), GFP_ATOMIC);
+		if (!work)
+			return -ENOMEM;
+
+		INIT_WORK(&work->work, vblank_control_worker);
+		work->dm = dm;
+		work->acrtc = acrtc;
+		work->enable = enable;
+
+		if (acrtc_state->stream) {
+			dc_stream_retain(acrtc_state->stream);
+			work->stream = acrtc_state->stream;
+		}
+
+		queue_work(dm->vblank_control_workqueue, &work->work);
+	}
+
+	return 0;
+}
+
+int dm_enable_vblank(struct drm_crtc *crtc)
+{
+	return dm_set_vblank(crtc, true);
+}
+
+void dm_disable_vblank(struct drm_crtc *crtc)
+{
+	dm_set_vblank(crtc, false);
+}
+
+static void dm_crtc_destroy_state(struct drm_crtc *crtc,
+				  struct drm_crtc_state *state)
+{
+	struct dm_crtc_state *cur = to_dm_crtc_state(state);
+
+	/* TODO Destroy dc_stream objects are stream object is flattened */
+	if (cur->stream)
+		dc_stream_release(cur->stream);
+
+
+	__drm_atomic_helper_crtc_destroy_state(state);
+
+
+	kfree(state);
+}
+
+static struct drm_crtc_state *dm_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+	struct dm_crtc_state *state, *cur;
+
+	cur = to_dm_crtc_state(crtc->state);
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+	if (cur->stream) {
+		state->stream = cur->stream;
+		dc_stream_retain(state->stream);
+	}
+
+	state->active_planes = cur->active_planes;
+	state->vrr_infopacket = cur->vrr_infopacket;
+	state->abm_level = cur->abm_level;
+	state->vrr_supported = cur->vrr_supported;
+	state->freesync_config = cur->freesync_config;
+	state->cm_has_degamma = cur->cm_has_degamma;
+	state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
+	state->mpo_requested = cur->mpo_requested;
+	/* TODO Duplicate dc_stream after objects are stream object is flattened */
+
+	return &state->base;
+}
+
+static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
+{
+	drm_crtc_cleanup(crtc);
+	kfree(crtc);
+}
+
+static void dm_crtc_reset_state(struct drm_crtc *crtc)
+{
+	struct dm_crtc_state *state;
+
+	if (crtc->state)
+		dm_crtc_destroy_state(crtc, crtc->state);
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (WARN_ON(!state))
+		return;
+
+	__drm_atomic_helper_crtc_reset(crtc, &state->base);
+}
+
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc)
+{
+	crtc_debugfs_init(crtc);
+
+	return 0;
+}
+#endif
+
+/* Implemented only the options currently available for the driver */
+static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
+	.reset = dm_crtc_reset_state,
+	.destroy = amdgpu_dm_crtc_destroy,
+	.set_config = drm_atomic_helper_set_config,
+	.page_flip = drm_atomic_helper_page_flip,
+	.atomic_duplicate_state = dm_crtc_duplicate_state,
+	.atomic_destroy_state = dm_crtc_destroy_state,
+	.set_crc_source = amdgpu_dm_crtc_set_crc_source,
+	.verify_crc_source = amdgpu_dm_crtc_verify_crc_source,
+	.get_crc_sources = amdgpu_dm_crtc_get_crc_sources,
+	.get_vblank_counter = amdgpu_get_vblank_counter_kms,
+	.enable_vblank = dm_enable_vblank,
+	.disable_vblank = dm_disable_vblank,
+	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
+#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
+	.late_register = amdgpu_dm_crtc_late_register,
+#endif
+};
+
+static void dm_crtc_helper_disable(struct drm_crtc *crtc)
+{
+}
+
+static int count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
+{
+	struct drm_atomic_state *state = new_crtc_state->state;
+	struct drm_plane *plane;
+	int num_active = 0;
+
+	drm_for_each_plane_mask(plane, state->dev, new_crtc_state->plane_mask) {
+		struct drm_plane_state *new_plane_state;
+
+		/* Cursor planes are "fake". */
+		if (plane->type == DRM_PLANE_TYPE_CURSOR)
+			continue;
+
+		new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+
+		if (!new_plane_state) {
+			/*
+			 * The plane is enable on the CRTC and hasn't changed
+			 * state. This means that it previously passed
+			 * validation and is therefore enabled.
+			 */
+			num_active += 1;
+			continue;
+		}
+
+		/* We need a framebuffer to be considered enabled. */
+		num_active += (new_plane_state->fb != NULL);
+	}
+
+	return num_active;
+}
+
+static void dm_update_crtc_active_planes(struct drm_crtc *crtc,
+					 struct drm_crtc_state *new_crtc_state)
+{
+	struct dm_crtc_state *dm_new_crtc_state =
+		to_dm_crtc_state(new_crtc_state);
+
+	dm_new_crtc_state->active_planes = 0;
+
+	if (!dm_new_crtc_state->stream)
+		return;
+
+	dm_new_crtc_state->active_planes =
+		count_crtc_active_planes(new_crtc_state);
+}
+
+static bool dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
+				      const struct drm_display_mode *mode,
+				      struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+				      struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
+										crtc);
+	struct amdgpu_device *adev = drm_to_adev(crtc->dev);
+	struct dc *dc = adev->dm.dc;
+	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
+	int ret = -EINVAL;
+
+	trace_amdgpu_dm_crtc_atomic_check(crtc_state);
+
+	dm_update_crtc_active_planes(crtc, crtc_state);
+
+	if (WARN_ON(unlikely(!dm_crtc_state->stream &&
+			modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
+		return ret;
+	}
+
+	/*
+	 * We require the primary plane to be enabled whenever the CRTC is, otherwise
+	 * drm_mode_cursor_universal may end up trying to enable the cursor plane while all other
+	 * planes are disabled, which is not supported by the hardware. And there is legacy
+	 * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
+	 */
+	if (crtc_state->enable &&
+		!(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
+		DRM_DEBUG_ATOMIC("Can't enable a CRTC without enabling the primary plane\n");
+		return -EINVAL;
+	}
+
+	/* In some use cases, like reset, no stream is attached */
+	if (!dm_crtc_state->stream)
+		return 0;
+
+	if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
+		return 0;
+
+	DRM_DEBUG_ATOMIC("Failed DC stream validation\n");
+	return ret;
+}
+
+static const struct drm_crtc_helper_funcs amdgpu_dm_crtc_helper_funcs = {
+	.disable = dm_crtc_helper_disable,
+	.atomic_check = dm_crtc_helper_atomic_check,
+	.mode_fixup = dm_crtc_helper_mode_fixup,
+	.get_scanout_position = amdgpu_crtc_get_scanout_position,
+};
+
+int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
+			       struct drm_plane *plane,
+			       uint32_t crtc_index)
+{
+	struct amdgpu_crtc *acrtc = NULL;
+	struct drm_plane *cursor_plane;
+
+	int res = -ENOMEM;
+
+	cursor_plane = kzalloc(sizeof(*cursor_plane), GFP_KERNEL);
+	if (!cursor_plane)
+		goto fail;
+
+	cursor_plane->type = DRM_PLANE_TYPE_CURSOR;
+	res = amdgpu_dm_plane_init(dm, cursor_plane, 0, NULL);
+
+	acrtc = kzalloc(sizeof(struct amdgpu_crtc), GFP_KERNEL);
+	if (!acrtc)
+		goto fail;
+
+	res = drm_crtc_init_with_planes(
+			dm->ddev,
+			&acrtc->base,
+			plane,
+			cursor_plane,
+			&amdgpu_dm_crtc_funcs, NULL);
+
+	if (res)
+		goto fail;
+
+	drm_crtc_helper_add(&acrtc->base, &amdgpu_dm_crtc_helper_funcs);
+
+	/* Create (reset) the plane state */
+	if (acrtc->base.funcs->reset)
+		acrtc->base.funcs->reset(&acrtc->base);
+
+	acrtc->max_cursor_width = dm->adev->dm.dc->caps.max_cursor_size;
+	acrtc->max_cursor_height = dm->adev->dm.dc->caps.max_cursor_size;
+
+	acrtc->crtc_id = crtc_index;
+	acrtc->base.enabled = false;
+	acrtc->otg_inst = -1;
+
+	dm->adev->mode_info.crtcs[crtc_index] = acrtc;
+	drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
+				   true, MAX_COLOR_LUT_ENTRIES);
+	drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
+
+	return 0;
+
+fail:
+	kfree(acrtc);
+	kfree(cursor_plane);
+	return res;
+}
+
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h
new file mode 100644
index 000000000000..1ac8692354cf
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __AMDGPU_DM_CRTC_H__
+#define __AMDGPU_DM_CRTC_H__
+
+void dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc);
+
+bool modeset_required(struct drm_crtc_state *crtc_state,
+		      struct dc_stream_state *new_stream,
+		      struct dc_stream_state *old_stream);
+
+int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable);
+
+bool amdgpu_dm_vrr_active_irq(struct amdgpu_crtc *acrtc);
+
+bool amdgpu_dm_vrr_active(struct dm_crtc_state *dm_state);
+
+int dm_enable_vblank(struct drm_crtc *crtc);
+
+void dm_disable_vblank(struct drm_crtc *crtc);
+
+int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
+			struct drm_plane *plane,
+			uint32_t link_index);
+
+#endif
+
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 10/31] drm/amd/display: remove number of DSC slices override in DML
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (8 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 09/31] drm/amd/display: Create a file dedicated for CRTC Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 11/31] drm/amd/display: Fix hard hang if DSC is disabled Rodrigo Siqueira
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, Wenjing Liu, solomon.chiu,
	Aurabindo.Pillai, Alvin Lee, wayne.lin, Bhawanpreet.Lakha,
	agustin.gutierrez, pavle.kotarac

From: Wenjing Liu <wenjing.liu@amd.com>

[why]
Number of DSC slices is an input to DML with high dependency
on display specific capability. This isn't something DML can decide
on its own. DML has to use the original number of DSC slices input
to DML during validation without modification. Otherwise the
computed DSC delay will not reflect the current configuration
and therefore causes validation failures.

[how]
Remove DML override for number of DSC slices parameter.

Reviewed-by: Alvin Lee <Alvin.Lee2@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
---
 .../dc/dml/dcn32/display_mode_vba_32.c        | 20 -------------------
 1 file changed, 20 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
index c6c3a9e6731a..1712843dafaa 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
@@ -1897,26 +1897,6 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 				v->MaximumSwathWidthInLineBufferChroma);
 	}
 
-	/*Number Of DSC Slices*/
-	for (k = 0; k < mode_lib->vba.NumberOfActiveSurfaces; ++k) {
-		if (mode_lib->vba.BlendingAndTiming[k] == k) {
-			if (mode_lib->vba.PixelClockBackEnd[k] > 4800) {
-				mode_lib->vba.NumberOfDSCSlices[k] = dml_ceil(mode_lib->vba.PixelClockBackEnd[k] / 600,
-						4);
-			} else if (mode_lib->vba.PixelClockBackEnd[k] > 2400) {
-				mode_lib->vba.NumberOfDSCSlices[k] = 8;
-			} else if (mode_lib->vba.PixelClockBackEnd[k] > 1200) {
-				mode_lib->vba.NumberOfDSCSlices[k] = 4;
-			} else if (mode_lib->vba.PixelClockBackEnd[k] > 340) {
-				mode_lib->vba.NumberOfDSCSlices[k] = 2;
-			} else {
-				mode_lib->vba.NumberOfDSCSlices[k] = 1;
-			}
-		} else {
-			mode_lib->vba.NumberOfDSCSlices[k] = 0;
-		}
-	}
-
 	dml32_CalculateSwathAndDETConfiguration(
 			mode_lib->vba.DETSizeOverride,
 			mode_lib->vba.UsesMALLForPStateChange,
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 11/31] drm/amd/display: Fix hard hang if DSC is disabled
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (9 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 10/31] drm/amd/display: remove number of DSC slices override in DML Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 12/31] drm/amd/display: Don't set dram clock change requirement for SubVP Rodrigo Siqueira
                   ` (20 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

We want to calculate the DTB clock values when DSC is enabled; however,
this is not the current behavior implemented in DCN32. Right now, DML is
trying to calculate DSC values even if DSC is disabled; as a result, we
can have a hard hang due to wrong clock calculation. This commit fixes
this issue by moving the calculation after the DSC check.

Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../dc/dml/dcn32/display_mode_vba_util_32.c   | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
index 5a701d9df0f7..febaff7d7343 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
@@ -1686,17 +1686,22 @@ double dml32_RequiredDTBCLK(
 		unsigned int              AudioRate,
 		unsigned int              AudioLayout)
 {
-	double PixelWordRate = PixelClock /  (OutputFormat == dm_444 ? 1 : 2);
-	double HCActive = dml_ceil(DSCSlices * dml_ceil(OutputBpp *
-			dml_ceil(HActive / DSCSlices, 1) / 8.0, 1) / 3.0, 1);
-	double HCBlank = 64 + 32 *
-			dml_ceil(AudioRate *  (AudioLayout == 1 ? 1 : 0.25) * HTotal / (PixelClock * 1000), 1);
-	double AverageTribyteRate = PixelWordRate * (HCActive + HCBlank) / HTotal;
-	double HActiveTribyteRate = PixelWordRate * HCActive / HActive;
+	double PixelWordRate;
+	double HCActive;
+	double HCBlank;
+	double AverageTribyteRate;
+	double HActiveTribyteRate;
 
 	if (DSCEnable != true)
 		return dml_max(PixelClock / 4.0 * OutputBpp / 24.0, 25.0);
 
+	PixelWordRate = PixelClock /  (OutputFormat == dm_444 ? 1 : 2);
+	HCActive = dml_ceil(DSCSlices * dml_ceil(OutputBpp *
+			dml_ceil(HActive / DSCSlices, 1) / 8.0, 1) / 3.0, 1);
+	HCBlank = 64 + 32 *
+			dml_ceil(AudioRate *  (AudioLayout == 1 ? 1 : 0.25) * HTotal / (PixelClock * 1000), 1);
+	AverageTribyteRate = PixelWordRate * (HCActive + HCBlank) / HTotal;
+	HActiveTribyteRate = PixelWordRate * HCActive / HActive;
 	return dml_max4(PixelWordRate / 4.0, AverageTribyteRate / 4.0, HActiveTribyteRate / 4.0, 25.0) * 1.002;
 }
 
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 12/31] drm/amd/display: Don't set dram clock change requirement for SubVP
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (10 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 11/31] drm/amd/display: Fix hard hang if DSC is disabled Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 13/31] drm/amd/display: Update de-tile override to anticipate pipe splitting Rodrigo Siqueira
                   ` (19 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	Alvin Lee, wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

From: Alvin Lee <Alvin.Lee2@amd.com>

[Description]
In general cases we want to keep the dram clock change requirement (we
prefer configs that support MCLK switch). Only override to false for
SubVP.

Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index f913daabcca5..92d87745d933 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -2984,6 +2984,7 @@ int dcn32_populate_dml_pipes_from_context(
 	int i, pipe_cnt;
 	struct resource_context *res_ctx = &context->res_ctx;
 	struct pipe_ctx *pipe;
+	bool subvp_in_use = false;
 
 	dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
 
@@ -3006,6 +3007,7 @@ int dcn32_populate_dml_pipes_from_context(
 		switch (pipe->stream->mall_stream_config.type) {
 		case SUBVP_MAIN:
 			pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_sub_viewport;
+			subvp_in_use = true;
 			break;
 		case SUBVP_PHANTOM:
 			pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_phantom_pipe;
@@ -3076,6 +3078,14 @@ int dcn32_populate_dml_pipes_from_context(
 
 	dcn32_update_det_override_for_mpo(dc, context, pipes);
 
+	// In general cases we want to keep the dram clock change requirement
+	// (prefer configs that support MCLK switch). Only override to false
+	// for SubVP
+	if (subvp_in_use)
+		context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false;
+	else
+		context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true;
+
 	return pipe_cnt;
 }
 
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 13/31] drm/amd/display: Update de-tile override to anticipate pipe splitting
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (11 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 12/31] drm/amd/display: Don't set dram clock change requirement for SubVP Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 14/31] drm/amd/display: Disable GPUVM in IP resource configuration Rodrigo Siqueira
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Dmytro Laktyushkin, Sunpeng.Li,
	Harry.Wentland, qingqing.zhuo, Rodrigo.Siqueira, roman.li,
	Taimur Hassan, solomon.chiu, Aurabindo.Pillai, wayne.lin,
	Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

From: Taimur Hassan <Syed.Hassan@amd.com>

[Why]
For certain MPO configurations, DML will split a pipe after DET buffer has
already been allocated by driver, resulting in allocation of more DET
segments than the configurable return buffer has, causing underflow.

[How]
Determine during DET override calculation whether or not a pipe will be
split later on by DML, and distribute DET segments based on expected
number of pipes.

Reviewed-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Taimur Hassan <Syed.Hassan@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c |  22 ++--
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |   6 +-
 .../display/dc/dcn32/dcn32_resource_helpers.c | 112 +++++++++---------
 3 files changed, 69 insertions(+), 71 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 92d87745d933..631876832dfa 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -2984,7 +2984,7 @@ int dcn32_populate_dml_pipes_from_context(
 	int i, pipe_cnt;
 	struct resource_context *res_ctx = &context->res_ctx;
 	struct pipe_ctx *pipe;
-	bool subvp_in_use = false;
+	bool subvp_in_use = false, is_pipe_split_expected[MAX_PIPES];
 
 	dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
 
@@ -3046,6 +3046,9 @@ int dcn32_populate_dml_pipes_from_context(
 			if (dc->debug.enable_single_display_2to1_odm_policy)
 				pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1;
 		}
+
+		is_pipe_split_expected[i] = dcn32_predict_pipe_split(context, pipes[i].pipe, i);
+
 		pipe_cnt++;
 	}
 
@@ -3053,8 +3056,7 @@ int dcn32_populate_dml_pipes_from_context(
 	 * the DET available for each pipe). Use the DET override input to maintain our driver
 	 * policy.
 	 */
-	switch (pipe_cnt) {
-	case 1:
+	if (pipe_cnt == 1 && !is_pipe_split_expected[0]) {
 		pipes[0].pipe.src.det_size_override = DCN3_2_MAX_DET_SIZE;
 		if (pipe->plane_state && !dc->debug.disable_z9_mpc) {
 			if (!is_dual_plane(pipe->plane_state->format)) {
@@ -3065,18 +3067,8 @@ int dcn32_populate_dml_pipes_from_context(
 					pipes[0].pipe.src.det_size_override = 320; // 5K or higher
 			}
 		}
-		break;
-	case 2:
-	case 3:
-	case 4:
-		// For 2 and 3 pipes, use (MAX_DET_SIZE / pipe_cnt), for 4 pipes use default size for each pipe
-		for (i = 0; i < pipe_cnt; i++) {
-			pipes[i].pipe.src.det_size_override = (pipe_cnt < 4) ? (DCN3_2_MAX_DET_SIZE / pipe_cnt) : DCN3_2_DEFAULT_DET_SIZE;
-		}
-		break;
-	}
-
-	dcn32_update_det_override_for_mpo(dc, context, pipes);
+	} else
+		dcn32_determine_det_override(context, pipes, is_pipe_split_expected, pipe_cnt);
 
 	// In general cases we want to keep the dram clock change requirement
 	// (prefer configs that support MCLK switch). Only override to false
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index db4546317cb5..10254ab7e9d9 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -100,7 +100,9 @@ bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc,
 bool dcn32_subvp_in_use(struct dc *dc,
 		struct dc_state *context);
 
-void dcn32_update_det_override_for_mpo(struct dc *dc, struct dc_state *context,
-	display_e2e_pipe_params_st *pipes);
+bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st pipe, int index);
+
+void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes,
+		bool *is_pipe_split_expected, int pipe_cnt);
 
 #endif /* _DCN32_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
index e001f6d1f6c3..a6ef1dba01fe 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
@@ -26,6 +26,8 @@
 // header file of functions being implemented
 #include "dcn32_resource.h"
 #include "dcn20/dcn20_resource.h"
+#include "dml/dcn32/display_mode_vba_util_32.h"
+
 /**
  * ********************************************************************************************
  * dcn32_helper_populate_phantom_dlg_params: Get DLG params for phantom pipes and populate pipe_ctx
@@ -195,66 +197,68 @@ bool dcn32_subvp_in_use(struct dc *dc,
 	return false;
 }
 
-/* For MPO we adjust the DET allocation to ensure we have enough DET buffer when an MPO pipe
- * is removed. For example for 1 MPO + 1 non-MPO normally we would allocate 6 DET segments
- * for each pipe [6, 6, 6]. But when transitioning out of MPO it would change from
- * [6, 6, 6] -> [9, 9]. However, if VUPDATE for the non-MPO pipe comes first we would be
- * trying to allocate more DET than what's currently available which would result in underflow.
- *
- * In this case we must ensure there is enough buffer when transitioning in and out of MPO:
- *
- * 1 MPO (2 plane) + 1 non-MPO case:
- * [4, 4, 9]<->[9, 9]: Allocate 4 each for MPO pipes, and maintain 9 for non-MPO pipe
- *
- * 1 MPO (2 plane) + 2 non-MPO case:
- * [3, 3, 5, 5]<->[6, 6, 6]
- *
- * 1 MPO (3 plane) + 1 non-MPO case:
- * [3, 3, 3, 9]<->[4, 4, 9] or [3, 3, 3, 6]<->[9, 9]
- *
- * For multi-display MPO case all pipes will have 4 segments:
- * Removing MPO on one of the displays will result in 3 pipes
- * (1 MPO and 1 non-MPO which is covered by single MPO stream case).
- */
-void dcn32_update_det_override_for_mpo(struct dc *dc, struct dc_state *context,
-	display_e2e_pipe_params_st *pipes)
+bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st pipe, int index)
 {
-	uint8_t i, mpo_stream_index, pipe_cnt;
-	uint8_t mpo_stream_count = 0;
-	uint8_t mpo_planes = 0; // Only used in single display MPO case
-	unsigned int j;
-	struct resource_context *res_ctx = &context->res_ctx;
+	double pscl_throughput, pscl_throughput_chroma, dpp_clk_single_dpp, clock,
+		clk_frequency = 0.0, vco_speed = context->bw_ctx.dml.soc.dispclk_dppclk_vco_speed_mhz;
 
-	for (i = 0; i < context->stream_count; i++) {
-		if (context->stream_status[i].plane_count > 1) {
-			mpo_stream_index = i;
-			mpo_stream_count++;
-			mpo_planes = context->stream_status[i].plane_count;
-		}
-	}
+	dml32_CalculateSinglePipeDPPCLKAndSCLThroughput(pipe.scale_ratio_depth.hscl_ratio,
+			pipe.scale_ratio_depth.hscl_ratio_c,
+			pipe.scale_ratio_depth.vscl_ratio,
+			pipe.scale_ratio_depth.vscl_ratio_c,
+			context->bw_ctx.dml.ip.max_dchub_pscl_bw_pix_per_clk,
+			context->bw_ctx.dml.ip.max_pscl_lb_bw_pix_per_clk,
+			pipe.dest.pixel_rate_mhz,
+			pipe.src.source_format,
+			pipe.scale_taps.htaps,
+			pipe.scale_taps.htaps_c,
+			pipe.scale_taps.vtaps,
+			pipe.scale_taps.vtaps_c,
 
-	if (mpo_stream_count == 1) {
-		for (j = 0, pipe_cnt = 0; j < dc->res_pool->pipe_count; j++) {
-			if (!res_ctx->pipe_ctx[j].stream)
-				continue;
+			/* Output */
+			&pscl_throughput, &pscl_throughput_chroma,
+			&dpp_clk_single_dpp);
 
-			if (context->res_ctx.pipe_ctx[j].stream == context->streams[mpo_stream_index]) {
-				// For 3 plane MPO + 1 non-MPO, do [3, 3, 3, 9]
-				// For 2 plane MPO + 1 non-MPO, do [4, 4, 9]
-				if (context->stream_count - mpo_stream_count == 1)
-					pipes[pipe_cnt].pipe.src.det_size_override = DCN3_2_DET_SEG_SIZE * (mpo_planes == 2 ? 4 : 3);
-				else if (context->stream_count - mpo_stream_count == 2)
-					pipes[pipe_cnt].pipe.src.det_size_override = DCN3_2_DET_SEG_SIZE * 3;
+	clock = dpp_clk_single_dpp * (1 + context->bw_ctx.dml.soc.dcn_downspread_percent / 100);
+
+	if (clock > 0)
+		clk_frequency = vco_speed * 4.0 / ((int) (vco_speed * 4.0));
+
+	if (clk_frequency > context->bw_ctx.dml.soc.clock_limits[index].dppclk_mhz)
+		return true;
+	else
+		return false;
+}
+
+void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes,
+		bool *is_pipe_split_expected, int pipe_cnt)
+{
+	int i, j, count, stream_segments, pipe_segments[MAX_PIPES];
+
+	if (context->stream_count > 0) {
+		stream_segments = 18 / context->stream_count;
+		for (i = 0, count = 0; i < context->stream_count; i++) {
+			for (j = 0; j < pipe_cnt; j++) {
+				if (context->res_ctx.pipe_ctx[j].stream == context->streams[i]) {
+					count++;
+					if (is_pipe_split_expected[j])
+						count++;
+				}
+			}
+			pipe_segments[i] = stream_segments / count;
+		}
 
-			} else if (context->res_ctx.pipe_ctx[j].stream &&
-					context->res_ctx.pipe_ctx[j].stream != context->streams[mpo_stream_index]) {
-				// Update for non-MPO pipes
-				if (context->stream_count - mpo_stream_count == 1)
-					pipes[pipe_cnt].pipe.src.det_size_override = DCN3_2_DET_SEG_SIZE * 9;
-				else if (context->stream_count - mpo_stream_count == 2)
-					pipes[pipe_cnt].pipe.src.det_size_override = DCN3_2_DET_SEG_SIZE * 5;
+		for (i = 0; i < pipe_cnt; i++) {
+			pipes[i].pipe.src.det_size_override = 0;
+			for (j = 0; j < context->stream_count; j++) {
+				if (context->res_ctx.pipe_ctx[i].stream == context->streams[j]) {
+					pipes[i].pipe.src.det_size_override = pipe_segments[j] * DCN3_2_DET_SEG_SIZE;
+					break;
+				}
 			}
-			pipe_cnt++;
 		}
+	} else {
+		for (i = 0; i < pipe_cnt; i++)
+			pipes[i].pipe.src.det_size_override = 4 * DCN3_2_DET_SEG_SIZE; //DCN3_2_DEFAULT_DET_SIZE
 	}
 }
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 14/31] drm/amd/display: Disable GPUVM in IP resource configuration
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (12 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 13/31] drm/amd/display: Update de-tile override to anticipate pipe splitting Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 15/31] drm/amd/display: Loop through all pipes for DET allocation Rodrigo Siqueira
                   ` (17 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Vladimir Stempen, Sunpeng.Li,
	Harry.Wentland, qingqing.zhuo, Martin Leung, Rodrigo.Siqueira,
	roman.li, solomon.chiu, Aurabindo.Pillai, wayne.lin,
	Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

From: Vladimir Stempen <vladimir.stempen@amd.com>

[Why]
VM enabled in IP configuration causes UCLK not
reaching DPM0. The expectation for VM enable should
be that KMD will indicate to DAL when VM is enabled,
then DAL will set the bit accordingly

[How]
Set gpuvm_enable to zero in DCN3_20 and DCN3_21 resource.

Reviewed-by: Martin Leung <Martin.Leung@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Vladimir Stempen <vladimir.stempen@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c   | 2 +-
 drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 631876832dfa..0cb44ea9753b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -120,7 +120,7 @@ static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C
 #define DCN3_2_MIN_COMPBUF_SIZE_KB 128
 
 struct _vcs_dpi_ip_params_st dcn3_2_ip = {
-	.gpuvm_enable = 1,
+	.gpuvm_enable = 0,
 	.gpuvm_max_page_table_levels = 4,
 	.hostvm_enable = 0,
 	.rob_buffer_size_kbytes = 128,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index ebbeebf972dc..d218c6dd71aa 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -123,7 +123,7 @@ static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C
 #define DCN3_2_DEFAULT_DET_SIZE 256
 
 struct _vcs_dpi_ip_params_st dcn3_21_ip = {
-	.gpuvm_enable = 1,
+	.gpuvm_enable = 0,
 	.gpuvm_max_page_table_levels = 4,
 	.hostvm_enable = 0,
 	.rob_buffer_size_kbytes = 128,
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 15/31] drm/amd/display: Loop through all pipes for DET allocation
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (13 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 14/31] drm/amd/display: Disable GPUVM in IP resource configuration Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 16/31] drm/amd/display: Update Cursor Attribute MALL cache Rodrigo Siqueira
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, Taimur Hassan, solomon.chiu,
	Aurabindo.Pillai, Alvin Lee, wayne.lin, Bhawanpreet.Lakha,
	agustin.gutierrez, pavle.kotarac

From: Taimur Hassan <Syed.Hassan@amd.com>

[Why & How]
There are cases where the pipes populated are not all at the top
of the pipes list under context. Loop through all pipes for DET
allocation instead of just the number of populated ones, even if
some unpopulated pipes are iterated through unnecessarily.

Reviewed-by: Alvin Lee <Alvin.Lee2@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Taimur Hassan <Syed.Hassan@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 0cb44ea9753b..32da47e24839 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -3068,7 +3068,7 @@ int dcn32_populate_dml_pipes_from_context(
 			}
 		}
 	} else
-		dcn32_determine_det_override(context, pipes, is_pipe_split_expected, pipe_cnt);
+		dcn32_determine_det_override(context, pipes, is_pipe_split_expected, dc->res_pool->pipe_count);
 
 	// In general cases we want to keep the dram clock change requirement
 	// (prefer configs that support MCLK switch). Only override to false
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 16/31] drm/amd/display: Update Cursor Attribute MALL cache
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (14 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 15/31] drm/amd/display: Loop through all pipes for DET allocation Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 17/31] drm/amd/display: Update DML logic for unbounded req handling Rodrigo Siqueira
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Chris Park, Sunpeng.Li, Harry.Wentland,
	qingqing.zhuo, Rodrigo.Siqueira, roman.li, solomon.chiu,
	Aurabindo.Pillai, Alvin Lee, wayne.lin, Bhawanpreet.Lakha,
	agustin.gutierrez, pavle.kotarac

From: Chris Park <chris.park@amd.com>

[Why]
Cursor size can update without MALL cache update.
Update the register on cursor attribute as well.

[How]
Update cursor MALL cache on cursor attribute update.

Reviewed-by: Alvin Lee <Alvin.Lee2@amd.com>
Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Chris Park <chris.park@amd.com>
---
 .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c | 40 ++++++++++++++++++-
 .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h |  3 ++
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
index 0a7d64306481..3176b04a7740 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c
@@ -94,6 +94,44 @@ void hubp32_phantom_hubp_post_enable(struct hubp *hubp)
 	}
 }
 
+void hubp32_cursor_set_attributes(
+		struct hubp *hubp,
+		const struct dc_cursor_attributes *attr)
+{
+	struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+	enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch);
+	enum cursor_lines_per_chunk lpc = hubp2_get_lines_per_chunk(
+			attr->width, attr->color_format);
+
+	hubp->curs_attr = *attr;
+
+	REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
+			CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part);
+	REG_UPDATE(CURSOR_SURFACE_ADDRESS,
+			CURSOR_SURFACE_ADDRESS, attr->address.low_part);
+
+	REG_UPDATE_2(CURSOR_SIZE,
+			CURSOR_WIDTH, attr->width,
+			CURSOR_HEIGHT, attr->height);
+
+	REG_UPDATE_4(CURSOR_CONTROL,
+			CURSOR_MODE, attr->color_format,
+			CURSOR_2X_MAGNIFY, attr->attribute_flags.bits.ENABLE_MAGNIFICATION,
+			CURSOR_PITCH, hw_pitch,
+			CURSOR_LINES_PER_CHUNK, lpc);
+
+	REG_SET_2(CURSOR_SETTINGS, 0,
+			/* no shift of the cursor HDL schedule */
+			CURSOR0_DST_Y_OFFSET, 0,
+			 /* used to shift the cursor chunk request deadline */
+			CURSOR0_CHUNK_HDL_ADJUST, 3);
+
+	if (attr->width * attr->height * 4 > 16384)
+		REG_UPDATE(DCHUBP_MALL_CONFIG, USE_MALL_FOR_CURSOR, true);
+	else
+		REG_UPDATE(DCHUBP_MALL_CONFIG, USE_MALL_FOR_CURSOR, false);
+}
+
 static struct hubp_funcs dcn32_hubp_funcs = {
 	.hubp_enable_tripleBuffer = hubp2_enable_triplebuffer,
 	.hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled,
@@ -106,7 +144,7 @@ static struct hubp_funcs dcn32_hubp_funcs = {
 	.set_blank = hubp2_set_blank,
 	.dcc_control = hubp3_dcc_control,
 	.mem_program_viewport = min_set_viewport,
-	.set_cursor_attributes	= hubp2_cursor_set_attributes,
+	.set_cursor_attributes	= hubp32_cursor_set_attributes,
 	.set_cursor_position	= hubp2_cursor_set_position,
 	.hubp_clk_cntl = hubp2_clk_cntl,
 	.hubp_vtg_sel = hubp2_vtg_sel,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h
index 00b4211389c2..c4315d50fbb0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h
@@ -58,6 +58,9 @@ void hubp32_prepare_subvp_buffering(struct hubp *hubp, bool enable);
 
 void hubp32_phantom_hubp_post_enable(struct hubp *hubp);
 
+void hubp32_cursor_set_attributes(struct hubp *hubp,
+		const struct dc_cursor_attributes *attr);
+
 bool hubp32_construct(
 	struct dcn20_hubp *hubp2,
 	struct dc_context *ctx,
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 17/31] drm/amd/display: Update DML logic for unbounded req handling
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (15 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 16/31] drm/amd/display: Update Cursor Attribute MALL cache Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 18/31] drm/amd/display: Drop FPU flags from dcn32_clk_mgr Rodrigo Siqueira
                   ` (14 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Jun Lei, Bhawanpreet.Lakha, agustin.gutierrez,
	pavle.kotarac

From: Jun Lei <jun.lei@amd.com>

[why]
Unbounded request logic in resource/DML has some issues where unbounded
request is being enabled incorrectly. SW today enables unbounded request
unconditionally in hardware, on the assumption that HW can always
support it in single pipe scenarios.

This worked until now because the same assumption is made in DML. A new
DML update is needed to fix a bug, where there are single pipe scenarios
where unbounded cannot be enabled, and this change in DML needs to be
ported in, and dcn32 resource logic fixed.

[how]
First, dcn32_resource should program unbounded req in HW according to
unbounded req enablement output from DML, as opposed to DML input.

Second, port in DML update which disables unbounded req in some
scenarios to fix an issue with poor stutter performance

Signed-off-by: Jun Lei <jun.lei@amd.com>
Reviewed-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 11 +++-
 .../dc/dml/dcn32/display_mode_vba_32.c        | 44 +++++++++++++---
 .../dc/dml/dcn32/display_mode_vba_util_32.c   | 51 ++++++++++++++++---
 .../dc/dml/dcn32/display_mode_vba_util_32.h   | 10 +++-
 .../drm/amd/display/dc/dml/display_mode_vba.c |  1 +
 5 files changed, 103 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 32da47e24839..39214a0dcdf2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -3322,6 +3322,7 @@ void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, display
 {
 	int i, pipe_idx;
 	bool usr_retraining_support = false;
+	bool unbounded_req_enabled = false;
 
 	/* Writeback MCIF_WB arbitration parameters */
 	dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt);
@@ -3357,6 +3358,14 @@ void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, display
 	if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz)
 		context->bw_ctx.bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz;
 
+	unbounded_req_enabled = get_unbounded_request_enabled(&context->bw_ctx.dml, pipes, pipe_cnt);
+
+	if (unbounded_req_enabled && pipe_cnt > 1) {
+		// Unbounded requesting should not ever be used when more than 1 pipe is enabled.
+		ASSERT(false);
+		unbounded_req_enabled = false;
+	}
+
 	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
 		if (!context->res_ctx.pipe_ctx[i].stream)
 			continue;
@@ -3375,7 +3384,7 @@ void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, display
 		} else {
 			context->res_ctx.pipe_ctx[i].det_buffer_size_kb = get_det_buffer_size_kbytes(&context->bw_ctx.dml, pipes, pipe_cnt,
 							pipe_idx);
-			context->res_ctx.pipe_ctx[i].unbounded_req = pipes[pipe_idx].pipe.src.unbounded_req_mode;
+			context->res_ctx.pipe_ctx[i].unbounded_req = unbounded_req_enabled;
 		}
 		if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
 			context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
index 1712843dafaa..092782b6e341 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_32.c
@@ -226,6 +226,9 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 				mode_lib->vba.NumberOfActiveSurfaces,
 				mode_lib->vba.nomDETInKByte,
 				mode_lib->vba.UseUnboundedRequesting,
+				mode_lib->vba.DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment,
+				mode_lib->vba.ip.pixel_chunk_size_kbytes,
+				mode_lib->vba.ip.rob_buffer_size_kbytes,
 				mode_lib->vba.CompressedBufferSegmentSizeInkByteFinal,
 				v->dummy_vars
 					.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation
@@ -287,6 +290,10 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 				mode_lib->vba.DETBufferSizeC,
 				&v->UnboundedRequestEnabled,
 				&v->CompressedBufferSizeInkByte,
+				&v->CompBufReservedSpaceKBytes,
+				&v->dummy_vars
+					.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation
+					.dummy_boolean,       /* bool *CompBufReservedSpaceNeedAjustment */
 				v->dummy_vars
 					.DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation
 					.dummy_boolean_array, /* bool ViewportSizeSupportPerSurface[] */
@@ -295,6 +302,9 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 					 .dummy_boolean); /* bool *ViewportSizeSupport */
 	}
 
+	v->CompBufReservedSpaceZs     = v->CompBufReservedSpaceKBytes * 1024.0 / 256.0;
+	v->CompBufReservedSpace64B    = v->CompBufReservedSpaceKBytes * 1024.0 / 64.0;
+
 	// DCFCLK Deep Sleep
 	dml32_CalculateDCFCLKDeepSleep(
 			mode_lib->vba.NumberOfActiveSurfaces,
@@ -1532,8 +1542,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 			v->TotalDataReadBandwidth,
 			mode_lib->vba.DCFCLK,
 			mode_lib->vba.ReturnBW,
-			mode_lib->vba.CompbufReservedSpace64B,
-			mode_lib->vba.CompbufReservedSpaceZs,
+			v->CompbufReservedSpace64B,
+			v->CompbufReservedSpaceZs,
 			mode_lib->vba.SRExitTime,
 			mode_lib->vba.SRExitZ8Time,
 			mode_lib->vba.SynchronizeTimingsFinal,
@@ -1598,8 +1608,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 				v->TotalDataReadBandwidth,
 				mode_lib->vba.DCFCLK,
 				mode_lib->vba.ReturnBW,
-				0, //mode_lib->vba.CompbufReservedSpace64B,
-				0, //mode_lib->vba.CompbufReservedSpaceZs,
+				0, //CompbufReservedSpace64B,
+				0, //CompbufReservedSpaceZs,
 				mode_lib->vba.SRExitTime,
 				mode_lib->vba.SRExitZ8Time,
 				mode_lib->vba.SynchronizeTimingsFinal,
@@ -1661,6 +1671,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
 void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
 {
 	unsigned int dummy_integer[4];
+	bool dummy_boolean[2];
 	bool MPCCombineMethodAsNeededForPStateChangeAndVoltage;
 	bool MPCCombineMethodAsPossible;
 	enum odm_combine_mode dummy_odm_mode[DC__NUM_DPP__MAX];
@@ -1675,6 +1686,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 	bool SubViewportMALLPStateMethod;
 	bool PhantomPipeMALLPStateMethod;
 	unsigned int MaximumMPCCombine;
+	bool CompBufReservedSpaceNeedAdjustment;
+	bool CompBufReservedSpaceNeedAdjustmentSingleDPP;
 
 #ifdef __DML_VBA_DEBUG__
 	dml_print("DML::%s: called\n", __func__);
@@ -1907,6 +1920,9 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 			mode_lib->vba.NumberOfActiveSurfaces,
 			mode_lib->vba.nomDETInKByte,
 			mode_lib->vba.UseUnboundedRequesting,
+			mode_lib->vba.DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment,
+			mode_lib->vba.ip.pixel_chunk_size_kbytes,
+			mode_lib->vba.ip.rob_buffer_size_kbytes,
 			mode_lib->vba.CompressedBufferSegmentSizeInkByteFinal,
 			mode_lib->vba.Output,
 			mode_lib->vba.ReadBandwidthLuma,
@@ -1954,6 +1970,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 			v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_integer_array[7], /* Long            DETBufferSizeC[]  */
 			&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_boolean_array[0][0], /* bool           *UnboundedRequestEnabled  */
 			&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_integer_array[0][0], /* Long           *CompressedBufferSizeInkByte  */
+			&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_integer_array[1][0], /* Long           *CompBufReservedSpaceKBytes */
+			&CompBufReservedSpaceNeedAdjustmentSingleDPP,
 			mode_lib->vba.SingleDPPViewportSizeSupportPerSurface,/* bool ViewportSizeSupportPerSurface[] */
 			&v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_boolean_array[1][0]); /* bool           *ViewportSizeSupport */
 
@@ -2122,9 +2140,18 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 				}
 			}
 
+			// if TotalNumberOfActiveDPP is > 1, then there should be no unbounded req mode (hw limitation), the comp buf reserved adjustment is not needed regardless
+			// if TotalNumberOfActiveDPP is == 1, then will use the SingleDPP version of unbounded_req for the decision
+			CompBufReservedSpaceNeedAdjustment = (mode_lib->vba.TotalNumberOfActiveDPP[i][j] > 1) ? 0 : CompBufReservedSpaceNeedAdjustmentSingleDPP;
+
+
+
 			if (j == 1 && !dml32_UnboundedRequest(mode_lib->vba.UseUnboundedRequesting,
-							mode_lib->vba.TotalNumberOfActiveDPP[i][j], NoChroma,
-							mode_lib->vba.Output[0])) {
+					mode_lib->vba.TotalNumberOfActiveDPP[i][j], NoChroma,
+					mode_lib->vba.Output[0],
+					mode_lib->vba.SurfaceTiling[0],
+					CompBufReservedSpaceNeedAdjustment,
+					mode_lib->vba.DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment)) {
 				while (!(mode_lib->vba.TotalNumberOfActiveDPP[i][j] >= mode_lib->vba.MaxNumDPP
 						|| mode_lib->vba.TotalNumberOfSingleDPPSurfaces[i][j] == 0)) {
 					double BWOfNonCombinedSurfaceOfMaximumBandwidth = 0;
@@ -2502,6 +2529,9 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 					mode_lib->vba.NumberOfActiveSurfaces,
 					mode_lib->vba.nomDETInKByte,
 					mode_lib->vba.UseUnboundedRequesting,
+					mode_lib->vba.DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment,
+					mode_lib->vba.ip.pixel_chunk_size_kbytes,
+					mode_lib->vba.ip.rob_buffer_size_kbytes,
 					mode_lib->vba.CompressedBufferSegmentSizeInkByteFinal,
 					mode_lib->vba.Output,
 					mode_lib->vba.ReadBandwidthLuma,
@@ -2548,6 +2578,8 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
 					mode_lib->vba.DETBufferSizeCThisState,
 					&mode_lib->vba.UnboundedRequestEnabledThisState,
 					&mode_lib->vba.CompressedBufferSizeInkByteThisState,
+					&dummy_integer[0], /* Long CompBufReservedSpaceKBytes */
+					&dummy_boolean[0], /* bool CompBufReservedSpaceNeedAdjustment */
 					v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.dummy_boolean_array[0],
 					&mode_lib->vba.ViewportSizeSupport[i][j]);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
index febaff7d7343..f7fe8f039ba3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c
@@ -454,6 +454,9 @@ void dml32_CalculateSwathAndDETConfiguration(
 		unsigned int NumberOfActiveSurfaces,
 		unsigned int nomDETInKByte,
 		enum unbounded_requesting_policy UseUnboundedRequestingFinal,
+		bool DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment,
+		unsigned int PixelChunkSizeKBytes,
+		unsigned int ROBSizeKBytes,
 		unsigned int CompressedBufferSegmentSizeInkByteFinal,
 		enum output_encoder_class Output[],
 		double ReadBandwidthLuma[],
@@ -501,6 +504,8 @@ void dml32_CalculateSwathAndDETConfiguration(
 		unsigned int DETBufferSizeC[],
 		bool *UnboundedRequestEnabled,
 		unsigned int *CompressedBufferSizeInkByte,
+		unsigned int *CompBufReservedSpaceKBytes,
+		bool *CompBufReservedSpaceNeedAdjustment,
 		bool ViewportSizeSupportPerSurface[],
 		bool *ViewportSizeSupport)
 {
@@ -519,6 +524,8 @@ void dml32_CalculateSwathAndDETConfiguration(
 
 #ifdef __DML_VBA_DEBUG__
 	dml_print("DML::%s: ForceSingleDPP = %d\n", __func__, ForceSingleDPP);
+	dml_print("DML::%s: ROBSizeKBytes = %d\n", __func__, ROBSizeKBytes);
+	dml_print("DML::%s: PixelChunkSizeKBytes = %d\n", __func__, PixelChunkSizeKBytes);
 #endif
 	dml32_CalculateSwathWidth(ForceSingleDPP,
 			NumberOfActiveSurfaces,
@@ -588,8 +595,24 @@ void dml32_CalculateSwathAndDETConfiguration(
 		}
 	}
 
-	*UnboundedRequestEnabled = dml32_UnboundedRequest(UseUnboundedRequestingFinal, TotalActiveDPP,
-			NoChromaSurfaces, Output[0]);
+	// By default, just set the reserved space to 2 pixel chunks size
+	*CompBufReservedSpaceKBytes = PixelChunkSizeKBytes * 2;
+
+	// if unbounded req is enabled, program reserved space such that the ROB will not hold more than 8 swaths worth of data
+	// - assume worst-case compression rate of 4. [ROB size - 8 * swath_size / max_compression ratio]
+	// - assume for "narrow" vp case in which the ROB can fit 8 swaths, the DET should be big enough to do full size req
+	*CompBufReservedSpaceNeedAdjustment = ((int) ROBSizeKBytes - (int) *CompBufReservedSpaceKBytes) > (int) (RoundedUpMaxSwathSizeBytesY[0]/512);
+
+	if (*CompBufReservedSpaceNeedAdjustment == 1) {
+		*CompBufReservedSpaceKBytes = ROBSizeKBytes - RoundedUpMaxSwathSizeBytesY[0]/512;
+	}
+
+	#ifdef __DML_VBA_DEBUG__
+		dml_print("DML::%s: CompBufReservedSpaceKBytes          = %d\n",  __func__, *CompBufReservedSpaceKBytes);
+		dml_print("DML::%s: CompBufReservedSpaceNeedAdjustment  = %d\n",  __func__, *CompBufReservedSpaceNeedAdjustment);
+	#endif
+
+	*UnboundedRequestEnabled = dml32_UnboundedRequest(UseUnboundedRequestingFinal, TotalActiveDPP, NoChromaSurfaces, Output[0], SurfaceTiling[0], *CompBufReservedSpaceNeedAdjustment, DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment);
 
 	dml32_CalculateDETBufferSize(DETSizeOverride,
 			UseMALLForPStateChange,
@@ -907,9 +930,12 @@ void dml32_CalculateSwathWidth(
 } // CalculateSwathWidth
 
 bool dml32_UnboundedRequest(enum unbounded_requesting_policy UseUnboundedRequestingFinal,
-		unsigned int TotalNumberOfActiveDPP,
-		bool NoChroma,
-		enum output_encoder_class Output)
+			unsigned int TotalNumberOfActiveDPP,
+			bool NoChroma,
+			enum output_encoder_class Output,
+			enum dm_swizzle_mode SurfaceTiling,
+			bool CompBufReservedSpaceNeedAdjustment,
+			bool DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment)
 {
 	bool ret_val = false;
 
@@ -917,7 +943,20 @@ bool dml32_UnboundedRequest(enum unbounded_requesting_policy UseUnboundedRequest
 			TotalNumberOfActiveDPP == 1 && NoChroma);
 	if (UseUnboundedRequestingFinal == dm_unbounded_requesting_edp_only && Output != dm_edp)
 		ret_val = false;
-	return ret_val;
+
+	if (SurfaceTiling == dm_sw_linear)
+		ret_val = false;
+
+	if (CompBufReservedSpaceNeedAdjustment == 1 && DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment)
+		ret_val = false;
+
+#ifdef __DML_VBA_DEBUG__
+	dml_print("DML::%s: CompBufReservedSpaceNeedAdjustment  = %d\n",  __func__, CompBufReservedSpaceNeedAdjustment);
+	dml_print("DML::%s: DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment  = %d\n",  __func__, DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment);
+	dml_print("DML::%s: ret_val = %d\n",  __func__, ret_val);
+#endif
+
+	return (ret_val);
 }
 
 void dml32_CalculateDETBufferSize(
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
index 72461b934ee0..d293856ba906 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.h
@@ -90,6 +90,9 @@ void dml32_CalculateSwathAndDETConfiguration(
 		unsigned int NumberOfActiveSurfaces,
 		unsigned int nomDETInKByte,
 		enum unbounded_requesting_policy UseUnboundedRequestingFinal,
+		bool DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment,
+		unsigned int PixelChunkSizeKBytes,
+		unsigned int ROBSizeKBytes,
 		unsigned int CompressedBufferSegmentSizeInkByteFinal,
 		enum output_encoder_class Output[],
 		double ReadBandwidthLuma[],
@@ -137,6 +140,8 @@ void dml32_CalculateSwathAndDETConfiguration(
 		unsigned int DETBufferSizeC[],
 		bool *UnboundedRequestEnabled,
 		unsigned int *CompressedBufferSizeInkByte,
+		unsigned int *CompBufReservedSpaceKBytes,
+		bool *CompBufReservedSpaceNeedAdjustment,
 		bool ViewportSizeSupportPerSurface[],
 		bool *ViewportSizeSupport);
 
@@ -181,7 +186,10 @@ void dml32_CalculateSwathWidth(
 bool dml32_UnboundedRequest(enum unbounded_requesting_policy UseUnboundedRequestingFinal,
 		unsigned int TotalNumberOfActiveDPP,
 		bool NoChroma,
-		enum output_encoder_class Output);
+		enum output_encoder_class Output,
+		enum dm_swizzle_mode SurfaceTiling,
+		bool CompBufReservedSpaceNeedAdjustment,
+		bool DisableUnboundRequestIfCompBufReservedSpaceNeedAdjustment);
 
 void dml32_CalculateDETBufferSize(
 		unsigned int DETSizeOverride[],
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
index 083f89e276d6..22ce975527a3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
@@ -111,6 +111,7 @@ dml_get_attr_func(tcalc, mode_lib->vba.TCalc);
 dml_get_attr_func(fraction_of_urgent_bandwidth, mode_lib->vba.FractionOfUrgentBandwidth);
 dml_get_attr_func(fraction_of_urgent_bandwidth_imm_flip, mode_lib->vba.FractionOfUrgentBandwidthImmediateFlip);
 
+
 dml_get_attr_func(cstate_max_cap_mode, mode_lib->vba.DCHUBBUB_ARB_CSTATE_MAX_CAP_MODE);
 dml_get_attr_func(comp_buffer_size_kbytes, mode_lib->vba.CompressedBufferSizeInkByte);
 dml_get_attr_func(pixel_chunk_size_in_kbyte, mode_lib->vba.PixelChunkSizeInKByte);
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 18/31] drm/amd/display: Drop FPU flags from dcn32_clk_mgr
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (16 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 17/31] drm/amd/display: Update DML logic for unbounded req handling Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 19/31] drm/amd/display: Move populate phaton function to dml Rodrigo Siqueira
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

We are working to isolate FPU operations inside the DML folder, and the
file dcn32_clk_mgr has some of these operations. This commit moves the
FPU operations inside the clock manager and creates the dcn32_fpu file
to aggregate those operations. Note that there is no functional change
ere, just moving code from one part to another.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../gpu/drm/amd/display/dc/clk_mgr/Makefile   |  25 ----
 .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c  |  81 +------------
 drivers/gpu/drm/amd/display/dc/dml/Makefile   |   2 +
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 113 ++++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |  34 ++++++
 5 files changed, 153 insertions(+), 102 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h

diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
index 053084121db2..a48453612d10 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
@@ -188,31 +188,6 @@ CLK_MGR_DCN32 = dcn32_clk_mgr.o dcn32_clk_mgr_smu_msg.o
 
 AMD_DAL_CLK_MGR_DCN32 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn32/,$(CLK_MGR_DCN32))
 
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn32/dcn32_clk_mgr.o := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn32/dcn32_clk_mgr.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn32/dcn32_clk_mgr.o := -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/clk_mgr/dcn32/dcn32_clk_mgr.o := -msse2
-endif
-endif
-
 AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN32)
 
 endif
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
index 08f07f31fe73..10726571007d 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
@@ -42,6 +42,7 @@
 #include "dcn/dcn_3_2_0_sh_mask.h"
 
 #include "dcn32/dcn32_clk_mgr.h"
+#include "dml/dcn32/dcn32_fpu.h"
 
 #define DCN_BASE__INST0_SEG1                       0x000000C0
 
@@ -146,83 +147,9 @@ static void dcn32_init_single_clock(struct clk_mgr_internal *clk_mgr, PPCLK_e cl
 
 static void dcn32_build_wm_range_table(struct clk_mgr_internal *clk_mgr)
 {
-	/* defaults */
-	double pstate_latency_us = clk_mgr->base.ctx->dc->dml.soc.dram_clock_change_latency_us;
-	double fclk_change_latency_us = clk_mgr->base.ctx->dc->dml.soc.fclk_change_latency_us;
-	double sr_exit_time_us = clk_mgr->base.ctx->dc->dml.soc.sr_exit_time_us;
-	double sr_enter_plus_exit_time_us = clk_mgr->base.ctx->dc->dml.soc.sr_enter_plus_exit_time_us;
-	/* For min clocks use as reported by PM FW and report those as min */
-	uint16_t min_uclk_mhz			= clk_mgr->base.bw_params->clk_table.entries[0].memclk_mhz;
-	uint16_t min_dcfclk_mhz			= clk_mgr->base.bw_params->clk_table.entries[0].dcfclk_mhz;
-	uint16_t setb_min_uclk_mhz		= min_uclk_mhz;
-	uint16_t dcfclk_mhz_for_the_second_state = clk_mgr->base.ctx->dc->dml.soc.clock_limits[2].dcfclk_mhz;
-
-	/* For Set B ranges use min clocks state 2 when available, and report those to PM FW */
-	if (dcfclk_mhz_for_the_second_state)
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_dcfclk = dcfclk_mhz_for_the_second_state;
-	else
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_dcfclk = clk_mgr->base.bw_params->clk_table.entries[0].dcfclk_mhz;
-
-	if (clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz)
-		setb_min_uclk_mhz = clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz;
-
-	/* Set A - Normal - default values */
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].valid = true;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us = pstate_latency_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.fclk_change_latency_us = fclk_change_latency_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us = sr_exit_time_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_dcfclk = 0xFFFF;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_uclk = min_uclk_mhz;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_uclk = 0xFFFF;
-
-	/* Set B - Performance - higher clocks, using DPM[2] DCFCLK and UCLK */
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].valid = true;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us = pstate_latency_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.fclk_change_latency_us = fclk_change_latency_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us = sr_exit_time_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.max_dcfclk = 0xFFFF;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_uclk = setb_min_uclk_mhz;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.max_uclk = 0xFFFF;
-
-	/* Set C - Dummy P-State - P-State latency set to "dummy p-state" value */
-	/* 'DalDummyClockChangeLatencyNs' registry key option set to 0x7FFFFFFF can be used to disable Set C for dummy p-state */
-	if (clk_mgr->base.ctx->dc->bb_overrides.dummy_clock_change_latency_ns != 0x7FFFFFFF) {
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].valid = true;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us = 38;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.fclk_change_latency_us = fclk_change_latency_us;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us = sr_exit_time_us;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.wm_type = WATERMARKS_DUMMY_PSTATE;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_dcfclk = 0xFFFF;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_uclk = min_uclk_mhz;
-		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_uclk = 0xFFFF;
-		clk_mgr->base.bw_params->dummy_pstate_table[0].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[0].memclk_mhz * 16;
-		clk_mgr->base.bw_params->dummy_pstate_table[0].dummy_pstate_latency_us = 38;
-		clk_mgr->base.bw_params->dummy_pstate_table[1].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[1].memclk_mhz * 16;
-		clk_mgr->base.bw_params->dummy_pstate_table[1].dummy_pstate_latency_us = 9;
-		clk_mgr->base.bw_params->dummy_pstate_table[2].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz * 16;
-		clk_mgr->base.bw_params->dummy_pstate_table[2].dummy_pstate_latency_us = 8;
-		clk_mgr->base.bw_params->dummy_pstate_table[3].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[3].memclk_mhz * 16;
-		clk_mgr->base.bw_params->dummy_pstate_table[3].dummy_pstate_latency_us = 5;
-	}
-	/* Set D - MALL - SR enter and exit time specific to MALL, TBD after bringup or later phase for now use DRAM values / 2 */
-	/* For MALL DRAM clock change latency is N/A, for watermak calculations use lowest value dummy P state latency */
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].valid = true;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us = clk_mgr->base.bw_params->dummy_pstate_table[3].dummy_pstate_latency_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.fclk_change_latency_us = fclk_change_latency_us;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us = sr_exit_time_us; // TBD
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us; // TBD
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.wm_type = WATERMARKS_MALL;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_dcfclk = 0xFFFF;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.min_uclk = min_uclk_mhz;
-	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_uclk = 0xFFFF;
+	DC_FP_START();
+	dcn32_build_wm_range_table_fpu(clk_mgr);
+	DC_FP_END();
 }
 
 void dcn32_init_clocks(struct clk_mgr *clk_mgr_base)
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index c48688cdd7f7..01cb0ef3a2b0 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -72,6 +72,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/dcn30_fpu.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/dcn32_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_32.o := $(dml_ccflags) $(frame_warn_flag)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_rq_dlg_calc_32.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_util_32.o := $(dml_ccflags)
@@ -124,6 +125,7 @@ DML += dcn30/dcn30_fpu.o dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_3
 DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o
 DML += dcn32/display_mode_vba_32.o dcn32/display_rq_dlg_calc_32.o dcn32/display_mode_vba_util_32.o
 DML += dcn31/dcn31_fpu.o
+DML += dcn32/dcn32_fpu.o
 DML += dcn301/dcn301_fpu.o
 DML += dcn302/dcn302_fpu.o
 DML += dcn303/dcn303_fpu.o
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
new file mode 100644
index 000000000000..89b596599c3d
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "dcn32_fpu.h"
+
+// We need this includes for WATERMARKS_* defines
+#include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
+
+void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
+{
+	/* defaults */
+	double pstate_latency_us = clk_mgr->base.ctx->dc->dml.soc.dram_clock_change_latency_us;
+	double fclk_change_latency_us = clk_mgr->base.ctx->dc->dml.soc.fclk_change_latency_us;
+	double sr_exit_time_us = clk_mgr->base.ctx->dc->dml.soc.sr_exit_time_us;
+	double sr_enter_plus_exit_time_us = clk_mgr->base.ctx->dc->dml.soc.sr_enter_plus_exit_time_us;
+	/* For min clocks use as reported by PM FW and report those as min */
+	uint16_t min_uclk_mhz			= clk_mgr->base.bw_params->clk_table.entries[0].memclk_mhz;
+	uint16_t min_dcfclk_mhz			= clk_mgr->base.bw_params->clk_table.entries[0].dcfclk_mhz;
+	uint16_t setb_min_uclk_mhz		= min_uclk_mhz;
+	uint16_t dcfclk_mhz_for_the_second_state = clk_mgr->base.ctx->dc->dml.soc.clock_limits[2].dcfclk_mhz;
+
+	dc_assert_fp_enabled();
+
+	/* For Set B ranges use min clocks state 2 when available, and report those to PM FW */
+	if (dcfclk_mhz_for_the_second_state)
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_dcfclk = dcfclk_mhz_for_the_second_state;
+	else
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_dcfclk = clk_mgr->base.bw_params->clk_table.entries[0].dcfclk_mhz;
+
+	if (clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz)
+		setb_min_uclk_mhz = clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz;
+
+	/* Set A - Normal - default values */
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].valid = true;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us = pstate_latency_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.fclk_change_latency_us = fclk_change_latency_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us = sr_exit_time_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_dcfclk = 0xFFFF;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_uclk = min_uclk_mhz;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_uclk = 0xFFFF;
+
+	/* Set B - Performance - higher clocks, using DPM[2] DCFCLK and UCLK */
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].valid = true;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us = pstate_latency_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.fclk_change_latency_us = fclk_change_latency_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us = sr_exit_time_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.max_dcfclk = 0xFFFF;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.min_uclk = setb_min_uclk_mhz;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_B].pmfw_breakdown.max_uclk = 0xFFFF;
+
+	/* Set C - Dummy P-State - P-State latency set to "dummy p-state" value */
+	/* 'DalDummyClockChangeLatencyNs' registry key option set to 0x7FFFFFFF can be used to disable Set C for dummy p-state */
+	if (clk_mgr->base.ctx->dc->bb_overrides.dummy_clock_change_latency_ns != 0x7FFFFFFF) {
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].valid = true;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us = 38;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.fclk_change_latency_us = fclk_change_latency_us;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us = sr_exit_time_us;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.wm_type = WATERMARKS_DUMMY_PSTATE;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_dcfclk = 0xFFFF;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.min_uclk = min_uclk_mhz;
+		clk_mgr->base.bw_params->wm_table.nv_entries[WM_C].pmfw_breakdown.max_uclk = 0xFFFF;
+		clk_mgr->base.bw_params->dummy_pstate_table[0].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[0].memclk_mhz * 16;
+		clk_mgr->base.bw_params->dummy_pstate_table[0].dummy_pstate_latency_us = 38;
+		clk_mgr->base.bw_params->dummy_pstate_table[1].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[1].memclk_mhz * 16;
+		clk_mgr->base.bw_params->dummy_pstate_table[1].dummy_pstate_latency_us = 9;
+		clk_mgr->base.bw_params->dummy_pstate_table[2].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[2].memclk_mhz * 16;
+		clk_mgr->base.bw_params->dummy_pstate_table[2].dummy_pstate_latency_us = 8;
+		clk_mgr->base.bw_params->dummy_pstate_table[3].dram_speed_mts = clk_mgr->base.bw_params->clk_table.entries[3].memclk_mhz * 16;
+		clk_mgr->base.bw_params->dummy_pstate_table[3].dummy_pstate_latency_us = 5;
+	}
+	/* Set D - MALL - SR enter and exit time specific to MALL, TBD after bringup or later phase for now use DRAM values / 2 */
+	/* For MALL DRAM clock change latency is N/A, for watermak calculations use lowest value dummy P state latency */
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].valid = true;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us = clk_mgr->base.bw_params->dummy_pstate_table[3].dummy_pstate_latency_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.fclk_change_latency_us = fclk_change_latency_us;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us = sr_exit_time_us / 2; // TBD
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us = sr_enter_plus_exit_time_us / 2; // TBD
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.wm_type = WATERMARKS_MALL;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_dcfclk = 0xFFFF;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.min_uclk = min_uclk_mhz;
+	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_uclk = 0xFFFF;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
new file mode 100644
index 000000000000..72a6dd75af0e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN32_FPU_H__
+#define __DCN32_FPU_H__
+
+#include "clk_mgr_internal.h"
+
+void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr);
+
+#endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 19/31] drm/amd/display: Move populate phaton function to dml
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (17 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 18/31] drm/amd/display: Drop FPU flags from dcn32_clk_mgr Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 20/31] drm/amd/display: Move predict pipe to dml fpu folder Rodrigo Siqueira
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

The function dcn32_helper_populate_phantom_dlg_params uses FPU
operations. For this reason, this commit moves this function to the
dcn32_fpu file, and we ensure that we only invoke it under the
kernel_fpu protection.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c |  7 +++
 .../display/dc/dcn32/dcn32_resource_helpers.c | 44 -------------------
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 43 ++++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |  5 +++
 4 files changed, 55 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 39214a0dcdf2..411ce13847c2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -88,6 +88,7 @@
 #include "dml/dcn30/display_mode_vba_30.h"
 #include "vm_helper.h"
 #include "dcn20/dcn20_vmid.h"
+#include "dml/dcn32/dcn32_fpu.h"
 
 #define DCN_BASE__INST0_SEG1                       0x000000C0
 #define DCN_BASE__INST0_SEG2                       0x000034C0
@@ -312,6 +313,7 @@ enum dcn32_clk_src_array_id {
 		.reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \
 					regBIF_BX0_ ## reg_name
 
+#undef CTX
 #define CTX ctx
 #define REG(reg_name) \
 	(DCN_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
@@ -2667,6 +2669,11 @@ static void dcn32_full_validate_bw_helper(struct dc *dc,
 			memset(merge, 0, MAX_PIPES * sizeof(bool));
 			*vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge);
 
+			// Most populate phantom DLG params before programming hardware / timing for phantom pipe
+			DC_FP_START();
+			dcn32_helper_populate_phantom_dlg_params(dc, context, pipes, *pipe_cnt);
+			DC_FP_END();
+
 			// Note: We can't apply the phantom pipes to hardware at this time. We have to wait
 			// until driver has acquired the DMCUB lock to do it safely.
 		}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
index a6ef1dba01fe..633d3ee18cfa 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
@@ -28,50 +28,6 @@
 #include "dcn20/dcn20_resource.h"
 #include "dml/dcn32/display_mode_vba_util_32.h"
 
-/**
- * ********************************************************************************************
- * dcn32_helper_populate_phantom_dlg_params: Get DLG params for phantom pipes and populate pipe_ctx
- * with those params.
- *
- * This function must be called AFTER the phantom pipes are added to context and run through DML
- * (so that the DLG params for the phantom pipes can be populated), and BEFORE we program the
- * timing for the phantom pipes.
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] pipes: DML pipe params array
- * @param [in] pipe_cnt: DML pipe count
- *
- * @return: void
- *
- * ********************************************************************************************
- */
-void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
-		struct dc_state *context,
-		display_e2e_pipe_params_st *pipes,
-		int pipe_cnt)
-{
-	uint32_t i, pipe_idx;
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-		if (!pipe->stream)
-			continue;
-
-		if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
-			pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt,
-					pipe_idx);
-			pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
-					pipe_idx);
-			pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt,
-					pipe_idx);
-			pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
-					pipe_idx);
-			pipe->pipe_dlg_param = pipes[pipe_idx].pipe.dest;
-		}
-		pipe_idx++;
-	}
-}
-
 /**
  * ********************************************************************************************
  * dcn32_helper_calculate_num_ways_for_subvp: Calculate number of ways needed for SubVP
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 89b596599c3d..253ff9659b0d 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -111,3 +111,46 @@ void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
 	clk_mgr->base.bw_params->wm_table.nv_entries[WM_D].pmfw_breakdown.max_uclk = 0xFFFF;
 }
 
+/**
+ * dcn32_helper_populate_phantom_dlg_params - Get DLG params for phantom pipes
+ * and populate pipe_ctx with those params.
+ *
+ * This function must be called AFTER the phantom pipes are added to context
+ * and run through DML (so that the DLG params for the phantom pipes can be
+ * populated), and BEFORE we program the timing for the phantom pipes.
+ *
+ * @dc: [in] current dc state
+ * @context: [in] new dc state
+ * @pipes: [in] DML pipe params array
+ * @pipe_cnt: [in] DML pipe count
+ */
+void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
+					      struct dc_state *context,
+					      display_e2e_pipe_params_st *pipes,
+					      int pipe_cnt)
+{
+	uint32_t i, pipe_idx;
+
+	dc_assert_fp_enabled();
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+		if (!pipe->stream)
+			continue;
+
+		if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+			pipes[pipe_idx].pipe.dest.vstartup_start =
+				get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+			pipes[pipe_idx].pipe.dest.vupdate_offset =
+				get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+			pipes[pipe_idx].pipe.dest.vupdate_width =
+				get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+			pipes[pipe_idx].pipe.dest.vready_offset =
+				get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+			pipe->pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+		}
+		pipe_idx++;
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 72a6dd75af0e..492f99b6d561 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -31,4 +31,9 @@
 
 void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr);
 
+void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
+					      struct dc_state *context,
+					      display_e2e_pipe_params_st *pipes,
+					      int pipe_cnt);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 20/31] drm/amd/display: Move predict pipe to dml fpu folder
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (18 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 19/31] drm/amd/display: Move populate phaton function to dml Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 21/31] drm/amd/display: Move insert entry table to the FPU code Rodrigo Siqueira
                   ` (11 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

The function dcn32_predict_pipe_split uses FPU operations. This commit
moves this function to the dcn32_fpu file, and we ensure that we only
invoke it under the kernel_fpu protection.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c |  2 +
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |  2 -
 .../display/dc/dcn32/dcn32_resource_helpers.c | 33 ----------------
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 39 ++++++++++++++++++-
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |  4 ++
 5 files changed, 44 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 411ce13847c2..a56d87140eba 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -3054,7 +3054,9 @@ int dcn32_populate_dml_pipes_from_context(
 				pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1;
 		}
 
+		DC_FP_START();
 		is_pipe_split_expected[i] = dcn32_predict_pipe_split(context, pipes[i].pipe, i);
+		DC_FP_END();
 
 		pipe_cnt++;
 	}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index 10254ab7e9d9..901aa7e13bd2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -100,8 +100,6 @@ bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc,
 bool dcn32_subvp_in_use(struct dc *dc,
 		struct dc_state *context);
 
-bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st pipe, int index);
-
 void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes,
 		bool *is_pipe_split_expected, int pipe_cnt);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
index 633d3ee18cfa..796e3d966a76 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
@@ -153,39 +153,6 @@ bool dcn32_subvp_in_use(struct dc *dc,
 	return false;
 }
 
-bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st pipe, int index)
-{
-	double pscl_throughput, pscl_throughput_chroma, dpp_clk_single_dpp, clock,
-		clk_frequency = 0.0, vco_speed = context->bw_ctx.dml.soc.dispclk_dppclk_vco_speed_mhz;
-
-	dml32_CalculateSinglePipeDPPCLKAndSCLThroughput(pipe.scale_ratio_depth.hscl_ratio,
-			pipe.scale_ratio_depth.hscl_ratio_c,
-			pipe.scale_ratio_depth.vscl_ratio,
-			pipe.scale_ratio_depth.vscl_ratio_c,
-			context->bw_ctx.dml.ip.max_dchub_pscl_bw_pix_per_clk,
-			context->bw_ctx.dml.ip.max_pscl_lb_bw_pix_per_clk,
-			pipe.dest.pixel_rate_mhz,
-			pipe.src.source_format,
-			pipe.scale_taps.htaps,
-			pipe.scale_taps.htaps_c,
-			pipe.scale_taps.vtaps,
-			pipe.scale_taps.vtaps_c,
-
-			/* Output */
-			&pscl_throughput, &pscl_throughput_chroma,
-			&dpp_clk_single_dpp);
-
-	clock = dpp_clk_single_dpp * (1 + context->bw_ctx.dml.soc.dcn_downspread_percent / 100);
-
-	if (clock > 0)
-		clk_frequency = vco_speed * 4.0 / ((int) (vco_speed * 4.0));
-
-	if (clk_frequency > context->bw_ctx.dml.soc.clock_limits[index].dppclk_mhz)
-		return true;
-	else
-		return false;
-}
-
 void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes,
 		bool *is_pipe_split_expected, int pipe_cnt)
 {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 253ff9659b0d..1b9e34f1232a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -24,7 +24,7 @@
  *
  */
 #include "dcn32_fpu.h"
-
+#include "display_mode_vba_util_32.h"
 // We need this includes for WATERMARKS_* defines
 #include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
 
@@ -154,3 +154,40 @@ void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
 	}
 }
 
+bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st pipe, int index)
+{
+	double pscl_throughput;
+	double pscl_throughput_chroma;
+	double dpp_clk_single_dpp, clock;
+	double clk_frequency = 0.0;
+	double vco_speed = context->bw_ctx.dml.soc.dispclk_dppclk_vco_speed_mhz;
+
+	dc_assert_fp_enabled();
+
+	dml32_CalculateSinglePipeDPPCLKAndSCLThroughput(pipe.scale_ratio_depth.hscl_ratio,
+							pipe.scale_ratio_depth.hscl_ratio_c,
+							pipe.scale_ratio_depth.vscl_ratio,
+							pipe.scale_ratio_depth.vscl_ratio_c,
+							context->bw_ctx.dml.ip.max_dchub_pscl_bw_pix_per_clk,
+							context->bw_ctx.dml.ip.max_pscl_lb_bw_pix_per_clk,
+							pipe.dest.pixel_rate_mhz,
+							pipe.src.source_format,
+							pipe.scale_taps.htaps,
+							pipe.scale_taps.htaps_c,
+							pipe.scale_taps.vtaps,
+							pipe.scale_taps.vtaps_c,
+							/* Output */
+							&pscl_throughput, &pscl_throughput_chroma,
+							&dpp_clk_single_dpp);
+
+	clock = dpp_clk_single_dpp * (1 + context->bw_ctx.dml.soc.dcn_downspread_percent / 100);
+
+	if (clock > 0)
+		clk_frequency = vco_speed * 4.0 / ((int)(vco_speed * 4.0));
+
+	if (clk_frequency > context->bw_ctx.dml.soc.clock_limits[index].dppclk_mhz)
+		return true;
+	else
+		return false;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 492f99b6d561..d5f157cdd0b4 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -36,4 +36,8 @@ void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
 					      display_e2e_pipe_params_st *pipes,
 					      int pipe_cnt);
 
+bool dcn32_predict_pipe_split(struct dc_state *context,
+			      display_pipe_params_st pipe,
+			      int index);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 21/31] drm/amd/display: Move insert entry table to the FPU code
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (19 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 20/31] drm/amd/display: Move predict pipe to dml fpu folder Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 22/31] drm/amd/display: Move phanton stream to " Rodrigo Siqueira
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

The insert_entry_into_table_sorted function uses FPU operation and calls
other static functions support. This commit moves the insert entry
function with all the required struct and static functions to the FPU
file.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 188 +-----------------
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |   3 +
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 186 +++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |   9 +
 4 files changed, 208 insertions(+), 178 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index a56d87140eba..1c124231b00a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -115,137 +115,6 @@ static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C
 
 #define DC_LOGGER_INIT(logger)
 
-#define DCN3_2_DEFAULT_DET_SIZE 256
-#define DCN3_2_MAX_DET_SIZE 1152
-#define DCN3_2_MIN_DET_SIZE 128
-#define DCN3_2_MIN_COMPBUF_SIZE_KB 128
-
-struct _vcs_dpi_ip_params_st dcn3_2_ip = {
-	.gpuvm_enable = 0,
-	.gpuvm_max_page_table_levels = 4,
-	.hostvm_enable = 0,
-	.rob_buffer_size_kbytes = 128,
-	.det_buffer_size_kbytes = DCN3_2_DEFAULT_DET_SIZE,
-	.config_return_buffer_size_in_kbytes = 1280,
-	.compressed_buffer_segment_size_in_kbytes = 64,
-	.meta_fifo_size_in_kentries = 22,
-	.zero_size_buffer_entries = 512,
-	.compbuf_reserved_space_64b = 256,
-	.compbuf_reserved_space_zs = 64,
-	.dpp_output_buffer_pixels = 2560,
-	.opp_output_buffer_lines = 1,
-	.pixel_chunk_size_kbytes = 8,
-	.alpha_pixel_chunk_size_kbytes = 4, // not appearing in spreadsheet, match c code from hw team
-	.min_pixel_chunk_size_bytes = 1024,
-	.dcc_meta_buffer_size_bytes = 6272,
-	.meta_chunk_size_kbytes = 2,
-	.min_meta_chunk_size_bytes = 256,
-	.writeback_chunk_size_kbytes = 8,
-	.ptoi_supported = false,
-	.num_dsc = 4,
-	.maximum_dsc_bits_per_component = 12,
-	.maximum_pixels_per_line_per_dsc_unit = 6016,
-	.dsc422_native_support = true,
-	.is_line_buffer_bpp_fixed = true,
-	.line_buffer_fixed_bpp = 57,
-	.line_buffer_size_bits = 1171920, //DPP doc, DCN3_2_DisplayMode_73.xlsm still shows as 986880 bits with 48 bpp
-	.max_line_buffer_lines = 32,
-	.writeback_interface_buffer_size_kbytes = 90,
-	.max_num_dpp = 4,
-	.max_num_otg = 4,
-	.max_num_hdmi_frl_outputs = 1,
-	.max_num_wb = 1,
-	.max_dchub_pscl_bw_pix_per_clk = 4,
-	.max_pscl_lb_bw_pix_per_clk = 2,
-	.max_lb_vscl_bw_pix_per_clk = 4,
-	.max_vscl_hscl_bw_pix_per_clk = 4,
-	.max_hscl_ratio = 6,
-	.max_vscl_ratio = 6,
-	.max_hscl_taps = 8,
-	.max_vscl_taps = 8,
-	.dpte_buffer_size_in_pte_reqs_luma = 64,
-	.dpte_buffer_size_in_pte_reqs_chroma = 34,
-	.dispclk_ramp_margin_percent = 1,
-	.max_inter_dcn_tile_repeaters = 8,
-	.cursor_buffer_size = 16,
-	.cursor_chunk_size = 2,
-	.writeback_line_buffer_buffer_size = 0,
-	.writeback_min_hscl_ratio = 1,
-	.writeback_min_vscl_ratio = 1,
-	.writeback_max_hscl_ratio = 1,
-	.writeback_max_vscl_ratio = 1,
-	.writeback_max_hscl_taps = 1,
-	.writeback_max_vscl_taps = 1,
-	.dppclk_delay_subtotal = 47,
-	.dppclk_delay_scl = 50,
-	.dppclk_delay_scl_lb_only = 16,
-	.dppclk_delay_cnvc_formatter = 28,
-	.dppclk_delay_cnvc_cursor = 6,
-	.dispclk_delay_subtotal = 125,
-	.dynamic_metadata_vm_enabled = false,
-	.odm_combine_4to1_supported = false,
-	.dcc_supported = true,
-	.max_num_dp2p0_outputs = 2,
-	.max_num_dp2p0_streams = 4,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = {
-	.clock_limits = {
-		{
-			.state = 0,
-			.dcfclk_mhz = 1564.0,
-			.fabricclk_mhz = 400.0,
-			.dispclk_mhz = 2150.0,
-			.dppclk_mhz = 2150.0,
-			.phyclk_mhz = 810.0,
-			.phyclk_d18_mhz = 667.0,
-			.phyclk_d32_mhz = 625.0,
-			.socclk_mhz = 1200.0,
-			.dscclk_mhz = 716.667,
-			.dram_speed_mts = 1600.0,
-			.dtbclk_mhz = 1564.0,
-		},
-	},
-	.num_states = 1,
-	.sr_exit_time_us = 5.20,
-	.sr_enter_plus_exit_time_us = 9.60,
-	.sr_exit_z8_time_us = 285.0,
-	.sr_enter_plus_exit_z8_time_us = 320,
-	.writeback_latency_us = 12.0,
-	.round_trip_ping_latency_dcfclk_cycles = 263,
-	.urgent_latency_pixel_data_only_us = 4.0,
-	.urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
-	.urgent_latency_vm_data_only_us = 4.0,
-	.fclk_change_latency_us = 20,
-	.usr_retraining_latency_us = 2,
-	.smn_latency_us = 2,
-	.mall_allocated_for_dcn_mbytes = 64,
-	.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
-	.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
-	.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
-	.pct_ideal_sdp_bw_after_urgent = 100.0,
-	.pct_ideal_fabric_bw_after_urgent = 67.0,
-	.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0,
-	.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
-	.pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0, // N/A, for now keep as is until DML implemented
-	.pct_ideal_dram_bw_after_urgent_strobe = 67.0,
-	.max_avg_sdp_bw_use_normal_percent = 80.0,
-	.max_avg_fabric_bw_use_normal_percent = 60.0,
-	.max_avg_dram_bw_use_normal_strobe_percent = 50.0,
-	.max_avg_dram_bw_use_normal_percent = 15.0,
-	.num_chans = 8,
-	.dram_channel_width_bytes = 2,
-	.fabric_datapath_to_dcn_data_return_bytes = 64,
-	.return_bus_width_bytes = 64,
-	.downspread_percent = 0.38,
-	.dcn_downspread_percent = 0.5,
-	.dram_clock_change_latency_us = 400,
-	.dispclk_dppclk_vco_speed_mhz = 4300.0,
-	.do_urgent_latency_adjustment = true,
-	.urgent_latency_adjustment_fabric_clock_component_us = 1.0,
-	.urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
-};
-
 enum dcn32_clk_src_array_id {
 	DCN32_CLK_SRC_PLL0,
 	DCN32_CLK_SRC_PLL1,
@@ -3455,53 +3324,6 @@ static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
 	}
 }
 
-static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *entry)
-{
-	float memory_bw_kbytes_sec = entry->dram_speed_mts * dcn3_2_soc.num_chans *
-			dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
-
-	float fabric_bw_kbytes_sec = entry->fabricclk_mhz * dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100);
-
-	float sdp_bw_kbytes_sec = entry->dcfclk_mhz * dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100);
-
-	float limiting_bw_kbytes_sec = memory_bw_kbytes_sec;
-
-	if (fabric_bw_kbytes_sec < limiting_bw_kbytes_sec)
-		limiting_bw_kbytes_sec = fabric_bw_kbytes_sec;
-
-	if (sdp_bw_kbytes_sec < limiting_bw_kbytes_sec)
-		limiting_bw_kbytes_sec = sdp_bw_kbytes_sec;
-
-	return limiting_bw_kbytes_sec;
-}
-
-static void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
-		struct _vcs_dpi_voltage_scaling_st *entry)
-{
-	int index = 0;
-	int i = 0;
-	float net_bw_of_new_state = 0;
-
-	if (*num_entries == 0) {
-		table[0] = *entry;
-		(*num_entries)++;
-	} else {
-		net_bw_of_new_state = calculate_net_bw_in_kbytes_sec(entry);
-		while (net_bw_of_new_state > calculate_net_bw_in_kbytes_sec(&table[index])) {
-			index++;
-			if (index >= *num_entries)
-				break;
-		}
-
-		for (i = *num_entries; i > index; i--) {
-			table[i] = table[i - 1];
-		}
-
-		table[index] = *entry;
-		(*num_entries)++;
-	}
-}
-
 static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
 		unsigned int index)
 {
@@ -3586,7 +3408,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.dram_speed_mts = 0;
 
 		get_optimal_ntuple(&entry);
+		DC_FP_START();
 		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
 	}
 
 	// Insert the max DCFCLK
@@ -3595,7 +3419,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 	entry.dram_speed_mts = 0;
 
 	get_optimal_ntuple(&entry);
+	DC_FP_START();
 	insert_entry_into_table_sorted(table, num_entries, &entry);
+	DC_FP_END();
 
 	// Insert the UCLK DPMS
 	for (i = 0; i < num_uclk_dpms; i++) {
@@ -3604,7 +3430,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
 
 		get_optimal_ntuple(&entry);
+		DC_FP_START();
 		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
 	}
 
 	// If FCLK is coarse grained, insert individual DPMs.
@@ -3615,7 +3443,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 			entry.dram_speed_mts = 0;
 
 			get_optimal_ntuple(&entry);
+			DC_FP_START();
 			insert_entry_into_table_sorted(table, num_entries, &entry);
+			DC_FP_END();
 		}
 	}
 	// If FCLK fine grained, only insert max
@@ -3625,7 +3455,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.dram_speed_mts = 0;
 
 		get_optimal_ntuple(&entry);
+		DC_FP_START();
 		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
 	}
 
 	// At this point, the table contains all "points of interest" based on
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index 901aa7e13bd2..7ccad84b1f16 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -33,6 +33,9 @@
 #define TO_DCN32_RES_POOL(pool)\
 	container_of(pool, struct dcn32_resource_pool, base)
 
+extern struct _vcs_dpi_ip_params_st dcn3_2_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc;
+
 struct dcn32_resource_pool {
 	struct resource_pool base;
 };
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 1b9e34f1232a..4223a9a9dd45 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -28,6 +28,132 @@
 // We need this includes for WATERMARKS_* defines
 #include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
 
+struct _vcs_dpi_ip_params_st dcn3_2_ip = {
+	.gpuvm_enable = 0,
+	.gpuvm_max_page_table_levels = 4,
+	.hostvm_enable = 0,
+	.rob_buffer_size_kbytes = 128,
+	.det_buffer_size_kbytes = DCN3_2_DEFAULT_DET_SIZE,
+	.config_return_buffer_size_in_kbytes = 1280,
+	.compressed_buffer_segment_size_in_kbytes = 64,
+	.meta_fifo_size_in_kentries = 22,
+	.zero_size_buffer_entries = 512,
+	.compbuf_reserved_space_64b = 256,
+	.compbuf_reserved_space_zs = 64,
+	.dpp_output_buffer_pixels = 2560,
+	.opp_output_buffer_lines = 1,
+	.pixel_chunk_size_kbytes = 8,
+	.alpha_pixel_chunk_size_kbytes = 4,
+	.min_pixel_chunk_size_bytes = 1024,
+	.dcc_meta_buffer_size_bytes = 6272,
+	.meta_chunk_size_kbytes = 2,
+	.min_meta_chunk_size_bytes = 256,
+	.writeback_chunk_size_kbytes = 8,
+	.ptoi_supported = false,
+	.num_dsc = 4,
+	.maximum_dsc_bits_per_component = 12,
+	.maximum_pixels_per_line_per_dsc_unit = 6016,
+	.dsc422_native_support = true,
+	.is_line_buffer_bpp_fixed = true,
+	.line_buffer_fixed_bpp = 57,
+	.line_buffer_size_bits = 1171920,
+	.max_line_buffer_lines = 32,
+	.writeback_interface_buffer_size_kbytes = 90,
+	.max_num_dpp = 4,
+	.max_num_otg = 4,
+	.max_num_hdmi_frl_outputs = 1,
+	.max_num_wb = 1,
+	.max_dchub_pscl_bw_pix_per_clk = 4,
+	.max_pscl_lb_bw_pix_per_clk = 2,
+	.max_lb_vscl_bw_pix_per_clk = 4,
+	.max_vscl_hscl_bw_pix_per_clk = 4,
+	.max_hscl_ratio = 6,
+	.max_vscl_ratio = 6,
+	.max_hscl_taps = 8,
+	.max_vscl_taps = 8,
+	.dpte_buffer_size_in_pte_reqs_luma = 64,
+	.dpte_buffer_size_in_pte_reqs_chroma = 34,
+	.dispclk_ramp_margin_percent = 1,
+	.max_inter_dcn_tile_repeaters = 8,
+	.cursor_buffer_size = 16,
+	.cursor_chunk_size = 2,
+	.writeback_line_buffer_buffer_size = 0,
+	.writeback_min_hscl_ratio = 1,
+	.writeback_min_vscl_ratio = 1,
+	.writeback_max_hscl_ratio = 1,
+	.writeback_max_vscl_ratio = 1,
+	.writeback_max_hscl_taps = 1,
+	.writeback_max_vscl_taps = 1,
+	.dppclk_delay_subtotal = 47,
+	.dppclk_delay_scl = 50,
+	.dppclk_delay_scl_lb_only = 16,
+	.dppclk_delay_cnvc_formatter = 28,
+	.dppclk_delay_cnvc_cursor = 6,
+	.dispclk_delay_subtotal = 125,
+	.dynamic_metadata_vm_enabled = false,
+	.odm_combine_4to1_supported = false,
+	.dcc_supported = true,
+	.max_num_dp2p0_outputs = 2,
+	.max_num_dp2p0_streams = 4,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = {
+	.clock_limits = {
+		{
+			.state = 0,
+			.dcfclk_mhz = 1564.0,
+			.fabricclk_mhz = 400.0,
+			.dispclk_mhz = 2150.0,
+			.dppclk_mhz = 2150.0,
+			.phyclk_mhz = 810.0,
+			.phyclk_d18_mhz = 667.0,
+			.phyclk_d32_mhz = 625.0,
+			.socclk_mhz = 1200.0,
+			.dscclk_mhz = 716.667,
+			.dram_speed_mts = 16000.0,
+			.dtbclk_mhz = 1564.0,
+		},
+	},
+	.num_states = 1,
+	.sr_exit_time_us = 5.20,
+	.sr_enter_plus_exit_time_us = 9.60,
+	.sr_exit_z8_time_us = 285.0,
+	.sr_enter_plus_exit_z8_time_us = 320,
+	.writeback_latency_us = 12.0,
+	.round_trip_ping_latency_dcfclk_cycles = 263,
+	.urgent_latency_pixel_data_only_us = 4.0,
+	.urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+	.urgent_latency_vm_data_only_us = 4.0,
+	.fclk_change_latency_us = 20,
+	.usr_retraining_latency_us = 2,
+	.smn_latency_us = 2,
+	.mall_allocated_for_dcn_mbytes = 64,
+	.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+	.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+	.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+	.pct_ideal_sdp_bw_after_urgent = 100.0,
+	.pct_ideal_fabric_bw_after_urgent = 67.0,
+	.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0,
+	.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
+	.pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0, // N/A, for now keep as is until DML implemented
+	.pct_ideal_dram_bw_after_urgent_strobe = 67.0,
+	.max_avg_sdp_bw_use_normal_percent = 80.0,
+	.max_avg_fabric_bw_use_normal_percent = 60.0,
+	.max_avg_dram_bw_use_normal_strobe_percent = 50.0,
+	.max_avg_dram_bw_use_normal_percent = 15.0,
+	.num_chans = 8,
+	.dram_channel_width_bytes = 2,
+	.fabric_datapath_to_dcn_data_return_bytes = 64,
+	.return_bus_width_bytes = 64,
+	.downspread_percent = 0.38,
+	.dcn_downspread_percent = 0.5,
+	.dram_clock_change_latency_us = 400,
+	.dispclk_dppclk_vco_speed_mhz = 4300.0,
+	.do_urgent_latency_adjustment = true,
+	.urgent_latency_adjustment_fabric_clock_component_us = 1.0,
+	.urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+};
+
 void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
 {
 	/* defaults */
@@ -191,3 +317,63 @@ bool dcn32_predict_pipe_split(struct dc_state *context, display_pipe_params_st p
 		return false;
 }
 
+static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *entry)
+{
+	float memory_bw_kbytes_sec;
+	float fabric_bw_kbytes_sec;
+	float sdp_bw_kbytes_sec;
+	float limiting_bw_kbytes_sec;
+
+	memory_bw_kbytes_sec = entry->dram_speed_mts *
+				dcn3_2_soc.num_chans *
+				dcn3_2_soc.dram_channel_width_bytes *
+				((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
+
+	fabric_bw_kbytes_sec = entry->fabricclk_mhz *
+				dcn3_2_soc.return_bus_width_bytes *
+				((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100);
+
+	sdp_bw_kbytes_sec = entry->dcfclk_mhz *
+				dcn3_2_soc.return_bus_width_bytes *
+				((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100);
+
+	limiting_bw_kbytes_sec = memory_bw_kbytes_sec;
+
+	if (fabric_bw_kbytes_sec < limiting_bw_kbytes_sec)
+		limiting_bw_kbytes_sec = fabric_bw_kbytes_sec;
+
+	if (sdp_bw_kbytes_sec < limiting_bw_kbytes_sec)
+		limiting_bw_kbytes_sec = sdp_bw_kbytes_sec;
+
+	return limiting_bw_kbytes_sec;
+}
+
+void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
+				    unsigned int *num_entries,
+				    struct _vcs_dpi_voltage_scaling_st *entry)
+{
+	int i = 0;
+	int index = 0;
+	float net_bw_of_new_state = 0;
+
+	dc_assert_fp_enabled();
+
+	if (*num_entries == 0) {
+		table[0] = *entry;
+		(*num_entries)++;
+	} else {
+		net_bw_of_new_state = calculate_net_bw_in_kbytes_sec(entry);
+		while (net_bw_of_new_state > calculate_net_bw_in_kbytes_sec(&table[index])) {
+			index++;
+			if (index >= *num_entries)
+				break;
+		}
+
+		for (i = *num_entries; i > index; i--)
+			table[i] = table[i - 1];
+
+		table[index] = *entry;
+		(*num_entries)++;
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index d5f157cdd0b4..62cb0c1d462c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -29,6 +29,11 @@
 
 #include "clk_mgr_internal.h"
 
+#define DCN3_2_DEFAULT_DET_SIZE 256
+#define DCN3_2_MAX_DET_SIZE 1152
+#define DCN3_2_MIN_DET_SIZE 128
+#define DCN3_2_MIN_COMPBUF_SIZE_KB 128
+
 void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr);
 
 void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
@@ -40,4 +45,8 @@ bool dcn32_predict_pipe_split(struct dc_state *context,
 			      display_pipe_params_st pipe,
 			      int index);
 
+void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
+				    unsigned int *num_entries,
+				    struct _vcs_dpi_voltage_scaling_st *entry);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 22/31] drm/amd/display: Move phanton stream to FPU code
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (20 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 21/31] drm/amd/display: Move insert entry table to the FPU code Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 23/31] drm/amd/display: Move SubVP functions to dcn32_fpu Rodrigo Siqueira
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

This commit moves phanton FPU stream to dcn32_fpu file.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 89 +------------------
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 84 +++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |  8 ++
 3 files changed, 94 insertions(+), 87 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 1c124231b00a..a1bf24ad0787 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -1831,93 +1831,6 @@ static void dcn32_enable_phantom_plane(struct dc *dc,
 	}
 }
 
-/**
- * ***************************************************************************************
- * dcn32_set_phantom_stream_timing: Set timing params for the phantom stream
- *
- * Set timing params of the phantom stream based on calculated output from DML.
- * This function first gets the DML pipe index using the DC pipe index, then
- * calls into DML (get_subviewport_lines_needed_in_mall) to get the number of
- * lines required for SubVP MCLK switching and assigns to the phantom stream
- * accordingly.
- *
- * - The number of SubVP lines calculated in DML does not take into account
- * FW processing delays and required pstate allow width, so we must include
- * that separately.
- *
- * - Set phantom backporch = vstartup of main pipe
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] ref_pipe: Main pipe for the phantom stream
- * @param [in] pipes: DML pipe params
- * @param [in] pipe_cnt: number of DML pipes
- * @param [in] dc_pipe_idx: DC pipe index for the main pipe (i.e. ref_pipe)
- *
- * @return: void
- *
- * ***************************************************************************************
- */
-static void dcn32_set_phantom_stream_timing(struct dc *dc,
-		struct dc_state *context,
-		struct pipe_ctx *ref_pipe,
-		struct dc_stream_state *phantom_stream,
-		display_e2e_pipe_params_st *pipes,
-		unsigned int pipe_cnt,
-		unsigned int dc_pipe_idx)
-{
-	unsigned int i, pipe_idx;
-	struct pipe_ctx *pipe;
-	uint32_t phantom_vactive, phantom_bp, pstate_width_fw_delay_lines;
-	unsigned int vlevel = context->bw_ctx.dml.vba.VoltageLevel;
-	unsigned int dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
-	unsigned int socclk = context->bw_ctx.dml.vba.SOCCLKPerState[vlevel];
-
-	// Find DML pipe index (pipe_idx) using dc_pipe_idx
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		pipe = &context->res_ctx.pipe_ctx[i];
-
-		if (!pipe->stream)
-			continue;
-
-		if (i == dc_pipe_idx)
-			break;
-
-		pipe_idx++;
-	}
-
-	// Calculate lines required for pstate allow width and FW processing delays
-	pstate_width_fw_delay_lines = ((double)(dc->caps.subvp_fw_processing_delay_us +
-			dc->caps.subvp_pstate_allow_width_us) / 1000000) *
-			(ref_pipe->stream->timing.pix_clk_100hz * 100) /
-			(double)ref_pipe->stream->timing.h_total;
-
-	// Update clks_cfg for calling into recalculate
-	pipes[0].clks_cfg.voltage = vlevel;
-	pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
-	pipes[0].clks_cfg.socclk_mhz = socclk;
-
-	// DML calculation for MALL region doesn't take into account FW delay
-	// and required pstate allow width for multi-display cases
-	phantom_vactive = get_subviewport_lines_needed_in_mall(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx) +
-				pstate_width_fw_delay_lines;
-
-	// For backporch of phantom pipe, use vstartup of the main pipe
-	phantom_bp = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
-
-	phantom_stream->dst.y = 0;
-	phantom_stream->dst.height = phantom_vactive;
-	phantom_stream->src.y = 0;
-	phantom_stream->src.height = phantom_vactive;
-
-	phantom_stream->timing.v_addressable = phantom_vactive;
-	phantom_stream->timing.v_front_porch = 1;
-	phantom_stream->timing.v_total = phantom_stream->timing.v_addressable +
-						phantom_stream->timing.v_front_porch +
-						phantom_stream->timing.v_sync_width +
-						phantom_bp;
-}
-
 static struct dc_stream_state *dcn32_enable_phantom_stream(struct dc *dc,
 		struct dc_state *context,
 		display_e2e_pipe_params_st *pipes,
@@ -1939,7 +1852,9 @@ static struct dc_stream_state *dcn32_enable_phantom_stream(struct dc *dc,
 	memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing));
 	memcpy(&phantom_stream->src, &ref_pipe->stream->src, sizeof(phantom_stream->src));
 	memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst));
+	DC_FP_START();
 	dcn32_set_phantom_stream_timing(dc, context, ref_pipe, phantom_stream, pipes, pipe_cnt, dc_pipe_idx);
+	DC_FP_END();
 
 	dc_add_stream_to_ctx(dc, context, phantom_stream);
 	return phantom_stream;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 4223a9a9dd45..74ccf453349c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -377,3 +377,87 @@ void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
 	}
 }
 
+/**
+ * dcn32_set_phantom_stream_timing: Set timing params for the phantom stream
+ *
+ * Set timing params of the phantom stream based on calculated output from DML.
+ * This function first gets the DML pipe index using the DC pipe index, then
+ * calls into DML (get_subviewport_lines_needed_in_mall) to get the number of
+ * lines required for SubVP MCLK switching and assigns to the phantom stream
+ * accordingly.
+ *
+ * - The number of SubVP lines calculated in DML does not take into account
+ * FW processing delays and required pstate allow width, so we must include
+ * that separately.
+ *
+ * - Set phantom backporch = vstartup of main pipe
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ * @ref_pipe: Main pipe for the phantom stream
+ * @pipes: DML pipe params
+ * @pipe_cnt: number of DML pipes
+ * @dc_pipe_idx: DC pipe index for the main pipe (i.e. ref_pipe)
+ */
+void dcn32_set_phantom_stream_timing(struct dc *dc,
+				     struct dc_state *context,
+				     struct pipe_ctx *ref_pipe,
+				     struct dc_stream_state *phantom_stream,
+				     display_e2e_pipe_params_st *pipes,
+				     unsigned int pipe_cnt,
+				     unsigned int dc_pipe_idx)
+{
+	unsigned int i, pipe_idx;
+	struct pipe_ctx *pipe;
+	uint32_t phantom_vactive, phantom_bp, pstate_width_fw_delay_lines;
+	unsigned int vlevel = context->bw_ctx.dml.vba.VoltageLevel;
+	unsigned int dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
+	unsigned int socclk = context->bw_ctx.dml.vba.SOCCLKPerState[vlevel];
+
+	dc_assert_fp_enabled();
+
+	// Find DML pipe index (pipe_idx) using dc_pipe_idx
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		pipe = &context->res_ctx.pipe_ctx[i];
+
+		if (!pipe->stream)
+			continue;
+
+		if (i == dc_pipe_idx)
+			break;
+
+		pipe_idx++;
+	}
+
+	// Calculate lines required for pstate allow width and FW processing delays
+	pstate_width_fw_delay_lines = ((double)(dc->caps.subvp_fw_processing_delay_us +
+			dc->caps.subvp_pstate_allow_width_us) / 1000000) *
+			(ref_pipe->stream->timing.pix_clk_100hz * 100) /
+			(double)ref_pipe->stream->timing.h_total;
+
+	// Update clks_cfg for calling into recalculate
+	pipes[0].clks_cfg.voltage = vlevel;
+	pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+	pipes[0].clks_cfg.socclk_mhz = socclk;
+
+	// DML calculation for MALL region doesn't take into account FW delay
+	// and required pstate allow width for multi-display cases
+	phantom_vactive = get_subviewport_lines_needed_in_mall(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx) +
+				pstate_width_fw_delay_lines;
+
+	// For backporch of phantom pipe, use vstartup of the main pipe
+	phantom_bp = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+
+	phantom_stream->dst.y = 0;
+	phantom_stream->dst.height = phantom_vactive;
+	phantom_stream->src.y = 0;
+	phantom_stream->src.height = phantom_vactive;
+
+	phantom_stream->timing.v_addressable = phantom_vactive;
+	phantom_stream->timing.v_front_porch = 1;
+	phantom_stream->timing.v_total = phantom_stream->timing.v_addressable +
+						phantom_stream->timing.v_front_porch +
+						phantom_stream->timing.v_sync_width +
+						phantom_bp;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 62cb0c1d462c..4abef908dca9 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -49,4 +49,12 @@ void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
 				    unsigned int *num_entries,
 				    struct _vcs_dpi_voltage_scaling_st *entry);
 
+void dcn32_set_phantom_stream_timing(struct dc *dc,
+				     struct dc_state *context,
+				     struct pipe_ctx *ref_pipe,
+				     struct dc_stream_state *phantom_stream,
+				     display_e2e_pipe_params_st *pipes,
+				     unsigned int pipe_cnt,
+				     unsigned int dc_pipe_idx);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 23/31] drm/amd/display: Move SubVP functions to dcn32_fpu
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (21 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 22/31] drm/amd/display: Move phanton stream to " Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 24/31] drm/amd/display: Move wm and dlg calculation to FPU code Rodrigo Siqueira
                   ` (8 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

It looks like many of the code related to SubVP uses FPU operation, and
we have many static functions that are part of this feature. This commit
is a little bit large, but it only moves SubVP operation from one file
to another, and I had to do it in a single change due to dependencies
between functions.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 597 +-----------------
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |   2 +
 .../display/dc/dcn32/dcn32_resource_helpers.c |  11 +
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 597 ++++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |   8 +
 5 files changed, 620 insertions(+), 595 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index a1bf24ad0787..d508909ff7a9 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -1625,171 +1625,6 @@ bool dcn32_release_post_bldn_3dlut(
 	return ret;
 }
 
-/**
- ********************************************************************************************
- * dcn32_get_num_free_pipes: Calculate number of free pipes
- *
- * This function assumes that a "used" pipe is a pipe that has
- * both a stream and a plane assigned to it.
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- *
- * @return: Number of free pipes available in the context
- *
- ********************************************************************************************
- */
-static unsigned int dcn32_get_num_free_pipes(struct dc *dc, struct dc_state *context)
-{
-	unsigned int i;
-	unsigned int free_pipes = 0;
-	unsigned int num_pipes = 0;
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
-		if (pipe->stream && !pipe->top_pipe) {
-			while (pipe) {
-				num_pipes++;
-				pipe = pipe->bottom_pipe;
-			}
-		}
-	}
-
-	free_pipes = dc->res_pool->pipe_count - num_pipes;
-	return free_pipes;
-}
-
-/**
- ********************************************************************************************
- * dcn32_assign_subvp_pipe: Function to decide which pipe will use Sub-VP.
- *
- * We enter this function if we are Sub-VP capable (i.e. enough pipes available)
- * and regular P-State switching (i.e. VACTIVE/VBLANK) is not supported, or if
- * we are forcing SubVP P-State switching on the current config.
- *
- * The number of pipes used for the chosen surface must be less than or equal to the
- * number of free pipes available.
- *
- * In general we choose surfaces with the longest frame time first (better for SubVP + VBLANK).
- * For multi-display cases the ActiveDRAMClockChangeMargin doesn't provide enough info on its own
- * for determining which should be the SubVP pipe (need a way to determine if a pipe / plane doesn't
- * support MCLK switching naturally [i.e. ACTIVE or VBLANK]).
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [out] index: dc pipe index for the pipe chosen to have phantom pipes assigned
- *
- * @return: True if a valid pipe assignment was found for Sub-VP. Otherwise false.
- *
- ********************************************************************************************
- */
-
-static bool dcn32_assign_subvp_pipe(struct dc *dc,
-		struct dc_state *context,
-		unsigned int *index)
-{
-	unsigned int i, pipe_idx;
-	unsigned int max_frame_time = 0;
-	bool valid_assignment_found = false;
-	unsigned int free_pipes = dcn32_get_num_free_pipes(dc, context);
-	bool current_assignment_freesync = false;
-
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-		unsigned int num_pipes = 0;
-
-		if (!pipe->stream)
-			continue;
-
-		if (pipe->plane_state && !pipe->top_pipe &&
-				pipe->stream->mall_stream_config.type == SUBVP_NONE) {
-			while (pipe) {
-				num_pipes++;
-				pipe = pipe->bottom_pipe;
-			}
-
-			pipe = &context->res_ctx.pipe_ctx[i];
-			if (num_pipes <= free_pipes) {
-				struct dc_stream_state *stream = pipe->stream;
-				unsigned int frame_us = (stream->timing.v_total * stream->timing.h_total /
-						(double)(stream->timing.pix_clk_100hz * 100)) * 1000000;
-				if (frame_us > max_frame_time && !stream->ignore_msa_timing_param) {
-					*index = i;
-					max_frame_time = frame_us;
-					valid_assignment_found = true;
-					current_assignment_freesync = false;
-				/* For the 2-Freesync display case, still choose the one with the
-			     * longest frame time
-			     */
-				} else if (stream->ignore_msa_timing_param && (!valid_assignment_found ||
-						(current_assignment_freesync && frame_us > max_frame_time))) {
-					*index = i;
-					valid_assignment_found = true;
-					current_assignment_freesync = true;
-				}
-			}
-		}
-		pipe_idx++;
-	}
-	return valid_assignment_found;
-}
-
-/**
- * ***************************************************************************************
- * dcn32_enough_pipes_for_subvp: Function to check if there are "enough" pipes for SubVP.
- *
- * This function returns true if there are enough free pipes
- * to create the required phantom pipes for any given stream
- * (that does not already have phantom pipe assigned).
- *
- * e.g. For a 2 stream config where the first stream uses one
- * pipe and the second stream uses 2 pipes (i.e. pipe split),
- * this function will return true because there is 1 remaining
- * pipe which can be used as the phantom pipe for the non pipe
- * split pipe.
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- *
- * @return: True if there are enough free pipes to assign phantom pipes to at least one
- *          stream that does not already have phantom pipes assigned. Otherwise false.
- *
- * ***************************************************************************************
- */
-static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context)
-{
-	unsigned int i, split_cnt, free_pipes;
-	unsigned int min_pipe_split = dc->res_pool->pipe_count + 1; // init as max number of pipes + 1
-	bool subvp_possible = false;
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
-		// Find the minimum pipe split count for non SubVP pipes
-		if (pipe->stream && !pipe->top_pipe &&
-				pipe->stream->mall_stream_config.type == SUBVP_NONE) {
-			split_cnt = 0;
-			while (pipe) {
-				split_cnt++;
-				pipe = pipe->bottom_pipe;
-			}
-
-			if (split_cnt < min_pipe_split)
-				min_pipe_split = split_cnt;
-		}
-	}
-
-	free_pipes = dcn32_get_num_free_pipes(dc, context);
-
-	// SubVP only possible if at least one pipe is being used (i.e. free_pipes
-	// should not equal to the pipe_count)
-	if (free_pipes >= min_pipe_split && free_pipes < dc->res_pool->pipe_count)
-		subvp_possible = true;
-
-	return subvp_possible;
-}
-
 static void dcn32_enable_phantom_plane(struct dc *dc,
 		struct dc_state *context,
 		struct dc_stream_state *phantom_stream,
@@ -2034,436 +1869,6 @@ static struct pipe_ctx *dcn32_find_split_pipe(
 	return pipe;
 }
 
-
-/**
- * ***************************************************************************************
- * subvp_subvp_schedulable: Determine if SubVP + SubVP config is schedulable
- *
- * High level algorithm:
- * 1. Find longest microschedule length (in us) between the two SubVP pipes
- * 2. Check if the worst case overlap (VBLANK in middle of ACTIVE) for both
- * pipes still allows for the maximum microschedule to fit in the active
- * region for both pipes.
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- *
- * @return: bool - True if the SubVP + SubVP config is schedulable, false otherwise
- *
- * ***************************************************************************************
- */
-static bool subvp_subvp_schedulable(struct dc *dc, struct dc_state *context)
-{
-	struct pipe_ctx *subvp_pipes[2];
-	struct dc_stream_state *phantom = NULL;
-	uint32_t microschedule_lines = 0;
-	uint32_t index = 0;
-	uint32_t i;
-	uint32_t max_microschedule_us = 0;
-	int32_t vactive1_us, vactive2_us, vblank1_us, vblank2_us;
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-		uint32_t time_us = 0;
-
-		/* Loop to calculate the maximum microschedule time between the two SubVP pipes,
-		 * and also to store the two main SubVP pipe pointers in subvp_pipes[2].
-		 */
-		if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
-				pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
-			phantom = pipe->stream->mall_stream_config.paired_stream;
-			microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) +
-					phantom->timing.v_addressable;
-
-			// Round up when calculating microschedule time (+ 1 at the end)
-			time_us = (microschedule_lines * phantom->timing.h_total) /
-					(double)(phantom->timing.pix_clk_100hz * 100) * 1000000 +
-						dc->caps.subvp_prefetch_end_to_mall_start_us +
-						dc->caps.subvp_fw_processing_delay_us + 1;
-			if (time_us > max_microschedule_us)
-				max_microschedule_us = time_us;
-
-			subvp_pipes[index] = pipe;
-			index++;
-
-			// Maximum 2 SubVP pipes
-			if (index == 2)
-				break;
-		}
-	}
-	vactive1_us = ((subvp_pipes[0]->stream->timing.v_addressable * subvp_pipes[0]->stream->timing.h_total) /
-			(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
-	vactive2_us = ((subvp_pipes[1]->stream->timing.v_addressable * subvp_pipes[1]->stream->timing.h_total) /
-				(double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000;
-	vblank1_us = (((subvp_pipes[0]->stream->timing.v_total - subvp_pipes[0]->stream->timing.v_addressable) *
-			subvp_pipes[0]->stream->timing.h_total) /
-			(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
-	vblank2_us = (((subvp_pipes[1]->stream->timing.v_total - subvp_pipes[1]->stream->timing.v_addressable) *
-			subvp_pipes[1]->stream->timing.h_total) /
-			(double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000;
-
-	if ((vactive1_us - vblank2_us) / 2 > max_microschedule_us &&
-			(vactive2_us - vblank1_us) / 2 > max_microschedule_us)
-		return true;
-
-	return false;
-}
-
-/**
- * ***************************************************************************************
- * subvp_drr_schedulable: Determine if SubVP + DRR config is schedulable
- *
- * High level algorithm:
- * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe
- * 2. Determine the frame time for the DRR display when adding required margin for MCLK switching
- * (the margin is equal to the MALL region + DRR margin (500us))
- * 3.If (SubVP Active - Prefetch > Stretched DRR frame + max(MALL region, Stretched DRR frame))
- * then report the configuration as supported
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] drr_pipe: DRR pipe_ctx for the SubVP + DRR config
- *
- * @return: bool - True if the SubVP + DRR config is schedulable, false otherwise
- *
- * ***************************************************************************************
- */
-static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context, struct pipe_ctx *drr_pipe)
-{
-	bool schedulable = false;
-	uint32_t i;
-	struct pipe_ctx *pipe = NULL;
-	struct dc_crtc_timing *main_timing = NULL;
-	struct dc_crtc_timing *phantom_timing = NULL;
-	struct dc_crtc_timing *drr_timing = NULL;
-	int16_t prefetch_us = 0;
-	int16_t mall_region_us = 0;
-	int16_t drr_frame_us = 0;	// nominal frame time
-	int16_t subvp_active_us = 0;
-	int16_t stretched_drr_us = 0;
-	int16_t drr_stretched_vblank_us = 0;
-	int16_t max_vblank_mallregion = 0;
-
-	// Find SubVP pipe
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		pipe = &context->res_ctx.pipe_ctx[i];
-
-		// We check for master pipe, but it shouldn't matter since we only need
-		// the pipe for timing info (stream should be same for any pipe splits)
-		if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
-			continue;
-
-		// Find the SubVP pipe
-		if (pipe->stream->mall_stream_config.type == SUBVP_MAIN)
-			break;
-	}
-
-	main_timing = &pipe->stream->timing;
-	phantom_timing = &pipe->stream->mall_stream_config.paired_stream->timing;
-	drr_timing = &drr_pipe->stream->timing;
-	prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
-			(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
-			dc->caps.subvp_prefetch_end_to_mall_start_us;
-	subvp_active_us = main_timing->v_addressable * main_timing->h_total /
-			(double)(main_timing->pix_clk_100hz * 100) * 1000000;
-	drr_frame_us = drr_timing->v_total * drr_timing->h_total /
-			(double)(drr_timing->pix_clk_100hz * 100) * 1000000;
-	// P-State allow width and FW delays already included phantom_timing->v_addressable
-	mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
-			(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
-	stretched_drr_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US;
-	drr_stretched_vblank_us = (drr_timing->v_total - drr_timing->v_addressable) * drr_timing->h_total /
-			(double)(drr_timing->pix_clk_100hz * 100) * 1000000 + (stretched_drr_us - drr_frame_us);
-	max_vblank_mallregion = drr_stretched_vblank_us > mall_region_us ? drr_stretched_vblank_us : mall_region_us;
-
-	/* We consider SubVP + DRR schedulable if the stretched frame duration of the DRR display (i.e. the
-	 * highest refresh rate + margin that can support UCLK P-State switch) passes the static analysis
-	 * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
-	 * and the max of (VBLANK blanking time, MALL region)).
-	 */
-	if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
-			subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
-		schedulable = true;
-
-	return schedulable;
-}
-
-/**
- * ***************************************************************************************
- * subvp_vblank_schedulable: Determine if SubVP + VBLANK config is schedulable
- *
- * High level algorithm:
- * 1. Get timing for SubVP pipe, phantom pipe, and VBLANK pipe
- * 2. If (SubVP Active - Prefetch > Vblank Frame Time + max(MALL region, Vblank blanking time))
- * then report the configuration as supported
- * 3. If the VBLANK display is DRR, then take the DRR static schedulability path
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- *
- * @return: bool - True if the SubVP + VBLANK/DRR config is schedulable, false otherwise
- *
- * ***************************************************************************************
- */
-static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
-{
-	struct pipe_ctx *pipe = NULL;
-	struct pipe_ctx *subvp_pipe = NULL;
-	bool found = false;
-	bool schedulable = false;
-	uint32_t i = 0;
-	uint8_t vblank_index = 0;
-	uint16_t prefetch_us = 0;
-	uint16_t mall_region_us = 0;
-	uint16_t vblank_frame_us = 0;
-	uint16_t subvp_active_us = 0;
-	uint16_t vblank_blank_us = 0;
-	uint16_t max_vblank_mallregion = 0;
-	struct dc_crtc_timing *main_timing = NULL;
-	struct dc_crtc_timing *phantom_timing = NULL;
-	struct dc_crtc_timing *vblank_timing = NULL;
-
-	/* For SubVP + VBLANK/DRR cases, we assume there can only be
-	 * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK
-	 * is supported, it is either a single VBLANK case or two VBLANK
-	 * displays which are synchronized (in which case they have identical
-	 * timings).
-	 */
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		pipe = &context->res_ctx.pipe_ctx[i];
-
-		// We check for master pipe, but it shouldn't matter since we only need
-		// the pipe for timing info (stream should be same for any pipe splits)
-		if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
-			continue;
-
-		if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) {
-			// Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe).
-			vblank_index = i;
-			found = true;
-		}
-
-		if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN)
-			subvp_pipe = pipe;
-	}
-	// Use ignore_msa_timing_param flag to identify as DRR
-	if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) {
-		// SUBVP + DRR case
-		schedulable = subvp_drr_schedulable(dc, context, &context->res_ctx.pipe_ctx[vblank_index]);
-	} else if (found) {
-		main_timing = &subvp_pipe->stream->timing;
-		phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
-		vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing;
-		// Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe
-		// Also include the prefetch end to mallstart delay time
-		prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
-				(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
-				dc->caps.subvp_prefetch_end_to_mall_start_us;
-		// P-State allow width and FW delays already included phantom_timing->v_addressable
-		mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
-				(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
-		vblank_frame_us = vblank_timing->v_total * vblank_timing->h_total /
-				(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
-		vblank_blank_us =  (vblank_timing->v_total - vblank_timing->v_addressable) * vblank_timing->h_total /
-				(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
-		subvp_active_us = main_timing->v_addressable * main_timing->h_total /
-				(double)(main_timing->pix_clk_100hz * 100) * 1000000;
-		max_vblank_mallregion = vblank_blank_us > mall_region_us ? vblank_blank_us : mall_region_us;
-
-		// Schedulable if VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
-		// and the max of (VBLANK blanking time, MALL region)
-		// TODO: Possibly add some margin (i.e. the below conditions should be [...] > X instead of [...] > 0)
-		if (subvp_active_us - prefetch_us - vblank_frame_us - max_vblank_mallregion > 0)
-			schedulable = true;
-	}
-	return schedulable;
-}
-
-/**
- * ********************************************************************************************
- * subvp_validate_static_schedulability: Check which SubVP case is calculated and handle
- * static analysis based on the case.
- *
- * Three cases:
- * 1. SubVP + SubVP
- * 2. SubVP + VBLANK (DRR checked internally)
- * 3. SubVP + VACTIVE (currently unsupported)
- *
- * @param [in] dc: current dc state
- * @param [in] context: new dc state
- * @param [in] vlevel: Voltage level calculated by DML
- *
- * @return: bool - True if statically schedulable, false otherwise
- *
- * ********************************************************************************************
- */
-static bool subvp_validate_static_schedulability(struct dc *dc,
-				struct dc_state *context,
-				int vlevel)
-{
-	bool schedulable = true;	// true by default for single display case
-	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
-	uint32_t i, pipe_idx;
-	uint8_t subvp_count = 0;
-	uint8_t vactive_count = 0;
-
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
-		if (!pipe->stream)
-			continue;
-
-		if (pipe->plane_state && !pipe->top_pipe &&
-				pipe->stream->mall_stream_config.type == SUBVP_MAIN)
-			subvp_count++;
-
-		// Count how many planes are capable of VACTIVE switching (SubVP + VACTIVE unsupported)
-		if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0) {
-			vactive_count++;
-		}
-		pipe_idx++;
-	}
-
-	if (subvp_count == 2) {
-		// Static schedulability check for SubVP + SubVP case
-		schedulable = subvp_subvp_schedulable(dc, context);
-	} else if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vblank_w_mall_sub_vp) {
-		// Static schedulability check for SubVP + VBLANK case. Also handle the case where
-		// DML outputs SubVP + VBLANK + VACTIVE (DML will report as SubVP + VBLANK)
-		if (vactive_count > 0)
-			schedulable = false;
-		else
-			schedulable = subvp_vblank_schedulable(dc, context);
-	} else if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vactive_w_mall_sub_vp) {
-		// SubVP + VACTIVE currently unsupported
-		schedulable = false;
-	}
-	return schedulable;
-}
-
-static void dcn32_full_validate_bw_helper(struct dc *dc,
-		struct dc_state *context,
-		display_e2e_pipe_params_st *pipes,
-		int *vlevel,
-		int *split,
-		bool *merge,
-		int *pipe_cnt)
-{
-	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
-	unsigned int dc_pipe_idx = 0;
-	bool found_supported_config = false;
-	struct pipe_ctx *pipe = NULL;
-	uint32_t non_subvp_pipes = 0;
-	bool drr_pipe_found = false;
-	uint32_t drr_pipe_index = 0;
-	uint32_t i = 0;
-
-	/*
-	 * DML favors voltage over p-state, but we're more interested in
-	 * supporting p-state over voltage. We can't support p-state in
-	 * prefetch mode > 0 so try capping the prefetch mode to start.
-	 */
-	context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
-			dm_prefetch_support_uclk_fclk_and_stutter;
-	*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
-	/* This may adjust vlevel and maxMpcComb */
-	if (*vlevel < context->bw_ctx.dml.soc.num_states)
-		*vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge);
-
-	/* Conditions for setting up phantom pipes for SubVP:
-	 * 1. Not force disable SubVP
-	 * 2. Full update (i.e. !fast_validate)
-	 * 3. Enough pipes are available to support SubVP (TODO: Which pipes will use VACTIVE / VBLANK / SUBVP?)
-	 * 4. Display configuration passes validation
-	 * 5. (Config doesn't support MCLK in VACTIVE/VBLANK || dc->debug.force_subvp_mclk_switch)
-	 */
-	if (!dc->debug.force_disable_subvp && dcn32_all_pipes_have_stream_and_plane(dc, context) &&
-			(*vlevel == context->bw_ctx.dml.soc.num_states ||
-			vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported ||
-			dc->debug.force_subvp_mclk_switch)) {
-
-		dcn32_merge_pipes_for_subvp(dc, context);
-
-		while (!found_supported_config && dcn32_enough_pipes_for_subvp(dc, context) &&
-				dcn32_assign_subvp_pipe(dc, context, &dc_pipe_idx)) {
-
-			/* For the case where *vlevel = num_states, bandwidth validation has failed for this config.
-			 * Adding phantom pipes won't change the validation result, so change the DML input param
-			 * for P-State support before adding phantom pipes and recalculating the DML result.
-			 * However, this case is only applicable for SubVP + DRR cases because the prefetch mode
-			 * will not allow for switch in VBLANK. The DRR display must have it's VBLANK stretched
-			 * enough to support support MCLK switching.
-			 */
-			if (*vlevel == context->bw_ctx.dml.soc.num_states) {
-				context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
-								dm_prefetch_support_stutter;
-				/* There are params (such as FabricClock) that need to be recalculated
-				 * after validation fails (otherwise it will be 0). Calculation for
-				 * phantom vactive requires call into DML, so we must ensure all the
-				 * vba params are valid otherwise we'll get incorrect phantom vactive.
-				 */
-				*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
-			}
-
-			dc->res_pool->funcs->add_phantom_pipes(dc, context, pipes, *pipe_cnt, dc_pipe_idx);
-
-			*pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, false);
-			*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
-
-			if (*vlevel < context->bw_ctx.dml.soc.num_states &&
-					vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported
-					&& subvp_validate_static_schedulability(dc, context, *vlevel)) {
-				found_supported_config = true;
-			} else if (*vlevel < context->bw_ctx.dml.soc.num_states &&
-					vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
-				/* Case where 1 SubVP is added, and DML reports MCLK unsupported. This handles
-				 * the case for SubVP + DRR, where the DRR display does not support MCLK switch
-				 * at it's native refresh rate / timing.
-				 */
-				for (i = 0; i < dc->res_pool->pipe_count; i++) {
-					pipe = &context->res_ctx.pipe_ctx[i];
-					if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
-							pipe->stream->mall_stream_config.type == SUBVP_NONE) {
-						non_subvp_pipes++;
-						// Use ignore_msa_timing_param flag to identify as DRR
-						if (pipe->stream->ignore_msa_timing_param) {
-							drr_pipe_found = true;
-							drr_pipe_index = i;
-						}
-					}
-				}
-				// If there is only 1 remaining non SubVP pipe that is DRR, check static
-				// schedulability for SubVP + DRR.
-				if (non_subvp_pipes == 1 && drr_pipe_found) {
-					found_supported_config = subvp_drr_schedulable(dc,
-							context, &context->res_ctx.pipe_ctx[drr_pipe_index]);
-				}
-			}
-		}
-
-		// If SubVP pipe config is unsupported (or cannot be used for UCLK switching)
-		// remove phantom pipes and repopulate dml pipes
-		if (!found_supported_config) {
-			dc->res_pool->funcs->remove_phantom_pipes(dc, context);
-			vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] = dm_dram_clock_change_unsupported;
-			*pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, false);
-		} else {
-			// only call dcn20_validate_apply_pipe_split_flags if we found a supported config
-			memset(split, 0, MAX_PIPES * sizeof(int));
-			memset(merge, 0, MAX_PIPES * sizeof(bool));
-			*vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge);
-
-			// Most populate phantom DLG params before programming hardware / timing for phantom pipe
-			DC_FP_START();
-			dcn32_helper_populate_phantom_dlg_params(dc, context, pipes, *pipe_cnt);
-			DC_FP_END();
-
-			// Note: We can't apply the phantom pipes to hardware at this time. We have to wait
-			// until driver has acquired the DMCUB lock to do it safely.
-		}
-	}
-}
-
 static bool dcn32_internal_validate_bw(
 		struct dc *dc,
 		struct dc_state *context,
@@ -2499,7 +1904,9 @@ static bool dcn32_internal_validate_bw(
 	dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt);
 
 	if (!fast_validate) {
+		DC_FP_START();
 		dcn32_full_validate_bw_helper(dc, context, pipes, &vlevel, split, merge, &pipe_cnt);
+		DC_FP_END();
 	}
 
 	if (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states ||
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index 7ccad84b1f16..37d37067e983 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -103,6 +103,8 @@ bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc,
 bool dcn32_subvp_in_use(struct dc *dc,
 		struct dc_state *context);
 
+bool dcn32_mpo_in_use(struct dc_state *context);
+
 void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes,
 		bool *is_pipe_split_expected, int pipe_cnt);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
index 796e3d966a76..47caa2c6d5b4 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
@@ -153,6 +153,17 @@ bool dcn32_subvp_in_use(struct dc *dc,
 	return false;
 }
 
+bool dcn32_mpo_in_use(struct dc_state *context)
+{
+	uint32_t i;
+
+	for (i = 0; i < context->stream_count; i++) {
+		if (context->stream_status[i].plane_count > 1)
+			return true;
+	}
+	return false;
+}
+
 void dcn32_determine_det_override(struct dc_state *context, display_e2e_pipe_params_st *pipes,
 		bool *is_pipe_split_expected, int pipe_cnt)
 {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 74ccf453349c..82d801933aec 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -24,6 +24,8 @@
  *
  */
 #include "dcn32_fpu.h"
+#include "dcn32/dcn32_resource.h"
+#include "dcn20/dcn20_resource.h"
 #include "display_mode_vba_util_32.h"
 // We need this includes for WATERMARKS_* defines
 #include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
@@ -461,3 +463,598 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
 						phantom_bp;
 }
 
+/**
+ * dcn32_get_num_free_pipes: Calculate number of free pipes
+ *
+ * This function assumes that a "used" pipe is a pipe that has
+ * both a stream and a plane assigned to it.
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ *
+ * Return:
+ * Number of free pipes available in the context
+ */
+static unsigned int dcn32_get_num_free_pipes(struct dc *dc, struct dc_state *context)
+{
+	unsigned int i;
+	unsigned int free_pipes = 0;
+	unsigned int num_pipes = 0;
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+		if (pipe->stream && !pipe->top_pipe) {
+			while (pipe) {
+				num_pipes++;
+				pipe = pipe->bottom_pipe;
+			}
+		}
+	}
+
+	free_pipes = dc->res_pool->pipe_count - num_pipes;
+	return free_pipes;
+}
+
+/**
+ * dcn32_assign_subvp_pipe: Function to decide which pipe will use Sub-VP.
+ *
+ * We enter this function if we are Sub-VP capable (i.e. enough pipes available)
+ * and regular P-State switching (i.e. VACTIVE/VBLANK) is not supported, or if
+ * we are forcing SubVP P-State switching on the current config.
+ *
+ * The number of pipes used for the chosen surface must be less than or equal to the
+ * number of free pipes available.
+ *
+ * In general we choose surfaces with the longest frame time first (better for SubVP + VBLANK).
+ * For multi-display cases the ActiveDRAMClockChangeMargin doesn't provide enough info on its own
+ * for determining which should be the SubVP pipe (need a way to determine if a pipe / plane doesn't
+ * support MCLK switching naturally [i.e. ACTIVE or VBLANK]).
+ *
+ * @param dc: current dc state
+ * @param context: new dc state
+ * @param index: [out] dc pipe index for the pipe chosen to have phantom pipes assigned
+ *
+ * Return:
+ * True if a valid pipe assignment was found for Sub-VP. Otherwise false.
+ */
+static bool dcn32_assign_subvp_pipe(struct dc *dc,
+				    struct dc_state *context,
+				    unsigned int *index)
+{
+	unsigned int i, pipe_idx;
+	unsigned int max_frame_time = 0;
+	bool valid_assignment_found = false;
+	unsigned int free_pipes = dcn32_get_num_free_pipes(dc, context);
+	bool current_assignment_freesync = false;
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+		unsigned int num_pipes = 0;
+		unsigned int refresh_rate = 0;
+
+		if (!pipe->stream)
+			continue;
+
+		// Round up
+		refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 +
+				pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1)
+				/ (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total);
+		if (pipe->plane_state && !pipe->top_pipe &&
+				pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120) {
+			while (pipe) {
+				num_pipes++;
+				pipe = pipe->bottom_pipe;
+			}
+
+			pipe = &context->res_ctx.pipe_ctx[i];
+			if (num_pipes <= free_pipes) {
+				struct dc_stream_state *stream = pipe->stream;
+				unsigned int frame_us = (stream->timing.v_total * stream->timing.h_total /
+						(double)(stream->timing.pix_clk_100hz * 100)) * 1000000;
+				if (frame_us > max_frame_time && !stream->ignore_msa_timing_param) {
+					*index = i;
+					max_frame_time = frame_us;
+					valid_assignment_found = true;
+					current_assignment_freesync = false;
+				/* For the 2-Freesync display case, still choose the one with the
+			     * longest frame time
+			     */
+				} else if (stream->ignore_msa_timing_param && (!valid_assignment_found ||
+						(current_assignment_freesync && frame_us > max_frame_time))) {
+					*index = i;
+					valid_assignment_found = true;
+					current_assignment_freesync = true;
+				}
+			}
+		}
+		pipe_idx++;
+	}
+	return valid_assignment_found;
+}
+
+/**
+ * dcn32_enough_pipes_for_subvp: Function to check if there are "enough" pipes for SubVP.
+ *
+ * This function returns true if there are enough free pipes
+ * to create the required phantom pipes for any given stream
+ * (that does not already have phantom pipe assigned).
+ *
+ * e.g. For a 2 stream config where the first stream uses one
+ * pipe and the second stream uses 2 pipes (i.e. pipe split),
+ * this function will return true because there is 1 remaining
+ * pipe which can be used as the phantom pipe for the non pipe
+ * split pipe.
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ *
+ * Return:
+ * True if there are enough free pipes to assign phantom pipes to at least one
+ * stream that does not already have phantom pipes assigned. Otherwise false.
+ */
+static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context)
+{
+	unsigned int i, split_cnt, free_pipes;
+	unsigned int min_pipe_split = dc->res_pool->pipe_count + 1; // init as max number of pipes + 1
+	bool subvp_possible = false;
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+		// Find the minimum pipe split count for non SubVP pipes
+		if (pipe->stream && !pipe->top_pipe &&
+		    pipe->stream->mall_stream_config.type == SUBVP_NONE) {
+			split_cnt = 0;
+			while (pipe) {
+				split_cnt++;
+				pipe = pipe->bottom_pipe;
+			}
+
+			if (split_cnt < min_pipe_split)
+				min_pipe_split = split_cnt;
+		}
+	}
+
+	free_pipes = dcn32_get_num_free_pipes(dc, context);
+
+	// SubVP only possible if at least one pipe is being used (i.e. free_pipes
+	// should not equal to the pipe_count)
+	if (free_pipes >= min_pipe_split && free_pipes < dc->res_pool->pipe_count)
+		subvp_possible = true;
+
+	return subvp_possible;
+}
+
+/**
+ * subvp_subvp_schedulable: Determine if SubVP + SubVP config is schedulable
+ *
+ * High level algorithm:
+ * 1. Find longest microschedule length (in us) between the two SubVP pipes
+ * 2. Check if the worst case overlap (VBLANK in middle of ACTIVE) for both
+ * pipes still allows for the maximum microschedule to fit in the active
+ * region for both pipes.
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ *
+ * Return:
+ * bool - True if the SubVP + SubVP config is schedulable, false otherwise
+ */
+static bool subvp_subvp_schedulable(struct dc *dc, struct dc_state *context)
+{
+	struct pipe_ctx *subvp_pipes[2];
+	struct dc_stream_state *phantom = NULL;
+	uint32_t microschedule_lines = 0;
+	uint32_t index = 0;
+	uint32_t i;
+	uint32_t max_microschedule_us = 0;
+	int32_t vactive1_us, vactive2_us, vblank1_us, vblank2_us;
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+		uint32_t time_us = 0;
+
+		/* Loop to calculate the maximum microschedule time between the two SubVP pipes,
+		 * and also to store the two main SubVP pipe pointers in subvp_pipes[2].
+		 */
+		if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
+		    pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
+			phantom = pipe->stream->mall_stream_config.paired_stream;
+			microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) +
+					phantom->timing.v_addressable;
+
+			// Round up when calculating microschedule time (+ 1 at the end)
+			time_us = (microschedule_lines * phantom->timing.h_total) /
+					(double)(phantom->timing.pix_clk_100hz * 100) * 1000000 +
+						dc->caps.subvp_prefetch_end_to_mall_start_us +
+						dc->caps.subvp_fw_processing_delay_us + 1;
+			if (time_us > max_microschedule_us)
+				max_microschedule_us = time_us;
+
+			subvp_pipes[index] = pipe;
+			index++;
+
+			// Maximum 2 SubVP pipes
+			if (index == 2)
+				break;
+		}
+	}
+	vactive1_us = ((subvp_pipes[0]->stream->timing.v_addressable * subvp_pipes[0]->stream->timing.h_total) /
+			(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
+	vactive2_us = ((subvp_pipes[1]->stream->timing.v_addressable * subvp_pipes[1]->stream->timing.h_total) /
+				(double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000;
+	vblank1_us = (((subvp_pipes[0]->stream->timing.v_total - subvp_pipes[0]->stream->timing.v_addressable) *
+			subvp_pipes[0]->stream->timing.h_total) /
+			(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
+	vblank2_us = (((subvp_pipes[1]->stream->timing.v_total - subvp_pipes[1]->stream->timing.v_addressable) *
+			subvp_pipes[1]->stream->timing.h_total) /
+			(double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000;
+
+	if ((vactive1_us - vblank2_us) / 2 > max_microschedule_us &&
+	    (vactive2_us - vblank1_us) / 2 > max_microschedule_us)
+		return true;
+
+	return false;
+}
+
+/**
+ * subvp_drr_schedulable: Determine if SubVP + DRR config is schedulable
+ *
+ * High level algorithm:
+ * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe
+ * 2. Determine the frame time for the DRR display when adding required margin for MCLK switching
+ * (the margin is equal to the MALL region + DRR margin (500us))
+ * 3.If (SubVP Active - Prefetch > Stretched DRR frame + max(MALL region, Stretched DRR frame))
+ * then report the configuration as supported
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ * @drr_pipe: DRR pipe_ctx for the SubVP + DRR config
+ *
+ * Return:
+ * bool - True if the SubVP + DRR config is schedulable, false otherwise
+ */
+static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context, struct pipe_ctx *drr_pipe)
+{
+	bool schedulable = false;
+	uint32_t i;
+	struct pipe_ctx *pipe = NULL;
+	struct dc_crtc_timing *main_timing = NULL;
+	struct dc_crtc_timing *phantom_timing = NULL;
+	struct dc_crtc_timing *drr_timing = NULL;
+	int16_t prefetch_us = 0;
+	int16_t mall_region_us = 0;
+	int16_t drr_frame_us = 0;	// nominal frame time
+	int16_t subvp_active_us = 0;
+	int16_t stretched_drr_us = 0;
+	int16_t drr_stretched_vblank_us = 0;
+	int16_t max_vblank_mallregion = 0;
+
+	// Find SubVP pipe
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		pipe = &context->res_ctx.pipe_ctx[i];
+
+		// We check for master pipe, but it shouldn't matter since we only need
+		// the pipe for timing info (stream should be same for any pipe splits)
+		if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
+			continue;
+
+		// Find the SubVP pipe
+		if (pipe->stream->mall_stream_config.type == SUBVP_MAIN)
+			break;
+	}
+
+	main_timing = &pipe->stream->timing;
+	phantom_timing = &pipe->stream->mall_stream_config.paired_stream->timing;
+	drr_timing = &drr_pipe->stream->timing;
+	prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
+			(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
+			dc->caps.subvp_prefetch_end_to_mall_start_us;
+	subvp_active_us = main_timing->v_addressable * main_timing->h_total /
+			(double)(main_timing->pix_clk_100hz * 100) * 1000000;
+	drr_frame_us = drr_timing->v_total * drr_timing->h_total /
+			(double)(drr_timing->pix_clk_100hz * 100) * 1000000;
+	// P-State allow width and FW delays already included phantom_timing->v_addressable
+	mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
+			(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
+	stretched_drr_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US;
+	drr_stretched_vblank_us = (drr_timing->v_total - drr_timing->v_addressable) * drr_timing->h_total /
+			(double)(drr_timing->pix_clk_100hz * 100) * 1000000 + (stretched_drr_us - drr_frame_us);
+	max_vblank_mallregion = drr_stretched_vblank_us > mall_region_us ? drr_stretched_vblank_us : mall_region_us;
+
+	/* We consider SubVP + DRR schedulable if the stretched frame duration of the DRR display (i.e. the
+	 * highest refresh rate + margin that can support UCLK P-State switch) passes the static analysis
+	 * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
+	 * and the max of (VBLANK blanking time, MALL region)).
+	 */
+	if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
+			subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
+		schedulable = true;
+
+	return schedulable;
+}
+
+
+/**
+ * subvp_vblank_schedulable: Determine if SubVP + VBLANK config is schedulable
+ *
+ * High level algorithm:
+ * 1. Get timing for SubVP pipe, phantom pipe, and VBLANK pipe
+ * 2. If (SubVP Active - Prefetch > Vblank Frame Time + max(MALL region, Vblank blanking time))
+ * then report the configuration as supported
+ * 3. If the VBLANK display is DRR, then take the DRR static schedulability path
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ *
+ * Return:
+ * bool - True if the SubVP + VBLANK/DRR config is schedulable, false otherwise
+ */
+static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
+{
+	struct pipe_ctx *pipe = NULL;
+	struct pipe_ctx *subvp_pipe = NULL;
+	bool found = false;
+	bool schedulable = false;
+	uint32_t i = 0;
+	uint8_t vblank_index = 0;
+	uint16_t prefetch_us = 0;
+	uint16_t mall_region_us = 0;
+	uint16_t vblank_frame_us = 0;
+	uint16_t subvp_active_us = 0;
+	uint16_t vblank_blank_us = 0;
+	uint16_t max_vblank_mallregion = 0;
+	struct dc_crtc_timing *main_timing = NULL;
+	struct dc_crtc_timing *phantom_timing = NULL;
+	struct dc_crtc_timing *vblank_timing = NULL;
+
+	/* For SubVP + VBLANK/DRR cases, we assume there can only be
+	 * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK
+	 * is supported, it is either a single VBLANK case or two VBLANK
+	 * displays which are synchronized (in which case they have identical
+	 * timings).
+	 */
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		pipe = &context->res_ctx.pipe_ctx[i];
+
+		// We check for master pipe, but it shouldn't matter since we only need
+		// the pipe for timing info (stream should be same for any pipe splits)
+		if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
+			continue;
+
+		if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) {
+			// Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe).
+			vblank_index = i;
+			found = true;
+		}
+
+		if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN)
+			subvp_pipe = pipe;
+	}
+	// Use ignore_msa_timing_param flag to identify as DRR
+	if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) {
+		// SUBVP + DRR case
+		schedulable = subvp_drr_schedulable(dc, context, &context->res_ctx.pipe_ctx[vblank_index]);
+	} else if (found) {
+		main_timing = &subvp_pipe->stream->timing;
+		phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing;
+		vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing;
+		// Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe
+		// Also include the prefetch end to mallstart delay time
+		prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
+				(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
+				dc->caps.subvp_prefetch_end_to_mall_start_us;
+		// P-State allow width and FW delays already included phantom_timing->v_addressable
+		mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
+				(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
+		vblank_frame_us = vblank_timing->v_total * vblank_timing->h_total /
+				(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
+		vblank_blank_us =  (vblank_timing->v_total - vblank_timing->v_addressable) * vblank_timing->h_total /
+				(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
+		subvp_active_us = main_timing->v_addressable * main_timing->h_total /
+				(double)(main_timing->pix_clk_100hz * 100) * 1000000;
+		max_vblank_mallregion = vblank_blank_us > mall_region_us ? vblank_blank_us : mall_region_us;
+
+		// Schedulable if VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
+		// and the max of (VBLANK blanking time, MALL region)
+		// TODO: Possibly add some margin (i.e. the below conditions should be [...] > X instead of [...] > 0)
+		if (subvp_active_us - prefetch_us - vblank_frame_us - max_vblank_mallregion > 0)
+			schedulable = true;
+	}
+	return schedulable;
+}
+
+/**
+ * subvp_validate_static_schedulability: Check which SubVP case is calculated and handle
+ * static analysis based on the case.
+ *
+ * Three cases:
+ * 1. SubVP + SubVP
+ * 2. SubVP + VBLANK (DRR checked internally)
+ * 3. SubVP + VACTIVE (currently unsupported)
+ *
+ * @dc: current dc state
+ * @context: new dc state
+ * @vlevel: Voltage level calculated by DML
+ *
+ * Return:
+ * bool - True if statically schedulable, false otherwise
+ */
+static bool subvp_validate_static_schedulability(struct dc *dc,
+				struct dc_state *context,
+				int vlevel)
+{
+	bool schedulable = true;	// true by default for single display case
+	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
+	uint32_t i, pipe_idx;
+	uint8_t subvp_count = 0;
+	uint8_t vactive_count = 0;
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+		if (!pipe->stream)
+			continue;
+
+		if (pipe->plane_state && !pipe->top_pipe &&
+				pipe->stream->mall_stream_config.type == SUBVP_MAIN)
+			subvp_count++;
+
+		// Count how many planes that aren't SubVP/phantom are capable of VACTIVE
+		// switching (SubVP + VACTIVE unsupported). In situations where we force
+		// SubVP for a VACTIVE plane, we don't want to increment the vactive_count.
+		if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0 &&
+		    pipe->stream->mall_stream_config.type == SUBVP_NONE) {
+			vactive_count++;
+		}
+		pipe_idx++;
+	}
+
+	if (subvp_count == 2) {
+		// Static schedulability check for SubVP + SubVP case
+		schedulable = subvp_subvp_schedulable(dc, context);
+	} else if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vblank_w_mall_sub_vp) {
+		// Static schedulability check for SubVP + VBLANK case. Also handle the case where
+		// DML outputs SubVP + VBLANK + VACTIVE (DML will report as SubVP + VBLANK)
+		if (vactive_count > 0)
+			schedulable = false;
+		else
+			schedulable = subvp_vblank_schedulable(dc, context);
+	} else if (vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vactive_w_mall_sub_vp &&
+			vactive_count > 0) {
+		// For single display SubVP cases, DML will output dm_dram_clock_change_vactive_w_mall_sub_vp by default.
+		// We tell the difference between SubVP vs. SubVP + VACTIVE by checking the vactive_count.
+		// SubVP + VACTIVE currently unsupported
+		schedulable = false;
+	}
+	return schedulable;
+}
+
+void dcn32_full_validate_bw_helper(struct dc *dc,
+				   struct dc_state *context,
+				   display_e2e_pipe_params_st *pipes,
+				   int *vlevel,
+				   int *split,
+				   bool *merge,
+				   int *pipe_cnt)
+{
+	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
+	unsigned int dc_pipe_idx = 0;
+	bool found_supported_config = false;
+	struct pipe_ctx *pipe = NULL;
+	uint32_t non_subvp_pipes = 0;
+	bool drr_pipe_found = false;
+	uint32_t drr_pipe_index = 0;
+	uint32_t i = 0;
+
+	dc_assert_fp_enabled();
+
+	/*
+	 * DML favors voltage over p-state, but we're more interested in
+	 * supporting p-state over voltage. We can't support p-state in
+	 * prefetch mode > 0 so try capping the prefetch mode to start.
+	 */
+	context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+			dm_prefetch_support_uclk_fclk_and_stutter;
+	*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
+	/* This may adjust vlevel and maxMpcComb */
+	if (*vlevel < context->bw_ctx.dml.soc.num_states)
+		*vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge);
+
+	/* Conditions for setting up phantom pipes for SubVP:
+	 * 1. Not force disable SubVP
+	 * 2. Full update (i.e. !fast_validate)
+	 * 3. Enough pipes are available to support SubVP (TODO: Which pipes will use VACTIVE / VBLANK / SUBVP?)
+	 * 4. Display configuration passes validation
+	 * 5. (Config doesn't support MCLK in VACTIVE/VBLANK || dc->debug.force_subvp_mclk_switch)
+	 */
+	if (!dc->debug.force_disable_subvp && dcn32_all_pipes_have_stream_and_plane(dc, context) &&
+	    !dcn32_mpo_in_use(context) && (*vlevel == context->bw_ctx.dml.soc.num_states ||
+	    vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported ||
+	    dc->debug.force_subvp_mclk_switch)) {
+
+		dcn32_merge_pipes_for_subvp(dc, context);
+
+		while (!found_supported_config && dcn32_enough_pipes_for_subvp(dc, context) &&
+			dcn32_assign_subvp_pipe(dc, context, &dc_pipe_idx)) {
+			/* For the case where *vlevel = num_states, bandwidth validation has failed for this config.
+			 * Adding phantom pipes won't change the validation result, so change the DML input param
+			 * for P-State support before adding phantom pipes and recalculating the DML result.
+			 * However, this case is only applicable for SubVP + DRR cases because the prefetch mode
+			 * will not allow for switch in VBLANK. The DRR display must have it's VBLANK stretched
+			 * enough to support MCLK switching.
+			 */
+			if (*vlevel == context->bw_ctx.dml.soc.num_states) {
+				context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+								dm_prefetch_support_stutter;
+				/* There are params (such as FabricClock) that need to be recalculated
+				 * after validation fails (otherwise it will be 0). Calculation for
+				 * phantom vactive requires call into DML, so we must ensure all the
+				 * vba params are valid otherwise we'll get incorrect phantom vactive.
+				 */
+				*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
+			}
+
+			dc->res_pool->funcs->add_phantom_pipes(dc, context, pipes, *pipe_cnt, dc_pipe_idx);
+
+			*pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, false);
+			// Populate dppclk to trigger a recalculate in dml_get_voltage_level
+			// so the phantom pipe DLG params can be assigned correctly.
+			pipes[0].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, *pipe_cnt, 0);
+			*vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, *pipe_cnt);
+
+			if (*vlevel < context->bw_ctx.dml.soc.num_states &&
+			    vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported
+			    && subvp_validate_static_schedulability(dc, context, *vlevel)) {
+				found_supported_config = true;
+			} else if (*vlevel < context->bw_ctx.dml.soc.num_states &&
+					vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
+				/* Case where 1 SubVP is added, and DML reports MCLK unsupported. This handles
+				 * the case for SubVP + DRR, where the DRR display does not support MCLK switch
+				 * at it's native refresh rate / timing.
+				 */
+				for (i = 0; i < dc->res_pool->pipe_count; i++) {
+					pipe = &context->res_ctx.pipe_ctx[i];
+					if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
+					    pipe->stream->mall_stream_config.type == SUBVP_NONE) {
+						non_subvp_pipes++;
+						// Use ignore_msa_timing_param flag to identify as DRR
+						if (pipe->stream->ignore_msa_timing_param) {
+							drr_pipe_found = true;
+							drr_pipe_index = i;
+						}
+					}
+				}
+				// If there is only 1 remaining non SubVP pipe that is DRR, check static
+				// schedulability for SubVP + DRR.
+				if (non_subvp_pipes == 1 && drr_pipe_found) {
+					found_supported_config = subvp_drr_schedulable(dc, context,
+										       &context->res_ctx.pipe_ctx[drr_pipe_index]);
+				}
+			}
+		}
+
+		// If SubVP pipe config is unsupported (or cannot be used for UCLK switching)
+		// remove phantom pipes and repopulate dml pipes
+		if (!found_supported_config) {
+			dc->res_pool->funcs->remove_phantom_pipes(dc, context);
+			vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] = dm_dram_clock_change_unsupported;
+			*pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, false);
+		} else {
+			// only call dcn20_validate_apply_pipe_split_flags if we found a supported config
+			memset(split, 0, MAX_PIPES * sizeof(int));
+			memset(merge, 0, MAX_PIPES * sizeof(bool));
+			*vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, *vlevel, split, merge);
+
+			// Most populate phantom DLG params before programming hardware / timing for phantom pipe
+			DC_FP_START();
+			dcn32_helper_populate_phantom_dlg_params(dc, context, pipes, *pipe_cnt);
+			DC_FP_END();
+
+			// Note: We can't apply the phantom pipes to hardware at this time. We have to wait
+			// until driver has acquired the DMCUB lock to do it safely.
+		}
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 4abef908dca9..29fb6b1bc17f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -57,4 +57,12 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
 				     unsigned int pipe_cnt,
 				     unsigned int dc_pipe_idx);
 
+void dcn32_full_validate_bw_helper(struct dc *dc,
+				   struct dc_state *context,
+				   display_e2e_pipe_params_st *pipes,
+				   int *vlevel,
+				   int *split,
+				   bool *merge,
+				   int *pipe_cnt);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 24/31] drm/amd/display: Move wm and dlg calculation to FPU code
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (22 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 23/31] drm/amd/display: Move SubVP functions to dcn32_fpu Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:16 ` [PATCH 25/31] drm/amd/display: Move dlg params calculation Rodrigo Siqueira
                   ` (7 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

Move dcn32_calculate_wm_and_dlg from dcn32 resources to the FPU code.
Additionally, this commit adds an interface to it.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 196 +-----------------
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 185 +++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |   5 +
 3 files changed, 195 insertions(+), 191 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index d508909ff7a9..45768eff9315 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -2281,187 +2281,6 @@ int dcn32_populate_dml_pipes_from_context(
 	return pipe_cnt;
 }
 
-void dcn32_calculate_wm_and_dlg_fp(
-		struct dc *dc, struct dc_state *context,
-		display_e2e_pipe_params_st *pipes,
-		int pipe_cnt,
-		int vlevel)
-{
-	int i, pipe_idx, vlevel_temp = 0;
-	double dcfclk = dcn3_2_soc.clock_limits[0].dcfclk_mhz;
-	double dcfclk_from_validation = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
-	unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed;
-	bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] !=
-			dm_dram_clock_change_unsupported;
-
-	// Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK
-	if (!pstate_en && dcn32_subvp_in_use(dc, context)) {
-		context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
-		pstate_en = true;
-	}
-
-	/* Set B:
-	 * For Set B calculations use clocks from clock_limits[2] when available i.e. when SMU is present,
-	 * otherwise use arbitrary low value from spreadsheet for DCFCLK as lower is safer for watermark
-	 * calculations to cover bootup clocks.
-	 * DCFCLK: soc.clock_limits[2] when available
-	 * UCLK: soc.clock_limits[2] when available
-	 */
-	if (dcn3_2_soc.num_states > 2) {
-		vlevel_temp = 2;
-		dcfclk = dcn3_2_soc.clock_limits[2].dcfclk_mhz;
-	} else
-		dcfclk = 615; //DCFCLK Vmin_lv
-
-	pipes[0].clks_cfg.voltage = vlevel_temp;
-	pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
-	pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel_temp].socclk_mhz;
-
-	if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
-		context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
-		context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.fclk_change_latency_us;
-		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
-		context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
-	}
-	context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.b.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
-	/* Set D:
-	 * All clocks min.
-	 * DCFCLK: Min, as reported by PM FW when available
-	 * UCLK  : Min, as reported by PM FW when available
-	 * sr_enter_exit/sr_exit should be lower than used for DRAM (TBD after bringup or later, use as decided in Clk Mgr)
-	 */
-
-	if (dcn3_2_soc.num_states > 2) {
-		vlevel_temp = 0;
-		dcfclk = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz;
-	} else
-		dcfclk = 615; //DCFCLK Vmin_lv
-
-	pipes[0].clks_cfg.voltage = vlevel_temp;
-	pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
-	pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel_temp].socclk_mhz;
-
-	if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
-		context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
-		context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.fclk_change_latency_us;
-		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
-		context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
-	}
-	context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.d.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
-	/* Set C, for Dummy P-State:
-	 * All clocks min.
-	 * DCFCLK: Min, as reported by PM FW, when available
-	 * UCLK  : Min,  as reported by PM FW, when available
-	 * pstate latency as per UCLK state dummy pstate latency
-	 */
-	// For Set A and Set C use values from validation
-	pipes[0].clks_cfg.voltage = vlevel;
-	pipes[0].clks_cfg.dcfclk_mhz = dcfclk_from_validation;
-	pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
-
-	if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
-		unsigned int min_dram_speed_mts_margin = 160;
-
-		if ((!pstate_en))
-			min_dram_speed_mts = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz * 16;
-
-		/* find largest table entry that is lower than dram speed, but lower than DPM0 still uses DPM0 */
-		for (i = 3; i > 0; i--)
-			if (min_dram_speed_mts + min_dram_speed_mts_margin > dc->clk_mgr->bw_params->dummy_pstate_table[i].dram_speed_mts)
-				break;
-
-		context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[i].dummy_pstate_latency_us;
-		context->bw_ctx.dml.soc.dummy_pstate_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[i].dummy_pstate_latency_us;
-		context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.fclk_change_latency_us;
-		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
-		context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
-	}
-	context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	context->bw_ctx.bw.dcn.watermarks.c.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
-	if ((!pstate_en) && (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid)) {
-		/* The only difference between A and C is p-state latency, if p-state is not supported
-		 * with full p-state latency we want to calculate DLG based on dummy p-state latency,
-		 * Set A p-state watermark set to 0 on DCN32, when p-state unsupported, for now keep as DCN32.
-		 */
-		context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c;
-		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0;
-	} else {
-		/* Set A:
-		 * All clocks min.
-		 * DCFCLK: Min, as reported by PM FW, when available
-		 * UCLK: Min, as reported by PM FW, when available
-		 */
-		dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
-		context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-		context->bw_ctx.bw.dcn.watermarks.a.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-	}
-
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		if (!context->res_ctx.pipe_ctx[i].stream)
-			continue;
-
-		pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
-		pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
-
-		if (dc->config.forced_clocks) {
-			pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
-			pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
-		}
-		if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
-			pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
-		if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
-			pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
-
-		pipe_idx++;
-	}
-
-	context->perf_params.stutter_period_us = context->bw_ctx.dml.vba.StutterPeriod;
-
-	dcn32_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
-
-	if (!pstate_en)
-		/* Restore full p-state latency */
-		context->bw_ctx.dml.soc.dram_clock_change_latency_us =
-				dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
-}
-
 static struct dc_cap_funcs cap_funcs = {
 	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
 };
@@ -2489,18 +2308,13 @@ static void dcn32_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
 		(dcn3_2_soc.return_bus_width_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100));
 }
 
-void dcn32_calculate_wm_and_dlg(
-		struct dc *dc, struct dc_state *context,
-		display_e2e_pipe_params_st *pipes,
-		int pipe_cnt,
-		int vlevel)
+void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,
+				display_e2e_pipe_params_st *pipes,
+				int pipe_cnt,
+				int vlevel)
 {
     DC_FP_START();
-    dcn32_calculate_wm_and_dlg_fp(
-		dc, context,
-		pipes,
-		pipe_cnt,
-		vlevel);
+    dcn32_calculate_wm_and_dlg_fpu(dc, context, pipes, pipe_cnt, vlevel);
     DC_FP_END();
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 82d801933aec..353d3a74e40b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -1058,3 +1058,188 @@ void dcn32_full_validate_bw_helper(struct dc *dc,
 	}
 }
 
+void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
+				display_e2e_pipe_params_st *pipes,
+				int pipe_cnt,
+				int vlevel)
+{
+	int i, pipe_idx, vlevel_temp = 0;
+	double dcfclk = dcn3_2_soc.clock_limits[0].dcfclk_mhz;
+	double dcfclk_from_validation = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
+	bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] !=
+			dm_dram_clock_change_unsupported;
+
+	dc_assert_fp_enabled();
+
+	// Override DRAMClockChangeSupport for SubVP + DRR case where the DRR cannot switch without stretching it's VBLANK
+	if (!pstate_en && dcn32_subvp_in_use(dc, context)) {
+		context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] = dm_dram_clock_change_vblank_w_mall_sub_vp;
+		pstate_en = true;
+	}
+
+	/* Set B:
+	 * For Set B calculations use clocks from clock_limits[2] when available i.e. when SMU is present,
+	 * otherwise use arbitrary low value from spreadsheet for DCFCLK as lower is safer for watermark
+	 * calculations to cover bootup clocks.
+	 * DCFCLK: soc.clock_limits[2] when available
+	 * UCLK: soc.clock_limits[2] when available
+	 */
+	if (dcn3_2_soc.num_states > 2) {
+		vlevel_temp = 2;
+		dcfclk = dcn3_2_soc.clock_limits[2].dcfclk_mhz;
+	} else
+		dcfclk = 615; //DCFCLK Vmin_lv
+
+	pipes[0].clks_cfg.voltage = vlevel_temp;
+	pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+	pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel_temp].socclk_mhz;
+
+	if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
+		context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
+		context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.fclk_change_latency_us;
+		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
+		context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
+	}
+	context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.b.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+	/* Set D:
+	 * All clocks min.
+	 * DCFCLK: Min, as reported by PM FW when available
+	 * UCLK  : Min, as reported by PM FW when available
+	 * sr_enter_exit/sr_exit should be lower than used for DRAM (TBD after bringup or later, use as decided in Clk Mgr)
+	 */
+
+	if (dcn3_2_soc.num_states > 2) {
+		vlevel_temp = 0;
+		dcfclk = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz;
+	} else
+		dcfclk = 615; //DCFCLK Vmin_lv
+
+	pipes[0].clks_cfg.voltage = vlevel_temp;
+	pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+	pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel_temp].socclk_mhz;
+
+	if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
+		context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
+		context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.fclk_change_latency_us;
+		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
+		context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
+	}
+	context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.d.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+	/* Set C, for Dummy P-State:
+	 * All clocks min.
+	 * DCFCLK: Min, as reported by PM FW, when available
+	 * UCLK  : Min,  as reported by PM FW, when available
+	 * pstate latency as per UCLK state dummy pstate latency
+	 */
+
+	// For Set A and Set C use values from validation
+	pipes[0].clks_cfg.voltage = vlevel;
+	pipes[0].clks_cfg.dcfclk_mhz = dcfclk_from_validation;
+	pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+
+	if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
+		unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed;
+		unsigned int min_dram_speed_mts_margin = 160;
+
+		if (context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] ==
+				dm_dram_clock_change_unsupported)
+			min_dram_speed_mts = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz * 16;
+
+		/* find largest table entry that is lower than dram speed, but lower than DPM0 still uses DPM0 */
+		for (i = 3; i > 0; i--)
+			if (min_dram_speed_mts + min_dram_speed_mts_margin > dc->clk_mgr->bw_params->dummy_pstate_table[i].dram_speed_mts)
+				break;
+
+		context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[i].dummy_pstate_latency_us;
+		context->bw_ctx.dml.soc.fclk_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.fclk_change_latency_us;
+		context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
+		context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
+	}
+
+	context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	context->bw_ctx.bw.dcn.watermarks.c.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+	if ((!pstate_en) && (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid)) {
+		/* The only difference between A and C is p-state latency, if p-state is not supported
+		 * with full p-state latency we want to calculate DLG based on dummy p-state latency,
+		 * Set A p-state watermark set to 0 on DCN30, when p-state unsupported, for now keep as DCN30.
+		 */
+		context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c;
+		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0;
+	} else {
+		/* Set A:
+		 * All clocks min.
+		 * DCFCLK: Min, as reported by PM FW, when available
+		 * UCLK: Min, as reported by PM FW, when available
+		 */
+		dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
+		context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.fclk_pstate_change_ns = get_fclk_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+		context->bw_ctx.bw.dcn.watermarks.a.usr_retraining_ns = get_usr_retraining_watermark(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+	}
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		if (!context->res_ctx.pipe_ctx[i].stream)
+			continue;
+
+		pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
+		pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+
+		if (dc->config.forced_clocks) {
+			pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
+			pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
+		}
+		if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
+			pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
+		if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
+			pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
+
+		pipe_idx++;
+	}
+
+	context->perf_params.stutter_period_us = context->bw_ctx.dml.vba.StutterPeriod;
+
+	dcn32_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+
+	if (!pstate_en)
+		/* Restore full p-state latency */
+		context->bw_ctx.dml.soc.dram_clock_change_latency_us =
+				dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
+
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 29fb6b1bc17f..c7602f084be2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -65,4 +65,9 @@ void dcn32_full_validate_bw_helper(struct dc *dc,
 				   bool *merge,
 				   int *pipe_cnt);
 
+void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
+				display_e2e_pipe_params_st *pipes,
+				int pipe_cnt,
+				int vlevel);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 25/31] drm/amd/display: Move dlg params calculation
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (23 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 24/31] drm/amd/display: Move wm and dlg calculation to FPU code Rodrigo Siqueira
@ 2022-07-15 18:16 ` Rodrigo Siqueira
  2022-07-15 18:17 ` [PATCH 26/31] drm/amd/display: Move ntuple to insert entry Rodrigo Siqueira
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:16 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

Move dlg params calculation to the FPU folder and make it static.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 485 +----------------
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |   6 -
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 506 +++++++++++++++++-
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |  13 +-
 4 files changed, 513 insertions(+), 497 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 45768eff9315..32edb3e5715a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -1753,368 +1753,6 @@ void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context,
 	}
 }
 
-static bool dcn32_split_stream_for_mpc_or_odm(
-		const struct dc *dc,
-		struct resource_context *res_ctx,
-		struct pipe_ctx *pri_pipe,
-		struct pipe_ctx *sec_pipe,
-		bool odm)
-{
-	int pipe_idx = sec_pipe->pipe_idx;
-	const struct resource_pool *pool = dc->res_pool;
-
-	if (pri_pipe->plane_state) {
-		/* ODM + window MPO, where MPO window is on left half only */
-		if (pri_pipe->plane_state->clip_rect.x + pri_pipe->plane_state->clip_rect.width <=
-				pri_pipe->stream->src.x + pri_pipe->stream->src.width/2)
-			return true;
-
-		/* ODM + window MPO, where MPO window is on right half only */
-		if (pri_pipe->plane_state->clip_rect.x >= pri_pipe->stream->src.width/2)
-			return true;
-	}
-
-	*sec_pipe = *pri_pipe;
-
-	sec_pipe->pipe_idx = pipe_idx;
-	sec_pipe->plane_res.mi = pool->mis[pipe_idx];
-	sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
-	sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
-	sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
-	sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
-	sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
-	sec_pipe->stream_res.dsc = NULL;
-	if (odm) {
-		if (pri_pipe->next_odm_pipe) {
-			ASSERT(pri_pipe->next_odm_pipe != sec_pipe);
-			sec_pipe->next_odm_pipe = pri_pipe->next_odm_pipe;
-			sec_pipe->next_odm_pipe->prev_odm_pipe = sec_pipe;
-		}
-		if (pri_pipe->top_pipe && pri_pipe->top_pipe->next_odm_pipe) {
-			pri_pipe->top_pipe->next_odm_pipe->bottom_pipe = sec_pipe;
-			sec_pipe->top_pipe = pri_pipe->top_pipe->next_odm_pipe;
-		}
-		if (pri_pipe->bottom_pipe && pri_pipe->bottom_pipe->next_odm_pipe) {
-			pri_pipe->bottom_pipe->next_odm_pipe->top_pipe = sec_pipe;
-			sec_pipe->bottom_pipe = pri_pipe->bottom_pipe->next_odm_pipe;
-		}
-		pri_pipe->next_odm_pipe = sec_pipe;
-		sec_pipe->prev_odm_pipe = pri_pipe;
-		ASSERT(sec_pipe->top_pipe == NULL);
-
-		if (!sec_pipe->top_pipe)
-			sec_pipe->stream_res.opp = pool->opps[pipe_idx];
-		else
-			sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
-		if (sec_pipe->stream->timing.flags.DSC == 1) {
-			dcn20_acquire_dsc(dc, res_ctx, &sec_pipe->stream_res.dsc, pipe_idx);
-			ASSERT(sec_pipe->stream_res.dsc);
-			if (sec_pipe->stream_res.dsc == NULL)
-				return false;
-		}
-	} else {
-		if (pri_pipe->bottom_pipe) {
-			ASSERT(pri_pipe->bottom_pipe != sec_pipe);
-			sec_pipe->bottom_pipe = pri_pipe->bottom_pipe;
-			sec_pipe->bottom_pipe->top_pipe = sec_pipe;
-		}
-		pri_pipe->bottom_pipe = sec_pipe;
-		sec_pipe->top_pipe = pri_pipe;
-
-		ASSERT(pri_pipe->plane_state);
-	}
-
-	return true;
-}
-
-static struct pipe_ctx *dcn32_find_split_pipe(
-		struct dc *dc,
-		struct dc_state *context,
-		int old_index)
-{
-	struct pipe_ctx *pipe = NULL;
-	int i;
-
-	if (old_index >= 0 && context->res_ctx.pipe_ctx[old_index].stream == NULL) {
-		pipe = &context->res_ctx.pipe_ctx[old_index];
-		pipe->pipe_idx = old_index;
-	}
-
-	if (!pipe)
-		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
-			if (dc->current_state->res_ctx.pipe_ctx[i].top_pipe == NULL
-					&& dc->current_state->res_ctx.pipe_ctx[i].prev_odm_pipe == NULL) {
-				if (context->res_ctx.pipe_ctx[i].stream == NULL) {
-					pipe = &context->res_ctx.pipe_ctx[i];
-					pipe->pipe_idx = i;
-					break;
-				}
-			}
-		}
-
-	/*
-	 * May need to fix pipes getting tossed from 1 opp to another on flip
-	 * Add for debugging transient underflow during topology updates:
-	 * ASSERT(pipe);
-	 */
-	if (!pipe)
-		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
-			if (context->res_ctx.pipe_ctx[i].stream == NULL) {
-				pipe = &context->res_ctx.pipe_ctx[i];
-				pipe->pipe_idx = i;
-				break;
-			}
-		}
-
-	return pipe;
-}
-
-static bool dcn32_internal_validate_bw(
-		struct dc *dc,
-		struct dc_state *context,
-		display_e2e_pipe_params_st *pipes,
-		int *pipe_cnt_out,
-		int *vlevel_out,
-		bool fast_validate)
-{
-	bool out = false;
-	bool repopulate_pipes = false;
-	int split[MAX_PIPES] = { 0 };
-	bool merge[MAX_PIPES] = { false };
-	bool newly_split[MAX_PIPES] = { false };
-	int pipe_cnt, i, pipe_idx, vlevel;
-	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
-
-	ASSERT(pipes);
-	if (!pipes)
-		return false;
-
-	// For each full update, remove all existing phantom pipes first
-	dc->res_pool->funcs->remove_phantom_pipes(dc, context);
-
-	dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
-
-	pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
-
-	if (!pipe_cnt) {
-		out = true;
-		goto validate_out;
-	}
-
-	dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt);
-
-	if (!fast_validate) {
-		DC_FP_START();
-		dcn32_full_validate_bw_helper(dc, context, pipes, &vlevel, split, merge, &pipe_cnt);
-		DC_FP_END();
-	}
-
-	if (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states ||
-			vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
-		/*
-		 * If mode is unsupported or there's still no p-state support then
-		 * fall back to favoring voltage.
-		 *
-		 * We don't actually support prefetch mode 2, so require that we
-		 * at least support prefetch mode 1.
-		 */
-		context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
-				dm_prefetch_support_stutter;
-
-		vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
-		if (vlevel < context->bw_ctx.dml.soc.num_states) {
-			memset(split, 0, MAX_PIPES * sizeof(int));
-			memset(merge, 0, MAX_PIPES * sizeof(bool));
-			vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
-		}
-	}
-
-	dml_log_mode_support_params(&context->bw_ctx.dml);
-
-	if (vlevel == context->bw_ctx.dml.soc.num_states)
-		goto validate_fail;
-
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-		struct pipe_ctx *mpo_pipe = pipe->bottom_pipe;
-
-		if (!pipe->stream)
-			continue;
-
-		/* We only support full screen mpo with ODM */
-		if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled
-				&& pipe->plane_state && mpo_pipe
-				&& memcmp(&mpo_pipe->plane_res.scl_data.recout,
-						&pipe->plane_res.scl_data.recout,
-						sizeof(struct rect)) != 0) {
-			ASSERT(mpo_pipe->plane_state != pipe->plane_state);
-			goto validate_fail;
-		}
-		pipe_idx++;
-	}
-
-	/* merge pipes if necessary */
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
-		/*skip pipes that don't need merging*/
-		if (!merge[i])
-			continue;
-
-		/* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */
-		if (pipe->prev_odm_pipe) {
-			/*split off odm pipe*/
-			pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe;
-			if (pipe->next_odm_pipe)
-				pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe;
-
-			pipe->bottom_pipe = NULL;
-			pipe->next_odm_pipe = NULL;
-			pipe->plane_state = NULL;
-			pipe->stream = NULL;
-			pipe->top_pipe = NULL;
-			pipe->prev_odm_pipe = NULL;
-			if (pipe->stream_res.dsc)
-				dcn20_release_dsc(&context->res_ctx, dc->res_pool, &pipe->stream_res.dsc);
-			memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
-			memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
-			repopulate_pipes = true;
-		} else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
-			struct pipe_ctx *top_pipe = pipe->top_pipe;
-			struct pipe_ctx *bottom_pipe = pipe->bottom_pipe;
-
-			top_pipe->bottom_pipe = bottom_pipe;
-			if (bottom_pipe)
-				bottom_pipe->top_pipe = top_pipe;
-
-			pipe->top_pipe = NULL;
-			pipe->bottom_pipe = NULL;
-			pipe->plane_state = NULL;
-			pipe->stream = NULL;
-			memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
-			memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
-			repopulate_pipes = true;
-		} else
-			ASSERT(0); /* Should never try to merge master pipe */
-
-	}
-
-	for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-		struct pipe_ctx *hsplit_pipe = NULL;
-		bool odm;
-		int old_index = -1;
-
-		if (!pipe->stream || newly_split[i])
-			continue;
-
-		pipe_idx++;
-		odm = vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled;
-
-		if (!pipe->plane_state && !odm)
-			continue;
-
-		if (split[i]) {
-			if (odm) {
-				if (split[i] == 4 && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe)
-					old_index = old_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
-				else if (old_pipe->next_odm_pipe)
-					old_index = old_pipe->next_odm_pipe->pipe_idx;
-			} else {
-				if (split[i] == 4 && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
-						old_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
-					old_index = old_pipe->bottom_pipe->bottom_pipe->pipe_idx;
-				else if (old_pipe->bottom_pipe &&
-						old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
-					old_index = old_pipe->bottom_pipe->pipe_idx;
-			}
-			hsplit_pipe = dcn32_find_split_pipe(dc, context, old_index);
-			ASSERT(hsplit_pipe);
-			if (!hsplit_pipe)
-				goto validate_fail;
-
-			if (!dcn32_split_stream_for_mpc_or_odm(
-					dc, &context->res_ctx,
-					pipe, hsplit_pipe, odm))
-				goto validate_fail;
-
-			newly_split[hsplit_pipe->pipe_idx] = true;
-			repopulate_pipes = true;
-		}
-		if (split[i] == 4) {
-			struct pipe_ctx *pipe_4to1;
-
-			if (odm && old_pipe->next_odm_pipe)
-				old_index = old_pipe->next_odm_pipe->pipe_idx;
-			else if (!odm && old_pipe->bottom_pipe &&
-						old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
-				old_index = old_pipe->bottom_pipe->pipe_idx;
-			else
-				old_index = -1;
-			pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
-			ASSERT(pipe_4to1);
-			if (!pipe_4to1)
-				goto validate_fail;
-			if (!dcn32_split_stream_for_mpc_or_odm(
-					dc, &context->res_ctx,
-					pipe, pipe_4to1, odm))
-				goto validate_fail;
-			newly_split[pipe_4to1->pipe_idx] = true;
-
-			if (odm && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe
-					&& old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe)
-				old_index = old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
-			else if (!odm && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
-					old_pipe->bottom_pipe->bottom_pipe->bottom_pipe &&
-					old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
-				old_index = old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx;
-			else
-				old_index = -1;
-			pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
-			ASSERT(pipe_4to1);
-			if (!pipe_4to1)
-				goto validate_fail;
-			if (!dcn32_split_stream_for_mpc_or_odm(
-					dc, &context->res_ctx,
-					hsplit_pipe, pipe_4to1, odm))
-				goto validate_fail;
-			newly_split[pipe_4to1->pipe_idx] = true;
-		}
-		if (odm)
-			dcn20_build_mapped_resource(dc, context, pipe->stream);
-	}
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
-		if (pipe->plane_state) {
-			if (!resource_build_scaling_params(pipe))
-				goto validate_fail;
-		}
-	}
-
-	/* Actual dsc count per stream dsc validation*/
-	if (!dcn20_validate_dsc(dc, context)) {
-		vba->ValidationStatus[vba->soc.num_states] = DML_FAIL_DSC_VALIDATION_FAILURE;
-		goto validate_fail;
-	}
-
-	if (repopulate_pipes)
-		pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
-	*vlevel_out = vlevel;
-	*pipe_cnt_out = pipe_cnt;
-
-	out = true;
-	goto validate_out;
-
-validate_fail:
-	out = false;
-
-validate_out:
-	return out;
-}
-
 bool dcn32_validate_bandwidth(struct dc *dc,
 		struct dc_state *context,
 		bool fast_validate)
@@ -2130,9 +1768,9 @@ bool dcn32_validate_bandwidth(struct dc *dc,
 
 	BW_VAL_TRACE_COUNT();
 
-    DC_FP_START();
+	DC_FP_START();
 	out = dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
-    DC_FP_END();
+	DC_FP_END();
 
 	if (pipe_cnt == 0)
 		goto validate_out;
@@ -2318,125 +1956,6 @@ void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,
     DC_FP_END();
 }
 
-static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
-{
-	int i;
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		if (!context->res_ctx.pipe_ctx[i].stream)
-			continue;
-		if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
-			return true;
-	}
-	return false;
-}
-
-void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes,
-		int pipe_cnt, int vlevel)
-{
-	int i, pipe_idx;
-	bool usr_retraining_support = false;
-	bool unbounded_req_enabled = false;
-
-	/* Writeback MCIF_WB arbitration parameters */
-	dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt);
-
-	context->bw_ctx.bw.dcn.clk.dispclk_khz = context->bw_ctx.dml.vba.DISPCLK * 1000;
-	context->bw_ctx.bw.dcn.clk.dcfclk_khz = context->bw_ctx.dml.vba.DCFCLK * 1000;
-	context->bw_ctx.bw.dcn.clk.socclk_khz = context->bw_ctx.dml.vba.SOCCLK * 1000;
-	context->bw_ctx.bw.dcn.clk.dramclk_khz = context->bw_ctx.dml.vba.DRAMSpeed * 1000 / 16;
-	context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = context->bw_ctx.dml.vba.DCFCLKDeepSleep * 1000;
-	context->bw_ctx.bw.dcn.clk.fclk_khz = context->bw_ctx.dml.vba.FabricClock * 1000;
-	context->bw_ctx.bw.dcn.clk.p_state_change_support =
-			context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb]
-					!= dm_dram_clock_change_unsupported;
-	context->bw_ctx.bw.dcn.clk.num_ways = dcn32_helper_calculate_num_ways_for_subvp(dc, context);
-	/*
- *
-	 * TODO: needs FAMS
-	 * Pstate change might not be supported by hardware, but it might be
-	 * possible with firmware driven vertical blank stretching.
-	 */
-	// context->bw_ctx.bw.dcn.clk.p_state_change_support |= context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching;
-	context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
-	context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context);
-	context->bw_ctx.bw.dcn.clk.ref_dtbclk_khz = context->bw_ctx.dml.vba.DTBCLKPerState[vlevel] * 1000;
-	if (context->bw_ctx.dml.vba.FCLKChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_fclock_change_unsupported)
-		context->bw_ctx.bw.dcn.clk.fclk_p_state_change_support = false;
-	else
-		context->bw_ctx.bw.dcn.clk.fclk_p_state_change_support = true;
-
-	usr_retraining_support = context->bw_ctx.dml.vba.USRRetrainingSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
-	ASSERT(usr_retraining_support);
-
-	if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz)
-		context->bw_ctx.bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz;
-
-	unbounded_req_enabled = get_unbounded_request_enabled(&context->bw_ctx.dml, pipes, pipe_cnt);
-
-	if (unbounded_req_enabled && pipe_cnt > 1) {
-		// Unbounded requesting should not ever be used when more than 1 pipe is enabled.
-		ASSERT(false);
-		unbounded_req_enabled = false;
-	}
-
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-		if (!context->res_ctx.pipe_ctx[i].stream)
-			continue;
-		pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt,
-				pipe_idx);
-		pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
-				pipe_idx);
-		pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt,
-				pipe_idx);
-		pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
-				pipe_idx);
-		if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) {
-			// Phantom pipe requires that DET_SIZE = 0 and no unbounded requests
-			context->res_ctx.pipe_ctx[i].det_buffer_size_kb = 0;
-			context->res_ctx.pipe_ctx[i].unbounded_req = false;
-		} else {
-			context->res_ctx.pipe_ctx[i].det_buffer_size_kb = get_det_buffer_size_kbytes(&context->bw_ctx.dml, pipes, pipe_cnt,
-							pipe_idx);
-			context->res_ctx.pipe_ctx[i].unbounded_req = unbounded_req_enabled;
-		}
-		if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
-			context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
-		context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
-		context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
-		pipe_idx++;
-	}
-	/*save a original dppclock copy*/
-	context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
-	context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
-	context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz
-			* 1000;
-	context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz
-			* 1000;
-
-	context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes;
-
-	for (i = 0; i < dc->res_pool->pipe_count; i++) {
-		if (context->res_ctx.pipe_ctx[i].stream)
-			context->bw_ctx.bw.dcn.compbuf_size_kb -= context->res_ctx.pipe_ctx[i].det_buffer_size_kb;
-	}
-
-	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
-
-		if (!context->res_ctx.pipe_ctx[i].stream)
-			continue;
-
-		context->bw_ctx.dml.funcs.rq_dlg_get_dlg_reg_v2(&context->bw_ctx.dml,
-				&context->res_ctx.pipe_ctx[i].dlg_regs, &context->res_ctx.pipe_ctx[i].ttu_regs, pipes,
-				pipe_cnt, pipe_idx);
-
-		context->bw_ctx.dml.funcs.rq_dlg_get_rq_reg_v2(&context->res_ctx.pipe_ctx[i].rq_regs,
-				&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
-
-		pipe_idx++;
-	}
-}
-
 static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
 {
 	if (entry->dcfclk_mhz > 0) {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
index 37d37067e983..fc0fe48023a0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
@@ -44,12 +44,6 @@ struct resource_pool *dcn32_create_resource_pool(
 		const struct dc_init_data *init_data,
 		struct dc *dc);
 
-void dcn32_calculate_dlg_params(
-		struct dc *dc, struct dc_state *context,
-		display_e2e_pipe_params_st *pipes,
-		int pipe_cnt,
-		int vlevel);
-
 struct panel_cntl *dcn32_panel_cntl_create(
 		const struct panel_cntl_init_data *init_data);
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 353d3a74e40b..66102db87265 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -24,12 +24,15 @@
  *
  */
 #include "dcn32_fpu.h"
+#include "dc_link_dp.h"
 #include "dcn32/dcn32_resource.h"
 #include "dcn20/dcn20_resource.h"
 #include "display_mode_vba_util_32.h"
 // We need this includes for WATERMARKS_* defines
 #include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
 
+#define DC_LOGGER_INIT(logger)
+
 struct _vcs_dpi_ip_params_st dcn3_2_ip = {
 	.gpuvm_enable = 0,
 	.gpuvm_max_page_table_levels = 4,
@@ -931,7 +934,7 @@ static bool subvp_validate_static_schedulability(struct dc *dc,
 	return schedulable;
 }
 
-void dcn32_full_validate_bw_helper(struct dc *dc,
+static void dcn32_full_validate_bw_helper(struct dc *dc,
 				   struct dc_state *context,
 				   display_e2e_pipe_params_st *pipes,
 				   int *vlevel,
@@ -1058,6 +1061,507 @@ void dcn32_full_validate_bw_helper(struct dc *dc,
 	}
 }
 
+static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
+{
+	int i;
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		if (!context->res_ctx.pipe_ctx[i].stream)
+			continue;
+		if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
+			return true;
+	}
+	return false;
+}
+
+static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
+				       display_e2e_pipe_params_st *pipes,
+				       int pipe_cnt, int vlevel)
+{
+	int i, pipe_idx;
+	bool usr_retraining_support = false;
+	bool unbounded_req_enabled = false;
+
+	dc_assert_fp_enabled();
+
+	/* Writeback MCIF_WB arbitration parameters */
+	dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt);
+
+	context->bw_ctx.bw.dcn.clk.dispclk_khz = context->bw_ctx.dml.vba.DISPCLK * 1000;
+	context->bw_ctx.bw.dcn.clk.dcfclk_khz = context->bw_ctx.dml.vba.DCFCLK * 1000;
+	context->bw_ctx.bw.dcn.clk.socclk_khz = context->bw_ctx.dml.vba.SOCCLK * 1000;
+	context->bw_ctx.bw.dcn.clk.dramclk_khz = context->bw_ctx.dml.vba.DRAMSpeed * 1000 / 16;
+	context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = context->bw_ctx.dml.vba.DCFCLKDeepSleep * 1000;
+	context->bw_ctx.bw.dcn.clk.fclk_khz = context->bw_ctx.dml.vba.FabricClock * 1000;
+	context->bw_ctx.bw.dcn.clk.p_state_change_support =
+			context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb]
+					!= dm_dram_clock_change_unsupported;
+	context->bw_ctx.bw.dcn.clk.num_ways = dcn32_helper_calculate_num_ways_for_subvp(dc, context);
+
+	context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
+	context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context);
+	context->bw_ctx.bw.dcn.clk.ref_dtbclk_khz = context->bw_ctx.dml.vba.DTBCLKPerState[vlevel] * 1000;
+	if (context->bw_ctx.dml.vba.FCLKChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_fclock_change_unsupported)
+		context->bw_ctx.bw.dcn.clk.fclk_p_state_change_support = false;
+	else
+		context->bw_ctx.bw.dcn.clk.fclk_p_state_change_support = true;
+
+	usr_retraining_support = context->bw_ctx.dml.vba.USRRetrainingSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
+	ASSERT(usr_retraining_support);
+
+	if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz)
+		context->bw_ctx.bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz;
+
+	unbounded_req_enabled = get_unbounded_request_enabled(&context->bw_ctx.dml, pipes, pipe_cnt);
+
+	if (unbounded_req_enabled && pipe_cnt > 1) {
+		// Unbounded requesting should not ever be used when more than 1 pipe is enabled.
+		ASSERT(false);
+		unbounded_req_enabled = false;
+	}
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		if (!context->res_ctx.pipe_ctx[i].stream)
+			continue;
+		pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt,
+				pipe_idx);
+		pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
+				pipe_idx);
+		pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt,
+				pipe_idx);
+		pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt,
+				pipe_idx);
+
+		if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) {
+			// Phantom pipe requires that DET_SIZE = 0 and no unbounded requests
+			context->res_ctx.pipe_ctx[i].det_buffer_size_kb = 0;
+			context->res_ctx.pipe_ctx[i].unbounded_req = false;
+		} else {
+			context->res_ctx.pipe_ctx[i].det_buffer_size_kb = get_det_buffer_size_kbytes(&context->bw_ctx.dml, pipes, pipe_cnt,
+							pipe_idx);
+			context->res_ctx.pipe_ctx[i].unbounded_req = unbounded_req_enabled;
+		}
+
+		if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
+			context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+		context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+		context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+		pipe_idx++;
+	}
+	/*save a original dppclock copy*/
+	context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
+	context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
+	context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz
+			* 1000;
+	context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz
+			* 1000;
+
+	context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes;
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		if (context->res_ctx.pipe_ctx[i].stream)
+			context->bw_ctx.bw.dcn.compbuf_size_kb -= context->res_ctx.pipe_ctx[i].det_buffer_size_kb;
+	}
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+
+		if (!context->res_ctx.pipe_ctx[i].stream)
+			continue;
+
+		context->bw_ctx.dml.funcs.rq_dlg_get_dlg_reg_v2(&context->bw_ctx.dml,
+				&context->res_ctx.pipe_ctx[i].dlg_regs, &context->res_ctx.pipe_ctx[i].ttu_regs, pipes,
+				pipe_cnt, pipe_idx);
+
+		context->bw_ctx.dml.funcs.rq_dlg_get_rq_reg_v2(&context->res_ctx.pipe_ctx[i].rq_regs,
+				&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+		pipe_idx++;
+	}
+}
+
+static struct pipe_ctx *dcn32_find_split_pipe(
+		struct dc *dc,
+		struct dc_state *context,
+		int old_index)
+{
+	struct pipe_ctx *pipe = NULL;
+	int i;
+
+	if (old_index >= 0 && context->res_ctx.pipe_ctx[old_index].stream == NULL) {
+		pipe = &context->res_ctx.pipe_ctx[old_index];
+		pipe->pipe_idx = old_index;
+	}
+
+	if (!pipe)
+		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
+			if (dc->current_state->res_ctx.pipe_ctx[i].top_pipe == NULL
+					&& dc->current_state->res_ctx.pipe_ctx[i].prev_odm_pipe == NULL) {
+				if (context->res_ctx.pipe_ctx[i].stream == NULL) {
+					pipe = &context->res_ctx.pipe_ctx[i];
+					pipe->pipe_idx = i;
+					break;
+				}
+			}
+		}
+
+	/*
+	 * May need to fix pipes getting tossed from 1 opp to another on flip
+	 * Add for debugging transient underflow during topology updates:
+	 * ASSERT(pipe);
+	 */
+	if (!pipe)
+		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {
+			if (context->res_ctx.pipe_ctx[i].stream == NULL) {
+				pipe = &context->res_ctx.pipe_ctx[i];
+				pipe->pipe_idx = i;
+				break;
+			}
+		}
+
+	return pipe;
+}
+
+static bool dcn32_split_stream_for_mpc_or_odm(
+		const struct dc *dc,
+		struct resource_context *res_ctx,
+		struct pipe_ctx *pri_pipe,
+		struct pipe_ctx *sec_pipe,
+		bool odm)
+{
+	int pipe_idx = sec_pipe->pipe_idx;
+	const struct resource_pool *pool = dc->res_pool;
+
+	DC_LOGGER_INIT(dc->ctx->logger);
+
+	if (odm && pri_pipe->plane_state) {
+		/* ODM + window MPO, where MPO window is on left half only */
+		if (pri_pipe->plane_state->clip_rect.x + pri_pipe->plane_state->clip_rect.width <=
+				pri_pipe->stream->src.x + pri_pipe->stream->src.width/2) {
+
+			DC_LOG_SCALER("%s - ODM + window MPO(left). pri_pipe:%d\n",
+					__func__,
+					pri_pipe->pipe_idx);
+			return true;
+		}
+
+		/* ODM + window MPO, where MPO window is on right half only */
+		if (pri_pipe->plane_state->clip_rect.x >= pri_pipe->stream->src.x +  pri_pipe->stream->src.width/2) {
+
+			DC_LOG_SCALER("%s - ODM + window MPO(right). pri_pipe:%d\n",
+					__func__,
+					pri_pipe->pipe_idx);
+			return true;
+		}
+	}
+
+	*sec_pipe = *pri_pipe;
+
+	sec_pipe->pipe_idx = pipe_idx;
+	sec_pipe->plane_res.mi = pool->mis[pipe_idx];
+	sec_pipe->plane_res.hubp = pool->hubps[pipe_idx];
+	sec_pipe->plane_res.ipp = pool->ipps[pipe_idx];
+	sec_pipe->plane_res.xfm = pool->transforms[pipe_idx];
+	sec_pipe->plane_res.dpp = pool->dpps[pipe_idx];
+	sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst;
+	sec_pipe->stream_res.dsc = NULL;
+	if (odm) {
+		if (pri_pipe->next_odm_pipe) {
+			ASSERT(pri_pipe->next_odm_pipe != sec_pipe);
+			sec_pipe->next_odm_pipe = pri_pipe->next_odm_pipe;
+			sec_pipe->next_odm_pipe->prev_odm_pipe = sec_pipe;
+		}
+		if (pri_pipe->top_pipe && pri_pipe->top_pipe->next_odm_pipe) {
+			pri_pipe->top_pipe->next_odm_pipe->bottom_pipe = sec_pipe;
+			sec_pipe->top_pipe = pri_pipe->top_pipe->next_odm_pipe;
+		}
+		if (pri_pipe->bottom_pipe && pri_pipe->bottom_pipe->next_odm_pipe) {
+			pri_pipe->bottom_pipe->next_odm_pipe->top_pipe = sec_pipe;
+			sec_pipe->bottom_pipe = pri_pipe->bottom_pipe->next_odm_pipe;
+		}
+		pri_pipe->next_odm_pipe = sec_pipe;
+		sec_pipe->prev_odm_pipe = pri_pipe;
+		ASSERT(sec_pipe->top_pipe == NULL);
+
+		if (!sec_pipe->top_pipe)
+			sec_pipe->stream_res.opp = pool->opps[pipe_idx];
+		else
+			sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp;
+		if (sec_pipe->stream->timing.flags.DSC == 1) {
+			dcn20_acquire_dsc(dc, res_ctx, &sec_pipe->stream_res.dsc, pipe_idx);
+			ASSERT(sec_pipe->stream_res.dsc);
+			if (sec_pipe->stream_res.dsc == NULL)
+				return false;
+		}
+	} else {
+		if (pri_pipe->bottom_pipe) {
+			ASSERT(pri_pipe->bottom_pipe != sec_pipe);
+			sec_pipe->bottom_pipe = pri_pipe->bottom_pipe;
+			sec_pipe->bottom_pipe->top_pipe = sec_pipe;
+		}
+		pri_pipe->bottom_pipe = sec_pipe;
+		sec_pipe->top_pipe = pri_pipe;
+
+		ASSERT(pri_pipe->plane_state);
+	}
+
+	return true;
+}
+
+bool dcn32_internal_validate_bw(struct dc *dc,
+				struct dc_state *context,
+				display_e2e_pipe_params_st *pipes,
+				int *pipe_cnt_out,
+				int *vlevel_out,
+				bool fast_validate)
+{
+	bool out = false;
+	bool repopulate_pipes = false;
+	int split[MAX_PIPES] = { 0 };
+	bool merge[MAX_PIPES] = { false };
+	bool newly_split[MAX_PIPES] = { false };
+	int pipe_cnt, i, pipe_idx, vlevel;
+	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
+
+	dc_assert_fp_enabled();
+
+	ASSERT(pipes);
+	if (!pipes)
+		return false;
+
+	// For each full update, remove all existing phantom pipes first
+	dc->res_pool->funcs->remove_phantom_pipes(dc, context);
+
+	dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
+
+	pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
+
+	if (!pipe_cnt) {
+		out = true;
+		goto validate_out;
+	}
+
+	dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt);
+
+	if (!fast_validate) {
+		DC_FP_START();
+		dcn32_full_validate_bw_helper(dc, context, pipes, &vlevel, split, merge, &pipe_cnt);
+		DC_FP_END();
+	}
+
+	if (fast_validate || vlevel == context->bw_ctx.dml.soc.num_states ||
+			vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported) {
+		/*
+		 * If mode is unsupported or there's still no p-state support then
+		 * fall back to favoring voltage.
+		 *
+		 * If Prefetch mode 0 failed for this config, or passed with Max UCLK, try if
+		 * supported with Prefetch mode 1 (dm_prefetch_support_fclk_and_stutter == 2)
+		 */
+		context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+				dm_prefetch_support_fclk_and_stutter;
+
+		vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
+
+		/* Last attempt with Prefetch mode 2 (dm_prefetch_support_stutter == 3) */
+		if (vlevel == context->bw_ctx.dml.soc.num_states) {
+			context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final =
+				dm_prefetch_support_stutter;
+			vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt);
+		}
+
+		if (vlevel < context->bw_ctx.dml.soc.num_states) {
+			memset(split, 0, sizeof(split));
+			memset(merge, 0, sizeof(merge));
+			vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge);
+		}
+	}
+
+	dml_log_mode_support_params(&context->bw_ctx.dml);
+
+	if (vlevel == context->bw_ctx.dml.soc.num_states)
+		goto validate_fail;
+
+	for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+		struct pipe_ctx *mpo_pipe = pipe->bottom_pipe;
+
+		if (!pipe->stream)
+			continue;
+
+		if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled
+				&& !dc->config.enable_windowed_mpo_odm
+				&& pipe->plane_state && mpo_pipe
+				&& memcmp(&mpo_pipe->plane_res.scl_data.recout,
+						&pipe->plane_res.scl_data.recout,
+						sizeof(struct rect)) != 0) {
+			ASSERT(mpo_pipe->plane_state != pipe->plane_state);
+			goto validate_fail;
+		}
+		pipe_idx++;
+	}
+
+	/* merge pipes if necessary */
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+		/*skip pipes that don't need merging*/
+		if (!merge[i])
+			continue;
+
+		/* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */
+		if (pipe->prev_odm_pipe) {
+			/*split off odm pipe*/
+			pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe;
+			if (pipe->next_odm_pipe)
+				pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe;
+
+			pipe->bottom_pipe = NULL;
+			pipe->next_odm_pipe = NULL;
+			pipe->plane_state = NULL;
+			pipe->stream = NULL;
+			pipe->top_pipe = NULL;
+			pipe->prev_odm_pipe = NULL;
+			if (pipe->stream_res.dsc)
+				dcn20_release_dsc(&context->res_ctx, dc->res_pool, &pipe->stream_res.dsc);
+			memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
+			memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
+			repopulate_pipes = true;
+		} else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
+			struct pipe_ctx *top_pipe = pipe->top_pipe;
+			struct pipe_ctx *bottom_pipe = pipe->bottom_pipe;
+
+			top_pipe->bottom_pipe = bottom_pipe;
+			if (bottom_pipe)
+				bottom_pipe->top_pipe = top_pipe;
+
+			pipe->top_pipe = NULL;
+			pipe->bottom_pipe = NULL;
+			pipe->plane_state = NULL;
+			pipe->stream = NULL;
+			memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
+			memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
+			repopulate_pipes = true;
+		} else
+			ASSERT(0); /* Should never try to merge master pipe */
+
+	}
+
+	for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+		struct pipe_ctx *hsplit_pipe = NULL;
+		bool odm;
+		int old_index = -1;
+
+		if (!pipe->stream || newly_split[i])
+			continue;
+
+		pipe_idx++;
+		odm = vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled;
+
+		if (!pipe->plane_state && !odm)
+			continue;
+
+		if (split[i]) {
+			if (odm) {
+				if (split[i] == 4 && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe)
+					old_index = old_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
+				else if (old_pipe->next_odm_pipe)
+					old_index = old_pipe->next_odm_pipe->pipe_idx;
+			} else {
+				if (split[i] == 4 && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
+						old_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
+					old_index = old_pipe->bottom_pipe->bottom_pipe->pipe_idx;
+				else if (old_pipe->bottom_pipe &&
+						old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
+					old_index = old_pipe->bottom_pipe->pipe_idx;
+			}
+			hsplit_pipe = dcn32_find_split_pipe(dc, context, old_index);
+			ASSERT(hsplit_pipe);
+			if (!hsplit_pipe)
+				goto validate_fail;
+
+			if (!dcn32_split_stream_for_mpc_or_odm(
+					dc, &context->res_ctx,
+					pipe, hsplit_pipe, odm))
+				goto validate_fail;
+
+			newly_split[hsplit_pipe->pipe_idx] = true;
+			repopulate_pipes = true;
+		}
+		if (split[i] == 4) {
+			struct pipe_ctx *pipe_4to1;
+
+			if (odm && old_pipe->next_odm_pipe)
+				old_index = old_pipe->next_odm_pipe->pipe_idx;
+			else if (!odm && old_pipe->bottom_pipe &&
+						old_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
+				old_index = old_pipe->bottom_pipe->pipe_idx;
+			else
+				old_index = -1;
+			pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
+			ASSERT(pipe_4to1);
+			if (!pipe_4to1)
+				goto validate_fail;
+			if (!dcn32_split_stream_for_mpc_or_odm(
+					dc, &context->res_ctx,
+					pipe, pipe_4to1, odm))
+				goto validate_fail;
+			newly_split[pipe_4to1->pipe_idx] = true;
+
+			if (odm && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe
+					&& old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe)
+				old_index = old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe->pipe_idx;
+			else if (!odm && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe &&
+					old_pipe->bottom_pipe->bottom_pipe->bottom_pipe &&
+					old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state)
+				old_index = old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx;
+			else
+				old_index = -1;
+			pipe_4to1 = dcn32_find_split_pipe(dc, context, old_index);
+			ASSERT(pipe_4to1);
+			if (!pipe_4to1)
+				goto validate_fail;
+			if (!dcn32_split_stream_for_mpc_or_odm(
+					dc, &context->res_ctx,
+					hsplit_pipe, pipe_4to1, odm))
+				goto validate_fail;
+			newly_split[pipe_4to1->pipe_idx] = true;
+		}
+		if (odm)
+			dcn20_build_mapped_resource(dc, context, pipe->stream);
+	}
+
+	for (i = 0; i < dc->res_pool->pipe_count; i++) {
+		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+		if (pipe->plane_state) {
+			if (!resource_build_scaling_params(pipe))
+				goto validate_fail;
+		}
+	}
+
+	/* Actual dsc count per stream dsc validation*/
+	if (!dcn20_validate_dsc(dc, context)) {
+		vba->ValidationStatus[vba->soc.num_states] = DML_FAIL_DSC_VALIDATION_FAILURE;
+		goto validate_fail;
+	}
+
+	if (repopulate_pipes)
+		pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
+	*vlevel_out = vlevel;
+	*pipe_cnt_out = pipe_cnt;
+
+	out = true;
+	goto validate_out;
+
+validate_fail:
+	out = false;
+
+validate_out:
+	return out;
+}
+
+
 void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
 				display_e2e_pipe_params_st *pipes,
 				int pipe_cnt,
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index c7602f084be2..56973debc348 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -57,13 +57,12 @@ void dcn32_set_phantom_stream_timing(struct dc *dc,
 				     unsigned int pipe_cnt,
 				     unsigned int dc_pipe_idx);
 
-void dcn32_full_validate_bw_helper(struct dc *dc,
-				   struct dc_state *context,
-				   display_e2e_pipe_params_st *pipes,
-				   int *vlevel,
-				   int *split,
-				   bool *merge,
-				   int *pipe_cnt);
+bool dcn32_internal_validate_bw(struct dc *dc,
+				struct dc_state *context,
+				display_e2e_pipe_params_st *pipes,
+				int *pipe_cnt_out,
+				int *vlevel_out,
+				bool fast_validate);
 
 void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
 				display_e2e_pipe_params_st *pipes,
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 26/31] drm/amd/display: Move ntuple to insert entry
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (24 preceding siblings ...)
  2022-07-15 18:16 ` [PATCH 25/31] drm/amd/display: Move dlg params calculation Rodrigo Siqueira
@ 2022-07-15 18:17 ` Rodrigo Siqueira
  2022-07-15 18:17 ` [PATCH 27/31] drm/amd/display: Move bounding box to FPU folder Rodrigo Siqueira
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:17 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

Move get_optimal_ntuple to the FPU code and call it inside
insert_entry_into_table_sorted.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 28 -------------------
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 25 +++++++++++++++++
 2 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index 32edb3e5715a..adcc83e6ea55 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -1956,29 +1956,6 @@ void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,
     DC_FP_END();
 }
 
-static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
-{
-	if (entry->dcfclk_mhz > 0) {
-		float bw_on_sdp = entry->dcfclk_mhz * dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100);
-
-		entry->fabricclk_mhz = bw_on_sdp / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100));
-		entry->dram_speed_mts = bw_on_sdp / (dcn3_2_soc.num_chans *
-				dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
-	} else if (entry->fabricclk_mhz > 0) {
-		float bw_on_fabric = entry->fabricclk_mhz * dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100);
-
-		entry->dcfclk_mhz = bw_on_fabric / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100));
-		entry->dram_speed_mts = bw_on_fabric / (dcn3_2_soc.num_chans *
-				dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
-	} else if (entry->dram_speed_mts > 0) {
-		float bw_on_dram = entry->dram_speed_mts * dcn3_2_soc.num_chans *
-				dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
-
-		entry->fabricclk_mhz = bw_on_dram / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100));
-		entry->dcfclk_mhz = bw_on_dram / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100));
-	}
-}
-
 static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
 		unsigned int index)
 {
@@ -2062,7 +2039,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.fabricclk_mhz = 0;
 		entry.dram_speed_mts = 0;
 
-		get_optimal_ntuple(&entry);
 		DC_FP_START();
 		insert_entry_into_table_sorted(table, num_entries, &entry);
 		DC_FP_END();
@@ -2073,7 +2049,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 	entry.fabricclk_mhz = 0;
 	entry.dram_speed_mts = 0;
 
-	get_optimal_ntuple(&entry);
 	DC_FP_START();
 	insert_entry_into_table_sorted(table, num_entries, &entry);
 	DC_FP_END();
@@ -2084,7 +2059,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.fabricclk_mhz = 0;
 		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
 
-		get_optimal_ntuple(&entry);
 		DC_FP_START();
 		insert_entry_into_table_sorted(table, num_entries, &entry);
 		DC_FP_END();
@@ -2097,7 +2071,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 			entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
 			entry.dram_speed_mts = 0;
 
-			get_optimal_ntuple(&entry);
 			DC_FP_START();
 			insert_entry_into_table_sorted(table, num_entries, &entry);
 			DC_FP_END();
@@ -2109,7 +2082,6 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.fabricclk_mhz = max_fclk_mhz;
 		entry.dram_speed_mts = 0;
 
-		get_optimal_ntuple(&entry);
 		DC_FP_START();
 		insert_entry_into_table_sorted(table, num_entries, &entry);
 		DC_FP_END();
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 66102db87265..7c60a954737b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -353,6 +353,29 @@ static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *
 	return limiting_bw_kbytes_sec;
 }
 
+static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
+{
+	if (entry->dcfclk_mhz > 0) {
+		float bw_on_sdp = entry->dcfclk_mhz * dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100);
+
+		entry->fabricclk_mhz = bw_on_sdp / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100));
+		entry->dram_speed_mts = bw_on_sdp / (dcn3_2_soc.num_chans *
+				dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
+	} else if (entry->fabricclk_mhz > 0) {
+		float bw_on_fabric = entry->fabricclk_mhz * dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100);
+
+		entry->dcfclk_mhz = bw_on_fabric / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100));
+		entry->dram_speed_mts = bw_on_fabric / (dcn3_2_soc.num_chans *
+				dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
+	} else if (entry->dram_speed_mts > 0) {
+		float bw_on_dram = entry->dram_speed_mts * dcn3_2_soc.num_chans *
+				dcn3_2_soc.dram_channel_width_bytes * ((float)dcn3_2_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
+
+		entry->fabricclk_mhz = bw_on_dram / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_fabric_bw_after_urgent / 100));
+		entry->dcfclk_mhz = bw_on_dram / (dcn3_2_soc.return_bus_width_bytes * ((float)dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / 100));
+	}
+}
+
 void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
 				    unsigned int *num_entries,
 				    struct _vcs_dpi_voltage_scaling_st *entry)
@@ -363,6 +386,8 @@ void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
 
 	dc_assert_fp_enabled();
 
+	get_optimal_ntuple(entry);
+
 	if (*num_entries == 0) {
 		table[0] = *entry;
 		(*num_entries)++;
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 27/31] drm/amd/display: Move bounding box to FPU folder
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (25 preceding siblings ...)
  2022-07-15 18:17 ` [PATCH 26/31] drm/amd/display: Move ntuple to insert entry Rodrigo Siqueira
@ 2022-07-15 18:17 ` Rodrigo Siqueira
  2022-07-15 18:17 ` [PATCH 28/31] drm/amd/display: Drop FPU flags from dcn32 Makefile Rodrigo Siqueira
                   ` (4 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:17 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

The final part of the DCN32 code that uses FPU is the bounding box code,
and this commit move it to dcn32_fpu.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 460 +----------------
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 470 ++++++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |   2 +
 3 files changed, 474 insertions(+), 458 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
index adcc83e6ea55..b2e7d59e743f 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
@@ -1923,29 +1923,6 @@ static struct dc_cap_funcs cap_funcs = {
 	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
 };
 
-
-static void dcn32_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
-		unsigned int *optimal_dcfclk,
-		unsigned int *optimal_fclk)
-{
-	double bw_from_dram, bw_from_dram1, bw_from_dram2;
-
-	bw_from_dram1 = uclk_mts * dcn3_2_soc.num_chans *
-		dcn3_2_soc.dram_channel_width_bytes * (dcn3_2_soc.max_avg_dram_bw_use_normal_percent / 100);
-	bw_from_dram2 = uclk_mts * dcn3_2_soc.num_chans *
-		dcn3_2_soc.dram_channel_width_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100);
-
-	bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
-
-	if (optimal_fclk)
-		*optimal_fclk = bw_from_dram /
-		(dcn3_2_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100));
-
-	if (optimal_dcfclk)
-		*optimal_dcfclk =  bw_from_dram /
-		(dcn3_2_soc.return_bus_width_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100));
-}
-
 void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,
 				display_e2e_pipe_params_st *pipes,
 				int pipe_cnt,
@@ -1956,444 +1933,11 @@ void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context,
     DC_FP_END();
 }
 
-static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
-		unsigned int index)
-{
-	int i;
-
-	if (*num_entries == 0)
-		return;
-
-	for (i = index; i < *num_entries - 1; i++) {
-		table[i] = table[i + 1];
-	}
-	memset(&table[--(*num_entries)], 0, sizeof(struct _vcs_dpi_voltage_scaling_st));
-}
-
-static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
-		struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
+static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
 {
-	int i, j;
-	struct _vcs_dpi_voltage_scaling_st entry = {0};
-
-	unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0,
-			max_phyclk_mhz = 0, max_dtbclk_mhz = 0, max_fclk_mhz = 0, max_uclk_mhz = 0;
-
-	unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299;
-
-	static const unsigned int num_dcfclk_stas = 5;
-	unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
-
-	unsigned int num_uclk_dpms = 0;
-	unsigned int num_fclk_dpms = 0;
-	unsigned int num_dcfclk_dpms = 0;
-
-	for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
-		if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
-			max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
-		if (bw_params->clk_table.entries[i].fclk_mhz > max_fclk_mhz)
-			max_fclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
-		if (bw_params->clk_table.entries[i].memclk_mhz > max_uclk_mhz)
-			max_uclk_mhz = bw_params->clk_table.entries[i].memclk_mhz;
-		if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
-			max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
-		if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
-			max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
-		if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
-			max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
-		if (bw_params->clk_table.entries[i].dtbclk_mhz > max_dtbclk_mhz)
-			max_dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
-
-		if (bw_params->clk_table.entries[i].memclk_mhz > 0)
-			num_uclk_dpms++;
-		if (bw_params->clk_table.entries[i].fclk_mhz > 0)
-			num_fclk_dpms++;
-		if (bw_params->clk_table.entries[i].dcfclk_mhz > 0)
-			num_dcfclk_dpms++;
-	}
-
-	if (!max_dcfclk_mhz || !max_dispclk_mhz || !max_dtbclk_mhz)
-		return -1;
-
-	if (max_dppclk_mhz == 0)
-		max_dppclk_mhz = max_dispclk_mhz;
-
-	if (max_fclk_mhz == 0)
-		max_fclk_mhz = max_dcfclk_mhz * dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / dcn3_2_soc.pct_ideal_fabric_bw_after_urgent;
-
-	if (max_phyclk_mhz == 0)
-		max_phyclk_mhz = dcn3_2_soc.clock_limits[0].phyclk_mhz;
-
-	*num_entries = 0;
-	entry.dispclk_mhz = max_dispclk_mhz;
-	entry.dscclk_mhz = max_dispclk_mhz / 3;
-	entry.dppclk_mhz = max_dppclk_mhz;
-	entry.dtbclk_mhz = max_dtbclk_mhz;
-	entry.phyclk_mhz = max_phyclk_mhz;
-	entry.phyclk_d18_mhz = dcn3_2_soc.clock_limits[0].phyclk_d18_mhz;
-	entry.phyclk_d32_mhz = dcn3_2_soc.clock_limits[0].phyclk_d32_mhz;
-
-	// Insert all the DCFCLK STAs
-	for (i = 0; i < num_dcfclk_stas; i++) {
-		entry.dcfclk_mhz = dcfclk_sta_targets[i];
-		entry.fabricclk_mhz = 0;
-		entry.dram_speed_mts = 0;
-
-		DC_FP_START();
-		insert_entry_into_table_sorted(table, num_entries, &entry);
-		DC_FP_END();
-	}
-
-	// Insert the max DCFCLK
-	entry.dcfclk_mhz = max_dcfclk_mhz;
-	entry.fabricclk_mhz = 0;
-	entry.dram_speed_mts = 0;
-
 	DC_FP_START();
-	insert_entry_into_table_sorted(table, num_entries, &entry);
+	dcn32_update_bw_bounding_box_fpu(dc, bw_params);
 	DC_FP_END();
-
-	// Insert the UCLK DPMS
-	for (i = 0; i < num_uclk_dpms; i++) {
-		entry.dcfclk_mhz = 0;
-		entry.fabricclk_mhz = 0;
-		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
-
-		DC_FP_START();
-		insert_entry_into_table_sorted(table, num_entries, &entry);
-		DC_FP_END();
-	}
-
-	// If FCLK is coarse grained, insert individual DPMs.
-	if (num_fclk_dpms > 2) {
-		for (i = 0; i < num_fclk_dpms; i++) {
-			entry.dcfclk_mhz = 0;
-			entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
-			entry.dram_speed_mts = 0;
-
-			DC_FP_START();
-			insert_entry_into_table_sorted(table, num_entries, &entry);
-			DC_FP_END();
-		}
-	}
-	// If FCLK fine grained, only insert max
-	else {
-		entry.dcfclk_mhz = 0;
-		entry.fabricclk_mhz = max_fclk_mhz;
-		entry.dram_speed_mts = 0;
-
-		DC_FP_START();
-		insert_entry_into_table_sorted(table, num_entries, &entry);
-		DC_FP_END();
-	}
-
-	// At this point, the table contains all "points of interest" based on
-	// DPMs from PMFW, and STAs.  Table is sorted by BW, and all clock
-	// ratios (by derate, are exact).
-
-	// Remove states that require higher clocks than are supported
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		if (table[i].dcfclk_mhz > max_dcfclk_mhz ||
-				table[i].fabricclk_mhz > max_fclk_mhz ||
-				table[i].dram_speed_mts > max_uclk_mhz * 16)
-			remove_entry_from_table_at_index(table, num_entries, i);
-	}
-
-	// At this point, the table only contains supported points of interest
-	// it could be used as is, but some states may be redundant due to
-	// coarse grained nature of some clocks, so we want to round up to
-	// coarse grained DPMs and remove duplicates.
-
-	// Round up UCLKs
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		for (j = 0; j < num_uclk_dpms; j++) {
-			if (bw_params->clk_table.entries[j].memclk_mhz * 16 >= table[i].dram_speed_mts) {
-				table[i].dram_speed_mts = bw_params->clk_table.entries[j].memclk_mhz * 16;
-				break;
-			}
-		}
-	}
-
-	// If FCLK is coarse grained, round up to next DPMs
-	if (num_fclk_dpms > 2) {
-		for (i = *num_entries - 1; i >= 0 ; i--) {
-			for (j = 0; j < num_fclk_dpms; j++) {
-				if (bw_params->clk_table.entries[j].fclk_mhz >= table[i].fabricclk_mhz) {
-					table[i].fabricclk_mhz = bw_params->clk_table.entries[j].fclk_mhz;
-					break;
-				}
-			}
-		}
-	}
-	// Otherwise, round up to minimum.
-	else {
-		for (i = *num_entries - 1; i >= 0 ; i--) {
-			if (table[i].fabricclk_mhz < min_fclk_mhz) {
-				table[i].fabricclk_mhz = min_fclk_mhz;
-				break;
-			}
-		}
-	}
-
-	// Round DCFCLKs up to minimum
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		if (table[i].dcfclk_mhz < min_dcfclk_mhz) {
-			table[i].dcfclk_mhz = min_dcfclk_mhz;
-			break;
-		}
-	}
-
-	// Remove duplicate states, note duplicate states are always neighbouring since table is sorted.
-	i = 0;
-	while (i < *num_entries - 1) {
-		if (table[i].dcfclk_mhz == table[i + 1].dcfclk_mhz &&
-				table[i].fabricclk_mhz == table[i + 1].fabricclk_mhz &&
-				table[i].dram_speed_mts == table[i + 1].dram_speed_mts)
-			remove_entry_from_table_at_index(table, num_entries, i + 1);
-		else
-			i++;
-	}
-
-	// Fix up the state indicies
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		table[i].state = i;
-	}
-
-	return 0;
-}
-
-/* dcn32_update_bw_bounding_box
- * This would override some dcn3_2 ip_or_soc initial parameters hardcoded from spreadsheet
- * with actual values as per dGPU SKU:
- * -with passed few options from dc->config
- * -with dentist_vco_frequency from Clk Mgr (currently hardcoded, but might need to get it from PM FW)
- * -with passed latency values (passed in ns units) in dc-> bb override for debugging purposes
- * -with passed latencies from VBIOS (in 100_ns units) if available for certain dGPU SKU
- * -with number of DRAM channels from VBIOS (which differ for certain dGPU SKU of the same ASIC)
- * -clocks levels with passed clk_table entries from Clk Mgr as reported by PM FW for different
- *  clocks (which might differ for certain dGPU SKU of the same ASIC)
- */
-static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
-{
-	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
-
-		/* Overrides from dc->config options */
-		dcn3_2_ip.clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
-
-		/* Override from passed dc->bb_overrides if available*/
-		if ((int)(dcn3_2_soc.sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns
-				&& dc->bb_overrides.sr_exit_time_ns) {
-			dcn3_2_soc.sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_2_soc.sr_enter_plus_exit_time_us * 1000)
-				!= dc->bb_overrides.sr_enter_plus_exit_time_ns
-				&& dc->bb_overrides.sr_enter_plus_exit_time_ns) {
-			dcn3_2_soc.sr_enter_plus_exit_time_us =
-				dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_2_soc.urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns
-			&& dc->bb_overrides.urgent_latency_ns) {
-			dcn3_2_soc.urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_2_soc.dram_clock_change_latency_us * 1000)
-				!= dc->bb_overrides.dram_clock_change_latency_ns
-				&& dc->bb_overrides.dram_clock_change_latency_ns) {
-			dcn3_2_soc.dram_clock_change_latency_us =
-				dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_2_soc.dummy_pstate_latency_us * 1000)
-				!= dc->bb_overrides.dummy_clock_change_latency_ns
-				&& dc->bb_overrides.dummy_clock_change_latency_ns) {
-			dcn3_2_soc.dummy_pstate_latency_us =
-				dc->bb_overrides.dummy_clock_change_latency_ns / 1000.0;
-		}
-
-		/* Override from VBIOS if VBIOS bb_info available */
-		if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
-			struct bp_soc_bb_info bb_info = {0};
-
-			if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
-				if (bb_info.dram_clock_change_latency_100ns > 0)
-					dcn3_2_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10;
-
-			if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
-				dcn3_2_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10;
-
-			if (bb_info.dram_sr_exit_latency_100ns > 0)
-				dcn3_2_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
-			}
-		}
-
-		/* Override from VBIOS for num_chan */
-		if (dc->ctx->dc_bios->vram_info.num_chans)
-			dcn3_2_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
-
-		if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
-			dcn3_2_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
-
-	}
-
-	/* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */
-	dcn3_2_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-	dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-
-	/* Overrides Clock levelsfrom CLK Mgr table entries as reported by PM FW */
-	if ((!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) && (bw_params->clk_table.entries[0].memclk_mhz)) {
-		if (dc->debug.use_legacy_soc_bb_mechanism) {
-			unsigned int i = 0, j = 0, num_states = 0;
-
-			unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
-			unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
-			unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
-			unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
-			unsigned int min_dcfclk = UINT_MAX;
-			/* Set 199 as first value in STA target array to have a minimum DCFCLK value.
-			 * For DCN32 we set min to 199 so minimum FCLK DPM0 (300Mhz can be achieved) */
-			unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
-			unsigned int num_dcfclk_sta_targets = 4, num_uclk_states = 0;
-			unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
-
-			for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
-				if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
-					max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
-				if (bw_params->clk_table.entries[i].dcfclk_mhz != 0 &&
-						bw_params->clk_table.entries[i].dcfclk_mhz < min_dcfclk)
-					min_dcfclk = bw_params->clk_table.entries[i].dcfclk_mhz;
-				if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
-					max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
-				if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
-					max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
-				if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
-					max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
-			}
-			if (min_dcfclk > dcfclk_sta_targets[0])
-				dcfclk_sta_targets[0] = min_dcfclk;
-			if (!max_dcfclk_mhz)
-				max_dcfclk_mhz = dcn3_2_soc.clock_limits[0].dcfclk_mhz;
-			if (!max_dispclk_mhz)
-				max_dispclk_mhz = dcn3_2_soc.clock_limits[0].dispclk_mhz;
-			if (!max_dppclk_mhz)
-				max_dppclk_mhz = dcn3_2_soc.clock_limits[0].dppclk_mhz;
-			if (!max_phyclk_mhz)
-				max_phyclk_mhz = dcn3_2_soc.clock_limits[0].phyclk_mhz;
-
-			if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
-				// If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array
-				dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
-				num_dcfclk_sta_targets++;
-			} else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
-				// If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates
-				for (i = 0; i < num_dcfclk_sta_targets; i++) {
-					if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
-						dcfclk_sta_targets[i] = max_dcfclk_mhz;
-						break;
-					}
-				}
-				// Update size of array since we "removed" duplicates
-				num_dcfclk_sta_targets = i + 1;
-			}
-
-			num_uclk_states = bw_params->clk_table.num_entries;
-
-			// Calculate optimal dcfclk for each uclk
-			for (i = 0; i < num_uclk_states; i++) {
-				dcn32_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
-						&optimal_dcfclk_for_uclk[i], NULL);
-				if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) {
-					optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
-				}
-			}
-
-			// Calculate optimal uclk for each dcfclk sta target
-			for (i = 0; i < num_dcfclk_sta_targets; i++) {
-				for (j = 0; j < num_uclk_states; j++) {
-					if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
-						optimal_uclk_for_dcfclk_sta_targets[i] =
-								bw_params->clk_table.entries[j].memclk_mhz * 16;
-						break;
-					}
-				}
-			}
-
-			i = 0;
-			j = 0;
-			// create the final dcfclk and uclk table
-			while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
-				if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
-					dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
-					dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
-				} else {
-					if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
-						dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
-						dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
-					} else {
-						j = num_uclk_states;
-					}
-				}
-			}
-
-			while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
-				dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
-				dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
-			}
-
-			while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
-					optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
-				dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
-				dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
-			}
-
-			dcn3_2_soc.num_states = num_states;
-			for (i = 0; i < dcn3_2_soc.num_states; i++) {
-				dcn3_2_soc.clock_limits[i].state = i;
-				dcn3_2_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
-				dcn3_2_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
-
-				/* Fill all states with max values of all these clocks */
-				dcn3_2_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
-				dcn3_2_soc.clock_limits[i].dppclk_mhz  = max_dppclk_mhz;
-				dcn3_2_soc.clock_limits[i].phyclk_mhz  = max_phyclk_mhz;
-				dcn3_2_soc.clock_limits[i].dscclk_mhz  = max_dispclk_mhz / 3;
-
-				/* Populate from bw_params for DTBCLK, SOCCLK */
-				if (i > 0) {
-					if (!bw_params->clk_table.entries[i].dtbclk_mhz) {
-						dcn3_2_soc.clock_limits[i].dtbclk_mhz  = dcn3_2_soc.clock_limits[i-1].dtbclk_mhz;
-					} else {
-						dcn3_2_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
-					}
-				} else if (bw_params->clk_table.entries[i].dtbclk_mhz) {
-					dcn3_2_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
-				}
-
-				if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
-					dcn3_2_soc.clock_limits[i].socclk_mhz = dcn3_2_soc.clock_limits[i-1].socclk_mhz;
-				else
-					dcn3_2_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
-
-				if (!dram_speed_mts[i] && i > 0)
-					dcn3_2_soc.clock_limits[i].dram_speed_mts = dcn3_2_soc.clock_limits[i-1].dram_speed_mts;
-				else
-					dcn3_2_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
-
-				/* These clocks cannot come from bw_params, always fill from dcn3_2_soc[0] */
-				/* PHYCLK_D18, PHYCLK_D32 */
-				dcn3_2_soc.clock_limits[i].phyclk_d18_mhz = dcn3_2_soc.clock_limits[0].phyclk_d18_mhz;
-				dcn3_2_soc.clock_limits[i].phyclk_d32_mhz = dcn3_2_soc.clock_limits[0].phyclk_d32_mhz;
-			}
-		} else {
-			build_synthetic_soc_states(bw_params, dcn3_2_soc.clock_limits, &dcn3_2_soc.num_states);
-		}
-
-		/* Re-init DML with updated bb */
-		dml_init_instance(&dc->dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32);
-		if (dc->current_state)
-			dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32);
-	}
 }
 
 static struct resource_funcs dcn32_res_pool_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
index 7c60a954737b..9175fe1f9be3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
@@ -1772,3 +1772,473 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
 
 }
 
+static void dcn32_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
+		unsigned int *optimal_dcfclk,
+		unsigned int *optimal_fclk)
+{
+	double bw_from_dram, bw_from_dram1, bw_from_dram2;
+
+	bw_from_dram1 = uclk_mts * dcn3_2_soc.num_chans *
+		dcn3_2_soc.dram_channel_width_bytes * (dcn3_2_soc.max_avg_dram_bw_use_normal_percent / 100);
+	bw_from_dram2 = uclk_mts * dcn3_2_soc.num_chans *
+		dcn3_2_soc.dram_channel_width_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100);
+
+	bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
+
+	if (optimal_fclk)
+		*optimal_fclk = bw_from_dram /
+		(dcn3_2_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100));
+
+	if (optimal_dcfclk)
+		*optimal_dcfclk =  bw_from_dram /
+		(dcn3_2_soc.return_bus_width_bytes * (dcn3_2_soc.max_avg_sdp_bw_use_normal_percent / 100));
+}
+
+static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
+		unsigned int index)
+{
+	int i;
+
+	if (*num_entries == 0)
+		return;
+
+	for (i = index; i < *num_entries - 1; i++) {
+		table[i] = table[i + 1];
+	}
+	memset(&table[--(*num_entries)], 0, sizeof(struct _vcs_dpi_voltage_scaling_st));
+}
+
+static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
+		struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
+{
+	int i, j;
+	struct _vcs_dpi_voltage_scaling_st entry = {0};
+
+	unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0,
+			max_phyclk_mhz = 0, max_dtbclk_mhz = 0, max_fclk_mhz = 0, max_uclk_mhz = 0;
+
+	unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299;
+
+	static const unsigned int num_dcfclk_stas = 5;
+	unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
+
+	unsigned int num_uclk_dpms = 0;
+	unsigned int num_fclk_dpms = 0;
+	unsigned int num_dcfclk_dpms = 0;
+
+	for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
+		if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
+			max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+		if (bw_params->clk_table.entries[i].fclk_mhz > max_fclk_mhz)
+			max_fclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
+		if (bw_params->clk_table.entries[i].memclk_mhz > max_uclk_mhz)
+			max_uclk_mhz = bw_params->clk_table.entries[i].memclk_mhz;
+		if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
+			max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+		if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
+			max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+		if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
+			max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+		if (bw_params->clk_table.entries[i].dtbclk_mhz > max_dtbclk_mhz)
+			max_dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
+
+		if (bw_params->clk_table.entries[i].memclk_mhz > 0)
+			num_uclk_dpms++;
+		if (bw_params->clk_table.entries[i].fclk_mhz > 0)
+			num_fclk_dpms++;
+		if (bw_params->clk_table.entries[i].dcfclk_mhz > 0)
+			num_dcfclk_dpms++;
+	}
+
+	if (!max_dcfclk_mhz || !max_dispclk_mhz || !max_dtbclk_mhz)
+		return -1;
+
+	if (max_dppclk_mhz == 0)
+		max_dppclk_mhz = max_dispclk_mhz;
+
+	if (max_fclk_mhz == 0)
+		max_fclk_mhz = max_dcfclk_mhz * dcn3_2_soc.pct_ideal_sdp_bw_after_urgent / dcn3_2_soc.pct_ideal_fabric_bw_after_urgent;
+
+	if (max_phyclk_mhz == 0)
+		max_phyclk_mhz = dcn3_2_soc.clock_limits[0].phyclk_mhz;
+
+	*num_entries = 0;
+	entry.dispclk_mhz = max_dispclk_mhz;
+	entry.dscclk_mhz = max_dispclk_mhz / 3;
+	entry.dppclk_mhz = max_dppclk_mhz;
+	entry.dtbclk_mhz = max_dtbclk_mhz;
+	entry.phyclk_mhz = max_phyclk_mhz;
+	entry.phyclk_d18_mhz = dcn3_2_soc.clock_limits[0].phyclk_d18_mhz;
+	entry.phyclk_d32_mhz = dcn3_2_soc.clock_limits[0].phyclk_d32_mhz;
+
+	// Insert all the DCFCLK STAs
+	for (i = 0; i < num_dcfclk_stas; i++) {
+		entry.dcfclk_mhz = dcfclk_sta_targets[i];
+		entry.fabricclk_mhz = 0;
+		entry.dram_speed_mts = 0;
+
+		DC_FP_START();
+		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
+	}
+
+	// Insert the max DCFCLK
+	entry.dcfclk_mhz = max_dcfclk_mhz;
+	entry.fabricclk_mhz = 0;
+	entry.dram_speed_mts = 0;
+
+	DC_FP_START();
+	insert_entry_into_table_sorted(table, num_entries, &entry);
+	DC_FP_END();
+
+	// Insert the UCLK DPMS
+	for (i = 0; i < num_uclk_dpms; i++) {
+		entry.dcfclk_mhz = 0;
+		entry.fabricclk_mhz = 0;
+		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
+
+		DC_FP_START();
+		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
+	}
+
+	// If FCLK is coarse grained, insert individual DPMs.
+	if (num_fclk_dpms > 2) {
+		for (i = 0; i < num_fclk_dpms; i++) {
+			entry.dcfclk_mhz = 0;
+			entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
+			entry.dram_speed_mts = 0;
+
+			DC_FP_START();
+			insert_entry_into_table_sorted(table, num_entries, &entry);
+			DC_FP_END();
+		}
+	}
+	// If FCLK fine grained, only insert max
+	else {
+		entry.dcfclk_mhz = 0;
+		entry.fabricclk_mhz = max_fclk_mhz;
+		entry.dram_speed_mts = 0;
+
+		DC_FP_START();
+		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
+	}
+
+	// At this point, the table contains all "points of interest" based on
+	// DPMs from PMFW, and STAs.  Table is sorted by BW, and all clock
+	// ratios (by derate, are exact).
+
+	// Remove states that require higher clocks than are supported
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		if (table[i].dcfclk_mhz > max_dcfclk_mhz ||
+				table[i].fabricclk_mhz > max_fclk_mhz ||
+				table[i].dram_speed_mts > max_uclk_mhz * 16)
+			remove_entry_from_table_at_index(table, num_entries, i);
+	}
+
+	// At this point, the table only contains supported points of interest
+	// it could be used as is, but some states may be redundant due to
+	// coarse grained nature of some clocks, so we want to round up to
+	// coarse grained DPMs and remove duplicates.
+
+	// Round up UCLKs
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		for (j = 0; j < num_uclk_dpms; j++) {
+			if (bw_params->clk_table.entries[j].memclk_mhz * 16 >= table[i].dram_speed_mts) {
+				table[i].dram_speed_mts = bw_params->clk_table.entries[j].memclk_mhz * 16;
+				break;
+			}
+		}
+	}
+
+	// If FCLK is coarse grained, round up to next DPMs
+	if (num_fclk_dpms > 2) {
+		for (i = *num_entries - 1; i >= 0 ; i--) {
+			for (j = 0; j < num_fclk_dpms; j++) {
+				if (bw_params->clk_table.entries[j].fclk_mhz >= table[i].fabricclk_mhz) {
+					table[i].fabricclk_mhz = bw_params->clk_table.entries[j].fclk_mhz;
+					break;
+				}
+			}
+		}
+	}
+	// Otherwise, round up to minimum.
+	else {
+		for (i = *num_entries - 1; i >= 0 ; i--) {
+			if (table[i].fabricclk_mhz < min_fclk_mhz) {
+				table[i].fabricclk_mhz = min_fclk_mhz;
+				break;
+			}
+		}
+	}
+
+	// Round DCFCLKs up to minimum
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		if (table[i].dcfclk_mhz < min_dcfclk_mhz) {
+			table[i].dcfclk_mhz = min_dcfclk_mhz;
+			break;
+		}
+	}
+
+	// Remove duplicate states, note duplicate states are always neighbouring since table is sorted.
+	i = 0;
+	while (i < *num_entries - 1) {
+		if (table[i].dcfclk_mhz == table[i + 1].dcfclk_mhz &&
+				table[i].fabricclk_mhz == table[i + 1].fabricclk_mhz &&
+				table[i].dram_speed_mts == table[i + 1].dram_speed_mts)
+			remove_entry_from_table_at_index(table, num_entries, i + 1);
+		else
+			i++;
+	}
+
+	// Fix up the state indicies
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		table[i].state = i;
+	}
+
+	return 0;
+}
+
+/**
+ * dcn32_update_bw_bounding_box
+ *
+ * This would override some dcn3_2 ip_or_soc initial parameters hardcoded from
+ * spreadsheet with actual values as per dGPU SKU:
+ * - with passed few options from dc->config
+ * - with dentist_vco_frequency from Clk Mgr (currently hardcoded, but might
+ *   need to get it from PM FW)
+ * - with passed latency values (passed in ns units) in dc-> bb override for
+ *   debugging purposes
+ * - with passed latencies from VBIOS (in 100_ns units) if available for
+ *   certain dGPU SKU
+ * - with number of DRAM channels from VBIOS (which differ for certain dGPU SKU
+ *   of the same ASIC)
+ * - clocks levels with passed clk_table entries from Clk Mgr as reported by PM
+ *   FW for different clocks (which might differ for certain dGPU SKU of the
+ *   same ASIC)
+ */
+void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	dc_assert_fp_enabled();
+
+	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+		/* Overrides from dc->config options */
+		dcn3_2_ip.clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
+
+		/* Override from passed dc->bb_overrides if available*/
+		if ((int)(dcn3_2_soc.sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns
+				&& dc->bb_overrides.sr_exit_time_ns) {
+			dcn3_2_soc.sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_2_soc.sr_enter_plus_exit_time_us * 1000)
+				!= dc->bb_overrides.sr_enter_plus_exit_time_ns
+				&& dc->bb_overrides.sr_enter_plus_exit_time_ns) {
+			dcn3_2_soc.sr_enter_plus_exit_time_us =
+				dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_2_soc.urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns
+			&& dc->bb_overrides.urgent_latency_ns) {
+			dcn3_2_soc.urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_2_soc.dram_clock_change_latency_us * 1000)
+				!= dc->bb_overrides.dram_clock_change_latency_ns
+				&& dc->bb_overrides.dram_clock_change_latency_ns) {
+			dcn3_2_soc.dram_clock_change_latency_us =
+				dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_2_soc.dummy_pstate_latency_us * 1000)
+				!= dc->bb_overrides.dummy_clock_change_latency_ns
+				&& dc->bb_overrides.dummy_clock_change_latency_ns) {
+			dcn3_2_soc.dummy_pstate_latency_us =
+				dc->bb_overrides.dummy_clock_change_latency_ns / 1000.0;
+		}
+
+		/* Override from VBIOS if VBIOS bb_info available */
+		if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
+			struct bp_soc_bb_info bb_info = {0};
+
+			if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
+				if (bb_info.dram_clock_change_latency_100ns > 0)
+					dcn3_2_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10;
+
+			if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
+				dcn3_2_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10;
+
+			if (bb_info.dram_sr_exit_latency_100ns > 0)
+				dcn3_2_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
+			}
+		}
+
+		/* Override from VBIOS for num_chan */
+		if (dc->ctx->dc_bios->vram_info.num_chans)
+			dcn3_2_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+
+		if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+			dcn3_2_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
+
+	}
+
+	/* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */
+	dcn3_2_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+	dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+
+	/* Overrides Clock levelsfrom CLK Mgr table entries as reported by PM FW */
+	if ((!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) && (bw_params->clk_table.entries[0].memclk_mhz)) {
+		if (dc->debug.use_legacy_soc_bb_mechanism) {
+			unsigned int i = 0, j = 0, num_states = 0;
+
+			unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
+			unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
+			unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
+			unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
+			unsigned int min_dcfclk = UINT_MAX;
+			/* Set 199 as first value in STA target array to have a minimum DCFCLK value.
+			 * For DCN32 we set min to 199 so minimum FCLK DPM0 (300Mhz can be achieved) */
+			unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
+			unsigned int num_dcfclk_sta_targets = 4, num_uclk_states = 0;
+			unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
+
+			for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
+				if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
+					max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+				if (bw_params->clk_table.entries[i].dcfclk_mhz != 0 &&
+						bw_params->clk_table.entries[i].dcfclk_mhz < min_dcfclk)
+					min_dcfclk = bw_params->clk_table.entries[i].dcfclk_mhz;
+				if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
+					max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+				if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
+					max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+				if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
+					max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+			}
+			if (min_dcfclk > dcfclk_sta_targets[0])
+				dcfclk_sta_targets[0] = min_dcfclk;
+			if (!max_dcfclk_mhz)
+				max_dcfclk_mhz = dcn3_2_soc.clock_limits[0].dcfclk_mhz;
+			if (!max_dispclk_mhz)
+				max_dispclk_mhz = dcn3_2_soc.clock_limits[0].dispclk_mhz;
+			if (!max_dppclk_mhz)
+				max_dppclk_mhz = dcn3_2_soc.clock_limits[0].dppclk_mhz;
+			if (!max_phyclk_mhz)
+				max_phyclk_mhz = dcn3_2_soc.clock_limits[0].phyclk_mhz;
+
+			if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+				// If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array
+				dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
+				num_dcfclk_sta_targets++;
+			} else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+				// If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates
+				for (i = 0; i < num_dcfclk_sta_targets; i++) {
+					if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
+						dcfclk_sta_targets[i] = max_dcfclk_mhz;
+						break;
+					}
+				}
+				// Update size of array since we "removed" duplicates
+				num_dcfclk_sta_targets = i + 1;
+			}
+
+			num_uclk_states = bw_params->clk_table.num_entries;
+
+			// Calculate optimal dcfclk for each uclk
+			for (i = 0; i < num_uclk_states; i++) {
+				dcn32_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
+						&optimal_dcfclk_for_uclk[i], NULL);
+				if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) {
+					optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
+				}
+			}
+
+			// Calculate optimal uclk for each dcfclk sta target
+			for (i = 0; i < num_dcfclk_sta_targets; i++) {
+				for (j = 0; j < num_uclk_states; j++) {
+					if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
+						optimal_uclk_for_dcfclk_sta_targets[i] =
+								bw_params->clk_table.entries[j].memclk_mhz * 16;
+						break;
+					}
+				}
+			}
+
+			i = 0;
+			j = 0;
+			// create the final dcfclk and uclk table
+			while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
+				if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
+					dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+					dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+				} else {
+					if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+						dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+						dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+					} else {
+						j = num_uclk_states;
+					}
+				}
+			}
+
+			while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
+				dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+				dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+			}
+
+			while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
+					optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+				dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+				dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+			}
+
+			dcn3_2_soc.num_states = num_states;
+			for (i = 0; i < dcn3_2_soc.num_states; i++) {
+				dcn3_2_soc.clock_limits[i].state = i;
+				dcn3_2_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
+				dcn3_2_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
+
+				/* Fill all states with max values of all these clocks */
+				dcn3_2_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
+				dcn3_2_soc.clock_limits[i].dppclk_mhz  = max_dppclk_mhz;
+				dcn3_2_soc.clock_limits[i].phyclk_mhz  = max_phyclk_mhz;
+				dcn3_2_soc.clock_limits[i].dscclk_mhz  = max_dispclk_mhz / 3;
+
+				/* Populate from bw_params for DTBCLK, SOCCLK */
+				if (i > 0) {
+					if (!bw_params->clk_table.entries[i].dtbclk_mhz) {
+						dcn3_2_soc.clock_limits[i].dtbclk_mhz  = dcn3_2_soc.clock_limits[i-1].dtbclk_mhz;
+					} else {
+						dcn3_2_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+					}
+				} else if (bw_params->clk_table.entries[i].dtbclk_mhz) {
+					dcn3_2_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+				}
+
+				if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
+					dcn3_2_soc.clock_limits[i].socclk_mhz = dcn3_2_soc.clock_limits[i-1].socclk_mhz;
+				else
+					dcn3_2_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
+
+				if (!dram_speed_mts[i] && i > 0)
+					dcn3_2_soc.clock_limits[i].dram_speed_mts = dcn3_2_soc.clock_limits[i-1].dram_speed_mts;
+				else
+					dcn3_2_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
+
+				/* These clocks cannot come from bw_params, always fill from dcn3_2_soc[0] */
+				/* PHYCLK_D18, PHYCLK_D32 */
+				dcn3_2_soc.clock_limits[i].phyclk_d18_mhz = dcn3_2_soc.clock_limits[0].phyclk_d18_mhz;
+				dcn3_2_soc.clock_limits[i].phyclk_d32_mhz = dcn3_2_soc.clock_limits[0].phyclk_d32_mhz;
+			}
+		} else {
+			build_synthetic_soc_states(bw_params, dcn3_2_soc.clock_limits, &dcn3_2_soc.num_states);
+		}
+
+		/* Re-init DML with updated bb */
+		dml_init_instance(&dc->dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32);
+		if (dc->current_state)
+			dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32);
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
index 56973debc348..3ed06ab855be 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
@@ -69,4 +69,6 @@ void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
 				int pipe_cnt,
 				int vlevel);
 
+void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 28/31] drm/amd/display: Drop FPU flags from dcn32 Makefile
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (26 preceding siblings ...)
  2022-07-15 18:17 ` [PATCH 27/31] drm/amd/display: Move bounding box to FPU folder Rodrigo Siqueira
@ 2022-07-15 18:17 ` Rodrigo Siqueira
  2022-07-15 18:17 ` [PATCH 29/31] drm/amd/display: Create dcn321_fpu file Rodrigo Siqueira
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:17 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

This is the final commit from the FPU isolation for DCN32 and for this
reason we can finally remove flags related to FPU.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dcn32/Makefile | 28 -------------------
 1 file changed, 28 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile
index 932d85fa4262..e943b643ab6b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile
@@ -15,34 +15,6 @@ DCN32 = dcn32_resource.o dcn32_hubbub.o dcn32_hwseq.o dcn32_init.o \
 		dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_hpo_dp_link_encoder.o \
 		dcn32_resource_helpers.o dcn32_mpc.o
 
-ifdef CONFIG_X86
-dcn32_ccflags := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-dcn32_ccflags := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-dcn32_ccflags += -mpreferred-stack-boundary=4
-else
-dcn32_ccflags += -msse2
-endif
-endif
-
-CFLAGS_$(AMDDALPATH)/dc/dcn32/dcn32_resource_helpers.o := $(dcn32_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/dcn32/dcn32_resource.o := $(dcn32_ccflags)
-
 AMD_DAL_DCN32 = $(addprefix $(AMDDALPATH)/dc/dcn32/,$(DCN32))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_DCN32)
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 29/31] drm/amd/display: Create dcn321_fpu file
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (27 preceding siblings ...)
  2022-07-15 18:17 ` [PATCH 28/31] drm/amd/display: Drop FPU flags from dcn32 Makefile Rodrigo Siqueira
@ 2022-07-15 18:17 ` Rodrigo Siqueira
  2022-07-15 18:17 ` [PATCH 30/31] drm/amd/display: Drop FPU code from dcn321 resource Rodrigo Siqueira
                   ` (2 subsequent siblings)
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:17 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

The file dcn321_resource has a lot of FPU operations that should be
inside the dml folder. This commit introduces the dcn321_fpu file and
moves some of the FPU operation functions to this new file.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../amd/display/dc/dcn321/dcn321_resource.c   | 225 ++---------------
 .../amd/display/dc/dcn321/dcn321_resource.h   |   3 +
 drivers/gpu/drm/amd/display/dc/dml/Makefile   |   2 +
 .../amd/display/dc/dml/dcn321/dcn321_fpu.c    | 238 ++++++++++++++++++
 .../amd/display/dc/dml/dcn321/dcn321_fpu.h    |  36 +++
 5 files changed, 296 insertions(+), 208 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h

diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index d218c6dd71aa..6619bcb30de7 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -37,6 +37,8 @@
 #include "dcn20/dcn20_resource.h"
 #include "dcn30/dcn30_resource.h"
 
+#include "dml/dcn321/dcn321_fpu.h"
+
 #include "dcn10/dcn10_ipp.h"
 #include "dcn30/dcn30_hubbub.h"
 #include "dcn31/dcn31_hubbub.h"
@@ -120,134 +122,6 @@ static const struct IP_BASE DCN_BASE = { { { { 0x00000012, 0x000000C0, 0x000034C
 #define fixed16_to_double(x) (((double)x) / ((double) (1 << 16)))
 #define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x))
 
-#define DCN3_2_DEFAULT_DET_SIZE 256
-
-struct _vcs_dpi_ip_params_st dcn3_21_ip = {
-	.gpuvm_enable = 0,
-	.gpuvm_max_page_table_levels = 4,
-	.hostvm_enable = 0,
-	.rob_buffer_size_kbytes = 128,
-	.det_buffer_size_kbytes = DCN3_2_DEFAULT_DET_SIZE,
-	.config_return_buffer_size_in_kbytes = 1280,
-	.compressed_buffer_segment_size_in_kbytes = 64,
-	.meta_fifo_size_in_kentries = 22,
-	.zero_size_buffer_entries = 512,
-	.compbuf_reserved_space_64b = 256,
-	.compbuf_reserved_space_zs = 64,
-	.dpp_output_buffer_pixels = 2560,
-	.opp_output_buffer_lines = 1,
-	.pixel_chunk_size_kbytes = 8,
-	.alpha_pixel_chunk_size_kbytes = 4, // not appearing in spreadsheet, match c code from hw team
-	.min_pixel_chunk_size_bytes = 1024,
-	.dcc_meta_buffer_size_bytes = 6272,
-	.meta_chunk_size_kbytes = 2,
-	.min_meta_chunk_size_bytes = 256,
-	.writeback_chunk_size_kbytes = 8,
-	.ptoi_supported = false,
-	.num_dsc = 4,
-	.maximum_dsc_bits_per_component = 12,
-	.maximum_pixels_per_line_per_dsc_unit = 6016,
-	.dsc422_native_support = true,
-	.is_line_buffer_bpp_fixed = true,
-	.line_buffer_fixed_bpp = 57,
-	.line_buffer_size_bits = 1171920, //DPP doc, DCN3_2_DisplayMode_73.xlsm still shows as 986880 bits with 48 bpp
-	.max_line_buffer_lines = 32,
-	.writeback_interface_buffer_size_kbytes = 90,
-	.max_num_dpp = 4,
-	.max_num_otg = 4,
-	.max_num_hdmi_frl_outputs = 1,
-	.max_num_wb = 1,
-	.max_dchub_pscl_bw_pix_per_clk = 4,
-	.max_pscl_lb_bw_pix_per_clk = 2,
-	.max_lb_vscl_bw_pix_per_clk = 4,
-	.max_vscl_hscl_bw_pix_per_clk = 4,
-	.max_hscl_ratio = 6,
-	.max_vscl_ratio = 6,
-	.max_hscl_taps = 8,
-	.max_vscl_taps = 8,
-	.dpte_buffer_size_in_pte_reqs_luma = 64,
-	.dpte_buffer_size_in_pte_reqs_chroma = 34,
-	.dispclk_ramp_margin_percent = 1,
-	.max_inter_dcn_tile_repeaters = 8,
-	.cursor_buffer_size = 16,
-	.cursor_chunk_size = 2,
-	.writeback_line_buffer_buffer_size = 0,
-	.writeback_min_hscl_ratio = 1,
-	.writeback_min_vscl_ratio = 1,
-	.writeback_max_hscl_ratio = 1,
-	.writeback_max_vscl_ratio = 1,
-	.writeback_max_hscl_taps = 1,
-	.writeback_max_vscl_taps = 1,
-	.dppclk_delay_subtotal = 47,
-	.dppclk_delay_scl = 50,
-	.dppclk_delay_scl_lb_only = 16,
-	.dppclk_delay_cnvc_formatter = 28,
-	.dppclk_delay_cnvc_cursor = 6,
-	.dispclk_delay_subtotal = 125,
-	.dynamic_metadata_vm_enabled = false,
-	.odm_combine_4to1_supported = false,
-	.dcc_supported = true,
-	.max_num_dp2p0_outputs = 2,
-	.max_num_dp2p0_streams = 4,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = {
-	.clock_limits = {
-		{
-			.state = 0,
-			.dcfclk_mhz = 1564.0,
-			.fabricclk_mhz = 400.0,
-			.dispclk_mhz = 2150.0,
-			.dppclk_mhz = 2150.0,
-			.phyclk_mhz = 810.0,
-			.phyclk_d18_mhz = 667.0,
-			.phyclk_d32_mhz = 625.0,
-			.socclk_mhz = 1200.0,
-			.dscclk_mhz = 716.667,
-			.dram_speed_mts = 1600.0,
-			.dtbclk_mhz = 1564.0,
-		},
-	},
-	.num_states = 1,
-	.sr_exit_time_us = 5.20,
-	.sr_enter_plus_exit_time_us = 9.60,
-	.sr_exit_z8_time_us = 285.0,
-	.sr_enter_plus_exit_z8_time_us = 320,
-	.writeback_latency_us = 12.0,
-	.round_trip_ping_latency_dcfclk_cycles = 263,
-	.urgent_latency_pixel_data_only_us = 4.0,
-	.urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
-	.urgent_latency_vm_data_only_us = 4.0,
-	.fclk_change_latency_us = 20,
-	.usr_retraining_latency_us = 2,
-	.smn_latency_us = 2,
-	.mall_allocated_for_dcn_mbytes = 64,
-	.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
-	.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
-	.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
-	.pct_ideal_sdp_bw_after_urgent = 100.0,
-	.pct_ideal_fabric_bw_after_urgent = 67.0,
-	.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0,
-	.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
-	.pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0, // N/A, for now keep as is until DML implemented
-	.pct_ideal_dram_bw_after_urgent_strobe = 67.0,
-	.max_avg_sdp_bw_use_normal_percent = 80.0,
-	.max_avg_fabric_bw_use_normal_percent = 60.0,
-	.max_avg_dram_bw_use_normal_strobe_percent = 50.0,
-	.max_avg_dram_bw_use_normal_percent = 15.0,
-	.num_chans = 8,
-	.dram_channel_width_bytes = 2,
-	.fabric_datapath_to_dcn_data_return_bytes = 64,
-	.return_bus_width_bytes = 64,
-	.downspread_percent = 0.38,
-	.dcn_downspread_percent = 0.5,
-	.dram_clock_change_latency_us = 400,
-	.dispclk_dppclk_vco_speed_mhz = 4300.0,
-	.do_urgent_latency_adjustment = true,
-	.urgent_latency_adjustment_fabric_clock_component_us = 1.0,
-	.urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
-};
-
 enum dcn321_clk_src_array_id {
 	DCN321_CLK_SRC_PLL0,
 	DCN321_CLK_SRC_PLL1,
@@ -1719,76 +1593,6 @@ static void dcn321_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
 		(dcn3_21_soc.return_bus_width_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100));
 }
 
-static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
-{
-	if (entry->dcfclk_mhz > 0) {
-		float bw_on_sdp = entry->dcfclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100);
-
-		entry->fabricclk_mhz = bw_on_sdp / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100));
-		entry->dram_speed_mts = bw_on_sdp / (dcn3_21_soc.num_chans *
-				dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
-	} else if (entry->fabricclk_mhz > 0) {
-		float bw_on_fabric = entry->fabricclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100);
-
-		entry->dcfclk_mhz = bw_on_fabric / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100));
-		entry->dram_speed_mts = bw_on_fabric / (dcn3_21_soc.num_chans *
-				dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
-	} else if (entry->dram_speed_mts > 0) {
-		float bw_on_dram = entry->dram_speed_mts * dcn3_21_soc.num_chans *
-				dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
-
-		entry->fabricclk_mhz = bw_on_dram / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100));
-		entry->dcfclk_mhz = bw_on_dram / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100));
-	}
-}
-
-static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *entry)
-{
-	float memory_bw_kbytes_sec = entry->dram_speed_mts * dcn3_21_soc.num_chans *
-			dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
-
-	float fabric_bw_kbytes_sec = entry->fabricclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100);
-
-	float sdp_bw_kbytes_sec = entry->dcfclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100);
-
-	float limiting_bw_kbytes_sec = memory_bw_kbytes_sec;
-
-	if (fabric_bw_kbytes_sec < limiting_bw_kbytes_sec)
-		limiting_bw_kbytes_sec = fabric_bw_kbytes_sec;
-
-	if (sdp_bw_kbytes_sec < limiting_bw_kbytes_sec)
-		limiting_bw_kbytes_sec = sdp_bw_kbytes_sec;
-
-	return limiting_bw_kbytes_sec;
-}
-
-static void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
-		struct _vcs_dpi_voltage_scaling_st *entry)
-{
-	int index = 0;
-	int i = 0;
-	float net_bw_of_new_state = 0;
-
-	if (*num_entries == 0) {
-		table[0] = *entry;
-		(*num_entries)++;
-	} else {
-		net_bw_of_new_state = calculate_net_bw_in_kbytes_sec(entry);
-		while (net_bw_of_new_state > calculate_net_bw_in_kbytes_sec(&table[index])) {
-			index++;
-			if (index >= *num_entries)
-				break;
-		}
-
-		for (i = *num_entries; i > index; i--) {
-			table[i] = table[i - 1];
-		}
-
-		table[index] = *entry;
-		(*num_entries)++;
-	}
-}
-
 static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
 		unsigned int index)
 {
@@ -1872,8 +1676,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.fabricclk_mhz = 0;
 		entry.dram_speed_mts = 0;
 
-		get_optimal_ntuple(&entry);
-		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_START();
+		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
 	}
 
 	// Insert the max DCFCLK
@@ -1881,8 +1686,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 	entry.fabricclk_mhz = 0;
 	entry.dram_speed_mts = 0;
 
-	get_optimal_ntuple(&entry);
-	insert_entry_into_table_sorted(table, num_entries, &entry);
+	DC_FP_START();
+	dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+	DC_FP_END();
 
 	// Insert the UCLK DPMS
 	for (i = 0; i < num_uclk_dpms; i++) {
@@ -1890,8 +1696,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.fabricclk_mhz = 0;
 		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
 
-		get_optimal_ntuple(&entry);
-		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_START();
+		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
 	}
 
 	// If FCLK is coarse grained, insert individual DPMs.
@@ -1901,8 +1708,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 			entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
 			entry.dram_speed_mts = 0;
 
-			get_optimal_ntuple(&entry);
-			insert_entry_into_table_sorted(table, num_entries, &entry);
+			DC_FP_START();
+			dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+			DC_FP_END();
 		}
 	}
 	// If FCLK fine grained, only insert max
@@ -1911,8 +1719,9 @@ static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
 		entry.fabricclk_mhz = max_fclk_mhz;
 		entry.dram_speed_mts = 0;
 
-		get_optimal_ntuple(&entry);
-		insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_START();
+		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+		DC_FP_END();
 	}
 
 	// At this point, the table contains all "points of interest" based on
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h
index 2732085a0e88..82cbf009f2d3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h
@@ -31,6 +31,9 @@
 #define TO_DCN321_RES_POOL(pool)\
 	container_of(pool, struct dcn321_resource_pool, base)
 
+extern struct _vcs_dpi_ip_params_st dcn3_21_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc;
+
 struct dcn321_resource_pool {
 	struct resource_pool base;
 };
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index 01cb0ef3a2b0..359f6e9a1da0 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -76,6 +76,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/dcn32_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_32.o := $(dml_ccflags) $(frame_warn_flag)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_rq_dlg_calc_32.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn32/display_mode_vba_util_32.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn321/dcn321_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/dcn31_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_ccflags)
 CFLAGS_$(AMDDALPATH)/dc/dml/dcn302/dcn302_fpu.o := $(dml_ccflags)
@@ -126,6 +127,7 @@ DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o
 DML += dcn32/display_mode_vba_32.o dcn32/display_rq_dlg_calc_32.o dcn32/display_mode_vba_util_32.o
 DML += dcn31/dcn31_fpu.o
 DML += dcn32/dcn32_fpu.o
+DML += dcn321/dcn321_fpu.o
 DML += dcn301/dcn301_fpu.o
 DML += dcn302/dcn302_fpu.o
 DML += dcn303/dcn303_fpu.o
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
new file mode 100644
index 000000000000..78408698985b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "resource.h"
+#include "dcn321_fpu.h"
+#include "dcn32/dcn32_resource.h"
+#include "dcn321/dcn321_resource.h"
+
+#define DCN3_2_DEFAULT_DET_SIZE 256
+
+struct _vcs_dpi_ip_params_st dcn3_21_ip = {
+	.gpuvm_enable = 0,
+	.gpuvm_max_page_table_levels = 4,
+	.hostvm_enable = 0,
+	.rob_buffer_size_kbytes = 128,
+	.det_buffer_size_kbytes = DCN3_2_DEFAULT_DET_SIZE,
+	.config_return_buffer_size_in_kbytes = 1280,
+	.compressed_buffer_segment_size_in_kbytes = 64,
+	.meta_fifo_size_in_kentries = 22,
+	.zero_size_buffer_entries = 512,
+	.compbuf_reserved_space_64b = 256,
+	.compbuf_reserved_space_zs = 64,
+	.dpp_output_buffer_pixels = 2560,
+	.opp_output_buffer_lines = 1,
+	.pixel_chunk_size_kbytes = 8,
+	.alpha_pixel_chunk_size_kbytes = 4,
+	.min_pixel_chunk_size_bytes = 1024,
+	.dcc_meta_buffer_size_bytes = 6272,
+	.meta_chunk_size_kbytes = 2,
+	.min_meta_chunk_size_bytes = 256,
+	.writeback_chunk_size_kbytes = 8,
+	.ptoi_supported = false,
+	.num_dsc = 4,
+	.maximum_dsc_bits_per_component = 12,
+	.maximum_pixels_per_line_per_dsc_unit = 6016,
+	.dsc422_native_support = true,
+	.is_line_buffer_bpp_fixed = true,
+	.line_buffer_fixed_bpp = 57,
+	.line_buffer_size_bits = 1171920,
+	.max_line_buffer_lines = 32,
+	.writeback_interface_buffer_size_kbytes = 90,
+	.max_num_dpp = 4,
+	.max_num_otg = 4,
+	.max_num_hdmi_frl_outputs = 1,
+	.max_num_wb = 1,
+	.max_dchub_pscl_bw_pix_per_clk = 4,
+	.max_pscl_lb_bw_pix_per_clk = 2,
+	.max_lb_vscl_bw_pix_per_clk = 4,
+	.max_vscl_hscl_bw_pix_per_clk = 4,
+	.max_hscl_ratio = 6,
+	.max_vscl_ratio = 6,
+	.max_hscl_taps = 8,
+	.max_vscl_taps = 8,
+	.dpte_buffer_size_in_pte_reqs_luma = 64,
+	.dpte_buffer_size_in_pte_reqs_chroma = 34,
+	.dispclk_ramp_margin_percent = 1,
+	.max_inter_dcn_tile_repeaters = 8,
+	.cursor_buffer_size = 16,
+	.cursor_chunk_size = 2,
+	.writeback_line_buffer_buffer_size = 0,
+	.writeback_min_hscl_ratio = 1,
+	.writeback_min_vscl_ratio = 1,
+	.writeback_max_hscl_ratio = 1,
+	.writeback_max_vscl_ratio = 1,
+	.writeback_max_hscl_taps = 1,
+	.writeback_max_vscl_taps = 1,
+	.dppclk_delay_subtotal = 47,
+	.dppclk_delay_scl = 50,
+	.dppclk_delay_scl_lb_only = 16,
+	.dppclk_delay_cnvc_formatter = 28,
+	.dppclk_delay_cnvc_cursor = 6,
+	.dispclk_delay_subtotal = 125,
+	.dynamic_metadata_vm_enabled = false,
+	.odm_combine_4to1_supported = false,
+	.dcc_supported = true,
+	.max_num_dp2p0_outputs = 2,
+	.max_num_dp2p0_streams = 4,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc = {
+	.clock_limits = {
+		{
+			.state = 0,
+			.dcfclk_mhz = 1564.0,
+			.fabricclk_mhz = 400.0,
+			.dispclk_mhz = 2150.0,
+			.dppclk_mhz = 2150.0,
+			.phyclk_mhz = 810.0,
+			.phyclk_d18_mhz = 667.0,
+			.phyclk_d32_mhz = 625.0,
+			.socclk_mhz = 1200.0,
+			.dscclk_mhz = 716.667,
+			.dram_speed_mts = 1600.0,
+			.dtbclk_mhz = 1564.0,
+		},
+	},
+	.num_states = 1,
+	.sr_exit_time_us = 5.20,
+	.sr_enter_plus_exit_time_us = 9.60,
+	.sr_exit_z8_time_us = 285.0,
+	.sr_enter_plus_exit_z8_time_us = 320,
+	.writeback_latency_us = 12.0,
+	.round_trip_ping_latency_dcfclk_cycles = 263,
+	.urgent_latency_pixel_data_only_us = 4.0,
+	.urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+	.urgent_latency_vm_data_only_us = 4.0,
+	.fclk_change_latency_us = 20,
+	.usr_retraining_latency_us = 2,
+	.smn_latency_us = 2,
+	.mall_allocated_for_dcn_mbytes = 64,
+	.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+	.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+	.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+	.pct_ideal_sdp_bw_after_urgent = 100.0,
+	.pct_ideal_fabric_bw_after_urgent = 67.0,
+	.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0,
+	.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
+	.pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0, // N/A, for now keep as is until DML implemented
+	.pct_ideal_dram_bw_after_urgent_strobe = 67.0,
+	.max_avg_sdp_bw_use_normal_percent = 80.0,
+	.max_avg_fabric_bw_use_normal_percent = 60.0,
+	.max_avg_dram_bw_use_normal_strobe_percent = 50.0,
+	.max_avg_dram_bw_use_normal_percent = 15.0,
+	.num_chans = 8,
+	.dram_channel_width_bytes = 2,
+	.fabric_datapath_to_dcn_data_return_bytes = 64,
+	.return_bus_width_bytes = 64,
+	.downspread_percent = 0.38,
+	.dcn_downspread_percent = 0.5,
+	.dram_clock_change_latency_us = 400,
+	.dispclk_dppclk_vco_speed_mhz = 4300.0,
+	.do_urgent_latency_adjustment = true,
+	.urgent_latency_adjustment_fabric_clock_component_us = 1.0,
+	.urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+};
+
+static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
+{
+	if (entry->dcfclk_mhz > 0) {
+		float bw_on_sdp = entry->dcfclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100);
+
+		entry->fabricclk_mhz = bw_on_sdp / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100));
+		entry->dram_speed_mts = bw_on_sdp / (dcn3_21_soc.num_chans *
+				dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
+	} else if (entry->fabricclk_mhz > 0) {
+		float bw_on_fabric = entry->fabricclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100);
+
+		entry->dcfclk_mhz = bw_on_fabric / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100));
+		entry->dram_speed_mts = bw_on_fabric / (dcn3_21_soc.num_chans *
+				dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100));
+	} else if (entry->dram_speed_mts > 0) {
+		float bw_on_dram = entry->dram_speed_mts * dcn3_21_soc.num_chans *
+				dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
+
+		entry->fabricclk_mhz = bw_on_dram / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100));
+		entry->dcfclk_mhz = bw_on_dram / (dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100));
+	}
+}
+
+static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *entry)
+{
+	float memory_bw_kbytes_sec;
+	float fabric_bw_kbytes_sec;
+	float sdp_bw_kbytes_sec;
+	float limiting_bw_kbytes_sec;
+
+	memory_bw_kbytes_sec = entry->dram_speed_mts * dcn3_21_soc.num_chans *
+			dcn3_21_soc.dram_channel_width_bytes * ((float)dcn3_21_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only / 100);
+
+	fabric_bw_kbytes_sec = entry->fabricclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_fabric_bw_after_urgent / 100);
+
+	sdp_bw_kbytes_sec = entry->dcfclk_mhz * dcn3_21_soc.return_bus_width_bytes * ((float)dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / 100);
+
+	limiting_bw_kbytes_sec = memory_bw_kbytes_sec;
+
+	if (fabric_bw_kbytes_sec < limiting_bw_kbytes_sec)
+		limiting_bw_kbytes_sec = fabric_bw_kbytes_sec;
+
+	if (sdp_bw_kbytes_sec < limiting_bw_kbytes_sec)
+		limiting_bw_kbytes_sec = sdp_bw_kbytes_sec;
+
+	return limiting_bw_kbytes_sec;
+}
+
+void dcn321_insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
+					   unsigned int *num_entries,
+					   struct _vcs_dpi_voltage_scaling_st *entry)
+{
+	int i = 0;
+	int index = 0;
+	float net_bw_of_new_state = 0;
+
+	dc_assert_fp_enabled();
+
+	get_optimal_ntuple(entry);
+
+	if (*num_entries == 0) {
+		table[0] = *entry;
+		(*num_entries)++;
+	} else {
+		net_bw_of_new_state = calculate_net_bw_in_kbytes_sec(entry);
+		while (net_bw_of_new_state > calculate_net_bw_in_kbytes_sec(&table[index])) {
+			index++;
+			if (index >= *num_entries)
+				break;
+		}
+
+		for (i = *num_entries; i > index; i--)
+			table[i] = table[i - 1];
+
+		table[index] = *entry;
+		(*num_entries)++;
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h
new file mode 100644
index 000000000000..5b6b28526e18
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN32_FPU_H__
+#define __DCN32_FPU_H__
+
+#include "dml/display_mode_vba.h"
+
+void dcn321_insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
+					   unsigned int *num_entries,
+					   struct _vcs_dpi_voltage_scaling_st *entry);
+
+#endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 30/31] drm/amd/display: Drop FPU code from dcn321 resource
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (28 preceding siblings ...)
  2022-07-15 18:17 ` [PATCH 29/31] drm/amd/display: Create dcn321_fpu file Rodrigo Siqueira
@ 2022-07-15 18:17 ` Rodrigo Siqueira
  2022-07-15 18:17 ` [PATCH 31/31] drm/amd/display: 3.2.195 Rodrigo Siqueira
  2022-07-18 13:15 ` [PATCH 00/31] DC Patches July 15, 2022 Wheeler, Daniel
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:17 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Sunpeng.Li, Harry.Wentland, qingqing.zhuo,
	Rodrigo.Siqueira, roman.li, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Bhawanpreet.Lakha, agustin.gutierrez, pavle.kotarac

This commit fully move the missing FPU operations from dcn321 resource
to dcn321 fpu. It also remove those FPU flags from the Makefile.

Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
---
 .../gpu/drm/amd/display/dc/dcn321/Makefile    |  25 -
 .../amd/display/dc/dcn321/dcn321_resource.c   | 452 +-----------------
 .../amd/display/dc/dml/dcn321/dcn321_fpu.c    | 446 +++++++++++++++++
 .../amd/display/dc/dml/dcn321/dcn321_fpu.h    |   2 +
 4 files changed, 450 insertions(+), 475 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/Makefile b/drivers/gpu/drm/amd/display/dc/dcn321/Makefile
index e554fd6c16f2..0a199c83bb5b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/Makefile
@@ -12,31 +12,6 @@
 
 DCN321 = dcn321_resource.o dcn321_dio_link_encoder.o
 
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn321/dcn321_resource.o := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/dcn321/dcn321_resource.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/dcn321/dcn321_resource.o += -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/dcn321/dcn321_resource.o += -msse2
-endif
-endif
-
 AMD_DAL_DCN321 = $(addprefix $(AMDDALPATH)/dc/dcn321/,$(DCN321))
 
 AMD_DISPLAY_FILES += $(AMD_DAL_DCN321)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
index 6619bcb30de7..9ac0fcf79bed 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
@@ -1570,459 +1570,11 @@ static struct dc_cap_funcs cap_funcs = {
 	.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
 };
 
-
-static void dcn321_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
-		unsigned int *optimal_dcfclk,
-		unsigned int *optimal_fclk)
-{
-	double bw_from_dram, bw_from_dram1, bw_from_dram2;
-
-	bw_from_dram1 = uclk_mts * dcn3_21_soc.num_chans *
-		dcn3_21_soc.dram_channel_width_bytes * (dcn3_21_soc.max_avg_dram_bw_use_normal_percent / 100);
-	bw_from_dram2 = uclk_mts * dcn3_21_soc.num_chans *
-		dcn3_21_soc.dram_channel_width_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100);
-
-	bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
-
-	if (optimal_fclk)
-		*optimal_fclk = bw_from_dram /
-		(dcn3_21_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100));
-
-	if (optimal_dcfclk)
-		*optimal_dcfclk =  bw_from_dram /
-		(dcn3_21_soc.return_bus_width_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100));
-}
-
-static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
-		unsigned int index)
-{
-	int i;
-
-	if (*num_entries == 0)
-		return;
-
-	for (i = index; i < *num_entries - 1; i++) {
-		table[i] = table[i + 1];
-	}
-	memset(&table[--(*num_entries)], 0, sizeof(struct _vcs_dpi_voltage_scaling_st));
-}
-
-static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
-		struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
+static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
 {
-	int i, j;
-	struct _vcs_dpi_voltage_scaling_st entry = {0};
-
-	unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0,
-			max_phyclk_mhz = 0, max_dtbclk_mhz = 0, max_fclk_mhz = 0, max_uclk_mhz = 0;
-
-	unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299;
-
-	static const unsigned int num_dcfclk_stas = 5;
-	unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
-
-	unsigned int num_uclk_dpms = 0;
-	unsigned int num_fclk_dpms = 0;
-	unsigned int num_dcfclk_dpms = 0;
-
-	for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
-		if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
-			max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
-		if (bw_params->clk_table.entries[i].fclk_mhz > max_fclk_mhz)
-			max_fclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
-		if (bw_params->clk_table.entries[i].memclk_mhz > max_uclk_mhz)
-			max_uclk_mhz = bw_params->clk_table.entries[i].memclk_mhz;
-		if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
-			max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
-		if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
-			max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
-		if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
-			max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
-		if (bw_params->clk_table.entries[i].dtbclk_mhz > max_dtbclk_mhz)
-			max_dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
-
-		if (bw_params->clk_table.entries[i].memclk_mhz > 0)
-			num_uclk_dpms++;
-		if (bw_params->clk_table.entries[i].fclk_mhz > 0)
-			num_fclk_dpms++;
-		if (bw_params->clk_table.entries[i].dcfclk_mhz > 0)
-			num_dcfclk_dpms++;
-	}
-
-	if (!max_dcfclk_mhz || !max_dispclk_mhz || !max_dtbclk_mhz)
-		return -1;
-
-	if (max_dppclk_mhz == 0)
-		max_dppclk_mhz = max_dispclk_mhz;
-
-	if (max_fclk_mhz == 0)
-		max_fclk_mhz = max_dcfclk_mhz * dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / dcn3_21_soc.pct_ideal_fabric_bw_after_urgent;
-
-	if (max_phyclk_mhz == 0)
-		max_phyclk_mhz = dcn3_21_soc.clock_limits[0].phyclk_mhz;
-
-	*num_entries = 0;
-	entry.dispclk_mhz = max_dispclk_mhz;
-	entry.dscclk_mhz = max_dispclk_mhz / 3;
-	entry.dppclk_mhz = max_dppclk_mhz;
-	entry.dtbclk_mhz = max_dtbclk_mhz;
-	entry.phyclk_mhz = max_phyclk_mhz;
-	entry.phyclk_d18_mhz = dcn3_21_soc.clock_limits[0].phyclk_d18_mhz;
-	entry.phyclk_d32_mhz = dcn3_21_soc.clock_limits[0].phyclk_d32_mhz;
-
-	// Insert all the DCFCLK STAs
-	for (i = 0; i < num_dcfclk_stas; i++) {
-		entry.dcfclk_mhz = dcfclk_sta_targets[i];
-		entry.fabricclk_mhz = 0;
-		entry.dram_speed_mts = 0;
-
-		DC_FP_START();
-		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
-		DC_FP_END();
-	}
-
-	// Insert the max DCFCLK
-	entry.dcfclk_mhz = max_dcfclk_mhz;
-	entry.fabricclk_mhz = 0;
-	entry.dram_speed_mts = 0;
-
 	DC_FP_START();
-	dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+	dcn321_update_bw_bounding_box_fpu(dc, bw_params);
 	DC_FP_END();
-
-	// Insert the UCLK DPMS
-	for (i = 0; i < num_uclk_dpms; i++) {
-		entry.dcfclk_mhz = 0;
-		entry.fabricclk_mhz = 0;
-		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
-
-		DC_FP_START();
-		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
-		DC_FP_END();
-	}
-
-	// If FCLK is coarse grained, insert individual DPMs.
-	if (num_fclk_dpms > 2) {
-		for (i = 0; i < num_fclk_dpms; i++) {
-			entry.dcfclk_mhz = 0;
-			entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
-			entry.dram_speed_mts = 0;
-
-			DC_FP_START();
-			dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
-			DC_FP_END();
-		}
-	}
-	// If FCLK fine grained, only insert max
-	else {
-		entry.dcfclk_mhz = 0;
-		entry.fabricclk_mhz = max_fclk_mhz;
-		entry.dram_speed_mts = 0;
-
-		DC_FP_START();
-		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
-		DC_FP_END();
-	}
-
-	// At this point, the table contains all "points of interest" based on
-	// DPMs from PMFW, and STAs.  Table is sorted by BW, and all clock
-	// ratios (by derate, are exact).
-
-	// Remove states that require higher clocks than are supported
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		if (table[i].dcfclk_mhz > max_dcfclk_mhz ||
-				table[i].fabricclk_mhz > max_fclk_mhz ||
-				table[i].dram_speed_mts > max_uclk_mhz * 16)
-			remove_entry_from_table_at_index(table, num_entries, i);
-	}
-
-	// At this point, the table only contains supported points of interest
-	// it could be used as is, but some states may be redundant due to
-	// coarse grained nature of some clocks, so we want to round up to
-	// coarse grained DPMs and remove duplicates.
-
-	// Round up UCLKs
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		for (j = 0; j < num_uclk_dpms; j++) {
-			if (bw_params->clk_table.entries[j].memclk_mhz * 16 >= table[i].dram_speed_mts) {
-				table[i].dram_speed_mts = bw_params->clk_table.entries[j].memclk_mhz * 16;
-				break;
-			}
-		}
-	}
-
-	// If FCLK is coarse grained, round up to next DPMs
-	if (num_fclk_dpms > 2) {
-		for (i = *num_entries - 1; i >= 0 ; i--) {
-			for (j = 0; j < num_fclk_dpms; j++) {
-				if (bw_params->clk_table.entries[j].fclk_mhz >= table[i].fabricclk_mhz) {
-					table[i].fabricclk_mhz = bw_params->clk_table.entries[j].fclk_mhz;
-					break;
-				}
-			}
-		}
-	}
-	// Otherwise, round up to minimum.
-	else {
-		for (i = *num_entries - 1; i >= 0 ; i--) {
-			if (table[i].fabricclk_mhz < min_fclk_mhz) {
-				table[i].fabricclk_mhz = min_fclk_mhz;
-				break;
-			}
-		}
-	}
-
-	// Round DCFCLKs up to minimum
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		if (table[i].dcfclk_mhz < min_dcfclk_mhz) {
-			table[i].dcfclk_mhz = min_dcfclk_mhz;
-			break;
-		}
-	}
-
-	// Remove duplicate states, note duplicate states are always neighbouring since table is sorted.
-	i = 0;
-	while (i < *num_entries - 1) {
-		if (table[i].dcfclk_mhz == table[i + 1].dcfclk_mhz &&
-				table[i].fabricclk_mhz == table[i + 1].fabricclk_mhz &&
-				table[i].dram_speed_mts == table[i + 1].dram_speed_mts)
-			remove_entry_from_table_at_index(table, num_entries, i + 1);
-		else
-			i++;
-	}
-
-	// Fix up the state indicies
-	for (i = *num_entries - 1; i >= 0 ; i--) {
-		table[i].state = i;
-	}
-
-	return 0;
-}
-
-/* dcn321_update_bw_bounding_box
- * This would override some dcn3_2 ip_or_soc initial parameters hardcoded from spreadsheet
- * with actual values as per dGPU SKU:
- * -with passed few options from dc->config
- * -with dentist_vco_frequency from Clk Mgr (currently hardcoded, but might need to get it from PM FW)
- * -with passed latency values (passed in ns units) in dc-> bb override for debugging purposes
- * -with passed latencies from VBIOS (in 100_ns units) if available for certain dGPU SKU
- * -with number of DRAM channels from VBIOS (which differ for certain dGPU SKU of the same ASIC)
- * -clocks levels with passed clk_table entries from Clk Mgr as reported by PM FW for different
- *  clocks (which might differ for certain dGPU SKU of the same ASIC)
- */
-static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
-{
-	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
-		/* Overrides from dc->config options */
-		dcn3_21_ip.clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
-
-		/* Override from passed dc->bb_overrides if available*/
-		if ((int)(dcn3_21_soc.sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns
-				&& dc->bb_overrides.sr_exit_time_ns) {
-			dcn3_21_soc.sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_21_soc.sr_enter_plus_exit_time_us * 1000)
-				!= dc->bb_overrides.sr_enter_plus_exit_time_ns
-				&& dc->bb_overrides.sr_enter_plus_exit_time_ns) {
-			dcn3_21_soc.sr_enter_plus_exit_time_us =
-				dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_21_soc.urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns
-			&& dc->bb_overrides.urgent_latency_ns) {
-			dcn3_21_soc.urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_21_soc.dram_clock_change_latency_us * 1000)
-				!= dc->bb_overrides.dram_clock_change_latency_ns
-				&& dc->bb_overrides.dram_clock_change_latency_ns) {
-			dcn3_21_soc.dram_clock_change_latency_us =
-				dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
-		}
-
-		if ((int)(dcn3_21_soc.dummy_pstate_latency_us * 1000)
-				!= dc->bb_overrides.dummy_clock_change_latency_ns
-				&& dc->bb_overrides.dummy_clock_change_latency_ns) {
-			dcn3_21_soc.dummy_pstate_latency_us =
-				dc->bb_overrides.dummy_clock_change_latency_ns / 1000.0;
-		}
-
-		/* Override from VBIOS if VBIOS bb_info available */
-		if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
-			struct bp_soc_bb_info bb_info = {0};
-
-			if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
-				if (bb_info.dram_clock_change_latency_100ns > 0)
-					dcn3_21_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10;
-
-			if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
-				dcn3_21_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10;
-
-			if (bb_info.dram_sr_exit_latency_100ns > 0)
-				dcn3_21_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
-			}
-		}
-
-		/* Override from VBIOS for num_chan */
-		if (dc->ctx->dc_bios->vram_info.num_chans)
-			dcn3_21_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
-
-		if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
-			dcn3_21_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
-
-	}
-
-	/* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */
-	dcn3_21_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-	dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-
-	/* Overrides Clock levelsfrom CLK Mgr table entries as reported by PM FW */
-	if ((!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) && (bw_params->clk_table.entries[0].memclk_mhz)) {
-		if (dc->debug.use_legacy_soc_bb_mechanism) {
-			unsigned int i = 0, j = 0, num_states = 0;
-
-			unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
-			unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
-			unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
-			unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
-
-			unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {615, 906, 1324, 1564};
-			unsigned int num_dcfclk_sta_targets = 4, num_uclk_states = 0;
-			unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
-
-			for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
-				if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
-					max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
-				if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
-					max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
-				if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
-					max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
-				if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
-					max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
-			}
-			if (!max_dcfclk_mhz)
-				max_dcfclk_mhz = dcn3_21_soc.clock_limits[0].dcfclk_mhz;
-			if (!max_dispclk_mhz)
-				max_dispclk_mhz = dcn3_21_soc.clock_limits[0].dispclk_mhz;
-			if (!max_dppclk_mhz)
-				max_dppclk_mhz = dcn3_21_soc.clock_limits[0].dppclk_mhz;
-			if (!max_phyclk_mhz)
-				max_phyclk_mhz = dcn3_21_soc.clock_limits[0].phyclk_mhz;
-
-			if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
-				// If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array
-				dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
-				num_dcfclk_sta_targets++;
-			} else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
-				// If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates
-				for (i = 0; i < num_dcfclk_sta_targets; i++) {
-					if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
-						dcfclk_sta_targets[i] = max_dcfclk_mhz;
-						break;
-					}
-				}
-				// Update size of array since we "removed" duplicates
-				num_dcfclk_sta_targets = i + 1;
-			}
-
-			num_uclk_states = bw_params->clk_table.num_entries;
-
-			// Calculate optimal dcfclk for each uclk
-			for (i = 0; i < num_uclk_states; i++) {
-				dcn321_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
-						&optimal_dcfclk_for_uclk[i], NULL);
-				if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) {
-					optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
-				}
-			}
-
-			// Calculate optimal uclk for each dcfclk sta target
-			for (i = 0; i < num_dcfclk_sta_targets; i++) {
-				for (j = 0; j < num_uclk_states; j++) {
-					if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
-						optimal_uclk_for_dcfclk_sta_targets[i] =
-								bw_params->clk_table.entries[j].memclk_mhz * 16;
-						break;
-					}
-				}
-			}
-
-			i = 0;
-			j = 0;
-			// create the final dcfclk and uclk table
-			while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
-				if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
-					dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
-					dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
-				} else {
-					if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
-						dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
-						dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
-					} else {
-						j = num_uclk_states;
-					}
-				}
-			}
-
-			while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
-				dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
-				dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
-			}
-
-			while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
-					optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
-				dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
-				dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
-			}
-
-			dcn3_21_soc.num_states = num_states;
-			for (i = 0; i < dcn3_21_soc.num_states; i++) {
-				dcn3_21_soc.clock_limits[i].state = i;
-				dcn3_21_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
-				dcn3_21_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
-
-				/* Fill all states with max values of all these clocks */
-				dcn3_21_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
-				dcn3_21_soc.clock_limits[i].dppclk_mhz  = max_dppclk_mhz;
-				dcn3_21_soc.clock_limits[i].phyclk_mhz  = max_phyclk_mhz;
-				dcn3_21_soc.clock_limits[i].dscclk_mhz  = max_dispclk_mhz / 3;
-
-				/* Populate from bw_params for DTBCLK, SOCCLK */
-				if (i > 0) {
-					if (!bw_params->clk_table.entries[i].dtbclk_mhz) {
-						dcn3_21_soc.clock_limits[i].dtbclk_mhz  = dcn3_21_soc.clock_limits[i-1].dtbclk_mhz;
-					} else {
-						dcn3_21_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
-					}
-				} else if (bw_params->clk_table.entries[i].dtbclk_mhz) {
-					dcn3_21_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
-				}
-
-				if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
-					dcn3_21_soc.clock_limits[i].socclk_mhz = dcn3_21_soc.clock_limits[i-1].socclk_mhz;
-				else
-					dcn3_21_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
-
-				if (!dram_speed_mts[i] && i > 0)
-					dcn3_21_soc.clock_limits[i].dram_speed_mts = dcn3_21_soc.clock_limits[i-1].dram_speed_mts;
-				else
-					dcn3_21_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
-
-				/* These clocks cannot come from bw_params, always fill from dcn3_21_soc[0] */
-				/* PHYCLK_D18, PHYCLK_D32 */
-				dcn3_21_soc.clock_limits[i].phyclk_d18_mhz = dcn3_21_soc.clock_limits[0].phyclk_d18_mhz;
-				dcn3_21_soc.clock_limits[i].phyclk_d32_mhz = dcn3_21_soc.clock_limits[0].phyclk_d32_mhz;
-			}
-		} else {
-			build_synthetic_soc_states(bw_params, dcn3_21_soc.clock_limits, &dcn3_21_soc.num_states);
-		}
-
-		/* Re-init DML with updated bb */
-		dml_init_instance(&dc->dml, &dcn3_21_soc, &dcn3_21_ip, DML_PROJECT_DCN32);
-		if (dc->current_state)
-			dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_21_soc, &dcn3_21_ip, DML_PROJECT_DCN32);
-	}
 }
 
 static struct resource_funcs dcn321_res_pool_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
index 78408698985b..6e72336b7975 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
@@ -24,6 +24,7 @@
  *
  */
 
+#include "clk_mgr.h"
 #include "resource.h"
 #include "dcn321_fpu.h"
 #include "dcn32/dcn32_resource.h"
@@ -236,3 +237,448 @@ void dcn321_insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *t
 	}
 }
 
+static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
+		unsigned int index)
+{
+	int i;
+
+	if (*num_entries == 0)
+		return;
+
+	for (i = index; i < *num_entries - 1; i++) {
+		table[i] = table[i + 1];
+	}
+	memset(&table[--(*num_entries)], 0, sizeof(struct _vcs_dpi_voltage_scaling_st));
+}
+
+static int build_synthetic_soc_states(struct clk_bw_params *bw_params,
+		struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
+{
+	int i, j;
+	struct _vcs_dpi_voltage_scaling_st entry = {0};
+
+	unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0,
+			max_phyclk_mhz = 0, max_dtbclk_mhz = 0, max_fclk_mhz = 0, max_uclk_mhz = 0;
+
+	unsigned int min_dcfclk_mhz = 199, min_fclk_mhz = 299;
+
+	static const unsigned int num_dcfclk_stas = 5;
+	unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {199, 615, 906, 1324, 1564};
+
+	unsigned int num_uclk_dpms = 0;
+	unsigned int num_fclk_dpms = 0;
+	unsigned int num_dcfclk_dpms = 0;
+
+	for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
+		if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
+			max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+		if (bw_params->clk_table.entries[i].fclk_mhz > max_fclk_mhz)
+			max_fclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
+		if (bw_params->clk_table.entries[i].memclk_mhz > max_uclk_mhz)
+			max_uclk_mhz = bw_params->clk_table.entries[i].memclk_mhz;
+		if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
+			max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+		if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
+			max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+		if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
+			max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+		if (bw_params->clk_table.entries[i].dtbclk_mhz > max_dtbclk_mhz)
+			max_dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
+
+		if (bw_params->clk_table.entries[i].memclk_mhz > 0)
+			num_uclk_dpms++;
+		if (bw_params->clk_table.entries[i].fclk_mhz > 0)
+			num_fclk_dpms++;
+		if (bw_params->clk_table.entries[i].dcfclk_mhz > 0)
+			num_dcfclk_dpms++;
+	}
+
+	if (!max_dcfclk_mhz || !max_dispclk_mhz || !max_dtbclk_mhz)
+		return -1;
+
+	if (max_dppclk_mhz == 0)
+		max_dppclk_mhz = max_dispclk_mhz;
+
+	if (max_fclk_mhz == 0)
+		max_fclk_mhz = max_dcfclk_mhz * dcn3_21_soc.pct_ideal_sdp_bw_after_urgent / dcn3_21_soc.pct_ideal_fabric_bw_after_urgent;
+
+	if (max_phyclk_mhz == 0)
+		max_phyclk_mhz = dcn3_21_soc.clock_limits[0].phyclk_mhz;
+
+	*num_entries = 0;
+	entry.dispclk_mhz = max_dispclk_mhz;
+	entry.dscclk_mhz = max_dispclk_mhz / 3;
+	entry.dppclk_mhz = max_dppclk_mhz;
+	entry.dtbclk_mhz = max_dtbclk_mhz;
+	entry.phyclk_mhz = max_phyclk_mhz;
+	entry.phyclk_d18_mhz = dcn3_21_soc.clock_limits[0].phyclk_d18_mhz;
+	entry.phyclk_d32_mhz = dcn3_21_soc.clock_limits[0].phyclk_d32_mhz;
+
+	// Insert all the DCFCLK STAs
+	for (i = 0; i < num_dcfclk_stas; i++) {
+		entry.dcfclk_mhz = dcfclk_sta_targets[i];
+		entry.fabricclk_mhz = 0;
+		entry.dram_speed_mts = 0;
+
+		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+	}
+
+	// Insert the max DCFCLK
+	entry.dcfclk_mhz = max_dcfclk_mhz;
+	entry.fabricclk_mhz = 0;
+	entry.dram_speed_mts = 0;
+
+	dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+
+	// Insert the UCLK DPMS
+	for (i = 0; i < num_uclk_dpms; i++) {
+		entry.dcfclk_mhz = 0;
+		entry.fabricclk_mhz = 0;
+		entry.dram_speed_mts = bw_params->clk_table.entries[i].memclk_mhz * 16;
+
+		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+	}
+
+	// If FCLK is coarse grained, insert individual DPMs.
+	if (num_fclk_dpms > 2) {
+		for (i = 0; i < num_fclk_dpms; i++) {
+			entry.dcfclk_mhz = 0;
+			entry.fabricclk_mhz = bw_params->clk_table.entries[i].fclk_mhz;
+			entry.dram_speed_mts = 0;
+
+			dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+		}
+	}
+	// If FCLK fine grained, only insert max
+	else {
+		entry.dcfclk_mhz = 0;
+		entry.fabricclk_mhz = max_fclk_mhz;
+		entry.dram_speed_mts = 0;
+
+		dcn321_insert_entry_into_table_sorted(table, num_entries, &entry);
+	}
+
+	// At this point, the table contains all "points of interest" based on
+	// DPMs from PMFW, and STAs.  Table is sorted by BW, and all clock
+	// ratios (by derate, are exact).
+
+	// Remove states that require higher clocks than are supported
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		if (table[i].dcfclk_mhz > max_dcfclk_mhz ||
+				table[i].fabricclk_mhz > max_fclk_mhz ||
+				table[i].dram_speed_mts > max_uclk_mhz * 16)
+			remove_entry_from_table_at_index(table, num_entries, i);
+	}
+
+	// At this point, the table only contains supported points of interest
+	// it could be used as is, but some states may be redundant due to
+	// coarse grained nature of some clocks, so we want to round up to
+	// coarse grained DPMs and remove duplicates.
+
+	// Round up UCLKs
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		for (j = 0; j < num_uclk_dpms; j++) {
+			if (bw_params->clk_table.entries[j].memclk_mhz * 16 >= table[i].dram_speed_mts) {
+				table[i].dram_speed_mts = bw_params->clk_table.entries[j].memclk_mhz * 16;
+				break;
+			}
+		}
+	}
+
+	// If FCLK is coarse grained, round up to next DPMs
+	if (num_fclk_dpms > 2) {
+		for (i = *num_entries - 1; i >= 0 ; i--) {
+			for (j = 0; j < num_fclk_dpms; j++) {
+				if (bw_params->clk_table.entries[j].fclk_mhz >= table[i].fabricclk_mhz) {
+					table[i].fabricclk_mhz = bw_params->clk_table.entries[j].fclk_mhz;
+					break;
+				}
+			}
+		}
+	}
+	// Otherwise, round up to minimum.
+	else {
+		for (i = *num_entries - 1; i >= 0 ; i--) {
+			if (table[i].fabricclk_mhz < min_fclk_mhz) {
+				table[i].fabricclk_mhz = min_fclk_mhz;
+				break;
+			}
+		}
+	}
+
+	// Round DCFCLKs up to minimum
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		if (table[i].dcfclk_mhz < min_dcfclk_mhz) {
+			table[i].dcfclk_mhz = min_dcfclk_mhz;
+			break;
+		}
+	}
+
+	// Remove duplicate states, note duplicate states are always neighbouring since table is sorted.
+	i = 0;
+	while (i < *num_entries - 1) {
+		if (table[i].dcfclk_mhz == table[i + 1].dcfclk_mhz &&
+				table[i].fabricclk_mhz == table[i + 1].fabricclk_mhz &&
+				table[i].dram_speed_mts == table[i + 1].dram_speed_mts)
+			remove_entry_from_table_at_index(table, num_entries, i + 1);
+		else
+			i++;
+	}
+
+	// Fix up the state indicies
+	for (i = *num_entries - 1; i >= 0 ; i--) {
+		table[i].state = i;
+	}
+
+	return 0;
+}
+
+static void dcn321_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
+		unsigned int *optimal_dcfclk,
+		unsigned int *optimal_fclk)
+{
+	double bw_from_dram, bw_from_dram1, bw_from_dram2;
+
+	bw_from_dram1 = uclk_mts * dcn3_21_soc.num_chans *
+		dcn3_21_soc.dram_channel_width_bytes * (dcn3_21_soc.max_avg_dram_bw_use_normal_percent / 100);
+	bw_from_dram2 = uclk_mts * dcn3_21_soc.num_chans *
+		dcn3_21_soc.dram_channel_width_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100);
+
+	bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
+
+	if (optimal_fclk)
+		*optimal_fclk = bw_from_dram /
+		(dcn3_21_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100));
+
+	if (optimal_dcfclk)
+		*optimal_dcfclk =  bw_from_dram /
+		(dcn3_21_soc.return_bus_width_bytes * (dcn3_21_soc.max_avg_sdp_bw_use_normal_percent / 100));
+}
+
+/** dcn321_update_bw_bounding_box
+ * This would override some dcn3_2 ip_or_soc initial parameters hardcoded from spreadsheet
+ * with actual values as per dGPU SKU:
+ * -with passed few options from dc->config
+ * -with dentist_vco_frequency from Clk Mgr (currently hardcoded, but might need to get it from PM FW)
+ * -with passed latency values (passed in ns units) in dc-> bb override for debugging purposes
+ * -with passed latencies from VBIOS (in 100_ns units) if available for certain dGPU SKU
+ * -with number of DRAM channels from VBIOS (which differ for certain dGPU SKU of the same ASIC)
+ * -clocks levels with passed clk_table entries from Clk Mgr as reported by PM FW for different
+ *  clocks (which might differ for certain dGPU SKU of the same ASIC)
+ */
+void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
+{
+	dc_assert_fp_enabled();
+	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+		/* Overrides from dc->config options */
+		dcn3_21_ip.clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
+
+		/* Override from passed dc->bb_overrides if available*/
+		if ((int)(dcn3_21_soc.sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns
+				&& dc->bb_overrides.sr_exit_time_ns) {
+			dcn3_21_soc.sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_21_soc.sr_enter_plus_exit_time_us * 1000)
+				!= dc->bb_overrides.sr_enter_plus_exit_time_ns
+				&& dc->bb_overrides.sr_enter_plus_exit_time_ns) {
+			dcn3_21_soc.sr_enter_plus_exit_time_us =
+				dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_21_soc.urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns
+			&& dc->bb_overrides.urgent_latency_ns) {
+			dcn3_21_soc.urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_21_soc.dram_clock_change_latency_us * 1000)
+				!= dc->bb_overrides.dram_clock_change_latency_ns
+				&& dc->bb_overrides.dram_clock_change_latency_ns) {
+			dcn3_21_soc.dram_clock_change_latency_us =
+				dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
+		}
+
+		if ((int)(dcn3_21_soc.dummy_pstate_latency_us * 1000)
+				!= dc->bb_overrides.dummy_clock_change_latency_ns
+				&& dc->bb_overrides.dummy_clock_change_latency_ns) {
+			dcn3_21_soc.dummy_pstate_latency_us =
+				dc->bb_overrides.dummy_clock_change_latency_ns / 1000.0;
+		}
+
+		/* Override from VBIOS if VBIOS bb_info available */
+		if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
+			struct bp_soc_bb_info bb_info = {0};
+
+			if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
+				if (bb_info.dram_clock_change_latency_100ns > 0)
+					dcn3_21_soc.dram_clock_change_latency_us = bb_info.dram_clock_change_latency_100ns * 10;
+
+			if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
+				dcn3_21_soc.sr_enter_plus_exit_time_us = bb_info.dram_sr_enter_exit_latency_100ns * 10;
+
+			if (bb_info.dram_sr_exit_latency_100ns > 0)
+				dcn3_21_soc.sr_exit_time_us = bb_info.dram_sr_exit_latency_100ns * 10;
+			}
+		}
+
+		/* Override from VBIOS for num_chan */
+		if (dc->ctx->dc_bios->vram_info.num_chans)
+			dcn3_21_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+
+		if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+			dcn3_21_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
+
+	}
+
+	/* Override dispclk_dppclk_vco_speed_mhz from Clk Mgr */
+	dcn3_21_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+	dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+
+	/* Overrides Clock levelsfrom CLK Mgr table entries as reported by PM FW */
+	if ((!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) && (bw_params->clk_table.entries[0].memclk_mhz)) {
+		if (dc->debug.use_legacy_soc_bb_mechanism) {
+			unsigned int i = 0, j = 0, num_states = 0;
+
+			unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
+			unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
+			unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
+			unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
+
+			unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {615, 906, 1324, 1564};
+			unsigned int num_dcfclk_sta_targets = 4, num_uclk_states = 0;
+			unsigned int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
+
+			for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
+				if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
+					max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+				if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
+					max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+				if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
+					max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+				if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
+					max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+			}
+			if (!max_dcfclk_mhz)
+				max_dcfclk_mhz = dcn3_21_soc.clock_limits[0].dcfclk_mhz;
+			if (!max_dispclk_mhz)
+				max_dispclk_mhz = dcn3_21_soc.clock_limits[0].dispclk_mhz;
+			if (!max_dppclk_mhz)
+				max_dppclk_mhz = dcn3_21_soc.clock_limits[0].dppclk_mhz;
+			if (!max_phyclk_mhz)
+				max_phyclk_mhz = dcn3_21_soc.clock_limits[0].phyclk_mhz;
+
+			if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+				// If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array
+				dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
+				num_dcfclk_sta_targets++;
+			} else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+				// If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates
+				for (i = 0; i < num_dcfclk_sta_targets; i++) {
+					if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
+						dcfclk_sta_targets[i] = max_dcfclk_mhz;
+						break;
+					}
+				}
+				// Update size of array since we "removed" duplicates
+				num_dcfclk_sta_targets = i + 1;
+			}
+
+			num_uclk_states = bw_params->clk_table.num_entries;
+
+			// Calculate optimal dcfclk for each uclk
+			for (i = 0; i < num_uclk_states; i++) {
+				dcn321_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
+						&optimal_dcfclk_for_uclk[i], NULL);
+				if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) {
+					optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
+				}
+			}
+
+			// Calculate optimal uclk for each dcfclk sta target
+			for (i = 0; i < num_dcfclk_sta_targets; i++) {
+				for (j = 0; j < num_uclk_states; j++) {
+					if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
+						optimal_uclk_for_dcfclk_sta_targets[i] =
+								bw_params->clk_table.entries[j].memclk_mhz * 16;
+						break;
+					}
+				}
+			}
+
+			i = 0;
+			j = 0;
+			// create the final dcfclk and uclk table
+			while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
+				if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
+					dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+					dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+				} else {
+					if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+						dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+						dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+					} else {
+						j = num_uclk_states;
+					}
+				}
+			}
+
+			while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
+				dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+				dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+			}
+
+			while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
+					optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+				dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+				dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+			}
+
+			dcn3_21_soc.num_states = num_states;
+			for (i = 0; i < dcn3_21_soc.num_states; i++) {
+				dcn3_21_soc.clock_limits[i].state = i;
+				dcn3_21_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
+				dcn3_21_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
+
+				/* Fill all states with max values of all these clocks */
+				dcn3_21_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
+				dcn3_21_soc.clock_limits[i].dppclk_mhz  = max_dppclk_mhz;
+				dcn3_21_soc.clock_limits[i].phyclk_mhz  = max_phyclk_mhz;
+				dcn3_21_soc.clock_limits[i].dscclk_mhz  = max_dispclk_mhz / 3;
+
+				/* Populate from bw_params for DTBCLK, SOCCLK */
+				if (i > 0) {
+					if (!bw_params->clk_table.entries[i].dtbclk_mhz) {
+						dcn3_21_soc.clock_limits[i].dtbclk_mhz  = dcn3_21_soc.clock_limits[i-1].dtbclk_mhz;
+					} else {
+						dcn3_21_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+					}
+				} else if (bw_params->clk_table.entries[i].dtbclk_mhz) {
+					dcn3_21_soc.clock_limits[i].dtbclk_mhz  = bw_params->clk_table.entries[i].dtbclk_mhz;
+				}
+
+				if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
+					dcn3_21_soc.clock_limits[i].socclk_mhz = dcn3_21_soc.clock_limits[i-1].socclk_mhz;
+				else
+					dcn3_21_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
+
+				if (!dram_speed_mts[i] && i > 0)
+					dcn3_21_soc.clock_limits[i].dram_speed_mts = dcn3_21_soc.clock_limits[i-1].dram_speed_mts;
+				else
+					dcn3_21_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
+
+				/* These clocks cannot come from bw_params, always fill from dcn3_21_soc[0] */
+				/* PHYCLK_D18, PHYCLK_D32 */
+				dcn3_21_soc.clock_limits[i].phyclk_d18_mhz = dcn3_21_soc.clock_limits[0].phyclk_d18_mhz;
+				dcn3_21_soc.clock_limits[i].phyclk_d32_mhz = dcn3_21_soc.clock_limits[0].phyclk_d32_mhz;
+			}
+		} else {
+			build_synthetic_soc_states(bw_params, dcn3_21_soc.clock_limits, &dcn3_21_soc.num_states);
+		}
+
+		/* Re-init DML with updated bb */
+		dml_init_instance(&dc->dml, &dcn3_21_soc, &dcn3_21_ip, DML_PROJECT_DCN32);
+		if (dc->current_state)
+			dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_21_soc, &dcn3_21_ip, DML_PROJECT_DCN32);
+	}
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h
index 5b6b28526e18..e8fad9b4be69 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h
@@ -33,4 +33,6 @@ void dcn321_insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *t
 					   unsigned int *num_entries,
 					   struct _vcs_dpi_voltage_scaling_st *entry);
 
+void dcn321_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params);
+
 #endif
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 31/31] drm/amd/display: 3.2.195
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (29 preceding siblings ...)
  2022-07-15 18:17 ` [PATCH 30/31] drm/amd/display: Drop FPU code from dcn321 resource Rodrigo Siqueira
@ 2022-07-15 18:17 ` Rodrigo Siqueira
  2022-07-18 13:15 ` [PATCH 00/31] DC Patches July 15, 2022 Wheeler, Daniel
  31 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-15 18:17 UTC (permalink / raw)
  To: amd-gfx
  Cc: stylon.wang, Alan Liu, Aric Cyr, Sunpeng.Li, Harry.Wentland,
	qingqing.zhuo, Rodrigo.Siqueira, roman.li, solomon.chiu,
	Aurabindo.Pillai, wayne.lin, Bhawanpreet.Lakha,
	agustin.gutierrez, pavle.kotarac

From: Aric Cyr <aric.cyr@amd.com>

This version brings along following fixes:

- Isolate FPU operation for DCN32/321 under the DML folder
- Create a specific file for CRTC and plane based on amdgpu_dm
- Fix DSC issues
- Update DML logic

Acked-by: Alan Liu <HaoPing.Liu@amd.com>
Signed-off-by: Aric Cyr <aric.cyr@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dc.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index be41f9fcf1dd..d05bbe193bfa 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -47,7 +47,7 @@ struct aux_payload;
 struct set_config_cmd_payload;
 struct dmub_notification;
 
-#define DC_VER "3.2.194"
+#define DC_VER "3.2.195"
 
 #define MAX_SURFACES 3
 #define MAX_PLANES 6
-- 
2.37.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* RE: [PATCH 00/31] DC Patches July 15, 2022
  2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
                   ` (30 preceding siblings ...)
  2022-07-15 18:17 ` [PATCH 31/31] drm/amd/display: 3.2.195 Rodrigo Siqueira
@ 2022-07-18 13:15 ` Wheeler, Daniel
  31 siblings, 0 replies; 36+ messages in thread
From: Wheeler, Daniel @ 2022-07-18 13:15 UTC (permalink / raw)
  To: Siqueira, Rodrigo, amd-gfx
  Cc: Wang, Chao-kai (Stylon), Li, Sun peng (Leo),
	Wentland, Harry, Zhuo, Qingqing (Lillian),
	Siqueira, Rodrigo, Li, Roman, Chiu,  Solomon, Pillai, Aurabindo,
	Lin, Wayne, Lakha, Bhawanpreet, Gutierrez, Agustin, Kotarac,
	Pavle

[Public]

Hi all,
 
This week this patchset was tested on the following systems:
 
HP Envy 360, with Ryzen 5 4500U
Lenovo Thinkpad T14s Gen2, with AMD Ryzen 5 5650U 
Sapphire Pulse RX5700XT 
Reference AMD RX6800
Engineering board with Ryzen 9 5900H
 
These systems were tested on the following display types: 
eDP, (1080p 60hz [4500U, 5650U, 5900H])
VGA and DVI (1680x1050 60HZ [DP to VGA/DVI, USB-C to DVI/VGA])
DP/HDMI/USB-C (1440p 170hz, 4k 60hz, 4k 144hz [Includes USB-C to DP/HDMI adapters])
 
MST tested with Startech MST14DP123DP and 2x 4k 60Hz displays
DSC tested with Cable Matters 101075 (DP to 3x DP), and 201375 (USB-C to 3x DP) with 3x 4k60 displays
 
The testing is a mix of automated and manual tests. Manual testing includes (but is not limited to):
Changing display configurations and settings
Benchmark testing
Feature testing (Freesync, etc.)
 
Automated testing includes (but is not limited to):
Script testing (scripts to automate some of the manual checks)
IGT testing
 
The patchset consists of the amd-staging-drm-next branch (Head commit - 01a992129a037dee0834eabfd92e15eb376d185f) with new patches added on top of it. This branch is used for both Ubuntu and Chrome OS testing (ChromeOS on a bi-weekly basis).

 
Tested on Ubuntu 22.04 and Chrome OS
 
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
 
 
Thank you,
 
Dan Wheeler
Sr. Technologist | AMD
SW Display
------------------------------------------------------------------------------------------------------------------
1 Commerce Valley Dr E, Thornhill, ON L3T 7X6
amd.com

-----Original Message-----
From: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com> 
Sent: July 15, 2022 2:17 PM
To: amd-gfx@lists.freedesktop.org
Cc: Wentland, Harry <Harry.Wentland@amd.com>; Li, Sun peng (Leo) <Sunpeng.Li@amd.com>; Lakha, Bhawanpreet <Bhawanpreet.Lakha@amd.com>; Siqueira, Rodrigo <Rodrigo.Siqueira@amd.com>; Pillai, Aurabindo <Aurabindo.Pillai@amd.com>; Zhuo, Qingqing (Lillian) <Qingqing.Zhuo@amd.com>; Li, Roman <Roman.Li@amd.com>; Lin, Wayne <Wayne.Lin@amd.com>; Wang, Chao-kai (Stylon) <Stylon.Wang@amd.com>; Chiu, Solomon <Solomon.Chiu@amd.com>; Kotarac, Pavle <Pavle.Kotarac@amd.com>; Gutierrez, Agustin <Agustin.Gutierrez@amd.com>; Wheeler, Daniel <Daniel.Wheeler@amd.com>
Subject: [PATCH 00/31] DC Patches July 15, 2022

This DC patchset brings improvements in multiple areas. In summary, we
highlight:

- Isolate FPU operation for DCN32/321 under the DML folder
- Create a specific file for CRTC and plane based on amdgpu_dm
- Fix DSC issues
- Updates tp DML logic

Cc: Daniel Wheeler <daniel.wheeler@amd.com>

Thanks
Siqueira

Alvin Lee (2):
  drm/amd/display: Update in dml
  drm/amd/display: Don't set dram clock change requirement for SubVP

Aric Cyr (1):
  drm/amd/display: 3.2.195

Chris Park (1):
  drm/amd/display: Update Cursor Attribute MALL cache

Jun Lei (2):
  drm/amd/display: Remove unused variable
  drm/amd/display: Update DML logic for unbounded req handling

Rodrigo Siqueira (16):
  drm/amd/display: Create a file dedicated to planes
  drm/amd/display: Create a file dedicated for CRTC
  drm/amd/display: Fix hard hang if DSC is disabled
  drm/amd/display: Drop FPU flags from dcn32_clk_mgr
  drm/amd/display: Move populate phaton function to dml
  drm/amd/display: Move predict pipe to dml fpu folder
  drm/amd/display: Move insert entry table to the FPU code
  drm/amd/display: Move phanton stream to FPU code
  drm/amd/display: Move SubVP functions to dcn32_fpu
  drm/amd/display: Move wm and dlg calculation to FPU code
  drm/amd/display: Move dlg params calculation
  drm/amd/display: Move ntuple to insert entry
  drm/amd/display: Move bounding box to FPU folder
  drm/amd/display: Drop FPU flags from dcn32 Makefile
  drm/amd/display: Create dcn321_fpu file
  drm/amd/display: Drop FPU code from dcn321 resource

Taimur Hassan (2):
  drm/amd/display: Update de-tile override to anticipate pipe splitting
  drm/amd/display: Loop through all pipes for DET allocation

Vladimir Stempen (1):
  drm/amd/display: Disable GPUVM in IP resource configuration

Wayne Lin (5):
  drm/amd/display: Support vertical interrupt 0 for all dcn ASIC
  drm/amd/display: Expose function reset_cur_dp_mst_topology
  drm/amd/display: fix trigger_hotplug to support mst case
  drm/amd/display: Add is_mst_connector debugfs entry
  drm/amd/display: Add tags for indicating mst progress status

Wenjing Liu (1):
  drm/amd/display: remove number of DSC slices override in DML

 .../gpu/drm/amd/display/amdgpu_dm/Makefile    |    8 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2557 +++--------------
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   20 +
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    |  463 +++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.h    |   51 +
 .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c |  114 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   18 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |   13 +
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 1637 +++++++++++
 .../amd/display/amdgpu_dm/amdgpu_dm_plane.h   |   73 +
 .../gpu/drm/amd/display/dc/clk_mgr/Makefile   |   25 -
 .../display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c  |   81 +-
 drivers/gpu/drm/amd/display/dc/core/dc_link.c |    2 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |    3 +-
 drivers/gpu/drm/amd/display/dc/dc_link.h      |    3 +
 drivers/gpu/drm/amd/display/dc/dcn32/Makefile |   28 -
 .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.c |   40 +-
 .../gpu/drm/amd/display/dc/dcn32/dcn32_hubp.h |    3 +
 .../drm/amd/display/dc/dcn32/dcn32_resource.c | 2039 +------------
 .../drm/amd/display/dc/dcn32/dcn32_resource.h |   15 +-
 .../display/dc/dcn32/dcn32_resource_helpers.c |  130 +-
 .../gpu/drm/amd/display/dc/dcn321/Makefile    |   25 -
 .../amd/display/dc/dcn321/dcn321_resource.c   |  649 +----
 .../amd/display/dc/dcn321/dcn321_resource.h   |    3 +
 drivers/gpu/drm/amd/display/dc/dml/Makefile   |    4 +
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  | 2244 +++++++++++++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.h  |   74 +
 .../dc/dml/dcn32/display_mode_vba_32.c        |   64 +-
 .../dc/dml/dcn32/display_mode_vba_util_32.c   |   70 +-
 .../dc/dml/dcn32/display_mode_vba_util_32.h   |   10 +-
 .../amd/display/dc/dml/dcn321/dcn321_fpu.c    |  684 +++++
 .../amd/display/dc/dml/dcn321/dcn321_fpu.h    |   38 +
 .../amd/display/dc/dml/display_mode_structs.h |    1 +
 .../drm/amd/display/dc/dml/display_mode_vba.c |    2 +
 .../display/dc/irq/dcn30/irq_service_dcn30.c  |   14 +-
 .../dc/irq/dcn303/irq_service_dcn303.c        |   19 +
 36 files changed, 6035 insertions(+), 5189 deletions(-)  create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.h
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
 create mode 100644 drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.h

--
2.37.0

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 08/31] drm/amd/display: Create a file dedicated to planes
  2022-07-15 18:16 ` [PATCH 08/31] drm/amd/display: Create a file dedicated to planes Rodrigo Siqueira
@ 2022-07-18 14:29   ` Alex Deucher
  2022-07-18 14:55     ` Rodrigo Siqueira
  0 siblings, 1 reply; 36+ messages in thread
From: Alex Deucher @ 2022-07-18 14:29 UTC (permalink / raw)
  To: Rodrigo Siqueira
  Cc: Stylon Wang, Alan Liu, Leo (Sunpeng) Li, Bhawanpreet Lakha,
	Qingqing Zhuo, Roman Li, amd-gfx list, Solomon Chiu,
	Aurabindo Pillai, Wayne Lin, Wentland, Harry, Gutierrez, Agustin,
	Kotarac, Pavle

On Sat, Jul 16, 2022 at 10:38 AM Rodrigo Siqueira
<Rodrigo.Siqueira@amd.com> wrote:
>
> [Why]
> The amdgpu_dm file contains most of the code that works as an interface
> between DRM API and DC. As a result, this file becomes very large since
> it comprises multiple abstractions such as plane manipulation.
>
> [How]
> This commit extracts the plane code to its specific file named
> amdgpu_dm_plane. This change does not change anything inside the
> functions; the only exception is converting some static functions to a
> global function.
>
> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
> Acked-by: Alan Liu <HaoPing.Liu@amd.com>
> Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
> ---
>  .../gpu/drm/amd/display/amdgpu_dm/Makefile    |    7 +-
>  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2135 +++--------------
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 1637 +++++++++++++
>  .../amd/display/amdgpu_dm/amdgpu_dm_plane.h   |   73 +
>  4 files changed, 2057 insertions(+), 1795 deletions(-)
>  create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>  create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> index 718e123a3230..ec559ea902a3 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
> @@ -25,7 +25,12 @@
>
>
>
> -AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o
> +AMDGPUDM = \
> +       amdgpu_dm.o \
> +       amdgpu_dm_plane.o \
> +       amdgpu_dm_irq.o \
> +       amdgpu_dm_mst_types.o \
> +       amdgpu_dm_color.o
>
>  ifdef CONFIG_DRM_AMD_DC_DCN
>  AMDGPUDM += dc_fpu.o
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> index dae998e014b0..ceac70e93ece 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
> @@ -46,6 +46,7 @@
>  #include "amdgpu_ucode.h"
>  #include "atom.h"
>  #include "amdgpu_dm.h"
> +#include "amdgpu_dm_plane.h"
>  #ifdef CONFIG_DRM_AMD_DC_HDCP
>  #include "amdgpu_dm_hdcp.h"
>  #include <drm/drm_hdcp.h>
> @@ -203,10 +204,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev);
>  /* 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_plane_init(struct amdgpu_display_manager *dm,
> -                               struct drm_plane *plane,
> -                               unsigned long possible_crtcs,
> -                               const struct dc_plane_cap *plane_cap);
>  static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
>                                struct drm_plane *plane,
>                                uint32_t link_index);
> @@ -225,12 +222,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
>  static int amdgpu_dm_atomic_check(struct drm_device *dev,
>                                   struct drm_atomic_state *state);
>
> -static void handle_cursor_update(struct drm_plane *plane,
> -                                struct drm_plane_state *old_plane_state);
> -
> -static const struct drm_format_info *
> -amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
> -
>  static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector);
>  static void handle_hpd_rx_irq(void *param);
>
> @@ -4315,11 +4306,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
>         case IP_VERSION(3, 0, 0):
>         case IP_VERSION(3, 1, 2):
>         case IP_VERSION(3, 1, 3):
> -       case IP_VERSION(3, 1, 4):
>         case IP_VERSION(3, 1, 5):
>         case IP_VERSION(3, 1, 6):
>         case IP_VERSION(3, 2, 0):
>         case IP_VERSION(3, 2, 1):
> +       case IP_VERSION(3, 1, 4):
>         case IP_VERSION(2, 1, 0):

This hunk should probably be dropped?  It's unrelated to the patch and
makes the ordering incorrect.

Alex

>                 if (register_outbox_irq_handlers(dm->adev)) {
>                         DRM_ERROR("DM: Failed to initialize IRQ\n");
> @@ -4707,1104 +4698,222 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
>         .destroy = amdgpu_dm_encoder_destroy,
>  };
>
> -
> -static void get_min_max_dc_plane_scaling(struct drm_device *dev,
> -                                        struct drm_framebuffer *fb,
> -                                        int *min_downscale, int *max_upscale)
> -{
> -       struct amdgpu_device *adev = drm_to_adev(dev);
> -       struct dc *dc = adev->dm.dc;
> -       /* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
> -       struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
> -
> -       switch (fb->format->format) {
> -       case DRM_FORMAT_P010:
> -       case DRM_FORMAT_NV12:
> -       case DRM_FORMAT_NV21:
> -               *max_upscale = plane_cap->max_upscale_factor.nv12;
> -               *min_downscale = plane_cap->max_downscale_factor.nv12;
> -               break;
> -
> -       case DRM_FORMAT_XRGB16161616F:
> -       case DRM_FORMAT_ARGB16161616F:
> -       case DRM_FORMAT_XBGR16161616F:
> -       case DRM_FORMAT_ABGR16161616F:
> -               *max_upscale = plane_cap->max_upscale_factor.fp16;
> -               *min_downscale = plane_cap->max_downscale_factor.fp16;
> -               break;
> -
> -       default:
> -               *max_upscale = plane_cap->max_upscale_factor.argb8888;
> -               *min_downscale = plane_cap->max_downscale_factor.argb8888;
> -               break;
> -       }
> -
> -       /*
> -        * A factor of 1 in the plane_cap means to not allow scaling, ie. use a
> -        * scaling factor of 1.0 == 1000 units.
> -        */
> -       if (*max_upscale == 1)
> -               *max_upscale = 1000;
> -
> -       if (*min_downscale == 1)
> -               *min_downscale = 1000;
> -}
> -
> -
> -static int fill_dc_scaling_info(struct amdgpu_device *adev,
> -                               const struct drm_plane_state *state,
> -                               struct dc_scaling_info *scaling_info)
> +static int
> +fill_plane_color_attributes(const struct drm_plane_state *plane_state,
> +                           const enum surface_pixel_format format,
> +                           enum dc_color_space *color_space)
>  {
> -       int scale_w, scale_h, min_downscale, max_upscale;
> -
> -       memset(scaling_info, 0, sizeof(*scaling_info));
> -
> -       /* Source is fixed 16.16 but we ignore mantissa for now... */
> -       scaling_info->src_rect.x = state->src_x >> 16;
> -       scaling_info->src_rect.y = state->src_y >> 16;
> +       bool full_range;
>
> -       /*
> -        * For reasons we don't (yet) fully understand a non-zero
> -        * src_y coordinate into an NV12 buffer can cause a
> -        * system hang on DCN1x.
> -        * To avoid hangs (and maybe be overly cautious)
> -        * let's reject both non-zero src_x and src_y.
> -        *
> -        * We currently know of only one use-case to reproduce a
> -        * scenario with non-zero src_x and src_y for NV12, which
> -        * is to gesture the YouTube Android app into full screen
> -        * on ChromeOS.
> -        */
> -       if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) ||
> -           (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) &&
> -           (state->fb && state->fb->format->format == DRM_FORMAT_NV12 &&
> -           (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0)))
> -               return -EINVAL;
> +       *color_space = COLOR_SPACE_SRGB;
>
> -       scaling_info->src_rect.width = state->src_w >> 16;
> -       if (scaling_info->src_rect.width == 0)
> -               return -EINVAL;
> +       /* DRM color properties only affect non-RGB formats. */
> +       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
> +               return 0;
>
> -       scaling_info->src_rect.height = state->src_h >> 16;
> -       if (scaling_info->src_rect.height == 0)
> -               return -EINVAL;
> +       full_range = (plane_state->color_range == DRM_COLOR_YCBCR_FULL_RANGE);
>
> -       scaling_info->dst_rect.x = state->crtc_x;
> -       scaling_info->dst_rect.y = state->crtc_y;
> +       switch (plane_state->color_encoding) {
> +       case DRM_COLOR_YCBCR_BT601:
> +               if (full_range)
> +                       *color_space = COLOR_SPACE_YCBCR601;
> +               else
> +                       *color_space = COLOR_SPACE_YCBCR601_LIMITED;
> +               break;
>
> -       if (state->crtc_w == 0)
> -               return -EINVAL;
> +       case DRM_COLOR_YCBCR_BT709:
> +               if (full_range)
> +                       *color_space = COLOR_SPACE_YCBCR709;
> +               else
> +                       *color_space = COLOR_SPACE_YCBCR709_LIMITED;
> +               break;
>
> -       scaling_info->dst_rect.width = state->crtc_w;
> +       case DRM_COLOR_YCBCR_BT2020:
> +               if (full_range)
> +                       *color_space = COLOR_SPACE_2020_YCBCR;
> +               else
> +                       return -EINVAL;
> +               break;
>
> -       if (state->crtc_h == 0)
> +       default:
>                 return -EINVAL;
> -
> -       scaling_info->dst_rect.height = state->crtc_h;
> -
> -       /* DRM doesn't specify clipping on destination output. */
> -       scaling_info->clip_rect = scaling_info->dst_rect;
> -
> -       /* Validate scaling per-format with DC plane caps */
> -       if (state->plane && state->plane->dev && state->fb) {
> -               get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
> -                                            &min_downscale, &max_upscale);
> -       } else {
> -               min_downscale = 250;
> -               max_upscale = 16000;
>         }
>
> -       scale_w = scaling_info->dst_rect.width * 1000 /
> -                 scaling_info->src_rect.width;
> -
> -       if (scale_w < min_downscale || scale_w > max_upscale)
> -               return -EINVAL;
> -
> -       scale_h = scaling_info->dst_rect.height * 1000 /
> -                 scaling_info->src_rect.height;
> -
> -       if (scale_h < min_downscale || scale_h > max_upscale)
> -               return -EINVAL;
> -
> -       /*
> -        * The "scaling_quality" can be ignored for now, quality = 0 has DC
> -        * assume reasonable defaults based on the format.
> -        */
> -
>         return 0;
>  }
>
> -static void
> -fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info,
> -                                uint64_t tiling_flags)
> -{
> -       /* Fill GFX8 params */
> -       if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
> -               unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
> -
> -               bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
> -               bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
> -               mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
> -               tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
> -               num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
> -
> -               /* XXX fix me for VI */
> -               tiling_info->gfx8.num_banks = num_banks;
> -               tiling_info->gfx8.array_mode =
> -                               DC_ARRAY_2D_TILED_THIN1;
> -               tiling_info->gfx8.tile_split = tile_split;
> -               tiling_info->gfx8.bank_width = bankw;
> -               tiling_info->gfx8.bank_height = bankh;
> -               tiling_info->gfx8.tile_aspect = mtaspect;
> -               tiling_info->gfx8.tile_mode =
> -                               DC_ADDR_SURF_MICRO_TILING_DISPLAY;
> -       } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
> -                       == DC_ARRAY_1D_TILED_THIN1) {
> -               tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
> -       }
> -
> -       tiling_info->gfx8.pipe_config =
> -                       AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
> -}
> -
> -static void
> -fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev,
> -                                 union dc_tiling_info *tiling_info)
> -{
> -       tiling_info->gfx9.num_pipes =
> -               adev->gfx.config.gb_addr_config_fields.num_pipes;
> -       tiling_info->gfx9.num_banks =
> -               adev->gfx.config.gb_addr_config_fields.num_banks;
> -       tiling_info->gfx9.pipe_interleave =
> -               adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
> -       tiling_info->gfx9.num_shader_engines =
> -               adev->gfx.config.gb_addr_config_fields.num_se;
> -       tiling_info->gfx9.max_compressed_frags =
> -               adev->gfx.config.gb_addr_config_fields.max_compress_frags;
> -       tiling_info->gfx9.num_rb_per_se =
> -               adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
> -       tiling_info->gfx9.shaderEnable = 1;
> -       if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
> -               tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;
> -}
> -
>  static int
> -validate_dcc(struct amdgpu_device *adev,
> -            const enum surface_pixel_format format,
> -            const enum dc_rotation_angle rotation,
> -            const union dc_tiling_info *tiling_info,
> -            const struct dc_plane_dcc_param *dcc,
> -            const struct dc_plane_address *address,
> -            const struct plane_size *plane_size)
> +fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
> +                           const struct drm_plane_state *plane_state,
> +                           const uint64_t tiling_flags,
> +                           struct dc_plane_info *plane_info,
> +                           struct dc_plane_address *address,
> +                           bool tmz_surface,
> +                           bool force_disable_dcc)
>  {
> -       struct dc *dc = adev->dm.dc;
> -       struct dc_dcc_surface_param input;
> -       struct dc_surface_dcc_cap output;
> -
> -       memset(&input, 0, sizeof(input));
> -       memset(&output, 0, sizeof(output));
> +       const struct drm_framebuffer *fb = plane_state->fb;
> +       const struct amdgpu_framebuffer *afb =
> +               to_amdgpu_framebuffer(plane_state->fb);
> +       int ret;
>
> -       if (!dcc->enable)
> -               return 0;
> +       memset(plane_info, 0, sizeof(*plane_info));
>
> -       if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
> -           !dc->cap_funcs.get_dcc_compression_cap)
> +       switch (fb->format->format) {
> +       case DRM_FORMAT_C8:
> +               plane_info->format =
> +                       SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
> +               break;
> +       case DRM_FORMAT_RGB565:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
> +               break;
> +       case DRM_FORMAT_XRGB8888:
> +       case DRM_FORMAT_ARGB8888:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
> +               break;
> +       case DRM_FORMAT_XRGB2101010:
> +       case DRM_FORMAT_ARGB2101010:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
> +               break;
> +       case DRM_FORMAT_XBGR2101010:
> +       case DRM_FORMAT_ABGR2101010:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
> +               break;
> +       case DRM_FORMAT_XBGR8888:
> +       case DRM_FORMAT_ABGR8888:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR8888;
> +               break;
> +       case DRM_FORMAT_NV21:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
> +               break;
> +       case DRM_FORMAT_NV12:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
> +               break;
> +       case DRM_FORMAT_P010:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
> +               break;
> +       case DRM_FORMAT_XRGB16161616F:
> +       case DRM_FORMAT_ARGB16161616F:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
> +               break;
> +       case DRM_FORMAT_XBGR16161616F:
> +       case DRM_FORMAT_ABGR16161616F:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
> +               break;
> +       case DRM_FORMAT_XRGB16161616:
> +       case DRM_FORMAT_ARGB16161616:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616;
> +               break;
> +       case DRM_FORMAT_XBGR16161616:
> +       case DRM_FORMAT_ABGR16161616:
> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616;
> +               break;
> +       default:
> +               DRM_ERROR(
> +                       "Unsupported screen format %p4cc\n",
> +                       &fb->format->format);
>                 return -EINVAL;
> +       }
>
> -       input.format = format;
> -       input.surface_size.width = plane_size->surface_size.width;
> -       input.surface_size.height = plane_size->surface_size.height;
> -       input.swizzle_mode = tiling_info->gfx9.swizzle;
> -
> -       if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180)
> -               input.scan = SCAN_DIRECTION_HORIZONTAL;
> -       else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270)
> -               input.scan = SCAN_DIRECTION_VERTICAL;
> +       switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
> +       case DRM_MODE_ROTATE_0:
> +               plane_info->rotation = ROTATION_ANGLE_0;
> +               break;
> +       case DRM_MODE_ROTATE_90:
> +               plane_info->rotation = ROTATION_ANGLE_90;
> +               break;
> +       case DRM_MODE_ROTATE_180:
> +               plane_info->rotation = ROTATION_ANGLE_180;
> +               break;
> +       case DRM_MODE_ROTATE_270:
> +               plane_info->rotation = ROTATION_ANGLE_270;
> +               break;
> +       default:
> +               plane_info->rotation = ROTATION_ANGLE_0;
> +               break;
> +       }
>
> -       if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
> -               return -EINVAL;
>
> -       if (!output.capable)
> -               return -EINVAL;
> +       plane_info->visible = true;
> +       plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE;
>
> -       if (dcc->independent_64b_blks == 0 &&
> -           output.grph.rgb.independent_64b_blks != 0)
> -               return -EINVAL;
> +       plane_info->layer_index = 0;
>
> -       return 0;
> -}
> +       ret = fill_plane_color_attributes(plane_state, plane_info->format,
> +                                         &plane_info->color_space);
> +       if (ret)
> +               return ret;
>
> -static bool
> -modifier_has_dcc(uint64_t modifier)
> -{
> -       return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
> -}
> +       ret = fill_plane_buffer_attributes(adev, afb, plane_info->format,
> +                                          plane_info->rotation, tiling_flags,
> +                                          &plane_info->tiling_info,
> +                                          &plane_info->plane_size,
> +                                          &plane_info->dcc, address,
> +                                          tmz_surface, force_disable_dcc);
> +       if (ret)
> +               return ret;
>
> -static unsigned
> -modifier_gfx9_swizzle_mode(uint64_t modifier)
> -{
> -       if (modifier == DRM_FORMAT_MOD_LINEAR)
> -               return 0;
> +       fill_blending_from_plane_state(
> +               plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
> +               &plane_info->global_alpha, &plane_info->global_alpha_value);
>
> -       return AMD_FMT_MOD_GET(TILE, modifier);
> +       return 0;
>  }
>
> -static const struct drm_format_info *
> -amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> +static int fill_dc_plane_attributes(struct amdgpu_device *adev,
> +                                   struct dc_plane_state *dc_plane_state,
> +                                   struct drm_plane_state *plane_state,
> +                                   struct drm_crtc_state *crtc_state)
>  {
> -       return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]);
> -}
> +       struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
> +       struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb;
> +       struct dc_scaling_info scaling_info;
> +       struct dc_plane_info plane_info;
> +       int ret;
> +       bool force_disable_dcc = false;
>
> -static void
> -fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev,
> -                                   union dc_tiling_info *tiling_info,
> -                                   uint64_t modifier)
> -{
> -       unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
> -       unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
> -       unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier);
> -       unsigned int pipes_log2;
> +       ret = fill_dc_scaling_info(adev, plane_state, &scaling_info);
> +       if (ret)
> +               return ret;
>
> -       pipes_log2 = min(5u, mod_pipe_xor_bits);
> +       dc_plane_state->src_rect = scaling_info.src_rect;
> +       dc_plane_state->dst_rect = scaling_info.dst_rect;
> +       dc_plane_state->clip_rect = scaling_info.clip_rect;
> +       dc_plane_state->scaling_quality = scaling_info.scaling_quality;
>
> -       fill_gfx9_tiling_info_from_device(adev, tiling_info);
> +       force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
> +       ret = fill_dc_plane_info_and_addr(adev, plane_state,
> +                                         afb->tiling_flags,
> +                                         &plane_info,
> +                                         &dc_plane_state->address,
> +                                         afb->tmz_surface,
> +                                         force_disable_dcc);
> +       if (ret)
> +               return ret;
>
> -       if (!IS_AMD_FMT_MOD(modifier))
> -               return;
> +       dc_plane_state->format = plane_info.format;
> +       dc_plane_state->color_space = plane_info.color_space;
> +       dc_plane_state->format = plane_info.format;
> +       dc_plane_state->plane_size = plane_info.plane_size;
> +       dc_plane_state->rotation = plane_info.rotation;
> +       dc_plane_state->horizontal_mirror = plane_info.horizontal_mirror;
> +       dc_plane_state->stereo_format = plane_info.stereo_format;
> +       dc_plane_state->tiling_info = plane_info.tiling_info;
> +       dc_plane_state->visible = plane_info.visible;
> +       dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
> +       dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
> +       dc_plane_state->global_alpha = plane_info.global_alpha;
> +       dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
> +       dc_plane_state->dcc = plane_info.dcc;
> +       dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
> +       dc_plane_state->flip_int_enabled = true;
>
> -       tiling_info->gfx9.num_pipes = 1u << pipes_log2;
> -       tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2);
> -
> -       if (adev->family >= AMDGPU_FAMILY_NV) {
> -               tiling_info->gfx9.num_pkrs = 1u << pkrs_log2;
> -       } else {
> -               tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits;
> -
> -               /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */
> -       }
> -}
> -
> -enum dm_micro_swizzle {
> -       MICRO_SWIZZLE_Z = 0,
> -       MICRO_SWIZZLE_S = 1,
> -       MICRO_SWIZZLE_D = 2,
> -       MICRO_SWIZZLE_R = 3
> -};
> -
> -static bool dm_plane_format_mod_supported(struct drm_plane *plane,
> -                                         uint32_t format,
> -                                         uint64_t modifier)
> -{
> -       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> -       const struct drm_format_info *info = drm_format_info(format);
> -       int i;
> -
> -       enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3;
> -
> -       if (!info)
> -               return false;
> -
> -       /*
> -        * We always have to allow these modifiers:
> -        * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
> -        * 2. Not passing any modifiers is the same as explicitly passing INVALID.
> -        */
> -       if (modifier == DRM_FORMAT_MOD_LINEAR ||
> -           modifier == DRM_FORMAT_MOD_INVALID) {
> -               return true;
> -       }
> -
> -       /* Check that the modifier is on the list of the plane's supported modifiers. */
> -       for (i = 0; i < plane->modifier_count; i++) {
> -               if (modifier == plane->modifiers[i])
> -                       break;
> -       }
> -       if (i == plane->modifier_count)
> -               return false;
> -
> -       /*
> -        * For D swizzle the canonical modifier depends on the bpp, so check
> -        * it here.
> -        */
> -       if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 &&
> -           adev->family >= AMDGPU_FAMILY_NV) {
> -               if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4)
> -                       return false;
> -       }
> -
> -       if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D &&
> -           info->cpp[0] < 8)
> -               return false;
> -
> -       if (modifier_has_dcc(modifier)) {
> -               /* Per radeonsi comments 16/64 bpp are more complicated. */
> -               if (info->cpp[0] != 4)
> -                       return false;
> -               /* We support multi-planar formats, but not when combined with
> -                * additional DCC metadata planes. */
> -               if (info->num_planes > 1)
> -                       return false;
> -       }
> -
> -       return true;
> -}
> -
> -static void
> -add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod)
> -{
> -       if (!*mods)
> -               return;
> -
> -       if (*cap - *size < 1) {
> -               uint64_t new_cap = *cap * 2;
> -               uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL);
> -
> -               if (!new_mods) {
> -                       kfree(*mods);
> -                       *mods = NULL;
> -                       return;
> -               }
> -
> -               memcpy(new_mods, *mods, sizeof(uint64_t) * *size);
> -               kfree(*mods);
> -               *mods = new_mods;
> -               *cap = new_cap;
> -       }
> -
> -       (*mods)[*size] = mod;
> -       *size += 1;
> -}
> -
> -static void
> -add_gfx9_modifiers(const struct amdgpu_device *adev,
> -                  uint64_t **mods, uint64_t *size, uint64_t *capacity)
> -{
> -       int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
> -       int pipe_xor_bits = min(8, pipes +
> -                               ilog2(adev->gfx.config.gb_addr_config_fields.num_se));
> -       int bank_xor_bits = min(8 - pipe_xor_bits,
> -                               ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));
> -       int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +
> -                ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);
> -
> -
> -       if (adev->family == AMDGPU_FAMILY_RV) {
> -               /* Raven2 and later */
> -               bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81;
> -
> -               /*
> -                * No _D DCC swizzles yet because we only allow 32bpp, which
> -                * doesn't support _D on DCN
> -                */
> -
> -               if (has_constant_encode) {
> -                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> -                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> -                                   AMD_FMT_MOD_SET(DCC, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> -                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));
> -               }
> -
> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> -                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> -                           AMD_FMT_MOD_SET(DCC, 1) |
> -                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> -                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0));
> -
> -               if (has_constant_encode) {
> -                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> -                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> -                                   AMD_FMT_MOD_SET(DCC, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> -
> -                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                                   AMD_FMT_MOD_SET(RB, rb) |
> -                                   AMD_FMT_MOD_SET(PIPE, pipes));
> -               }
> -
> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> -                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> -                           AMD_FMT_MOD_SET(DCC, 1) |
> -                           AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> -                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> -                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) |
> -                           AMD_FMT_MOD_SET(RB, rb) |
> -                           AMD_FMT_MOD_SET(PIPE, pipes));
> -       }
> -
> -       /*
> -        * Only supported for 64bpp on Raven, will be filtered on format in
> -        * dm_plane_format_mod_supported.
> -        */
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
> -
> -       if (adev->family == AMDGPU_FAMILY_RV) {
> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> -                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
> -       }
> -
> -       /*
> -        * Only supported for 64bpp on Raven, will be filtered on format in
> -        * dm_plane_format_mod_supported.
> -        */
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> -
> -       if (adev->family == AMDGPU_FAMILY_RV) {
> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> -       }
> -}
> -
> -static void
> -add_gfx10_1_modifiers(const struct amdgpu_device *adev,
> -                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
> -{
> -       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(DCC, 1) |
> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(DCC, 1) |
> -                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
> -
> -
> -       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> -}
> -
> -static void
> -add_gfx10_3_modifiers(const struct amdgpu_device *adev,
> -                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
> -{
> -       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
> -       int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs);
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> -                   AMD_FMT_MOD_SET(DCC, 1) |
> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> -                   AMD_FMT_MOD_SET(DCC, 1) |
> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> -                   AMD_FMT_MOD_SET(DCC, 1) |
> -                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> -                   AMD_FMT_MOD_SET(DCC, 1) |
> -                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(PACKERS, pkrs));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                   AMD_FMT_MOD_SET(PACKERS, pkrs));
> -
> -       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> -}
> -
> -static void
> -add_gfx11_modifiers(struct amdgpu_device *adev,
> -                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
> -{
> -       int num_pipes = 0;
> -       int pipe_xor_bits = 0;
> -       int num_pkrs = 0;
> -       int pkrs = 0;
> -       u32 gb_addr_config;
> -       u8 i = 0;
> -       unsigned swizzle_r_x;
> -       uint64_t modifier_r_x;
> -       uint64_t modifier_dcc_best;
> -       uint64_t modifier_dcc_4k;
> -
> -       /* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from
> -        * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes} */
> -       gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG);
> -       ASSERT(gb_addr_config != 0);
> -
> -       num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS);
> -       pkrs = ilog2(num_pkrs);
> -       num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES);
> -       pipe_xor_bits = ilog2(num_pipes);
> -
> -       for (i = 0; i < 2; i++) {
> -               /* Insert the best one first. */
> -               /* R_X swizzle modes are the best for rendering and DCC requires them. */
> -               if (num_pipes > 16)
> -                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : AMD_FMT_MOD_TILE_GFX9_64K_R_X;
> -               else
> -                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX9_64K_R_X : AMD_FMT_MOD_TILE_GFX11_256K_R_X;
> -
> -               modifier_r_x = AMD_FMT_MOD |
> -                              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
> -                              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> -                              AMD_FMT_MOD_SET(TILE, swizzle_r_x) |
> -                              AMD_FMT_MOD_SET(PACKERS, pkrs);
> -
> -               /* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */
> -               modifier_dcc_best = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) |
> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> -                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B);
> -
> -               /* DCC settings for 4K and greater resolutions. (required by display hw) */
> -               modifier_dcc_4k = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
> -                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> -                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> -                                 AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B);
> -
> -               add_modifier(mods, size, capacity, modifier_dcc_best);
> -               add_modifier(mods, size, capacity, modifier_dcc_4k);
> -
> -               add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1));
> -               add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1));
> -
> -               add_modifier(mods, size, capacity, modifier_r_x);
> -       }
> -
> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> -             AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
> -                        AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D));
> -}
> -
> -static int
> -get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods)
> -{
> -       uint64_t size = 0, capacity = 128;
> -       *mods = NULL;
> -
> -       /* We have not hooked up any pre-GFX9 modifiers. */
> -       if (adev->family < AMDGPU_FAMILY_AI)
> -               return 0;
> -
> -       *mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL);
> -
> -       if (plane_type == DRM_PLANE_TYPE_CURSOR) {
> -               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
> -               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
> -               return *mods ? 0 : -ENOMEM;
> -       }
> -
> -       switch (adev->family) {
> -       case AMDGPU_FAMILY_AI:
> -       case AMDGPU_FAMILY_RV:
> -               add_gfx9_modifiers(adev, mods, &size, &capacity);
> -               break;
> -       case AMDGPU_FAMILY_NV:
> -       case AMDGPU_FAMILY_VGH:
> -       case AMDGPU_FAMILY_YC:
> -       case AMDGPU_FAMILY_GC_10_3_6:
> -       case AMDGPU_FAMILY_GC_10_3_7:
> -               if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
> -                       add_gfx10_3_modifiers(adev, mods, &size, &capacity);
> -               else
> -                       add_gfx10_1_modifiers(adev, mods, &size, &capacity);
> -               break;
> -       case AMDGPU_FAMILY_GC_11_0_0:
> -       case AMDGPU_FAMILY_GC_11_0_2:
> -               add_gfx11_modifiers(adev, mods, &size, &capacity);
> -               break;
> -       }
> -
> -       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
> -
> -       /* INVALID marks the end of the list. */
> -       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
> -
> -       if (!*mods)
> -               return -ENOMEM;
> -
> -       return 0;
> -}
> -
> -static int
> -fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
> -                                         const struct amdgpu_framebuffer *afb,
> -                                         const enum surface_pixel_format format,
> -                                         const enum dc_rotation_angle rotation,
> -                                         const struct plane_size *plane_size,
> -                                         union dc_tiling_info *tiling_info,
> -                                         struct dc_plane_dcc_param *dcc,
> -                                         struct dc_plane_address *address,
> -                                         const bool force_disable_dcc)
> -{
> -       const uint64_t modifier = afb->base.modifier;
> -       int ret = 0;
> -
> -       fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
> -       tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
> -
> -       if (modifier_has_dcc(modifier) && !force_disable_dcc) {
> -               uint64_t dcc_address = afb->address + afb->base.offsets[1];
> -               bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
> -               bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
> -
> -               dcc->enable = 1;
> -               dcc->meta_pitch = afb->base.pitches[1];
> -               dcc->independent_64b_blks = independent_64b_blks;
> -               if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
> -                       if (independent_64b_blks && independent_128b_blks)
> -                               dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl;
> -                       else if (independent_128b_blks)
> -                               dcc->dcc_ind_blk = hubp_ind_block_128b;
> -                       else if (independent_64b_blks && !independent_128b_blks)
> -                               dcc->dcc_ind_blk = hubp_ind_block_64b;
> -                       else
> -                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
> -               } else {
> -                       if (independent_64b_blks)
> -                               dcc->dcc_ind_blk = hubp_ind_block_64b;
> -                       else
> -                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
> -               }
> -
> -               address->grph.meta_addr.low_part = lower_32_bits(dcc_address);
> -               address->grph.meta_addr.high_part = upper_32_bits(dcc_address);
> -       }
> -
> -       ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
> -       if (ret)
> -               drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
> -
> -       return ret;
> -}
> -
> -static int
> -fill_plane_buffer_attributes(struct amdgpu_device *adev,
> -                            const struct amdgpu_framebuffer *afb,
> -                            const enum surface_pixel_format format,
> -                            const enum dc_rotation_angle rotation,
> -                            const uint64_t tiling_flags,
> -                            union dc_tiling_info *tiling_info,
> -                            struct plane_size *plane_size,
> -                            struct dc_plane_dcc_param *dcc,
> -                            struct dc_plane_address *address,
> -                            bool tmz_surface,
> -                            bool force_disable_dcc)
> -{
> -       const struct drm_framebuffer *fb = &afb->base;
> -       int ret;
> -
> -       memset(tiling_info, 0, sizeof(*tiling_info));
> -       memset(plane_size, 0, sizeof(*plane_size));
> -       memset(dcc, 0, sizeof(*dcc));
> -       memset(address, 0, sizeof(*address));
> -
> -       address->tmz_surface = tmz_surface;
> -
> -       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
> -               uint64_t addr = afb->address + fb->offsets[0];
> -
> -               plane_size->surface_size.x = 0;
> -               plane_size->surface_size.y = 0;
> -               plane_size->surface_size.width = fb->width;
> -               plane_size->surface_size.height = fb->height;
> -               plane_size->surface_pitch =
> -                       fb->pitches[0] / fb->format->cpp[0];
> -
> -               address->type = PLN_ADDR_TYPE_GRAPHICS;
> -               address->grph.addr.low_part = lower_32_bits(addr);
> -               address->grph.addr.high_part = upper_32_bits(addr);
> -       } else if (format < SURFACE_PIXEL_FORMAT_INVALID) {
> -               uint64_t luma_addr = afb->address + fb->offsets[0];
> -               uint64_t chroma_addr = afb->address + fb->offsets[1];
> -
> -               plane_size->surface_size.x = 0;
> -               plane_size->surface_size.y = 0;
> -               plane_size->surface_size.width = fb->width;
> -               plane_size->surface_size.height = fb->height;
> -               plane_size->surface_pitch =
> -                       fb->pitches[0] / fb->format->cpp[0];
> -
> -               plane_size->chroma_size.x = 0;
> -               plane_size->chroma_size.y = 0;
> -               /* TODO: set these based on surface format */
> -               plane_size->chroma_size.width = fb->width / 2;
> -               plane_size->chroma_size.height = fb->height / 2;
> -
> -               plane_size->chroma_pitch =
> -                       fb->pitches[1] / fb->format->cpp[1];
> -
> -               address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
> -               address->video_progressive.luma_addr.low_part =
> -                       lower_32_bits(luma_addr);
> -               address->video_progressive.luma_addr.high_part =
> -                       upper_32_bits(luma_addr);
> -               address->video_progressive.chroma_addr.low_part =
> -                       lower_32_bits(chroma_addr);
> -               address->video_progressive.chroma_addr.high_part =
> -                       upper_32_bits(chroma_addr);
> -       }
> -
> -       if (adev->family >= AMDGPU_FAMILY_AI) {
> -               ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format,
> -                                                               rotation, plane_size,
> -                                                               tiling_info, dcc,
> -                                                               address,
> -                                                               force_disable_dcc);
> -               if (ret)
> -                       return ret;
> -       } else {
> -               fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags);
> -       }
> -
> -       return 0;
> -}
> -
> -static void
> -fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
> -                              bool *per_pixel_alpha, bool *pre_multiplied_alpha,
> -                              bool *global_alpha, int *global_alpha_value)
> -{
> -       *per_pixel_alpha = false;
> -       *pre_multiplied_alpha = true;
> -       *global_alpha = false;
> -       *global_alpha_value = 0xff;
> -
> -       if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
> -               return;
> -
> -       if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
> -               plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
> -               static const uint32_t alpha_formats[] = {
> -                       DRM_FORMAT_ARGB8888,
> -                       DRM_FORMAT_RGBA8888,
> -                       DRM_FORMAT_ABGR8888,
> -               };
> -               uint32_t format = plane_state->fb->format->format;
> -               unsigned int i;
> -
> -               for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
> -                       if (format == alpha_formats[i]) {
> -                               *per_pixel_alpha = true;
> -                               break;
> -                       }
> -               }
> -
> -               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
> -                       *pre_multiplied_alpha = false;
> -       }
> -
> -       if (plane_state->alpha < 0xffff) {
> -               *global_alpha = true;
> -               *global_alpha_value = plane_state->alpha >> 8;
> -       }
> -}
> -
> -static int
> -fill_plane_color_attributes(const struct drm_plane_state *plane_state,
> -                           const enum surface_pixel_format format,
> -                           enum dc_color_space *color_space)
> -{
> -       bool full_range;
> -
> -       *color_space = COLOR_SPACE_SRGB;
> -
> -       /* DRM color properties only affect non-RGB formats. */
> -       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
> -               return 0;
> -
> -       full_range = (plane_state->color_range == DRM_COLOR_YCBCR_FULL_RANGE);
> -
> -       switch (plane_state->color_encoding) {
> -       case DRM_COLOR_YCBCR_BT601:
> -               if (full_range)
> -                       *color_space = COLOR_SPACE_YCBCR601;
> -               else
> -                       *color_space = COLOR_SPACE_YCBCR601_LIMITED;
> -               break;
> -
> -       case DRM_COLOR_YCBCR_BT709:
> -               if (full_range)
> -                       *color_space = COLOR_SPACE_YCBCR709;
> -               else
> -                       *color_space = COLOR_SPACE_YCBCR709_LIMITED;
> -               break;
> -
> -       case DRM_COLOR_YCBCR_BT2020:
> -               if (full_range)
> -                       *color_space = COLOR_SPACE_2020_YCBCR;
> -               else
> -                       return -EINVAL;
> -               break;
> -
> -       default:
> -               return -EINVAL;
> -       }
> -
> -       return 0;
> -}
> -
> -static int
> -fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
> -                           const struct drm_plane_state *plane_state,
> -                           const uint64_t tiling_flags,
> -                           struct dc_plane_info *plane_info,
> -                           struct dc_plane_address *address,
> -                           bool tmz_surface,
> -                           bool force_disable_dcc)
> -{
> -       const struct drm_framebuffer *fb = plane_state->fb;
> -       const struct amdgpu_framebuffer *afb =
> -               to_amdgpu_framebuffer(plane_state->fb);
> -       int ret;
> -
> -       memset(plane_info, 0, sizeof(*plane_info));
> -
> -       switch (fb->format->format) {
> -       case DRM_FORMAT_C8:
> -               plane_info->format =
> -                       SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
> -               break;
> -       case DRM_FORMAT_RGB565:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
> -               break;
> -       case DRM_FORMAT_XRGB8888:
> -       case DRM_FORMAT_ARGB8888:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
> -               break;
> -       case DRM_FORMAT_XRGB2101010:
> -       case DRM_FORMAT_ARGB2101010:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
> -               break;
> -       case DRM_FORMAT_XBGR2101010:
> -       case DRM_FORMAT_ABGR2101010:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
> -               break;
> -       case DRM_FORMAT_XBGR8888:
> -       case DRM_FORMAT_ABGR8888:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR8888;
> -               break;
> -       case DRM_FORMAT_NV21:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
> -               break;
> -       case DRM_FORMAT_NV12:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
> -               break;
> -       case DRM_FORMAT_P010:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
> -               break;
> -       case DRM_FORMAT_XRGB16161616F:
> -       case DRM_FORMAT_ARGB16161616F:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
> -               break;
> -       case DRM_FORMAT_XBGR16161616F:
> -       case DRM_FORMAT_ABGR16161616F:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
> -               break;
> -       case DRM_FORMAT_XRGB16161616:
> -       case DRM_FORMAT_ARGB16161616:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616;
> -               break;
> -       case DRM_FORMAT_XBGR16161616:
> -       case DRM_FORMAT_ABGR16161616:
> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616;
> -               break;
> -       default:
> -               DRM_ERROR(
> -                       "Unsupported screen format %p4cc\n",
> -                       &fb->format->format);
> -               return -EINVAL;
> -       }
> -
> -       switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
> -       case DRM_MODE_ROTATE_0:
> -               plane_info->rotation = ROTATION_ANGLE_0;
> -               break;
> -       case DRM_MODE_ROTATE_90:
> -               plane_info->rotation = ROTATION_ANGLE_90;
> -               break;
> -       case DRM_MODE_ROTATE_180:
> -               plane_info->rotation = ROTATION_ANGLE_180;
> -               break;
> -       case DRM_MODE_ROTATE_270:
> -               plane_info->rotation = ROTATION_ANGLE_270;
> -               break;
> -       default:
> -               plane_info->rotation = ROTATION_ANGLE_0;
> -               break;
> -       }
> -
> -       plane_info->visible = true;
> -       plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE;
> -
> -       plane_info->layer_index = 0;
> -
> -       ret = fill_plane_color_attributes(plane_state, plane_info->format,
> -                                         &plane_info->color_space);
> -       if (ret)
> -               return ret;
> -
> -       ret = fill_plane_buffer_attributes(adev, afb, plane_info->format,
> -                                          plane_info->rotation, tiling_flags,
> -                                          &plane_info->tiling_info,
> -                                          &plane_info->plane_size,
> -                                          &plane_info->dcc, address, tmz_surface,
> -                                          force_disable_dcc);
> -       if (ret)
> -               return ret;
> -
> -       fill_blending_from_plane_state(
> -               plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
> -               &plane_info->global_alpha, &plane_info->global_alpha_value);
> -
> -       return 0;
> -}
> -
> -static int fill_dc_plane_attributes(struct amdgpu_device *adev,
> -                                   struct dc_plane_state *dc_plane_state,
> -                                   struct drm_plane_state *plane_state,
> -                                   struct drm_crtc_state *crtc_state)
> -{
> -       struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
> -       struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb;
> -       struct dc_scaling_info scaling_info;
> -       struct dc_plane_info plane_info;
> -       int ret;
> -       bool force_disable_dcc = false;
> -
> -       ret = fill_dc_scaling_info(adev, plane_state, &scaling_info);
> -       if (ret)
> -               return ret;
> -
> -       dc_plane_state->src_rect = scaling_info.src_rect;
> -       dc_plane_state->dst_rect = scaling_info.dst_rect;
> -       dc_plane_state->clip_rect = scaling_info.clip_rect;
> -       dc_plane_state->scaling_quality = scaling_info.scaling_quality;
> -
> -       force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
> -       ret = fill_dc_plane_info_and_addr(adev, plane_state,
> -                                         afb->tiling_flags,
> -                                         &plane_info,
> -                                         &dc_plane_state->address,
> -                                         afb->tmz_surface,
> -                                         force_disable_dcc);
> -       if (ret)
> -               return ret;
> -
> -       dc_plane_state->format = plane_info.format;
> -       dc_plane_state->color_space = plane_info.color_space;
> -       dc_plane_state->format = plane_info.format;
> -       dc_plane_state->plane_size = plane_info.plane_size;
> -       dc_plane_state->rotation = plane_info.rotation;
> -       dc_plane_state->horizontal_mirror = plane_info.horizontal_mirror;
> -       dc_plane_state->stereo_format = plane_info.stereo_format;
> -       dc_plane_state->tiling_info = plane_info.tiling_info;
> -       dc_plane_state->visible = plane_info.visible;
> -       dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
> -       dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
> -       dc_plane_state->global_alpha = plane_info.global_alpha;
> -       dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
> -       dc_plane_state->dcc = plane_info.dcc;
> -       dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
> -       dc_plane_state->flip_int_enabled = true;
> -
> -       /*
> -        * Always set input transfer function, since plane state is refreshed
> -        * every time.
> -        */
> -       ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
> -       if (ret)
> -               return ret;
> +       /*
> +        * Always set input transfer function, since plane state is refreshed
> +        * every time.
> +        */
> +       ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
> +       if (ret)
> +               return ret;
>
>         return 0;
>  }
> @@ -6165,7 +5274,7 @@ static void fill_stream_properties_from_drm_display_mode(
>         timing_out->scan_type = SCANNING_TYPE_NODATA;
>         timing_out->hdmi_vic = 0;
>
> -       if(old_stream) {
> +       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;
> @@ -6387,16 +5496,126 @@ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
>         }
>  }
>
> +/**
> + * 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->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_DEBUG_DRIVER("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_DCN)
>  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)
> +                           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)) {
> +           sink->sink_signal == SIGNAL_TYPE_EDP)) {
>                 if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE ||
>                         sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
>                         dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
> @@ -6406,6 +5625,7 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
>         }
>  }
>
> +
>  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,
> @@ -6464,9 +5684,10 @@ static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector,
>         }
>  }
>
> +
>  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 dc_sink *sink, struct dc_stream_state *stream,
> +                                       struct dsc_dec_dpcd_caps *dsc_caps)
>  {
>         struct drm_connector *drm_connector = &aconnector->base;
>         uint32_t link_bandwidth_kbps;
> @@ -6477,7 +5698,6 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
>
>         link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
>                                                         dc_link_get_link_cap(aconnector->dc_link));
> -
>         if (stream->link && stream->link->local_sink)
>                 max_dsc_target_bpp_limit_override =
>                         stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit;
> @@ -6501,8 +5721,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
>                                                 &stream->timing,
>                                                 &stream->timing.dsc_cfg)) {
>                                 stream->timing.flags.DSC = 1;
> -                               DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from SST RX\n",
> -                                                                __func__, drm_connector->name);
> +                               DRM_DEBUG_DRIVER("%s: [%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);
> @@ -6530,126 +5749,16 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
>         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 /* CONFIG_DRM_AMD_DC_DCN */
> -
> -/**
> - * 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,120 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->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_DEBUG_DRIVER("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 (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 (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 (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 /* CONFIG_DRM_AMD_DC_DCN */
>
>  static struct dc_stream_state *
>  create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
> @@ -6674,6 +5783,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>  #if defined(CONFIG_DRM_AMD_DC_DCN)
>         struct dsc_dec_dpcd_caps dsc_caps;
>  #endif
> +
>         struct dc_sink *sink = NULL;
>
>         memset(&saved_mode, 0, sizeof(saved_mode));
> @@ -6737,7 +5847,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>                         drm_mode_copy(&mode, freesync_mode);
>                 } else {
>                         decide_crtc_timing_for_drm_display_mode(
> -                               &mode, preferred_mode, scale);
> +                                       &mode, preferred_mode, scale);
>
>                         preferred_refresh = drm_mode_vrefresh(preferred_mode);
>                 }
> @@ -6748,7 +5858,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>         else if (!dm_state)
>                 drm_mode_set_crtcinfo(&mode, 0);
>
> -       /*
> +       /*
>         * If scaling is enabled and refresh rate didn't change
>         * we copy the vic and polarities of the old timings
>         */
> @@ -6996,7 +6106,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
>             !aconnector->fake_enable)
>                 connected = (aconnector->dc_sink != NULL);
>         else
> -               connected = (aconnector->base.force == DRM_FORCE_ON);
> +               connected = (aconnector->base.force == DRM_FORCE_ON ||
> +                               aconnector->base.force == DRM_FORCE_ON_DIGITAL);
>
>         update_subconnector_property(aconnector);
>
> @@ -7120,18 +6231,21 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
>         int i;
>
>         /*
> -        * Call only if mst_mgr was iniitalized before since it's not done
> +        * 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);
>
> +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
> +       defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
>         for (i = 0; i < dm->num_of_edps; i++) {
>                 if ((link == dm->backlight_link[i]) && dm->backlight_dev[i]) {
>                         backlight_device_unregister(dm->backlight_dev[i]);
>                         dm->backlight_dev[i] = NULL;
>                 }
>         }
> +#endif
>
>         if (aconnector->dc_em_sink)
>                 dc_sink_release(aconnector->dc_em_sink);
> @@ -7172,6 +6286,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
>                 state->base.max_requested_bpc = 8;
>                 state->vcpi_slots = 0;
>                 state->pbn = 0;
> +
>                 if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
>                         state->abm_level = amdgpu_dm_abm_level;
>
> @@ -7561,10 +6676,10 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc,
>  }
>
>  static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
> -                                      struct drm_atomic_state *state)
> +                                     struct drm_atomic_state *state)
>  {
>         struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> -                                                                         crtc);
> +                                                                               crtc);
>         struct amdgpu_device *adev = drm_to_adev(crtc->dev);
>         struct dc *dc = adev->dm.dc;
>         struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
> @@ -7575,7 +6690,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
>         dm_update_crtc_active_planes(crtc, crtc_state);
>
>         if (WARN_ON(unlikely(!dm_crtc_state->stream &&
> -                    modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
> +                       modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
>                 return ret;
>         }
>
> @@ -7586,7 +6701,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
>          * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
>          */
>         if (crtc_state->enable &&
> -           !(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
> +               !(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
>                 DRM_DEBUG_ATOMIC("Can't enable a CRTC without enabling the primary plane\n");
>                 return -EINVAL;
>         }
> @@ -7624,21 +6739,21 @@ 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;
> -               }
> +       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;
>  }
>
> @@ -7669,7 +6784,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
>         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;
> +                         aconnector->force_yuv420_output;
>                 color_depth = convert_color_depth_from_display_info(connector,
>                                                                     is_y420,
>                                                                     max_bpc);
> @@ -7724,7 +6839,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
>                         if (!stream)
>                                 continue;
>
> -                       if ((struct amdgpu_dm_connector*)stream->dm_stream_context == aconnector)
> +                       if ((struct amdgpu_dm_connector *)stream->dm_stream_context == aconnector)
>                                 break;
>
>                         stream = NULL;
> @@ -7773,466 +6888,6 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
>  }
>  #endif
>
> -static void dm_drm_plane_reset(struct drm_plane *plane)
> -{
> -       struct dm_plane_state *amdgpu_state = NULL;
> -
> -       if (plane->state)
> -               plane->funcs->atomic_destroy_state(plane, plane->state);
> -
> -       amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
> -       WARN_ON(amdgpu_state == NULL);
> -
> -       if (amdgpu_state)
> -               __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
> -}
> -
> -static struct drm_plane_state *
> -dm_drm_plane_duplicate_state(struct drm_plane *plane)
> -{
> -       struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
> -
> -       old_dm_plane_state = to_dm_plane_state(plane->state);
> -       dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
> -       if (!dm_plane_state)
> -               return NULL;
> -
> -       __drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
> -
> -       if (old_dm_plane_state->dc_state) {
> -               dm_plane_state->dc_state = old_dm_plane_state->dc_state;
> -               dc_plane_state_retain(dm_plane_state->dc_state);
> -       }
> -
> -       return &dm_plane_state->base;
> -}
> -
> -static void dm_drm_plane_destroy_state(struct drm_plane *plane,
> -                               struct drm_plane_state *state)
> -{
> -       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
> -
> -       if (dm_plane_state->dc_state)
> -               dc_plane_state_release(dm_plane_state->dc_state);
> -
> -       drm_atomic_helper_plane_destroy_state(plane, state);
> -}
> -
> -static const struct drm_plane_funcs dm_plane_funcs = {
> -       .update_plane   = drm_atomic_helper_update_plane,
> -       .disable_plane  = drm_atomic_helper_disable_plane,
> -       .destroy        = drm_primary_helper_destroy,
> -       .reset = dm_drm_plane_reset,
> -       .atomic_duplicate_state = dm_drm_plane_duplicate_state,
> -       .atomic_destroy_state = dm_drm_plane_destroy_state,
> -       .format_mod_supported = dm_plane_format_mod_supported,
> -};
> -
> -static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
> -                                     struct drm_plane_state *new_state)
> -{
> -       struct amdgpu_framebuffer *afb;
> -       struct drm_gem_object *obj;
> -       struct amdgpu_device *adev;
> -       struct amdgpu_bo *rbo;
> -       struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
> -       struct list_head list;
> -       struct ttm_validate_buffer tv;
> -       struct ww_acquire_ctx ticket;
> -       uint32_t domain;
> -       int r;
> -
> -       if (!new_state->fb) {
> -               DRM_DEBUG_KMS("No FB bound\n");
> -               return 0;
> -       }
> -
> -       afb = to_amdgpu_framebuffer(new_state->fb);
> -       obj = new_state->fb->obj[0];
> -       rbo = gem_to_amdgpu_bo(obj);
> -       adev = amdgpu_ttm_adev(rbo->tbo.bdev);
> -       INIT_LIST_HEAD(&list);
> -
> -       tv.bo = &rbo->tbo;
> -       tv.num_shared = 1;
> -       list_add(&tv.head, &list);
> -
> -       r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
> -       if (r) {
> -               dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
> -               return r;
> -       }
> -
> -       if (plane->type != DRM_PLANE_TYPE_CURSOR)
> -               domain = amdgpu_display_supported_domains(adev, rbo->flags);
> -       else
> -               domain = AMDGPU_GEM_DOMAIN_VRAM;
> -
> -       r = amdgpu_bo_pin(rbo, domain);
> -       if (unlikely(r != 0)) {
> -               if (r != -ERESTARTSYS)
> -                       DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
> -               ttm_eu_backoff_reservation(&ticket, &list);
> -               return r;
> -       }
> -
> -       r = amdgpu_ttm_alloc_gart(&rbo->tbo);
> -       if (unlikely(r != 0)) {
> -               amdgpu_bo_unpin(rbo);
> -               ttm_eu_backoff_reservation(&ticket, &list);
> -               DRM_ERROR("%p bind failed\n", rbo);
> -               return r;
> -       }
> -
> -       ttm_eu_backoff_reservation(&ticket, &list);
> -
> -       afb->address = amdgpu_bo_gpu_offset(rbo);
> -
> -       amdgpu_bo_ref(rbo);
> -
> -       /**
> -        * We don't do surface updates on planes that have been newly created,
> -        * but we also don't have the afb->address during atomic check.
> -        *
> -        * Fill in buffer attributes depending on the address here, but only on
> -        * newly created planes since they're not being used by DC yet and this
> -        * won't modify global state.
> -        */
> -       dm_plane_state_old = to_dm_plane_state(plane->state);
> -       dm_plane_state_new = to_dm_plane_state(new_state);
> -
> -       if (dm_plane_state_new->dc_state &&
> -           dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
> -               struct dc_plane_state *plane_state =
> -                       dm_plane_state_new->dc_state;
> -               bool force_disable_dcc = !plane_state->dcc.enable;
> -
> -               fill_plane_buffer_attributes(
> -                       adev, afb, plane_state->format, plane_state->rotation,
> -                       afb->tiling_flags,
> -                       &plane_state->tiling_info, &plane_state->plane_size,
> -                       &plane_state->dcc, &plane_state->address,
> -                       afb->tmz_surface, force_disable_dcc);
> -       }
> -
> -       return 0;
> -}
> -
> -static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
> -                                      struct drm_plane_state *old_state)
> -{
> -       struct amdgpu_bo *rbo;
> -       int r;
> -
> -       if (!old_state->fb)
> -               return;
> -
> -       rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
> -       r = amdgpu_bo_reserve(rbo, false);
> -       if (unlikely(r)) {
> -               DRM_ERROR("failed to reserve rbo before unpin\n");
> -               return;
> -       }
> -
> -       amdgpu_bo_unpin(rbo);
> -       amdgpu_bo_unreserve(rbo);
> -       amdgpu_bo_unref(&rbo);
> -}
> -
> -static int dm_plane_helper_check_state(struct drm_plane_state *state,
> -                                      struct drm_crtc_state *new_crtc_state)
> -{
> -       struct drm_framebuffer *fb = state->fb;
> -       int min_downscale, max_upscale;
> -       int min_scale = 0;
> -       int max_scale = INT_MAX;
> -
> -       /* Plane enabled? Validate viewport and get scaling factors from plane caps. */
> -       if (fb && state->crtc) {
> -               /* Validate viewport to cover the case when only the position changes */
> -               if (state->plane->type != DRM_PLANE_TYPE_CURSOR) {
> -                       int viewport_width = state->crtc_w;
> -                       int viewport_height = state->crtc_h;
> -
> -                       if (state->crtc_x < 0)
> -                               viewport_width += state->crtc_x;
> -                       else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay)
> -                               viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x;
> -
> -                       if (state->crtc_y < 0)
> -                               viewport_height += state->crtc_y;
> -                       else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
> -                               viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
> -
> -                       if (viewport_width < 0 || viewport_height < 0) {
> -                               DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
> -                               return -EINVAL;
> -                       } else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
> -                               DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
> -                               return -EINVAL;
> -                       } else if (viewport_height < MIN_VIEWPORT_SIZE) {
> -                               DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
> -                               return -EINVAL;
> -                       }
> -
> -               }
> -
> -               /* Get min/max allowed scaling factors from plane caps. */
> -               get_min_max_dc_plane_scaling(state->crtc->dev, fb,
> -                                            &min_downscale, &max_upscale);
> -               /*
> -                * Convert to drm convention: 16.16 fixed point, instead of dc's
> -                * 1.0 == 1000. Also drm scaling is src/dst instead of dc's
> -                * dst/src, so min_scale = 1.0 / max_upscale, etc.
> -                */
> -               min_scale = (1000 << 16) / max_upscale;
> -               max_scale = (1000 << 16) / min_downscale;
> -       }
> -
> -       return drm_atomic_helper_check_plane_state(
> -               state, new_crtc_state, min_scale, max_scale, true, true);
> -}
> -
> -static int dm_plane_atomic_check(struct drm_plane *plane,
> -                                struct drm_atomic_state *state)
> -{
> -       struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> -                                                                                plane);
> -       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> -       struct dc *dc = adev->dm.dc;
> -       struct dm_plane_state *dm_plane_state;
> -       struct dc_scaling_info scaling_info;
> -       struct drm_crtc_state *new_crtc_state;
> -       int ret;
> -
> -       trace_amdgpu_dm_plane_atomic_check(new_plane_state);
> -
> -       dm_plane_state = to_dm_plane_state(new_plane_state);
> -
> -       if (!dm_plane_state->dc_state)
> -               return 0;
> -
> -       new_crtc_state =
> -               drm_atomic_get_new_crtc_state(state,
> -                                             new_plane_state->crtc);
> -       if (!new_crtc_state)
> -               return -EINVAL;
> -
> -       ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
> -       if (ret)
> -               return ret;
> -
> -       ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
> -       if (ret)
> -               return ret;
> -
> -       if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
> -               return 0;
> -
> -       return -EINVAL;
> -}
> -
> -static int dm_plane_atomic_async_check(struct drm_plane *plane,
> -                                      struct drm_atomic_state *state)
> -{
> -       /* Only support async updates on cursor planes. */
> -       if (plane->type != DRM_PLANE_TYPE_CURSOR)
> -               return -EINVAL;
> -
> -       return 0;
> -}
> -
> -static void dm_plane_atomic_async_update(struct drm_plane *plane,
> -                                        struct drm_atomic_state *state)
> -{
> -       struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> -                                                                          plane);
> -       struct drm_plane_state *old_state =
> -               drm_atomic_get_old_plane_state(state, plane);
> -
> -       trace_amdgpu_dm_atomic_update_cursor(new_state);
> -
> -       swap(plane->state->fb, new_state->fb);
> -
> -       plane->state->src_x = new_state->src_x;
> -       plane->state->src_y = new_state->src_y;
> -       plane->state->src_w = new_state->src_w;
> -       plane->state->src_h = new_state->src_h;
> -       plane->state->crtc_x = new_state->crtc_x;
> -       plane->state->crtc_y = new_state->crtc_y;
> -       plane->state->crtc_w = new_state->crtc_w;
> -       plane->state->crtc_h = new_state->crtc_h;
> -
> -       handle_cursor_update(plane, old_state);
> -}
> -
> -static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
> -       .prepare_fb = dm_plane_helper_prepare_fb,
> -       .cleanup_fb = dm_plane_helper_cleanup_fb,
> -       .atomic_check = dm_plane_atomic_check,
> -       .atomic_async_check = dm_plane_atomic_async_check,
> -       .atomic_async_update = dm_plane_atomic_async_update
> -};
> -
> -/*
> - * TODO: these are currently initialized to rgb formats only.
> - * For future use cases we should either initialize them dynamically based on
> - * plane capabilities, or initialize this array to all formats, so internal drm
> - * check will succeed, and let DC implement proper check
> - */
> -static const uint32_t rgb_formats[] = {
> -       DRM_FORMAT_XRGB8888,
> -       DRM_FORMAT_ARGB8888,
> -       DRM_FORMAT_RGBA8888,
> -       DRM_FORMAT_XRGB2101010,
> -       DRM_FORMAT_XBGR2101010,
> -       DRM_FORMAT_ARGB2101010,
> -       DRM_FORMAT_ABGR2101010,
> -       DRM_FORMAT_XRGB16161616,
> -       DRM_FORMAT_XBGR16161616,
> -       DRM_FORMAT_ARGB16161616,
> -       DRM_FORMAT_ABGR16161616,
> -       DRM_FORMAT_XBGR8888,
> -       DRM_FORMAT_ABGR8888,
> -       DRM_FORMAT_RGB565,
> -};
> -
> -static const uint32_t overlay_formats[] = {
> -       DRM_FORMAT_XRGB8888,
> -       DRM_FORMAT_ARGB8888,
> -       DRM_FORMAT_RGBA8888,
> -       DRM_FORMAT_XBGR8888,
> -       DRM_FORMAT_ABGR8888,
> -       DRM_FORMAT_RGB565
> -};
> -
> -static const u32 cursor_formats[] = {
> -       DRM_FORMAT_ARGB8888
> -};
> -
> -static int get_plane_formats(const struct drm_plane *plane,
> -                            const struct dc_plane_cap *plane_cap,
> -                            uint32_t *formats, int max_formats)
> -{
> -       int i, num_formats = 0;
> -
> -       /*
> -        * TODO: Query support for each group of formats directly from
> -        * DC plane caps. This will require adding more formats to the
> -        * caps list.
> -        */
> -
> -       switch (plane->type) {
> -       case DRM_PLANE_TYPE_PRIMARY:
> -               for (i = 0; i < ARRAY_SIZE(rgb_formats); ++i) {
> -                       if (num_formats >= max_formats)
> -                               break;
> -
> -                       formats[num_formats++] = rgb_formats[i];
> -               }
> -
> -               if (plane_cap && plane_cap->pixel_format_support.nv12)
> -                       formats[num_formats++] = DRM_FORMAT_NV12;
> -               if (plane_cap && plane_cap->pixel_format_support.p010)
> -                       formats[num_formats++] = DRM_FORMAT_P010;
> -               if (plane_cap && plane_cap->pixel_format_support.fp16) {
> -                       formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
> -                       formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
> -                       formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
> -                       formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
> -               }
> -               break;
> -
> -       case DRM_PLANE_TYPE_OVERLAY:
> -               for (i = 0; i < ARRAY_SIZE(overlay_formats); ++i) {
> -                       if (num_formats >= max_formats)
> -                               break;
> -
> -                       formats[num_formats++] = overlay_formats[i];
> -               }
> -               break;
> -
> -       case DRM_PLANE_TYPE_CURSOR:
> -               for (i = 0; i < ARRAY_SIZE(cursor_formats); ++i) {
> -                       if (num_formats >= max_formats)
> -                               break;
> -
> -                       formats[num_formats++] = cursor_formats[i];
> -               }
> -               break;
> -       }
> -
> -       return num_formats;
> -}
> -
> -static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
> -                               struct drm_plane *plane,
> -                               unsigned long possible_crtcs,
> -                               const struct dc_plane_cap *plane_cap)
> -{
> -       uint32_t formats[32];
> -       int num_formats;
> -       int res = -EPERM;
> -       unsigned int supported_rotations;
> -       uint64_t *modifiers = NULL;
> -
> -       num_formats = get_plane_formats(plane, plane_cap, formats,
> -                                       ARRAY_SIZE(formats));
> -
> -       res = get_plane_modifiers(dm->adev, plane->type, &modifiers);
> -       if (res)
> -               return res;
> -
> -       res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
> -                                      &dm_plane_funcs, formats, num_formats,
> -                                      modifiers, plane->type, NULL);
> -       kfree(modifiers);
> -       if (res)
> -               return res;
> -
> -       if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
> -           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);
> -
> -               drm_plane_create_alpha_property(plane);
> -               drm_plane_create_blend_mode_property(plane, blend_caps);
> -       }
> -
> -       if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
> -           plane_cap &&
> -           (plane_cap->pixel_format_support.nv12 ||
> -            plane_cap->pixel_format_support.p010)) {
> -               /* This only affects YUV formats. */
> -               drm_plane_create_color_properties(
> -                       plane,
> -                       BIT(DRM_COLOR_YCBCR_BT601) |
> -                       BIT(DRM_COLOR_YCBCR_BT709) |
> -                       BIT(DRM_COLOR_YCBCR_BT2020),
> -                       BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
> -                       BIT(DRM_COLOR_YCBCR_FULL_RANGE),
> -                       DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
> -       }
> -
> -       supported_rotations =
> -               DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
> -               DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
> -
> -       if (dm->adev->asic_type >= CHIP_BONAIRE &&
> -           plane->type != DRM_PLANE_TYPE_CURSOR)
> -               drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
> -                                                  supported_rotations);
> -
> -       drm_plane_helper_add(plane, &dm_plane_helper_funcs);
> -
> -       /* Create (reset) the plane state */
> -       if (plane->funcs->reset)
> -               plane->funcs->reset(plane);
> -
> -       return 0;
> -}
> -
>  static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
>                                struct drm_plane *plane,
>                                uint32_t crtc_index)
> @@ -9072,114 +7727,6 @@ static void remove_stream(struct amdgpu_device *adev,
>         acrtc->enabled = false;
>  }
>
> -static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
> -                              struct dc_cursor_position *position)
> -{
> -       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
> -       int x, y;
> -       int xorigin = 0, yorigin = 0;
> -
> -       if (!crtc || !plane->state->fb)
> -               return 0;
> -
> -       if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
> -           (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
> -               DRM_ERROR("%s: bad cursor width or height %d x %d\n",
> -                         __func__,
> -                         plane->state->crtc_w,
> -                         plane->state->crtc_h);
> -               return -EINVAL;
> -       }
> -
> -       x = plane->state->crtc_x;
> -       y = plane->state->crtc_y;
> -
> -       if (x <= -amdgpu_crtc->max_cursor_width ||
> -           y <= -amdgpu_crtc->max_cursor_height)
> -               return 0;
> -
> -       if (x < 0) {
> -               xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
> -               x = 0;
> -       }
> -       if (y < 0) {
> -               yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
> -               y = 0;
> -       }
> -       position->enable = true;
> -       position->translate_by_source = true;
> -       position->x = x;
> -       position->y = y;
> -       position->x_hotspot = xorigin;
> -       position->y_hotspot = yorigin;
> -
> -       return 0;
> -}
> -
> -static void handle_cursor_update(struct drm_plane *plane,
> -                                struct drm_plane_state *old_plane_state)
> -{
> -       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> -       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
> -       struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
> -       struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
> -       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
> -       uint64_t address = afb ? afb->address : 0;
> -       struct dc_cursor_position position = {0};
> -       struct dc_cursor_attributes attributes;
> -       int ret;
> -
> -       if (!plane->state->fb && !old_plane_state->fb)
> -               return;
> -
> -       DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
> -                     __func__,
> -                     amdgpu_crtc->crtc_id,
> -                     plane->state->crtc_w,
> -                     plane->state->crtc_h);
> -
> -       ret = get_cursor_position(plane, crtc, &position);
> -       if (ret)
> -               return;
> -
> -       if (!position.enable) {
> -               /* turn off cursor */
> -               if (crtc_state && crtc_state->stream) {
> -                       mutex_lock(&adev->dm.dc_lock);
> -                       dc_stream_set_cursor_position(crtc_state->stream,
> -                                                     &position);
> -                       mutex_unlock(&adev->dm.dc_lock);
> -               }
> -               return;
> -       }
> -
> -       amdgpu_crtc->cursor_width = plane->state->crtc_w;
> -       amdgpu_crtc->cursor_height = plane->state->crtc_h;
> -
> -       memset(&attributes, 0, sizeof(attributes));
> -       attributes.address.high_part = upper_32_bits(address);
> -       attributes.address.low_part  = lower_32_bits(address);
> -       attributes.width             = plane->state->crtc_w;
> -       attributes.height            = plane->state->crtc_h;
> -       attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
> -       attributes.rotation_angle    = 0;
> -       attributes.attribute_flags.value = 0;
> -
> -       attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
> -
> -       if (crtc_state->stream) {
> -               mutex_lock(&adev->dm.dc_lock);
> -               if (!dc_stream_set_cursor_attributes(crtc_state->stream,
> -                                                        &attributes))
> -                       DRM_ERROR("DC failed to set cursor attributes\n");
> -
> -               if (!dc_stream_set_cursor_position(crtc_state->stream,
> -                                                  &position))
> -                       DRM_ERROR("DC failed to set cursor position\n");
> -               mutex_unlock(&adev->dm.dc_lock);
> -       }
> -}
> -
>  static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
>  {
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> new file mode 100644
> index 000000000000..e27621e11947
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
> @@ -0,0 +1,1637 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright 2022 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_fourcc.h>
> +
> +#include "amdgpu.h"
> +#include "dal_asic_id.h"
> +#include "amdgpu_display.h"
> +#include "amdgpu_dm_trace.h"
> +#include "gc/gc_11_0_0_offset.h"
> +#include "gc/gc_11_0_0_sh_mask.h"
> +
> +/*
> + * TODO: these are currently initialized to rgb formats only.
> + * For future use cases we should either initialize them dynamically based on
> + * plane capabilities, or initialize this array to all formats, so internal drm
> + * check will succeed, and let DC implement proper check
> + */
> +static const uint32_t rgb_formats[] = {
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_RGBA8888,
> +       DRM_FORMAT_XRGB2101010,
> +       DRM_FORMAT_XBGR2101010,
> +       DRM_FORMAT_ARGB2101010,
> +       DRM_FORMAT_ABGR2101010,
> +       DRM_FORMAT_XRGB16161616,
> +       DRM_FORMAT_XBGR16161616,
> +       DRM_FORMAT_ARGB16161616,
> +       DRM_FORMAT_ABGR16161616,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_ABGR8888,
> +       DRM_FORMAT_RGB565,
> +};
> +
> +static const uint32_t overlay_formats[] = {
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_RGBA8888,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_ABGR8888,
> +       DRM_FORMAT_RGB565
> +};
> +
> +static const u32 cursor_formats[] = {
> +       DRM_FORMAT_ARGB8888
> +};
> +
> +enum dm_micro_swizzle {
> +       MICRO_SWIZZLE_Z = 0,
> +       MICRO_SWIZZLE_S = 1,
> +       MICRO_SWIZZLE_D = 2,
> +       MICRO_SWIZZLE_R = 3
> +};
> +
> +const struct drm_format_info *amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
> +{
> +       return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]);
> +}
> +
> +void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
> +                              bool *per_pixel_alpha, bool *pre_multiplied_alpha,
> +                              bool *global_alpha, int *global_alpha_value)
> +{
> +       *per_pixel_alpha = false;
> +       *pre_multiplied_alpha = true;
> +       *global_alpha = false;
> +       *global_alpha_value = 0xff;
> +
> +       if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
> +               return;
> +
> +       if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
> +               plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
> +               static const uint32_t alpha_formats[] = {
> +                       DRM_FORMAT_ARGB8888,
> +                       DRM_FORMAT_RGBA8888,
> +                       DRM_FORMAT_ABGR8888,
> +               };
> +               uint32_t format = plane_state->fb->format->format;
> +               unsigned int i;
> +
> +               for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
> +                       if (format == alpha_formats[i]) {
> +                               *per_pixel_alpha = true;
> +                               break;
> +                       }
> +               }
> +
> +               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
> +                       *pre_multiplied_alpha = false;
> +       }
> +
> +       if (plane_state->alpha < 0xffff) {
> +               *global_alpha = true;
> +               *global_alpha_value = plane_state->alpha >> 8;
> +       }
> +}
> +
> +static void add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod)
> +{
> +       if (!*mods)
> +               return;
> +
> +       if (*cap - *size < 1) {
> +               uint64_t new_cap = *cap * 2;
> +               uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL);
> +
> +               if (!new_mods) {
> +                       kfree(*mods);
> +                       *mods = NULL;
> +                       return;
> +               }
> +
> +               memcpy(new_mods, *mods, sizeof(uint64_t) * *size);
> +               kfree(*mods);
> +               *mods = new_mods;
> +               *cap = new_cap;
> +       }
> +
> +       (*mods)[*size] = mod;
> +       *size += 1;
> +}
> +
> +bool modifier_has_dcc(uint64_t modifier)
> +{
> +       return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
> +}
> +
> +unsigned modifier_gfx9_swizzle_mode(uint64_t modifier)
> +{
> +       if (modifier == DRM_FORMAT_MOD_LINEAR)
> +               return 0;
> +
> +       return AMD_FMT_MOD_GET(TILE, modifier);
> +}
> +
> +static void fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info,
> +                                uint64_t tiling_flags)
> +{
> +       /* Fill GFX8 params */
> +       if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
> +               unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
> +
> +               bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
> +               bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
> +               mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
> +               tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
> +               num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
> +
> +               /* XXX fix me for VI */
> +               tiling_info->gfx8.num_banks = num_banks;
> +               tiling_info->gfx8.array_mode =
> +                               DC_ARRAY_2D_TILED_THIN1;
> +               tiling_info->gfx8.tile_split = tile_split;
> +               tiling_info->gfx8.bank_width = bankw;
> +               tiling_info->gfx8.bank_height = bankh;
> +               tiling_info->gfx8.tile_aspect = mtaspect;
> +               tiling_info->gfx8.tile_mode =
> +                               DC_ADDR_SURF_MICRO_TILING_DISPLAY;
> +       } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
> +                       == DC_ARRAY_1D_TILED_THIN1) {
> +               tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
> +       }
> +
> +       tiling_info->gfx8.pipe_config =
> +                       AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
> +}
> +
> +static void fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev,
> +                                 union dc_tiling_info *tiling_info)
> +{
> +       /* Fill GFX9 params */
> +       tiling_info->gfx9.num_pipes =
> +               adev->gfx.config.gb_addr_config_fields.num_pipes;
> +       tiling_info->gfx9.num_banks =
> +               adev->gfx.config.gb_addr_config_fields.num_banks;
> +       tiling_info->gfx9.pipe_interleave =
> +               adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
> +       tiling_info->gfx9.num_shader_engines =
> +               adev->gfx.config.gb_addr_config_fields.num_se;
> +       tiling_info->gfx9.max_compressed_frags =
> +               adev->gfx.config.gb_addr_config_fields.max_compress_frags;
> +       tiling_info->gfx9.num_rb_per_se =
> +               adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
> +       tiling_info->gfx9.shaderEnable = 1;
> +       if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
> +               tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;
> +}
> +
> +static void fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev,
> +                                   union dc_tiling_info *tiling_info,
> +                                   uint64_t modifier)
> +{
> +       unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
> +       unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
> +       unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier);
> +       unsigned int pipes_log2;
> +
> +       pipes_log2 = min(5u, mod_pipe_xor_bits);
> +
> +       fill_gfx9_tiling_info_from_device(adev, tiling_info);
> +
> +       if (!IS_AMD_FMT_MOD(modifier))
> +               return;
> +
> +       tiling_info->gfx9.num_pipes = 1u << pipes_log2;
> +       tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2);
> +
> +       if (adev->family >= AMDGPU_FAMILY_NV) {
> +               tiling_info->gfx9.num_pkrs = 1u << pkrs_log2;
> +       } else {
> +               tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits;
> +
> +               /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */
> +       }
> +}
> +
> +static int validate_dcc(struct amdgpu_device *adev,
> +            const enum surface_pixel_format format,
> +            const enum dc_rotation_angle rotation,
> +            const union dc_tiling_info *tiling_info,
> +            const struct dc_plane_dcc_param *dcc,
> +            const struct dc_plane_address *address,
> +            const struct plane_size *plane_size)
> +{
> +       struct dc *dc = adev->dm.dc;
> +       struct dc_dcc_surface_param input;
> +       struct dc_surface_dcc_cap output;
> +
> +       memset(&input, 0, sizeof(input));
> +       memset(&output, 0, sizeof(output));
> +
> +       if (!dcc->enable)
> +               return 0;
> +
> +       if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
> +           !dc->cap_funcs.get_dcc_compression_cap)
> +               return -EINVAL;
> +
> +       input.format = format;
> +       input.surface_size.width = plane_size->surface_size.width;
> +       input.surface_size.height = plane_size->surface_size.height;
> +       input.swizzle_mode = tiling_info->gfx9.swizzle;
> +
> +       if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180)
> +               input.scan = SCAN_DIRECTION_HORIZONTAL;
> +       else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270)
> +               input.scan = SCAN_DIRECTION_VERTICAL;
> +
> +       if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
> +               return -EINVAL;
> +
> +       if (!output.capable)
> +               return -EINVAL;
> +
> +       if (dcc->independent_64b_blks == 0 &&
> +           output.grph.rgb.independent_64b_blks != 0)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static int fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
> +                                         const struct amdgpu_framebuffer *afb,
> +                                         const enum surface_pixel_format format,
> +                                         const enum dc_rotation_angle rotation,
> +                                         const struct plane_size *plane_size,
> +                                         union dc_tiling_info *tiling_info,
> +                                         struct dc_plane_dcc_param *dcc,
> +                                         struct dc_plane_address *address,
> +                                         const bool force_disable_dcc)
> +{
> +       const uint64_t modifier = afb->base.modifier;
> +       int ret = 0;
> +
> +       fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
> +       tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
> +
> +       if (modifier_has_dcc(modifier) && !force_disable_dcc) {
> +               uint64_t dcc_address = afb->address + afb->base.offsets[1];
> +               bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
> +               bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
> +
> +               dcc->enable = 1;
> +               dcc->meta_pitch = afb->base.pitches[1];
> +               dcc->independent_64b_blks = independent_64b_blks;
> +               if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
> +                       if (independent_64b_blks && independent_128b_blks)
> +                               dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl;
> +                       else if (independent_128b_blks)
> +                               dcc->dcc_ind_blk = hubp_ind_block_128b;
> +                       else if (independent_64b_blks && !independent_128b_blks)
> +                               dcc->dcc_ind_blk = hubp_ind_block_64b;
> +                       else
> +                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
> +               } else {
> +                       if (independent_64b_blks)
> +                               dcc->dcc_ind_blk = hubp_ind_block_64b;
> +                       else
> +                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
> +               }
> +
> +               address->grph.meta_addr.low_part = lower_32_bits(dcc_address);
> +               address->grph.meta_addr.high_part = upper_32_bits(dcc_address);
> +       }
> +
> +       ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
> +       if (ret)
> +               drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
> +
> +       return ret;
> +}
> +
> +static void add_gfx10_1_modifiers(const struct amdgpu_device *adev,
> +                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
> +{
> +       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(DCC, 1) |
> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(DCC, 1) |
> +                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
> +
> +
> +       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> +}
> +
> +static void add_gfx9_modifiers(const struct amdgpu_device *adev,
> +                  uint64_t **mods, uint64_t *size, uint64_t *capacity)
> +{
> +       int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
> +       int pipe_xor_bits = min(8, pipes +
> +                               ilog2(adev->gfx.config.gb_addr_config_fields.num_se));
> +       int bank_xor_bits = min(8 - pipe_xor_bits,
> +                               ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));
> +       int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +
> +                ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);
> +
> +
> +       if (adev->family == AMDGPU_FAMILY_RV) {
> +               /* Raven2 and later */
> +               bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81;
> +
> +               /*
> +                * No _D DCC swizzles yet because we only allow 32bpp, which
> +                * doesn't support _D on DCN
> +                */
> +
> +               if (has_constant_encode) {
> +                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> +                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> +                                   AMD_FMT_MOD_SET(DCC, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> +                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));
> +               }
> +
> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> +                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> +                           AMD_FMT_MOD_SET(DCC, 1) |
> +                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> +                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0));
> +
> +               if (has_constant_encode) {
> +                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> +                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> +                                   AMD_FMT_MOD_SET(DCC, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> +
> +                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                                   AMD_FMT_MOD_SET(RB, rb) |
> +                                   AMD_FMT_MOD_SET(PIPE, pipes));
> +               }
> +
> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> +                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
> +                           AMD_FMT_MOD_SET(DCC, 1) |
> +                           AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> +                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
> +                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) |
> +                           AMD_FMT_MOD_SET(RB, rb) |
> +                           AMD_FMT_MOD_SET(PIPE, pipes));
> +       }
> +
> +       /*
> +        * Only supported for 64bpp on Raven, will be filtered on format in
> +        * dm_plane_format_mod_supported.
> +        */
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
> +
> +       if (adev->family == AMDGPU_FAMILY_RV) {
> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
> +                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
> +       }
> +
> +       /*
> +        * Only supported for 64bpp on Raven, will be filtered on format in
> +        * dm_plane_format_mod_supported.
> +        */
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> +
> +       if (adev->family == AMDGPU_FAMILY_RV) {
> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> +       }
> +}
> +
> +static void add_gfx10_3_modifiers(const struct amdgpu_device *adev,
> +                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
> +{
> +       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
> +       int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs);
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> +                   AMD_FMT_MOD_SET(DCC, 1) |
> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> +                   AMD_FMT_MOD_SET(DCC, 1) |
> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> +                   AMD_FMT_MOD_SET(DCC, 1) |
> +                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
> +                   AMD_FMT_MOD_SET(DCC, 1) |
> +                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(PACKERS, pkrs));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                   AMD_FMT_MOD_SET(PACKERS, pkrs));
> +
> +       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
> +}
> +
> +static void add_gfx11_modifiers(struct amdgpu_device *adev,
> +                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
> +{
> +       int num_pipes = 0;
> +       int pipe_xor_bits = 0;
> +       int num_pkrs = 0;
> +       int pkrs = 0;
> +       u32 gb_addr_config;
> +       u8 i = 0;
> +       unsigned swizzle_r_x;
> +       uint64_t modifier_r_x;
> +       uint64_t modifier_dcc_best;
> +       uint64_t modifier_dcc_4k;
> +
> +       /* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from
> +        * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes}
> +        */
> +       gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG);
> +       ASSERT(gb_addr_config != 0);
> +
> +       num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS);
> +       pkrs = ilog2(num_pkrs);
> +       num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES);
> +       pipe_xor_bits = ilog2(num_pipes);
> +
> +       for (i = 0; i < 2; i++) {
> +               /* Insert the best one first. */
> +               /* R_X swizzle modes are the best for rendering and DCC requires them. */
> +               if (num_pipes > 16)
> +                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : AMD_FMT_MOD_TILE_GFX9_64K_R_X;
> +               else
> +                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX9_64K_R_X : AMD_FMT_MOD_TILE_GFX11_256K_R_X;
> +
> +               modifier_r_x = AMD_FMT_MOD |
> +                              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
> +                              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
> +                              AMD_FMT_MOD_SET(TILE, swizzle_r_x) |
> +                              AMD_FMT_MOD_SET(PACKERS, pkrs);
> +
> +               /* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */
> +               modifier_dcc_best = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) |
> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> +                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B);
> +
> +               /* DCC settings for 4K and greater resolutions. (required by display hw) */
> +               modifier_dcc_4k = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
> +                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
> +                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
> +                                 AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B);
> +
> +               add_modifier(mods, size, capacity, modifier_dcc_best);
> +               add_modifier(mods, size, capacity, modifier_dcc_4k);
> +
> +               add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1));
> +               add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1));
> +
> +               add_modifier(mods, size, capacity, modifier_r_x);
> +       }
> +
> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
> +                       AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
> +                       AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D));
> +}
> +
> +static int get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods)
> +{
> +       uint64_t size = 0, capacity = 128;
> +       *mods = NULL;
> +
> +       /* We have not hooked up any pre-GFX9 modifiers. */
> +       if (adev->family < AMDGPU_FAMILY_AI)
> +               return 0;
> +
> +       *mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL);
> +
> +       if (plane_type == DRM_PLANE_TYPE_CURSOR) {
> +               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
> +               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
> +               return *mods ? 0 : -ENOMEM;
> +       }
> +
> +       switch (adev->family) {
> +       case AMDGPU_FAMILY_AI:
> +       case AMDGPU_FAMILY_RV:
> +               add_gfx9_modifiers(adev, mods, &size, &capacity);
> +               break;
> +       case AMDGPU_FAMILY_NV:
> +       case AMDGPU_FAMILY_VGH:
> +       case AMDGPU_FAMILY_YC:
> +       case AMDGPU_FAMILY_GC_10_3_6:
> +       case AMDGPU_FAMILY_GC_10_3_7:
> +               if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
> +                       add_gfx10_3_modifiers(adev, mods, &size, &capacity);
> +               else
> +                       add_gfx10_1_modifiers(adev, mods, &size, &capacity);
> +               break;
> +       case AMDGPU_FAMILY_GC_11_0_0:
> +       case AMDGPU_FAMILY_GC_11_0_2:
> +               add_gfx11_modifiers(adev, mods, &size, &capacity);
> +               break;
> +       }
> +
> +       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
> +
> +       /* INVALID marks the end of the list. */
> +       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
> +
> +       if (!*mods)
> +               return -ENOMEM;
> +
> +       return 0;
> +}
> +
> +static int get_plane_formats(const struct drm_plane *plane,
> +                            const struct dc_plane_cap *plane_cap,
> +                            uint32_t *formats, int max_formats)
> +{
> +       int i, num_formats = 0;
> +
> +       /*
> +        * TODO: Query support for each group of formats directly from
> +        * DC plane caps. This will require adding more formats to the
> +        * caps list.
> +        */
> +
> +       switch (plane->type) {
> +       case DRM_PLANE_TYPE_PRIMARY:
> +               for (i = 0; i < ARRAY_SIZE(rgb_formats); ++i) {
> +                       if (num_formats >= max_formats)
> +                               break;
> +
> +                       formats[num_formats++] = rgb_formats[i];
> +               }
> +
> +               if (plane_cap && plane_cap->pixel_format_support.nv12)
> +                       formats[num_formats++] = DRM_FORMAT_NV12;
> +               if (plane_cap && plane_cap->pixel_format_support.p010)
> +                       formats[num_formats++] = DRM_FORMAT_P010;
> +               if (plane_cap && plane_cap->pixel_format_support.fp16) {
> +                       formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
> +                       formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
> +                       formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
> +                       formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
> +               }
> +               break;
> +
> +       case DRM_PLANE_TYPE_OVERLAY:
> +               for (i = 0; i < ARRAY_SIZE(overlay_formats); ++i) {
> +                       if (num_formats >= max_formats)
> +                               break;
> +
> +                       formats[num_formats++] = overlay_formats[i];
> +               }
> +               break;
> +
> +       case DRM_PLANE_TYPE_CURSOR:
> +               for (i = 0; i < ARRAY_SIZE(cursor_formats); ++i) {
> +                       if (num_formats >= max_formats)
> +                               break;
> +
> +                       formats[num_formats++] = cursor_formats[i];
> +               }
> +               break;
> +       }
> +
> +       return num_formats;
> +}
> +
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +static int attach_color_mgmt_properties(struct amdgpu_display_manager *dm, struct drm_plane *plane)
> +{
> +       drm_object_attach_property(&plane->base,
> +                                  dm->degamma_lut_property,
> +                                  0);
> +       drm_object_attach_property(&plane->base,
> +                                  dm->degamma_lut_size_property,
> +                                  MAX_COLOR_LUT_ENTRIES);
> +       drm_object_attach_property(&plane->base, dm->ctm_property,
> +                                  0);
> +       drm_object_attach_property(&plane->base, dm->sdr_boost_property,
> +                                  DEFAULT_SDR_BOOST);
> +
> +       return 0;
> +}
> +#endif
> +
> +int fill_plane_buffer_attributes(struct amdgpu_device *adev,
> +                            const struct amdgpu_framebuffer *afb,
> +                            const enum surface_pixel_format format,
> +                            const enum dc_rotation_angle rotation,
> +                            const uint64_t tiling_flags,
> +                            union dc_tiling_info *tiling_info,
> +                            struct plane_size *plane_size,
> +                            struct dc_plane_dcc_param *dcc,
> +                            struct dc_plane_address *address,
> +                            bool tmz_surface,
> +                            bool force_disable_dcc)
> +{
> +       const struct drm_framebuffer *fb = &afb->base;
> +       int ret;
> +
> +       memset(tiling_info, 0, sizeof(*tiling_info));
> +       memset(plane_size, 0, sizeof(*plane_size));
> +       memset(dcc, 0, sizeof(*dcc));
> +       memset(address, 0, sizeof(*address));
> +
> +       address->tmz_surface = tmz_surface;
> +
> +       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
> +               uint64_t addr = afb->address + fb->offsets[0];
> +
> +               plane_size->surface_size.x = 0;
> +               plane_size->surface_size.y = 0;
> +               plane_size->surface_size.width = fb->width;
> +               plane_size->surface_size.height = fb->height;
> +               plane_size->surface_pitch =
> +                       fb->pitches[0] / fb->format->cpp[0];
> +
> +               address->type = PLN_ADDR_TYPE_GRAPHICS;
> +               address->grph.addr.low_part = lower_32_bits(addr);
> +               address->grph.addr.high_part = upper_32_bits(addr);
> +       } else if (format < SURFACE_PIXEL_FORMAT_INVALID) {
> +               uint64_t luma_addr = afb->address + fb->offsets[0];
> +               uint64_t chroma_addr = afb->address + fb->offsets[1];
> +
> +               plane_size->surface_size.x = 0;
> +               plane_size->surface_size.y = 0;
> +               plane_size->surface_size.width = fb->width;
> +               plane_size->surface_size.height = fb->height;
> +               plane_size->surface_pitch =
> +                       fb->pitches[0] / fb->format->cpp[0];
> +
> +               plane_size->chroma_size.x = 0;
> +               plane_size->chroma_size.y = 0;
> +               /* TODO: set these based on surface format */
> +               plane_size->chroma_size.width = fb->width / 2;
> +               plane_size->chroma_size.height = fb->height / 2;
> +
> +               plane_size->chroma_pitch =
> +                       fb->pitches[1] / fb->format->cpp[1];
> +
> +               address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
> +               address->video_progressive.luma_addr.low_part =
> +                       lower_32_bits(luma_addr);
> +               address->video_progressive.luma_addr.high_part =
> +                       upper_32_bits(luma_addr);
> +               address->video_progressive.chroma_addr.low_part =
> +                       lower_32_bits(chroma_addr);
> +               address->video_progressive.chroma_addr.high_part =
> +                       upper_32_bits(chroma_addr);
> +       }
> +
> +       if (adev->family >= AMDGPU_FAMILY_AI) {
> +               ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format,
> +                                                               rotation, plane_size,
> +                                                               tiling_info, dcc,
> +                                                               address,
> +                                                               force_disable_dcc);
> +               if (ret)
> +                       return ret;
> +       } else {
> +               fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags);
> +       }
> +
> +       return 0;
> +}
> +
> +static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
> +                                     struct drm_plane_state *new_state)
> +{
> +       struct amdgpu_framebuffer *afb;
> +       struct drm_gem_object *obj;
> +       struct amdgpu_device *adev;
> +       struct amdgpu_bo *rbo;
> +       struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
> +       struct list_head list;
> +       struct ttm_validate_buffer tv;
> +       struct ww_acquire_ctx ticket;
> +       uint32_t domain;
> +       int r;
> +
> +       if (!new_state->fb) {
> +               DRM_DEBUG_KMS("No FB bound\n");
> +               return 0;
> +       }
> +
> +       afb = to_amdgpu_framebuffer(new_state->fb);
> +       obj = new_state->fb->obj[0];
> +       rbo = gem_to_amdgpu_bo(obj);
> +       adev = amdgpu_ttm_adev(rbo->tbo.bdev);
> +       INIT_LIST_HEAD(&list);
> +
> +       tv.bo = &rbo->tbo;
> +       tv.num_shared = 1;
> +       list_add(&tv.head, &list);
> +
> +       r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
> +       if (r) {
> +               dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
> +               return r;
> +       }
> +
> +       if (plane->type != DRM_PLANE_TYPE_CURSOR)
> +               domain = amdgpu_display_supported_domains(adev, rbo->flags);
> +       else
> +               domain = AMDGPU_GEM_DOMAIN_VRAM;
> +
> +       r = amdgpu_bo_pin(rbo, domain);
> +       if (unlikely(r != 0)) {
> +               if (r != -ERESTARTSYS)
> +                       DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
> +               ttm_eu_backoff_reservation(&ticket, &list);
> +               return r;
> +       }
> +
> +       r = amdgpu_ttm_alloc_gart(&rbo->tbo);
> +       if (unlikely(r != 0)) {
> +               amdgpu_bo_unpin(rbo);
> +               ttm_eu_backoff_reservation(&ticket, &list);
> +               DRM_ERROR("%p bind failed\n", rbo);
> +               return r;
> +       }
> +
> +       ttm_eu_backoff_reservation(&ticket, &list);
> +
> +       afb->address = amdgpu_bo_gpu_offset(rbo);
> +
> +       amdgpu_bo_ref(rbo);
> +
> +       /**
> +        * We don't do surface updates on planes that have been newly created,
> +        * but we also don't have the afb->address during atomic check.
> +        *
> +        * Fill in buffer attributes depending on the address here, but only on
> +        * newly created planes since they're not being used by DC yet and this
> +        * won't modify global state.
> +        */
> +       dm_plane_state_old = to_dm_plane_state(plane->state);
> +       dm_plane_state_new = to_dm_plane_state(new_state);
> +
> +       if (dm_plane_state_new->dc_state &&
> +           dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
> +               struct dc_plane_state *plane_state =
> +                       dm_plane_state_new->dc_state;
> +               bool force_disable_dcc = !plane_state->dcc.enable;
> +
> +               fill_plane_buffer_attributes(
> +                       adev, afb, plane_state->format, plane_state->rotation,
> +                       afb->tiling_flags,
> +                       &plane_state->tiling_info, &plane_state->plane_size,
> +                       &plane_state->dcc, &plane_state->address,
> +                       afb->tmz_surface, force_disable_dcc);
> +       }
> +
> +       return 0;
> +}
> +
> +static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
> +                                      struct drm_plane_state *old_state)
> +{
> +       struct amdgpu_bo *rbo;
> +       int r;
> +
> +       if (!old_state->fb)
> +               return;
> +
> +       rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
> +       r = amdgpu_bo_reserve(rbo, false);
> +       if (unlikely(r)) {
> +               DRM_ERROR("failed to reserve rbo before unpin\n");
> +               return;
> +       }
> +
> +       amdgpu_bo_unpin(rbo);
> +       amdgpu_bo_unreserve(rbo);
> +       amdgpu_bo_unref(&rbo);
> +}
> +
> +static void get_min_max_dc_plane_scaling(struct drm_device *dev,
> +                                        struct drm_framebuffer *fb,
> +                                        int *min_downscale, int *max_upscale)
> +{
> +       struct amdgpu_device *adev = drm_to_adev(dev);
> +       struct dc *dc = adev->dm.dc;
> +       /* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
> +       struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
> +
> +       switch (fb->format->format) {
> +       case DRM_FORMAT_P010:
> +       case DRM_FORMAT_NV12:
> +       case DRM_FORMAT_NV21:
> +               *max_upscale = plane_cap->max_upscale_factor.nv12;
> +               *min_downscale = plane_cap->max_downscale_factor.nv12;
> +               break;
> +
> +       case DRM_FORMAT_XRGB16161616F:
> +       case DRM_FORMAT_ARGB16161616F:
> +       case DRM_FORMAT_XBGR16161616F:
> +       case DRM_FORMAT_ABGR16161616F:
> +               *max_upscale = plane_cap->max_upscale_factor.fp16;
> +               *min_downscale = plane_cap->max_downscale_factor.fp16;
> +               break;
> +
> +       default:
> +               *max_upscale = plane_cap->max_upscale_factor.argb8888;
> +               *min_downscale = plane_cap->max_downscale_factor.argb8888;
> +               break;
> +       }
> +
> +       /*
> +        * A factor of 1 in the plane_cap means to not allow scaling, ie. use a
> +        * scaling factor of 1.0 == 1000 units.
> +        */
> +       if (*max_upscale == 1)
> +               *max_upscale = 1000;
> +
> +       if (*min_downscale == 1)
> +               *min_downscale = 1000;
> +}
> +
> +int dm_plane_helper_check_state(struct drm_plane_state *state,
> +                                      struct drm_crtc_state *new_crtc_state)
> +{
> +       struct drm_framebuffer *fb = state->fb;
> +       int min_downscale, max_upscale;
> +       int min_scale = 0;
> +       int max_scale = INT_MAX;
> +
> +       /* Plane enabled? Validate viewport and get scaling factors from plane caps. */
> +       if (fb && state->crtc) {
> +               /* Validate viewport to cover the case when only the position changes */
> +               if (state->plane->type != DRM_PLANE_TYPE_CURSOR) {
> +                       int viewport_width = state->crtc_w;
> +                       int viewport_height = state->crtc_h;
> +
> +                       if (state->crtc_x < 0)
> +                               viewport_width += state->crtc_x;
> +                       else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay)
> +                               viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x;
> +
> +                       if (state->crtc_y < 0)
> +                               viewport_height += state->crtc_y;
> +                       else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
> +                               viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
> +
> +                       if (viewport_width < 0 || viewport_height < 0) {
> +                               DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
> +                               return -EINVAL;
> +                       } else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
> +                               DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
> +                               return -EINVAL;
> +                       } else if (viewport_height < MIN_VIEWPORT_SIZE) {
> +                               DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
> +                               return -EINVAL;
> +                       }
> +
> +               }
> +
> +               /* Get min/max allowed scaling factors from plane caps. */
> +               get_min_max_dc_plane_scaling(state->crtc->dev, fb,
> +                                            &min_downscale, &max_upscale);
> +               /*
> +                * Convert to drm convention: 16.16 fixed point, instead of dc's
> +                * 1.0 == 1000. Also drm scaling is src/dst instead of dc's
> +                * dst/src, so min_scale = 1.0 / max_upscale, etc.
> +                */
> +               min_scale = (1000 << 16) / max_upscale;
> +               max_scale = (1000 << 16) / min_downscale;
> +       }
> +
> +       return drm_atomic_helper_check_plane_state(
> +               state, new_crtc_state, min_scale, max_scale, true, true);
> +}
> +
> +int fill_dc_scaling_info(struct amdgpu_device *adev,
> +                               const struct drm_plane_state *state,
> +                               struct dc_scaling_info *scaling_info)
> +{
> +       int scale_w, scale_h, min_downscale, max_upscale;
> +
> +       memset(scaling_info, 0, sizeof(*scaling_info));
> +
> +       /* Source is fixed 16.16 but we ignore mantissa for now... */
> +       scaling_info->src_rect.x = state->src_x >> 16;
> +       scaling_info->src_rect.y = state->src_y >> 16;
> +
> +       /*
> +        * For reasons we don't (yet) fully understand a non-zero
> +        * src_y coordinate into an NV12 buffer can cause a
> +        * system hang on DCN1x.
> +        * To avoid hangs (and maybe be overly cautious)
> +        * let's reject both non-zero src_x and src_y.
> +        *
> +        * We currently know of only one use-case to reproduce a
> +        * scenario with non-zero src_x and src_y for NV12, which
> +        * is to gesture the YouTube Android app into full screen
> +        * on ChromeOS.
> +        */
> +       if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) ||
> +           (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) &&
> +           (state->fb && state->fb->format->format == DRM_FORMAT_NV12 &&
> +           (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0)))
> +               return -EINVAL;
> +
> +       scaling_info->src_rect.width = state->src_w >> 16;
> +       if (scaling_info->src_rect.width == 0)
> +               return -EINVAL;
> +
> +       scaling_info->src_rect.height = state->src_h >> 16;
> +       if (scaling_info->src_rect.height == 0)
> +               return -EINVAL;
> +
> +       scaling_info->dst_rect.x = state->crtc_x;
> +       scaling_info->dst_rect.y = state->crtc_y;
> +
> +       if (state->crtc_w == 0)
> +               return -EINVAL;
> +
> +       scaling_info->dst_rect.width = state->crtc_w;
> +
> +       if (state->crtc_h == 0)
> +               return -EINVAL;
> +
> +       scaling_info->dst_rect.height = state->crtc_h;
> +
> +       /* DRM doesn't specify clipping on destination output. */
> +       scaling_info->clip_rect = scaling_info->dst_rect;
> +
> +       /* Validate scaling per-format with DC plane caps */
> +       if (state->plane && state->plane->dev && state->fb) {
> +               get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
> +                                            &min_downscale, &max_upscale);
> +       } else {
> +               min_downscale = 250;
> +               max_upscale = 16000;
> +       }
> +
> +       scale_w = scaling_info->dst_rect.width * 1000 /
> +                 scaling_info->src_rect.width;
> +
> +       if (scale_w < min_downscale || scale_w > max_upscale)
> +               return -EINVAL;
> +
> +       scale_h = scaling_info->dst_rect.height * 1000 /
> +                 scaling_info->src_rect.height;
> +
> +       if (scale_h < min_downscale || scale_h > max_upscale)
> +               return -EINVAL;
> +
> +       /*
> +        * The "scaling_quality" can be ignored for now, quality = 0 has DC
> +        * assume reasonable defaults based on the format.
> +        */
> +
> +       return 0;
> +}
> +
> +static int dm_plane_atomic_check(struct drm_plane *plane,
> +                                struct drm_atomic_state *state)
> +{
> +       struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
> +                                                                                plane);
> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> +       struct dc *dc = adev->dm.dc;
> +       struct dm_plane_state *dm_plane_state;
> +       struct dc_scaling_info scaling_info;
> +       struct drm_crtc_state *new_crtc_state;
> +       int ret;
> +
> +       trace_amdgpu_dm_plane_atomic_check(new_plane_state);
> +
> +       dm_plane_state = to_dm_plane_state(new_plane_state);
> +
> +       if (!dm_plane_state->dc_state)
> +               return 0;
> +
> +       new_crtc_state =
> +               drm_atomic_get_new_crtc_state(state,
> +                                             new_plane_state->crtc);
> +       if (!new_crtc_state)
> +               return -EINVAL;
> +
> +       ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
> +       if (ret)
> +               return ret;
> +
> +       ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
> +       if (ret)
> +               return ret;
> +
> +       if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
> +               return 0;
> +
> +       return -EINVAL;
> +}
> +
> +static int dm_plane_atomic_async_check(struct drm_plane *plane,
> +                                      struct drm_atomic_state *state)
> +{
> +       /* Only support async updates on cursor planes. */
> +       if (plane->type != DRM_PLANE_TYPE_CURSOR)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
> +                              struct dc_cursor_position *position)
> +{
> +       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
> +       int x, y;
> +       int xorigin = 0, yorigin = 0;
> +
> +       if (!crtc || !plane->state->fb)
> +               return 0;
> +
> +       if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
> +           (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
> +               DRM_ERROR("%s: bad cursor width or height %d x %d\n",
> +                         __func__,
> +                         plane->state->crtc_w,
> +                         plane->state->crtc_h);
> +               return -EINVAL;
> +       }
> +
> +       x = plane->state->crtc_x;
> +       y = plane->state->crtc_y;
> +
> +       if (x <= -amdgpu_crtc->max_cursor_width ||
> +           y <= -amdgpu_crtc->max_cursor_height)
> +               return 0;
> +
> +       if (x < 0) {
> +               xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
> +               x = 0;
> +       }
> +       if (y < 0) {
> +               yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
> +               y = 0;
> +       }
> +       position->enable = true;
> +       position->translate_by_source = true;
> +       position->x = x;
> +       position->y = y;
> +       position->x_hotspot = xorigin;
> +       position->y_hotspot = yorigin;
> +
> +       return 0;
> +}
> +
> +void handle_cursor_update(struct drm_plane *plane,
> +                                struct drm_plane_state *old_plane_state)
> +{
> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> +       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
> +       struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
> +       struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
> +       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
> +       uint64_t address = afb ? afb->address : 0;
> +       struct dc_cursor_position position = {0};
> +       struct dc_cursor_attributes attributes;
> +       int ret;
> +
> +       if (!plane->state->fb && !old_plane_state->fb)
> +               return;
> +
> +       DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
> +                     __func__,
> +                     amdgpu_crtc->crtc_id,
> +                     plane->state->crtc_w,
> +                     plane->state->crtc_h);
> +
> +       ret = get_cursor_position(plane, crtc, &position);
> +       if (ret)
> +               return;
> +
> +       if (!position.enable) {
> +               /* turn off cursor */
> +               if (crtc_state && crtc_state->stream) {
> +                       mutex_lock(&adev->dm.dc_lock);
> +                       dc_stream_set_cursor_position(crtc_state->stream,
> +                                                     &position);
> +                       mutex_unlock(&adev->dm.dc_lock);
> +               }
> +               return;
> +       }
> +
> +       amdgpu_crtc->cursor_width = plane->state->crtc_w;
> +       amdgpu_crtc->cursor_height = plane->state->crtc_h;
> +
> +       memset(&attributes, 0, sizeof(attributes));
> +       attributes.address.high_part = upper_32_bits(address);
> +       attributes.address.low_part  = lower_32_bits(address);
> +       attributes.width             = plane->state->crtc_w;
> +       attributes.height            = plane->state->crtc_h;
> +       attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
> +       attributes.rotation_angle    = 0;
> +       attributes.attribute_flags.value = 0;
> +
> +       attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
> +
> +       if (crtc_state->stream) {
> +               mutex_lock(&adev->dm.dc_lock);
> +               if (!dc_stream_set_cursor_attributes(crtc_state->stream,
> +                                                        &attributes))
> +                       DRM_ERROR("DC failed to set cursor attributes\n");
> +
> +               if (!dc_stream_set_cursor_position(crtc_state->stream,
> +                                                  &position))
> +                       DRM_ERROR("DC failed to set cursor position\n");
> +               mutex_unlock(&adev->dm.dc_lock);
> +       }
> +}
> +
> +static void dm_plane_atomic_async_update(struct drm_plane *plane,
> +                                        struct drm_atomic_state *state)
> +{
> +       struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
> +                                                                          plane);
> +       struct drm_plane_state *old_state =
> +               drm_atomic_get_old_plane_state(state, plane);
> +
> +       trace_amdgpu_dm_atomic_update_cursor(new_state);
> +
> +       swap(plane->state->fb, new_state->fb);
> +
> +       plane->state->src_x = new_state->src_x;
> +       plane->state->src_y = new_state->src_y;
> +       plane->state->src_w = new_state->src_w;
> +       plane->state->src_h = new_state->src_h;
> +       plane->state->crtc_x = new_state->crtc_x;
> +       plane->state->crtc_y = new_state->crtc_y;
> +       plane->state->crtc_w = new_state->crtc_w;
> +       plane->state->crtc_h = new_state->crtc_h;
> +
> +       handle_cursor_update(plane, old_state);
> +}
> +
> +static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
> +       .prepare_fb = dm_plane_helper_prepare_fb,
> +       .cleanup_fb = dm_plane_helper_cleanup_fb,
> +       .atomic_check = dm_plane_atomic_check,
> +       .atomic_async_check = dm_plane_atomic_async_check,
> +       .atomic_async_update = dm_plane_atomic_async_update
> +};
> +
> +static void dm_drm_plane_reset(struct drm_plane *plane)
> +{
> +       struct dm_plane_state *amdgpu_state = NULL;
> +
> +       if (plane->state)
> +               plane->funcs->atomic_destroy_state(plane, plane->state);
> +
> +       amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
> +       WARN_ON(amdgpu_state == NULL);
> +
> +       if (amdgpu_state)
> +               __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +       if (amdgpu_state)
> +               amdgpu_state->sdr_boost = DEFAULT_SDR_BOOST;
> +#endif
> +}
> +
> +static struct drm_plane_state *
> +dm_drm_plane_duplicate_state(struct drm_plane *plane)
> +{
> +       struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
> +
> +       old_dm_plane_state = to_dm_plane_state(plane->state);
> +       dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
> +       if (!dm_plane_state)
> +               return NULL;
> +
> +       __drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
> +
> +       if (old_dm_plane_state->dc_state) {
> +               dm_plane_state->dc_state = old_dm_plane_state->dc_state;
> +               dc_plane_state_retain(dm_plane_state->dc_state);
> +       }
> +
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +       if (dm_plane_state->degamma_lut)
> +               drm_property_blob_get(dm_plane_state->degamma_lut);
> +       if (dm_plane_state->ctm)
> +               drm_property_blob_get(dm_plane_state->ctm);
> +
> +       dm_plane_state->sdr_boost = old_dm_plane_state->sdr_boost;
> +#endif
> +
> +       return &dm_plane_state->base;
> +}
> +
> +static bool dm_plane_format_mod_supported(struct drm_plane *plane,
> +                                         uint32_t format,
> +                                         uint64_t modifier)
> +{
> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> +       const struct drm_format_info *info = drm_format_info(format);
> +       struct hw_asic_id asic_id = adev->dm.dc->ctx->asic_id;
> +
> +       enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3;
> +
> +       if (!info)
> +               return false;
> +
> +       /*
> +        * We always have to allow these modifiers:
> +        * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
> +        * 2. Not passing any modifiers is the same as explicitly passing INVALID.
> +        */
> +       if (modifier == DRM_FORMAT_MOD_LINEAR ||
> +           modifier == DRM_FORMAT_MOD_INVALID) {
> +               return true;
> +       }
> +
> +       /* check if swizzle mode is supported by this version of DCN */
> +       switch (asic_id.chip_family) {
> +       case FAMILY_SI:
> +       case FAMILY_CI:
> +       case FAMILY_KV:
> +       case FAMILY_CZ:
> +       case FAMILY_VI:
> +               /* asics before AI does not have modifier support */
> +               return false;
> +       case FAMILY_AI:
> +       case FAMILY_RV:
> +       case FAMILY_NV:
> +       case FAMILY_VGH:
> +       case FAMILY_YELLOW_CARP:
> +       case AMDGPU_FAMILY_GC_10_3_6:
> +       case AMDGPU_FAMILY_GC_10_3_7:
> +               switch (AMD_FMT_MOD_GET(TILE, modifier)) {
> +               case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_D:
> +                       return true;
> +               default:
> +                       return false;
> +               }
> +               break;
> +       case AMDGPU_FAMILY_GC_11_0_0:
> +               switch (AMD_FMT_MOD_GET(TILE, modifier)) {
> +               case AMD_FMT_MOD_TILE_GFX11_256K_R_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
> +               case AMD_FMT_MOD_TILE_GFX9_64K_D:
> +                       return true;
> +               default:
> +                       return false;
> +               }
> +               break;
> +       default:
> +               ASSERT(0); /* Unknown asic */
> +               break;
> +       }
> +
> +       /*
> +        * For D swizzle the canonical modifier depends on the bpp, so check
> +        * it here.
> +        */
> +       if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 &&
> +           adev->family >= AMDGPU_FAMILY_NV) {
> +               if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4)
> +                       return false;
> +       }
> +
> +       if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D &&
> +           info->cpp[0] < 8)
> +               return false;
> +
> +       if (modifier_has_dcc(modifier)) {
> +               /* Per radeonsi comments 16/64 bpp are more complicated. */
> +               if (info->cpp[0] != 4)
> +                       return false;
> +               /* We support multi-planar formats, but not when combined with
> +                * additional DCC metadata planes.
> +                */
> +               if (info->num_planes > 1)
> +                       return false;
> +       }
> +
> +       return true;
> +}
> +
> +static void dm_drm_plane_destroy_state(struct drm_plane *plane,
> +                               struct drm_plane_state *state)
> +{
> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
> +
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +       drm_property_blob_put(dm_plane_state->degamma_lut);
> +       drm_property_blob_put(dm_plane_state->ctm);
> +#endif
> +       if (dm_plane_state->dc_state)
> +               dc_plane_state_release(dm_plane_state->dc_state);
> +
> +       drm_atomic_helper_plane_destroy_state(plane, state);
> +}
> +
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +/* copied from drm_atomic_uapi.c */
> +static int atomic_replace_property_blob_from_id(struct drm_device *dev,
> +                                        struct drm_property_blob **blob,
> +                                        uint64_t blob_id,
> +                                        ssize_t expected_size,
> +                                        ssize_t expected_elem_size,
> +                                        bool *replaced)
> +{
> +       struct drm_property_blob *new_blob = NULL;
> +
> +       if (blob_id != 0) {
> +               new_blob = drm_property_lookup_blob(dev, blob_id);
> +               if (new_blob == NULL)
> +                       return -EINVAL;
> +
> +               if (expected_size > 0 &&
> +                   new_blob->length != expected_size) {
> +                       drm_property_blob_put(new_blob);
> +                       return -EINVAL;
> +               }
> +               if (expected_elem_size > 0 &&
> +                   new_blob->length % expected_elem_size != 0) {
> +                       drm_property_blob_put(new_blob);
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       *replaced |= drm_property_replace_blob(blob, new_blob);
> +       drm_property_blob_put(new_blob);
> +
> +       return 0;
> +}
> +
> +int dm_drm_plane_set_property(struct drm_plane *plane,
> +                             struct drm_plane_state *state,
> +                             struct drm_property *property,
> +                             uint64_t val)
> +{
> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
> +       int ret = 0;
> +       bool replaced;
> +
> +       if (property == adev->dm.degamma_lut_property) {
> +               ret = atomic_replace_property_blob_from_id(adev_to_drm(adev),
> +                               &dm_plane_state->degamma_lut,
> +                               val, -1, sizeof(struct drm_color_lut),
> +                               &replaced);
> +       } else if (property == adev->dm.ctm_property) {
> +               ret = atomic_replace_property_blob_from_id(adev_to_drm(adev),
> +                               &dm_plane_state->ctm,
> +                               val,
> +                               sizeof(struct drm_color_ctm), -1,
> +                               &replaced);
> +       } else if (property == adev->dm.sdr_boost_property) {
> +               dm_plane_state->sdr_boost = val;
> +       } else {
> +               return -EINVAL;
> +       }
> +
> +       return ret;
> +}
> +
> +int dm_drm_plane_get_property(struct drm_plane *plane,
> +                             const struct drm_plane_state *state,
> +                             struct drm_property *property,
> +                             uint64_t *val)
> +{
> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
> +
> +       if (property == adev->dm.degamma_lut_property) {
> +               *val = (dm_plane_state->degamma_lut) ?
> +                       dm_plane_state->degamma_lut->base.id : 0;
> +       } else if (property == adev->dm.ctm_property) {
> +               *val = (dm_plane_state->ctm) ? dm_plane_state->ctm->base.id : 0;
> +       } else if (property == adev->dm.sdr_boost_property) {
> +               *val = dm_plane_state->sdr_boost;
> +       } else {
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +static const struct drm_plane_funcs dm_plane_funcs = {
> +       .update_plane   = drm_atomic_helper_update_plane,
> +       .disable_plane  = drm_atomic_helper_disable_plane,
> +       .destroy        = drm_primary_helper_destroy,
> +       .reset = dm_drm_plane_reset,
> +       .atomic_duplicate_state = dm_drm_plane_duplicate_state,
> +       .atomic_destroy_state = dm_drm_plane_destroy_state,
> +       .format_mod_supported = dm_plane_format_mod_supported,
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +       .atomic_set_property = dm_drm_plane_set_property,
> +       .atomic_get_property = dm_drm_plane_get_property,
> +#endif
> +};
> +
> +int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
> +                               struct drm_plane *plane,
> +                               unsigned long possible_crtcs,
> +                               const struct dc_plane_cap *plane_cap)
> +{
> +       uint32_t formats[32];
> +       int num_formats;
> +       int res = -EPERM;
> +       unsigned int supported_rotations;
> +       uint64_t *modifiers = NULL;
> +
> +       num_formats = get_plane_formats(plane, plane_cap, formats,
> +                                       ARRAY_SIZE(formats));
> +
> +       res = get_plane_modifiers(dm->adev, plane->type, &modifiers);
> +       if (res)
> +               return res;
> +
> +       res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
> +                                      &dm_plane_funcs, formats, num_formats,
> +                                      modifiers, plane->type, NULL);
> +       kfree(modifiers);
> +       if (res)
> +               return res;
> +
> +       if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
> +           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);
> +
> +               drm_plane_create_alpha_property(plane);
> +               drm_plane_create_blend_mode_property(plane, blend_caps);
> +       }
> +
> +       if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
> +           plane_cap &&
> +           (plane_cap->pixel_format_support.nv12 ||
> +            plane_cap->pixel_format_support.p010)) {
> +               /* This only affects YUV formats. */
> +               drm_plane_create_color_properties(
> +                       plane,
> +                       BIT(DRM_COLOR_YCBCR_BT601) |
> +                       BIT(DRM_COLOR_YCBCR_BT709) |
> +                       BIT(DRM_COLOR_YCBCR_BT2020),
> +                       BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
> +                       BIT(DRM_COLOR_YCBCR_FULL_RANGE),
> +                       DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
> +       }
> +
> +       supported_rotations =
> +               DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
> +               DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
> +
> +       if (dm->adev->asic_type >= CHIP_BONAIRE &&
> +           plane->type != DRM_PLANE_TYPE_CURSOR)
> +               drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
> +                                                  supported_rotations);
> +
> +       drm_plane_helper_add(plane, &dm_plane_helper_funcs);
> +
> +#ifdef CONFIG_DRM_AMD_DC_HDR
> +       attach_color_mgmt_properties(dm, plane);
> +#endif
> +       /* Create (reset) the plane state */
> +       if (plane->funcs->reset)
> +               plane->funcs->reset(plane);
> +
> +       return 0;
> +}
> +
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
> new file mode 100644
> index 000000000000..95168c2cfa6f
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
> @@ -0,0 +1,73 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright 2022 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +
> +#ifndef __AMDGPU_DM_PLANE_H__
> +#define __AMDGPU_DM_PLANE_H__
> +
> +#include "dc.h"
> +
> +void handle_cursor_update(struct drm_plane *plane,
> +                         struct drm_plane_state *old_plane_state);
> +
> +int fill_dc_scaling_info(struct amdgpu_device *adev,
> +                        const struct drm_plane_state *state,
> +                        struct dc_scaling_info *scaling_info);
> +
> +void get_min_max_dc_plane_scaling(struct drm_device *dev,
> +                                 struct drm_framebuffer *fb,
> +                                 int *min_downscale, int *max_upscale);
> +
> +int dm_plane_helper_check_state(struct drm_plane_state *state,
> +                               struct drm_crtc_state *new_crtc_state);
> +
> +bool modifier_has_dcc(uint64_t modifier);
> +
> +unsigned int modifier_gfx9_swizzle_mode(uint64_t modifier);
> +
> +int fill_plane_buffer_attributes(struct amdgpu_device *adev,
> +                                const struct amdgpu_framebuffer *afb,
> +                                const enum surface_pixel_format format,
> +                                const enum dc_rotation_angle rotation,
> +                                const uint64_t tiling_flags,
> +                                union dc_tiling_info *tiling_info,
> +                                struct plane_size *plane_size,
> +                                struct dc_plane_dcc_param *dcc,
> +                                struct dc_plane_address *address,
> +                                bool tmz_surface,
> +                                bool force_disable_dcc);
> +
> +int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
> +                        struct drm_plane *plane,
> +                        unsigned long possible_crtcs,
> +                        const struct dc_plane_cap *plane_cap);
> +
> +const struct drm_format_info *amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
> +
> +void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
> +                                   bool *per_pixel_alpha, bool *pre_multiplied_alpha,
> +                                   bool *global_alpha, int *global_alpha_value);
> +
> +#endif
> --
> 2.37.0
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 08/31] drm/amd/display: Create a file dedicated to planes
  2022-07-18 14:29   ` Alex Deucher
@ 2022-07-18 14:55     ` Rodrigo Siqueira
  0 siblings, 0 replies; 36+ messages in thread
From: Rodrigo Siqueira @ 2022-07-18 14:55 UTC (permalink / raw)
  To: Alex Deucher
  Cc: Stylon Wang, Alan Liu, Leo (Sunpeng) Li, Bhawanpreet Lakha,
	Qingqing Zhuo, Roman Li, amd-gfx list, Solomon Chiu,
	Aurabindo Pillai, Wayne Lin, Wentland, Harry, Gutierrez, Agustin,
	Kotarac, Pavle


On 7/18/22 10:29, Alex Deucher wrote:
> On Sat, Jul 16, 2022 at 10:38 AM Rodrigo Siqueira
> <Rodrigo.Siqueira@amd.com> wrote:
>> [Why]
>> The amdgpu_dm file contains most of the code that works as an interface
>> between DRM API and DC. As a result, this file becomes very large since
>> it comprises multiple abstractions such as plane manipulation.
>>
>> [How]
>> This commit extracts the plane code to its specific file named
>> amdgpu_dm_plane. This change does not change anything inside the
>> functions; the only exception is converting some static functions to a
>> global function.
>>
>> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
>> Acked-by: Alan Liu <HaoPing.Liu@amd.com>
>> Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
>> ---
>>   .../gpu/drm/amd/display/amdgpu_dm/Makefile    |    7 +-
>>   .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2135 +++--------------
>>   .../amd/display/amdgpu_dm/amdgpu_dm_plane.c   | 1637 +++++++++++++
>>   .../amd/display/amdgpu_dm/amdgpu_dm_plane.h   |   73 +
>>   4 files changed, 2057 insertions(+), 1795 deletions(-)
>>   create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>>   create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
>>
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
>> index 718e123a3230..ec559ea902a3 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
>> @@ -25,7 +25,12 @@
>>
>>
>>
>> -AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o amdgpu_dm_color.o
>> +AMDGPUDM = \
>> +       amdgpu_dm.o \
>> +       amdgpu_dm_plane.o \
>> +       amdgpu_dm_irq.o \
>> +       amdgpu_dm_mst_types.o \
>> +       amdgpu_dm_color.o
>>
>>   ifdef CONFIG_DRM_AMD_DC_DCN
>>   AMDGPUDM += dc_fpu.o
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> index dae998e014b0..ceac70e93ece 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
>> @@ -46,6 +46,7 @@
>>   #include "amdgpu_ucode.h"
>>   #include "atom.h"
>>   #include "amdgpu_dm.h"
>> +#include "amdgpu_dm_plane.h"
>>   #ifdef CONFIG_DRM_AMD_DC_HDCP
>>   #include "amdgpu_dm_hdcp.h"
>>   #include <drm/drm_hdcp.h>
>> @@ -203,10 +204,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev);
>>   /* 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_plane_init(struct amdgpu_display_manager *dm,
>> -                               struct drm_plane *plane,
>> -                               unsigned long possible_crtcs,
>> -                               const struct dc_plane_cap *plane_cap);
>>   static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
>>                                 struct drm_plane *plane,
>>                                 uint32_t link_index);
>> @@ -225,12 +222,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
>>   static int amdgpu_dm_atomic_check(struct drm_device *dev,
>>                                    struct drm_atomic_state *state);
>>
>> -static void handle_cursor_update(struct drm_plane *plane,
>> -                                struct drm_plane_state *old_plane_state);
>> -
>> -static const struct drm_format_info *
>> -amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
>> -
>>   static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector);
>>   static void handle_hpd_rx_irq(void *param);
>>
>> @@ -4315,11 +4306,11 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
>>          case IP_VERSION(3, 0, 0):
>>          case IP_VERSION(3, 1, 2):
>>          case IP_VERSION(3, 1, 3):
>> -       case IP_VERSION(3, 1, 4):
>>          case IP_VERSION(3, 1, 5):
>>          case IP_VERSION(3, 1, 6):
>>          case IP_VERSION(3, 2, 0):
>>          case IP_VERSION(3, 2, 1):
>> +       case IP_VERSION(3, 1, 4):
>>          case IP_VERSION(2, 1, 0):
> This hunk should probably be dropped?  It's unrelated to the patch and
> makes the ordering incorrect.
Nice catch!
I think it was a merge conflict issue.
I'll fix it before merging this change.
Thanks.
Siqueira
>
> Alex
>
>>                  if (register_outbox_irq_handlers(dm->adev)) {
>>                          DRM_ERROR("DM: Failed to initialize IRQ\n");
>> @@ -4707,1104 +4698,222 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
>>          .destroy = amdgpu_dm_encoder_destroy,
>>   };
>>
>> -
>> -static void get_min_max_dc_plane_scaling(struct drm_device *dev,
>> -                                        struct drm_framebuffer *fb,
>> -                                        int *min_downscale, int *max_upscale)
>> -{
>> -       struct amdgpu_device *adev = drm_to_adev(dev);
>> -       struct dc *dc = adev->dm.dc;
>> -       /* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
>> -       struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
>> -
>> -       switch (fb->format->format) {
>> -       case DRM_FORMAT_P010:
>> -       case DRM_FORMAT_NV12:
>> -       case DRM_FORMAT_NV21:
>> -               *max_upscale = plane_cap->max_upscale_factor.nv12;
>> -               *min_downscale = plane_cap->max_downscale_factor.nv12;
>> -               break;
>> -
>> -       case DRM_FORMAT_XRGB16161616F:
>> -       case DRM_FORMAT_ARGB16161616F:
>> -       case DRM_FORMAT_XBGR16161616F:
>> -       case DRM_FORMAT_ABGR16161616F:
>> -               *max_upscale = plane_cap->max_upscale_factor.fp16;
>> -               *min_downscale = plane_cap->max_downscale_factor.fp16;
>> -               break;
>> -
>> -       default:
>> -               *max_upscale = plane_cap->max_upscale_factor.argb8888;
>> -               *min_downscale = plane_cap->max_downscale_factor.argb8888;
>> -               break;
>> -       }
>> -
>> -       /*
>> -        * A factor of 1 in the plane_cap means to not allow scaling, ie. use a
>> -        * scaling factor of 1.0 == 1000 units.
>> -        */
>> -       if (*max_upscale == 1)
>> -               *max_upscale = 1000;
>> -
>> -       if (*min_downscale == 1)
>> -               *min_downscale = 1000;
>> -}
>> -
>> -
>> -static int fill_dc_scaling_info(struct amdgpu_device *adev,
>> -                               const struct drm_plane_state *state,
>> -                               struct dc_scaling_info *scaling_info)
>> +static int
>> +fill_plane_color_attributes(const struct drm_plane_state *plane_state,
>> +                           const enum surface_pixel_format format,
>> +                           enum dc_color_space *color_space)
>>   {
>> -       int scale_w, scale_h, min_downscale, max_upscale;
>> -
>> -       memset(scaling_info, 0, sizeof(*scaling_info));
>> -
>> -       /* Source is fixed 16.16 but we ignore mantissa for now... */
>> -       scaling_info->src_rect.x = state->src_x >> 16;
>> -       scaling_info->src_rect.y = state->src_y >> 16;
>> +       bool full_range;
>>
>> -       /*
>> -        * For reasons we don't (yet) fully understand a non-zero
>> -        * src_y coordinate into an NV12 buffer can cause a
>> -        * system hang on DCN1x.
>> -        * To avoid hangs (and maybe be overly cautious)
>> -        * let's reject both non-zero src_x and src_y.
>> -        *
>> -        * We currently know of only one use-case to reproduce a
>> -        * scenario with non-zero src_x and src_y for NV12, which
>> -        * is to gesture the YouTube Android app into full screen
>> -        * on ChromeOS.
>> -        */
>> -       if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) ||
>> -           (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) &&
>> -           (state->fb && state->fb->format->format == DRM_FORMAT_NV12 &&
>> -           (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0)))
>> -               return -EINVAL;
>> +       *color_space = COLOR_SPACE_SRGB;
>>
>> -       scaling_info->src_rect.width = state->src_w >> 16;
>> -       if (scaling_info->src_rect.width == 0)
>> -               return -EINVAL;
>> +       /* DRM color properties only affect non-RGB formats. */
>> +       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
>> +               return 0;
>>
>> -       scaling_info->src_rect.height = state->src_h >> 16;
>> -       if (scaling_info->src_rect.height == 0)
>> -               return -EINVAL;
>> +       full_range = (plane_state->color_range == DRM_COLOR_YCBCR_FULL_RANGE);
>>
>> -       scaling_info->dst_rect.x = state->crtc_x;
>> -       scaling_info->dst_rect.y = state->crtc_y;
>> +       switch (plane_state->color_encoding) {
>> +       case DRM_COLOR_YCBCR_BT601:
>> +               if (full_range)
>> +                       *color_space = COLOR_SPACE_YCBCR601;
>> +               else
>> +                       *color_space = COLOR_SPACE_YCBCR601_LIMITED;
>> +               break;
>>
>> -       if (state->crtc_w == 0)
>> -               return -EINVAL;
>> +       case DRM_COLOR_YCBCR_BT709:
>> +               if (full_range)
>> +                       *color_space = COLOR_SPACE_YCBCR709;
>> +               else
>> +                       *color_space = COLOR_SPACE_YCBCR709_LIMITED;
>> +               break;
>>
>> -       scaling_info->dst_rect.width = state->crtc_w;
>> +       case DRM_COLOR_YCBCR_BT2020:
>> +               if (full_range)
>> +                       *color_space = COLOR_SPACE_2020_YCBCR;
>> +               else
>> +                       return -EINVAL;
>> +               break;
>>
>> -       if (state->crtc_h == 0)
>> +       default:
>>                  return -EINVAL;
>> -
>> -       scaling_info->dst_rect.height = state->crtc_h;
>> -
>> -       /* DRM doesn't specify clipping on destination output. */
>> -       scaling_info->clip_rect = scaling_info->dst_rect;
>> -
>> -       /* Validate scaling per-format with DC plane caps */
>> -       if (state->plane && state->plane->dev && state->fb) {
>> -               get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
>> -                                            &min_downscale, &max_upscale);
>> -       } else {
>> -               min_downscale = 250;
>> -               max_upscale = 16000;
>>          }
>>
>> -       scale_w = scaling_info->dst_rect.width * 1000 /
>> -                 scaling_info->src_rect.width;
>> -
>> -       if (scale_w < min_downscale || scale_w > max_upscale)
>> -               return -EINVAL;
>> -
>> -       scale_h = scaling_info->dst_rect.height * 1000 /
>> -                 scaling_info->src_rect.height;
>> -
>> -       if (scale_h < min_downscale || scale_h > max_upscale)
>> -               return -EINVAL;
>> -
>> -       /*
>> -        * The "scaling_quality" can be ignored for now, quality = 0 has DC
>> -        * assume reasonable defaults based on the format.
>> -        */
>> -
>>          return 0;
>>   }
>>
>> -static void
>> -fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info,
>> -                                uint64_t tiling_flags)
>> -{
>> -       /* Fill GFX8 params */
>> -       if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
>> -               unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
>> -
>> -               bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
>> -               bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
>> -               mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
>> -               tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
>> -               num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
>> -
>> -               /* XXX fix me for VI */
>> -               tiling_info->gfx8.num_banks = num_banks;
>> -               tiling_info->gfx8.array_mode =
>> -                               DC_ARRAY_2D_TILED_THIN1;
>> -               tiling_info->gfx8.tile_split = tile_split;
>> -               tiling_info->gfx8.bank_width = bankw;
>> -               tiling_info->gfx8.bank_height = bankh;
>> -               tiling_info->gfx8.tile_aspect = mtaspect;
>> -               tiling_info->gfx8.tile_mode =
>> -                               DC_ADDR_SURF_MICRO_TILING_DISPLAY;
>> -       } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
>> -                       == DC_ARRAY_1D_TILED_THIN1) {
>> -               tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
>> -       }
>> -
>> -       tiling_info->gfx8.pipe_config =
>> -                       AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
>> -}
>> -
>> -static void
>> -fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev,
>> -                                 union dc_tiling_info *tiling_info)
>> -{
>> -       tiling_info->gfx9.num_pipes =
>> -               adev->gfx.config.gb_addr_config_fields.num_pipes;
>> -       tiling_info->gfx9.num_banks =
>> -               adev->gfx.config.gb_addr_config_fields.num_banks;
>> -       tiling_info->gfx9.pipe_interleave =
>> -               adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
>> -       tiling_info->gfx9.num_shader_engines =
>> -               adev->gfx.config.gb_addr_config_fields.num_se;
>> -       tiling_info->gfx9.max_compressed_frags =
>> -               adev->gfx.config.gb_addr_config_fields.max_compress_frags;
>> -       tiling_info->gfx9.num_rb_per_se =
>> -               adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
>> -       tiling_info->gfx9.shaderEnable = 1;
>> -       if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
>> -               tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;
>> -}
>> -
>>   static int
>> -validate_dcc(struct amdgpu_device *adev,
>> -            const enum surface_pixel_format format,
>> -            const enum dc_rotation_angle rotation,
>> -            const union dc_tiling_info *tiling_info,
>> -            const struct dc_plane_dcc_param *dcc,
>> -            const struct dc_plane_address *address,
>> -            const struct plane_size *plane_size)
>> +fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
>> +                           const struct drm_plane_state *plane_state,
>> +                           const uint64_t tiling_flags,
>> +                           struct dc_plane_info *plane_info,
>> +                           struct dc_plane_address *address,
>> +                           bool tmz_surface,
>> +                           bool force_disable_dcc)
>>   {
>> -       struct dc *dc = adev->dm.dc;
>> -       struct dc_dcc_surface_param input;
>> -       struct dc_surface_dcc_cap output;
>> -
>> -       memset(&input, 0, sizeof(input));
>> -       memset(&output, 0, sizeof(output));
>> +       const struct drm_framebuffer *fb = plane_state->fb;
>> +       const struct amdgpu_framebuffer *afb =
>> +               to_amdgpu_framebuffer(plane_state->fb);
>> +       int ret;
>>
>> -       if (!dcc->enable)
>> -               return 0;
>> +       memset(plane_info, 0, sizeof(*plane_info));
>>
>> -       if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
>> -           !dc->cap_funcs.get_dcc_compression_cap)
>> +       switch (fb->format->format) {
>> +       case DRM_FORMAT_C8:
>> +               plane_info->format =
>> +                       SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
>> +               break;
>> +       case DRM_FORMAT_RGB565:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
>> +               break;
>> +       case DRM_FORMAT_XRGB8888:
>> +       case DRM_FORMAT_ARGB8888:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
>> +               break;
>> +       case DRM_FORMAT_XRGB2101010:
>> +       case DRM_FORMAT_ARGB2101010:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
>> +               break;
>> +       case DRM_FORMAT_XBGR2101010:
>> +       case DRM_FORMAT_ABGR2101010:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
>> +               break;
>> +       case DRM_FORMAT_XBGR8888:
>> +       case DRM_FORMAT_ABGR8888:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR8888;
>> +               break;
>> +       case DRM_FORMAT_NV21:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
>> +               break;
>> +       case DRM_FORMAT_NV12:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
>> +               break;
>> +       case DRM_FORMAT_P010:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
>> +               break;
>> +       case DRM_FORMAT_XRGB16161616F:
>> +       case DRM_FORMAT_ARGB16161616F:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
>> +               break;
>> +       case DRM_FORMAT_XBGR16161616F:
>> +       case DRM_FORMAT_ABGR16161616F:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
>> +               break;
>> +       case DRM_FORMAT_XRGB16161616:
>> +       case DRM_FORMAT_ARGB16161616:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616;
>> +               break;
>> +       case DRM_FORMAT_XBGR16161616:
>> +       case DRM_FORMAT_ABGR16161616:
>> +               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616;
>> +               break;
>> +       default:
>> +               DRM_ERROR(
>> +                       "Unsupported screen format %p4cc\n",
>> +                       &fb->format->format);
>>                  return -EINVAL;
>> +       }
>>
>> -       input.format = format;
>> -       input.surface_size.width = plane_size->surface_size.width;
>> -       input.surface_size.height = plane_size->surface_size.height;
>> -       input.swizzle_mode = tiling_info->gfx9.swizzle;
>> -
>> -       if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180)
>> -               input.scan = SCAN_DIRECTION_HORIZONTAL;
>> -       else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270)
>> -               input.scan = SCAN_DIRECTION_VERTICAL;
>> +       switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
>> +       case DRM_MODE_ROTATE_0:
>> +               plane_info->rotation = ROTATION_ANGLE_0;
>> +               break;
>> +       case DRM_MODE_ROTATE_90:
>> +               plane_info->rotation = ROTATION_ANGLE_90;
>> +               break;
>> +       case DRM_MODE_ROTATE_180:
>> +               plane_info->rotation = ROTATION_ANGLE_180;
>> +               break;
>> +       case DRM_MODE_ROTATE_270:
>> +               plane_info->rotation = ROTATION_ANGLE_270;
>> +               break;
>> +       default:
>> +               plane_info->rotation = ROTATION_ANGLE_0;
>> +               break;
>> +       }
>>
>> -       if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
>> -               return -EINVAL;
>>
>> -       if (!output.capable)
>> -               return -EINVAL;
>> +       plane_info->visible = true;
>> +       plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE;
>>
>> -       if (dcc->independent_64b_blks == 0 &&
>> -           output.grph.rgb.independent_64b_blks != 0)
>> -               return -EINVAL;
>> +       plane_info->layer_index = 0;
>>
>> -       return 0;
>> -}
>> +       ret = fill_plane_color_attributes(plane_state, plane_info->format,
>> +                                         &plane_info->color_space);
>> +       if (ret)
>> +               return ret;
>>
>> -static bool
>> -modifier_has_dcc(uint64_t modifier)
>> -{
>> -       return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
>> -}
>> +       ret = fill_plane_buffer_attributes(adev, afb, plane_info->format,
>> +                                          plane_info->rotation, tiling_flags,
>> +                                          &plane_info->tiling_info,
>> +                                          &plane_info->plane_size,
>> +                                          &plane_info->dcc, address,
>> +                                          tmz_surface, force_disable_dcc);
>> +       if (ret)
>> +               return ret;
>>
>> -static unsigned
>> -modifier_gfx9_swizzle_mode(uint64_t modifier)
>> -{
>> -       if (modifier == DRM_FORMAT_MOD_LINEAR)
>> -               return 0;
>> +       fill_blending_from_plane_state(
>> +               plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
>> +               &plane_info->global_alpha, &plane_info->global_alpha_value);
>>
>> -       return AMD_FMT_MOD_GET(TILE, modifier);
>> +       return 0;
>>   }
>>
>> -static const struct drm_format_info *
>> -amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>> +static int fill_dc_plane_attributes(struct amdgpu_device *adev,
>> +                                   struct dc_plane_state *dc_plane_state,
>> +                                   struct drm_plane_state *plane_state,
>> +                                   struct drm_crtc_state *crtc_state)
>>   {
>> -       return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]);
>> -}
>> +       struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
>> +       struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb;
>> +       struct dc_scaling_info scaling_info;
>> +       struct dc_plane_info plane_info;
>> +       int ret;
>> +       bool force_disable_dcc = false;
>>
>> -static void
>> -fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev,
>> -                                   union dc_tiling_info *tiling_info,
>> -                                   uint64_t modifier)
>> -{
>> -       unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
>> -       unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
>> -       unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier);
>> -       unsigned int pipes_log2;
>> +       ret = fill_dc_scaling_info(adev, plane_state, &scaling_info);
>> +       if (ret)
>> +               return ret;
>>
>> -       pipes_log2 = min(5u, mod_pipe_xor_bits);
>> +       dc_plane_state->src_rect = scaling_info.src_rect;
>> +       dc_plane_state->dst_rect = scaling_info.dst_rect;
>> +       dc_plane_state->clip_rect = scaling_info.clip_rect;
>> +       dc_plane_state->scaling_quality = scaling_info.scaling_quality;
>>
>> -       fill_gfx9_tiling_info_from_device(adev, tiling_info);
>> +       force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
>> +       ret = fill_dc_plane_info_and_addr(adev, plane_state,
>> +                                         afb->tiling_flags,
>> +                                         &plane_info,
>> +                                         &dc_plane_state->address,
>> +                                         afb->tmz_surface,
>> +                                         force_disable_dcc);
>> +       if (ret)
>> +               return ret;
>>
>> -       if (!IS_AMD_FMT_MOD(modifier))
>> -               return;
>> +       dc_plane_state->format = plane_info.format;
>> +       dc_plane_state->color_space = plane_info.color_space;
>> +       dc_plane_state->format = plane_info.format;
>> +       dc_plane_state->plane_size = plane_info.plane_size;
>> +       dc_plane_state->rotation = plane_info.rotation;
>> +       dc_plane_state->horizontal_mirror = plane_info.horizontal_mirror;
>> +       dc_plane_state->stereo_format = plane_info.stereo_format;
>> +       dc_plane_state->tiling_info = plane_info.tiling_info;
>> +       dc_plane_state->visible = plane_info.visible;
>> +       dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
>> +       dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
>> +       dc_plane_state->global_alpha = plane_info.global_alpha;
>> +       dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
>> +       dc_plane_state->dcc = plane_info.dcc;
>> +       dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
>> +       dc_plane_state->flip_int_enabled = true;
>>
>> -       tiling_info->gfx9.num_pipes = 1u << pipes_log2;
>> -       tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2);
>> -
>> -       if (adev->family >= AMDGPU_FAMILY_NV) {
>> -               tiling_info->gfx9.num_pkrs = 1u << pkrs_log2;
>> -       } else {
>> -               tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits;
>> -
>> -               /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */
>> -       }
>> -}
>> -
>> -enum dm_micro_swizzle {
>> -       MICRO_SWIZZLE_Z = 0,
>> -       MICRO_SWIZZLE_S = 1,
>> -       MICRO_SWIZZLE_D = 2,
>> -       MICRO_SWIZZLE_R = 3
>> -};
>> -
>> -static bool dm_plane_format_mod_supported(struct drm_plane *plane,
>> -                                         uint32_t format,
>> -                                         uint64_t modifier)
>> -{
>> -       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> -       const struct drm_format_info *info = drm_format_info(format);
>> -       int i;
>> -
>> -       enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3;
>> -
>> -       if (!info)
>> -               return false;
>> -
>> -       /*
>> -        * We always have to allow these modifiers:
>> -        * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
>> -        * 2. Not passing any modifiers is the same as explicitly passing INVALID.
>> -        */
>> -       if (modifier == DRM_FORMAT_MOD_LINEAR ||
>> -           modifier == DRM_FORMAT_MOD_INVALID) {
>> -               return true;
>> -       }
>> -
>> -       /* Check that the modifier is on the list of the plane's supported modifiers. */
>> -       for (i = 0; i < plane->modifier_count; i++) {
>> -               if (modifier == plane->modifiers[i])
>> -                       break;
>> -       }
>> -       if (i == plane->modifier_count)
>> -               return false;
>> -
>> -       /*
>> -        * For D swizzle the canonical modifier depends on the bpp, so check
>> -        * it here.
>> -        */
>> -       if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 &&
>> -           adev->family >= AMDGPU_FAMILY_NV) {
>> -               if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4)
>> -                       return false;
>> -       }
>> -
>> -       if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D &&
>> -           info->cpp[0] < 8)
>> -               return false;
>> -
>> -       if (modifier_has_dcc(modifier)) {
>> -               /* Per radeonsi comments 16/64 bpp are more complicated. */
>> -               if (info->cpp[0] != 4)
>> -                       return false;
>> -               /* We support multi-planar formats, but not when combined with
>> -                * additional DCC metadata planes. */
>> -               if (info->num_planes > 1)
>> -                       return false;
>> -       }
>> -
>> -       return true;
>> -}
>> -
>> -static void
>> -add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod)
>> -{
>> -       if (!*mods)
>> -               return;
>> -
>> -       if (*cap - *size < 1) {
>> -               uint64_t new_cap = *cap * 2;
>> -               uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL);
>> -
>> -               if (!new_mods) {
>> -                       kfree(*mods);
>> -                       *mods = NULL;
>> -                       return;
>> -               }
>> -
>> -               memcpy(new_mods, *mods, sizeof(uint64_t) * *size);
>> -               kfree(*mods);
>> -               *mods = new_mods;
>> -               *cap = new_cap;
>> -       }
>> -
>> -       (*mods)[*size] = mod;
>> -       *size += 1;
>> -}
>> -
>> -static void
>> -add_gfx9_modifiers(const struct amdgpu_device *adev,
>> -                  uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> -{
>> -       int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
>> -       int pipe_xor_bits = min(8, pipes +
>> -                               ilog2(adev->gfx.config.gb_addr_config_fields.num_se));
>> -       int bank_xor_bits = min(8 - pipe_xor_bits,
>> -                               ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));
>> -       int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +
>> -                ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);
>> -
>> -
>> -       if (adev->family == AMDGPU_FAMILY_RV) {
>> -               /* Raven2 and later */
>> -               bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81;
>> -
>> -               /*
>> -                * No _D DCC swizzles yet because we only allow 32bpp, which
>> -                * doesn't support _D on DCN
>> -                */
>> -
>> -               if (has_constant_encode) {
>> -                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> -                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> -                                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> -                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));
>> -               }
>> -
>> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> -                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> -                           AMD_FMT_MOD_SET(DCC, 1) |
>> -                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> -                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0));
>> -
>> -               if (has_constant_encode) {
>> -                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> -                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> -                                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> -
>> -                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                                   AMD_FMT_MOD_SET(RB, rb) |
>> -                                   AMD_FMT_MOD_SET(PIPE, pipes));
>> -               }
>> -
>> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> -                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> -                           AMD_FMT_MOD_SET(DCC, 1) |
>> -                           AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> -                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> -                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) |
>> -                           AMD_FMT_MOD_SET(RB, rb) |
>> -                           AMD_FMT_MOD_SET(PIPE, pipes));
>> -       }
>> -
>> -       /*
>> -        * Only supported for 64bpp on Raven, will be filtered on format in
>> -        * dm_plane_format_mod_supported.
>> -        */
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
>> -
>> -       if (adev->family == AMDGPU_FAMILY_RV) {
>> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> -                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
>> -       }
>> -
>> -       /*
>> -        * Only supported for 64bpp on Raven, will be filtered on format in
>> -        * dm_plane_format_mod_supported.
>> -        */
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> -
>> -       if (adev->family == AMDGPU_FAMILY_RV) {
>> -               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
>> -                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> -       }
>> -}
>> -
>> -static void
>> -add_gfx10_1_modifiers(const struct amdgpu_device *adev,
>> -                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> -{
>> -       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
>> -
>> -
>> -       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> -}
>> -
>> -static void
>> -add_gfx10_3_modifiers(const struct amdgpu_device *adev,
>> -                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> -{
>> -       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
>> -       int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs);
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> -                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> -                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> -                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> -                   AMD_FMT_MOD_SET(DCC, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> -                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(PACKERS, pkrs));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> -                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                   AMD_FMT_MOD_SET(PACKERS, pkrs));
>> -
>> -       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
>> -                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> -}
>> -
>> -static void
>> -add_gfx11_modifiers(struct amdgpu_device *adev,
>> -                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> -{
>> -       int num_pipes = 0;
>> -       int pipe_xor_bits = 0;
>> -       int num_pkrs = 0;
>> -       int pkrs = 0;
>> -       u32 gb_addr_config;
>> -       u8 i = 0;
>> -       unsigned swizzle_r_x;
>> -       uint64_t modifier_r_x;
>> -       uint64_t modifier_dcc_best;
>> -       uint64_t modifier_dcc_4k;
>> -
>> -       /* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from
>> -        * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes} */
>> -       gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG);
>> -       ASSERT(gb_addr_config != 0);
>> -
>> -       num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS);
>> -       pkrs = ilog2(num_pkrs);
>> -       num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES);
>> -       pipe_xor_bits = ilog2(num_pipes);
>> -
>> -       for (i = 0; i < 2; i++) {
>> -               /* Insert the best one first. */
>> -               /* R_X swizzle modes are the best for rendering and DCC requires them. */
>> -               if (num_pipes > 16)
>> -                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : AMD_FMT_MOD_TILE_GFX9_64K_R_X;
>> -               else
>> -                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX9_64K_R_X : AMD_FMT_MOD_TILE_GFX11_256K_R_X;
>> -
>> -               modifier_r_x = AMD_FMT_MOD |
>> -                              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
>> -                              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> -                              AMD_FMT_MOD_SET(TILE, swizzle_r_x) |
>> -                              AMD_FMT_MOD_SET(PACKERS, pkrs);
>> -
>> -               /* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */
>> -               modifier_dcc_best = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) |
>> -                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> -                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B);
>> -
>> -               /* DCC settings for 4K and greater resolutions. (required by display hw) */
>> -               modifier_dcc_4k = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
>> -                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> -                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> -                                 AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B);
>> -
>> -               add_modifier(mods, size, capacity, modifier_dcc_best);
>> -               add_modifier(mods, size, capacity, modifier_dcc_4k);
>> -
>> -               add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1));
>> -               add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1));
>> -
>> -               add_modifier(mods, size, capacity, modifier_r_x);
>> -       }
>> -
>> -       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> -             AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
>> -                        AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D));
>> -}
>> -
>> -static int
>> -get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods)
>> -{
>> -       uint64_t size = 0, capacity = 128;
>> -       *mods = NULL;
>> -
>> -       /* We have not hooked up any pre-GFX9 modifiers. */
>> -       if (adev->family < AMDGPU_FAMILY_AI)
>> -               return 0;
>> -
>> -       *mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL);
>> -
>> -       if (plane_type == DRM_PLANE_TYPE_CURSOR) {
>> -               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
>> -               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
>> -               return *mods ? 0 : -ENOMEM;
>> -       }
>> -
>> -       switch (adev->family) {
>> -       case AMDGPU_FAMILY_AI:
>> -       case AMDGPU_FAMILY_RV:
>> -               add_gfx9_modifiers(adev, mods, &size, &capacity);
>> -               break;
>> -       case AMDGPU_FAMILY_NV:
>> -       case AMDGPU_FAMILY_VGH:
>> -       case AMDGPU_FAMILY_YC:
>> -       case AMDGPU_FAMILY_GC_10_3_6:
>> -       case AMDGPU_FAMILY_GC_10_3_7:
>> -               if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
>> -                       add_gfx10_3_modifiers(adev, mods, &size, &capacity);
>> -               else
>> -                       add_gfx10_1_modifiers(adev, mods, &size, &capacity);
>> -               break;
>> -       case AMDGPU_FAMILY_GC_11_0_0:
>> -       case AMDGPU_FAMILY_GC_11_0_2:
>> -               add_gfx11_modifiers(adev, mods, &size, &capacity);
>> -               break;
>> -       }
>> -
>> -       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
>> -
>> -       /* INVALID marks the end of the list. */
>> -       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
>> -
>> -       if (!*mods)
>> -               return -ENOMEM;
>> -
>> -       return 0;
>> -}
>> -
>> -static int
>> -fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
>> -                                         const struct amdgpu_framebuffer *afb,
>> -                                         const enum surface_pixel_format format,
>> -                                         const enum dc_rotation_angle rotation,
>> -                                         const struct plane_size *plane_size,
>> -                                         union dc_tiling_info *tiling_info,
>> -                                         struct dc_plane_dcc_param *dcc,
>> -                                         struct dc_plane_address *address,
>> -                                         const bool force_disable_dcc)
>> -{
>> -       const uint64_t modifier = afb->base.modifier;
>> -       int ret = 0;
>> -
>> -       fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
>> -       tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
>> -
>> -       if (modifier_has_dcc(modifier) && !force_disable_dcc) {
>> -               uint64_t dcc_address = afb->address + afb->base.offsets[1];
>> -               bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
>> -               bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
>> -
>> -               dcc->enable = 1;
>> -               dcc->meta_pitch = afb->base.pitches[1];
>> -               dcc->independent_64b_blks = independent_64b_blks;
>> -               if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
>> -                       if (independent_64b_blks && independent_128b_blks)
>> -                               dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl;
>> -                       else if (independent_128b_blks)
>> -                               dcc->dcc_ind_blk = hubp_ind_block_128b;
>> -                       else if (independent_64b_blks && !independent_128b_blks)
>> -                               dcc->dcc_ind_blk = hubp_ind_block_64b;
>> -                       else
>> -                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
>> -               } else {
>> -                       if (independent_64b_blks)
>> -                               dcc->dcc_ind_blk = hubp_ind_block_64b;
>> -                       else
>> -                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
>> -               }
>> -
>> -               address->grph.meta_addr.low_part = lower_32_bits(dcc_address);
>> -               address->grph.meta_addr.high_part = upper_32_bits(dcc_address);
>> -       }
>> -
>> -       ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
>> -       if (ret)
>> -               drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
>> -
>> -       return ret;
>> -}
>> -
>> -static int
>> -fill_plane_buffer_attributes(struct amdgpu_device *adev,
>> -                            const struct amdgpu_framebuffer *afb,
>> -                            const enum surface_pixel_format format,
>> -                            const enum dc_rotation_angle rotation,
>> -                            const uint64_t tiling_flags,
>> -                            union dc_tiling_info *tiling_info,
>> -                            struct plane_size *plane_size,
>> -                            struct dc_plane_dcc_param *dcc,
>> -                            struct dc_plane_address *address,
>> -                            bool tmz_surface,
>> -                            bool force_disable_dcc)
>> -{
>> -       const struct drm_framebuffer *fb = &afb->base;
>> -       int ret;
>> -
>> -       memset(tiling_info, 0, sizeof(*tiling_info));
>> -       memset(plane_size, 0, sizeof(*plane_size));
>> -       memset(dcc, 0, sizeof(*dcc));
>> -       memset(address, 0, sizeof(*address));
>> -
>> -       address->tmz_surface = tmz_surface;
>> -
>> -       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
>> -               uint64_t addr = afb->address + fb->offsets[0];
>> -
>> -               plane_size->surface_size.x = 0;
>> -               plane_size->surface_size.y = 0;
>> -               plane_size->surface_size.width = fb->width;
>> -               plane_size->surface_size.height = fb->height;
>> -               plane_size->surface_pitch =
>> -                       fb->pitches[0] / fb->format->cpp[0];
>> -
>> -               address->type = PLN_ADDR_TYPE_GRAPHICS;
>> -               address->grph.addr.low_part = lower_32_bits(addr);
>> -               address->grph.addr.high_part = upper_32_bits(addr);
>> -       } else if (format < SURFACE_PIXEL_FORMAT_INVALID) {
>> -               uint64_t luma_addr = afb->address + fb->offsets[0];
>> -               uint64_t chroma_addr = afb->address + fb->offsets[1];
>> -
>> -               plane_size->surface_size.x = 0;
>> -               plane_size->surface_size.y = 0;
>> -               plane_size->surface_size.width = fb->width;
>> -               plane_size->surface_size.height = fb->height;
>> -               plane_size->surface_pitch =
>> -                       fb->pitches[0] / fb->format->cpp[0];
>> -
>> -               plane_size->chroma_size.x = 0;
>> -               plane_size->chroma_size.y = 0;
>> -               /* TODO: set these based on surface format */
>> -               plane_size->chroma_size.width = fb->width / 2;
>> -               plane_size->chroma_size.height = fb->height / 2;
>> -
>> -               plane_size->chroma_pitch =
>> -                       fb->pitches[1] / fb->format->cpp[1];
>> -
>> -               address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
>> -               address->video_progressive.luma_addr.low_part =
>> -                       lower_32_bits(luma_addr);
>> -               address->video_progressive.luma_addr.high_part =
>> -                       upper_32_bits(luma_addr);
>> -               address->video_progressive.chroma_addr.low_part =
>> -                       lower_32_bits(chroma_addr);
>> -               address->video_progressive.chroma_addr.high_part =
>> -                       upper_32_bits(chroma_addr);
>> -       }
>> -
>> -       if (adev->family >= AMDGPU_FAMILY_AI) {
>> -               ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format,
>> -                                                               rotation, plane_size,
>> -                                                               tiling_info, dcc,
>> -                                                               address,
>> -                                                               force_disable_dcc);
>> -               if (ret)
>> -                       return ret;
>> -       } else {
>> -               fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags);
>> -       }
>> -
>> -       return 0;
>> -}
>> -
>> -static void
>> -fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
>> -                              bool *per_pixel_alpha, bool *pre_multiplied_alpha,
>> -                              bool *global_alpha, int *global_alpha_value)
>> -{
>> -       *per_pixel_alpha = false;
>> -       *pre_multiplied_alpha = true;
>> -       *global_alpha = false;
>> -       *global_alpha_value = 0xff;
>> -
>> -       if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
>> -               return;
>> -
>> -       if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
>> -               plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
>> -               static const uint32_t alpha_formats[] = {
>> -                       DRM_FORMAT_ARGB8888,
>> -                       DRM_FORMAT_RGBA8888,
>> -                       DRM_FORMAT_ABGR8888,
>> -               };
>> -               uint32_t format = plane_state->fb->format->format;
>> -               unsigned int i;
>> -
>> -               for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
>> -                       if (format == alpha_formats[i]) {
>> -                               *per_pixel_alpha = true;
>> -                               break;
>> -                       }
>> -               }
>> -
>> -               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
>> -                       *pre_multiplied_alpha = false;
>> -       }
>> -
>> -       if (plane_state->alpha < 0xffff) {
>> -               *global_alpha = true;
>> -               *global_alpha_value = plane_state->alpha >> 8;
>> -       }
>> -}
>> -
>> -static int
>> -fill_plane_color_attributes(const struct drm_plane_state *plane_state,
>> -                           const enum surface_pixel_format format,
>> -                           enum dc_color_space *color_space)
>> -{
>> -       bool full_range;
>> -
>> -       *color_space = COLOR_SPACE_SRGB;
>> -
>> -       /* DRM color properties only affect non-RGB formats. */
>> -       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
>> -               return 0;
>> -
>> -       full_range = (plane_state->color_range == DRM_COLOR_YCBCR_FULL_RANGE);
>> -
>> -       switch (plane_state->color_encoding) {
>> -       case DRM_COLOR_YCBCR_BT601:
>> -               if (full_range)
>> -                       *color_space = COLOR_SPACE_YCBCR601;
>> -               else
>> -                       *color_space = COLOR_SPACE_YCBCR601_LIMITED;
>> -               break;
>> -
>> -       case DRM_COLOR_YCBCR_BT709:
>> -               if (full_range)
>> -                       *color_space = COLOR_SPACE_YCBCR709;
>> -               else
>> -                       *color_space = COLOR_SPACE_YCBCR709_LIMITED;
>> -               break;
>> -
>> -       case DRM_COLOR_YCBCR_BT2020:
>> -               if (full_range)
>> -                       *color_space = COLOR_SPACE_2020_YCBCR;
>> -               else
>> -                       return -EINVAL;
>> -               break;
>> -
>> -       default:
>> -               return -EINVAL;
>> -       }
>> -
>> -       return 0;
>> -}
>> -
>> -static int
>> -fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
>> -                           const struct drm_plane_state *plane_state,
>> -                           const uint64_t tiling_flags,
>> -                           struct dc_plane_info *plane_info,
>> -                           struct dc_plane_address *address,
>> -                           bool tmz_surface,
>> -                           bool force_disable_dcc)
>> -{
>> -       const struct drm_framebuffer *fb = plane_state->fb;
>> -       const struct amdgpu_framebuffer *afb =
>> -               to_amdgpu_framebuffer(plane_state->fb);
>> -       int ret;
>> -
>> -       memset(plane_info, 0, sizeof(*plane_info));
>> -
>> -       switch (fb->format->format) {
>> -       case DRM_FORMAT_C8:
>> -               plane_info->format =
>> -                       SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
>> -               break;
>> -       case DRM_FORMAT_RGB565:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
>> -               break;
>> -       case DRM_FORMAT_XRGB8888:
>> -       case DRM_FORMAT_ARGB8888:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
>> -               break;
>> -       case DRM_FORMAT_XRGB2101010:
>> -       case DRM_FORMAT_ARGB2101010:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
>> -               break;
>> -       case DRM_FORMAT_XBGR2101010:
>> -       case DRM_FORMAT_ABGR2101010:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
>> -               break;
>> -       case DRM_FORMAT_XBGR8888:
>> -       case DRM_FORMAT_ABGR8888:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR8888;
>> -               break;
>> -       case DRM_FORMAT_NV21:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
>> -               break;
>> -       case DRM_FORMAT_NV12:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
>> -               break;
>> -       case DRM_FORMAT_P010:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
>> -               break;
>> -       case DRM_FORMAT_XRGB16161616F:
>> -       case DRM_FORMAT_ARGB16161616F:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
>> -               break;
>> -       case DRM_FORMAT_XBGR16161616F:
>> -       case DRM_FORMAT_ABGR16161616F:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
>> -               break;
>> -       case DRM_FORMAT_XRGB16161616:
>> -       case DRM_FORMAT_ARGB16161616:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616;
>> -               break;
>> -       case DRM_FORMAT_XBGR16161616:
>> -       case DRM_FORMAT_ABGR16161616:
>> -               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616;
>> -               break;
>> -       default:
>> -               DRM_ERROR(
>> -                       "Unsupported screen format %p4cc\n",
>> -                       &fb->format->format);
>> -               return -EINVAL;
>> -       }
>> -
>> -       switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
>> -       case DRM_MODE_ROTATE_0:
>> -               plane_info->rotation = ROTATION_ANGLE_0;
>> -               break;
>> -       case DRM_MODE_ROTATE_90:
>> -               plane_info->rotation = ROTATION_ANGLE_90;
>> -               break;
>> -       case DRM_MODE_ROTATE_180:
>> -               plane_info->rotation = ROTATION_ANGLE_180;
>> -               break;
>> -       case DRM_MODE_ROTATE_270:
>> -               plane_info->rotation = ROTATION_ANGLE_270;
>> -               break;
>> -       default:
>> -               plane_info->rotation = ROTATION_ANGLE_0;
>> -               break;
>> -       }
>> -
>> -       plane_info->visible = true;
>> -       plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE;
>> -
>> -       plane_info->layer_index = 0;
>> -
>> -       ret = fill_plane_color_attributes(plane_state, plane_info->format,
>> -                                         &plane_info->color_space);
>> -       if (ret)
>> -               return ret;
>> -
>> -       ret = fill_plane_buffer_attributes(adev, afb, plane_info->format,
>> -                                          plane_info->rotation, tiling_flags,
>> -                                          &plane_info->tiling_info,
>> -                                          &plane_info->plane_size,
>> -                                          &plane_info->dcc, address, tmz_surface,
>> -                                          force_disable_dcc);
>> -       if (ret)
>> -               return ret;
>> -
>> -       fill_blending_from_plane_state(
>> -               plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
>> -               &plane_info->global_alpha, &plane_info->global_alpha_value);
>> -
>> -       return 0;
>> -}
>> -
>> -static int fill_dc_plane_attributes(struct amdgpu_device *adev,
>> -                                   struct dc_plane_state *dc_plane_state,
>> -                                   struct drm_plane_state *plane_state,
>> -                                   struct drm_crtc_state *crtc_state)
>> -{
>> -       struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
>> -       struct amdgpu_framebuffer *afb = (struct amdgpu_framebuffer *)plane_state->fb;
>> -       struct dc_scaling_info scaling_info;
>> -       struct dc_plane_info plane_info;
>> -       int ret;
>> -       bool force_disable_dcc = false;
>> -
>> -       ret = fill_dc_scaling_info(adev, plane_state, &scaling_info);
>> -       if (ret)
>> -               return ret;
>> -
>> -       dc_plane_state->src_rect = scaling_info.src_rect;
>> -       dc_plane_state->dst_rect = scaling_info.dst_rect;
>> -       dc_plane_state->clip_rect = scaling_info.clip_rect;
>> -       dc_plane_state->scaling_quality = scaling_info.scaling_quality;
>> -
>> -       force_disable_dcc = adev->asic_type == CHIP_RAVEN && adev->in_suspend;
>> -       ret = fill_dc_plane_info_and_addr(adev, plane_state,
>> -                                         afb->tiling_flags,
>> -                                         &plane_info,
>> -                                         &dc_plane_state->address,
>> -                                         afb->tmz_surface,
>> -                                         force_disable_dcc);
>> -       if (ret)
>> -               return ret;
>> -
>> -       dc_plane_state->format = plane_info.format;
>> -       dc_plane_state->color_space = plane_info.color_space;
>> -       dc_plane_state->format = plane_info.format;
>> -       dc_plane_state->plane_size = plane_info.plane_size;
>> -       dc_plane_state->rotation = plane_info.rotation;
>> -       dc_plane_state->horizontal_mirror = plane_info.horizontal_mirror;
>> -       dc_plane_state->stereo_format = plane_info.stereo_format;
>> -       dc_plane_state->tiling_info = plane_info.tiling_info;
>> -       dc_plane_state->visible = plane_info.visible;
>> -       dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
>> -       dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
>> -       dc_plane_state->global_alpha = plane_info.global_alpha;
>> -       dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
>> -       dc_plane_state->dcc = plane_info.dcc;
>> -       dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0
>> -       dc_plane_state->flip_int_enabled = true;
>> -
>> -       /*
>> -        * Always set input transfer function, since plane state is refreshed
>> -        * every time.
>> -        */
>> -       ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
>> -       if (ret)
>> -               return ret;
>> +       /*
>> +        * Always set input transfer function, since plane state is refreshed
>> +        * every time.
>> +        */
>> +       ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
>> +       if (ret)
>> +               return ret;
>>
>>          return 0;
>>   }
>> @@ -6165,7 +5274,7 @@ static void fill_stream_properties_from_drm_display_mode(
>>          timing_out->scan_type = SCANNING_TYPE_NODATA;
>>          timing_out->hdmi_vic = 0;
>>
>> -       if(old_stream) {
>> +       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;
>> @@ -6387,16 +5496,126 @@ static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context)
>>          }
>>   }
>>
>> +/**
>> + * 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->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_DEBUG_DRIVER("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_DCN)
>>   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)
>> +                           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)) {
>> +           sink->sink_signal == SIGNAL_TYPE_EDP)) {
>>                  if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE ||
>>                          sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
>>                          dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
>> @@ -6406,6 +5625,7 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
>>          }
>>   }
>>
>> +
>>   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,
>> @@ -6464,9 +5684,10 @@ static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector,
>>          }
>>   }
>>
>> +
>>   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 dc_sink *sink, struct dc_stream_state *stream,
>> +                                       struct dsc_dec_dpcd_caps *dsc_caps)
>>   {
>>          struct drm_connector *drm_connector = &aconnector->base;
>>          uint32_t link_bandwidth_kbps;
>> @@ -6477,7 +5698,6 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
>>
>>          link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
>>                                                          dc_link_get_link_cap(aconnector->dc_link));
>> -
>>          if (stream->link && stream->link->local_sink)
>>                  max_dsc_target_bpp_limit_override =
>>                          stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit;
>> @@ -6501,8 +5721,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
>>                                                  &stream->timing,
>>                                                  &stream->timing.dsc_cfg)) {
>>                                  stream->timing.flags.DSC = 1;
>> -                               DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from SST RX\n",
>> -                                                                __func__, drm_connector->name);
>> +                               DRM_DEBUG_DRIVER("%s: [%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);
>> @@ -6530,126 +5749,16 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
>>          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 /* CONFIG_DRM_AMD_DC_DCN */
>> -
>> -/**
>> - * 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,120 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->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_DEBUG_DRIVER("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 (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 (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 (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 /* CONFIG_DRM_AMD_DC_DCN */
>>
>>   static struct dc_stream_state *
>>   create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>> @@ -6674,6 +5783,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>>   #if defined(CONFIG_DRM_AMD_DC_DCN)
>>          struct dsc_dec_dpcd_caps dsc_caps;
>>   #endif
>> +
>>          struct dc_sink *sink = NULL;
>>
>>          memset(&saved_mode, 0, sizeof(saved_mode));
>> @@ -6737,7 +5847,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>>                          drm_mode_copy(&mode, freesync_mode);
>>                  } else {
>>                          decide_crtc_timing_for_drm_display_mode(
>> -                               &mode, preferred_mode, scale);
>> +                                       &mode, preferred_mode, scale);
>>
>>                          preferred_refresh = drm_mode_vrefresh(preferred_mode);
>>                  }
>> @@ -6748,7 +5858,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
>>          else if (!dm_state)
>>                  drm_mode_set_crtcinfo(&mode, 0);
>>
>> -       /*
>> +       /*
>>          * If scaling is enabled and refresh rate didn't change
>>          * we copy the vic and polarities of the old timings
>>          */
>> @@ -6996,7 +6106,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
>>              !aconnector->fake_enable)
>>                  connected = (aconnector->dc_sink != NULL);
>>          else
>> -               connected = (aconnector->base.force == DRM_FORCE_ON);
>> +               connected = (aconnector->base.force == DRM_FORCE_ON ||
>> +                               aconnector->base.force == DRM_FORCE_ON_DIGITAL);
>>
>>          update_subconnector_property(aconnector);
>>
>> @@ -7120,18 +6231,21 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
>>          int i;
>>
>>          /*
>> -        * Call only if mst_mgr was iniitalized before since it's not done
>> +        * 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);
>>
>> +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
>> +       defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
>>          for (i = 0; i < dm->num_of_edps; i++) {
>>                  if ((link == dm->backlight_link[i]) && dm->backlight_dev[i]) {
>>                          backlight_device_unregister(dm->backlight_dev[i]);
>>                          dm->backlight_dev[i] = NULL;
>>                  }
>>          }
>> +#endif
>>
>>          if (aconnector->dc_em_sink)
>>                  dc_sink_release(aconnector->dc_em_sink);
>> @@ -7172,6 +6286,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
>>                  state->base.max_requested_bpc = 8;
>>                  state->vcpi_slots = 0;
>>                  state->pbn = 0;
>> +
>>                  if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
>>                          state->abm_level = amdgpu_dm_abm_level;
>>
>> @@ -7561,10 +6676,10 @@ static void dm_update_crtc_active_planes(struct drm_crtc *crtc,
>>   }
>>
>>   static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
>> -                                      struct drm_atomic_state *state)
>> +                                     struct drm_atomic_state *state)
>>   {
>>          struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
>> -                                                                         crtc);
>> +                                                                               crtc);
>>          struct amdgpu_device *adev = drm_to_adev(crtc->dev);
>>          struct dc *dc = adev->dm.dc;
>>          struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
>> @@ -7575,7 +6690,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
>>          dm_update_crtc_active_planes(crtc, crtc_state);
>>
>>          if (WARN_ON(unlikely(!dm_crtc_state->stream &&
>> -                    modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
>> +                       modeset_required(crtc_state, NULL, dm_crtc_state->stream)))) {
>>                  return ret;
>>          }
>>
>> @@ -7586,7 +6701,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
>>           * userspace which stops using the HW cursor altogether in response to the resulting EINVAL.
>>           */
>>          if (crtc_state->enable &&
>> -           !(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
>> +               !(crtc_state->plane_mask & drm_plane_mask(crtc->primary))) {
>>                  DRM_DEBUG_ATOMIC("Can't enable a CRTC without enabling the primary plane\n");
>>                  return -EINVAL;
>>          }
>> @@ -7624,21 +6739,21 @@ 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;
>> -               }
>> +       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;
>>   }
>>
>> @@ -7669,7 +6784,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
>>          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;
>> +                         aconnector->force_yuv420_output;
>>                  color_depth = convert_color_depth_from_display_info(connector,
>>                                                                      is_y420,
>>                                                                      max_bpc);
>> @@ -7724,7 +6839,7 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
>>                          if (!stream)
>>                                  continue;
>>
>> -                       if ((struct amdgpu_dm_connector*)stream->dm_stream_context == aconnector)
>> +                       if ((struct amdgpu_dm_connector *)stream->dm_stream_context == aconnector)
>>                                  break;
>>
>>                          stream = NULL;
>> @@ -7773,466 +6888,6 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state,
>>   }
>>   #endif
>>
>> -static void dm_drm_plane_reset(struct drm_plane *plane)
>> -{
>> -       struct dm_plane_state *amdgpu_state = NULL;
>> -
>> -       if (plane->state)
>> -               plane->funcs->atomic_destroy_state(plane, plane->state);
>> -
>> -       amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
>> -       WARN_ON(amdgpu_state == NULL);
>> -
>> -       if (amdgpu_state)
>> -               __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
>> -}
>> -
>> -static struct drm_plane_state *
>> -dm_drm_plane_duplicate_state(struct drm_plane *plane)
>> -{
>> -       struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
>> -
>> -       old_dm_plane_state = to_dm_plane_state(plane->state);
>> -       dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
>> -       if (!dm_plane_state)
>> -               return NULL;
>> -
>> -       __drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
>> -
>> -       if (old_dm_plane_state->dc_state) {
>> -               dm_plane_state->dc_state = old_dm_plane_state->dc_state;
>> -               dc_plane_state_retain(dm_plane_state->dc_state);
>> -       }
>> -
>> -       return &dm_plane_state->base;
>> -}
>> -
>> -static void dm_drm_plane_destroy_state(struct drm_plane *plane,
>> -                               struct drm_plane_state *state)
>> -{
>> -       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
>> -
>> -       if (dm_plane_state->dc_state)
>> -               dc_plane_state_release(dm_plane_state->dc_state);
>> -
>> -       drm_atomic_helper_plane_destroy_state(plane, state);
>> -}
>> -
>> -static const struct drm_plane_funcs dm_plane_funcs = {
>> -       .update_plane   = drm_atomic_helper_update_plane,
>> -       .disable_plane  = drm_atomic_helper_disable_plane,
>> -       .destroy        = drm_primary_helper_destroy,
>> -       .reset = dm_drm_plane_reset,
>> -       .atomic_duplicate_state = dm_drm_plane_duplicate_state,
>> -       .atomic_destroy_state = dm_drm_plane_destroy_state,
>> -       .format_mod_supported = dm_plane_format_mod_supported,
>> -};
>> -
>> -static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
>> -                                     struct drm_plane_state *new_state)
>> -{
>> -       struct amdgpu_framebuffer *afb;
>> -       struct drm_gem_object *obj;
>> -       struct amdgpu_device *adev;
>> -       struct amdgpu_bo *rbo;
>> -       struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
>> -       struct list_head list;
>> -       struct ttm_validate_buffer tv;
>> -       struct ww_acquire_ctx ticket;
>> -       uint32_t domain;
>> -       int r;
>> -
>> -       if (!new_state->fb) {
>> -               DRM_DEBUG_KMS("No FB bound\n");
>> -               return 0;
>> -       }
>> -
>> -       afb = to_amdgpu_framebuffer(new_state->fb);
>> -       obj = new_state->fb->obj[0];
>> -       rbo = gem_to_amdgpu_bo(obj);
>> -       adev = amdgpu_ttm_adev(rbo->tbo.bdev);
>> -       INIT_LIST_HEAD(&list);
>> -
>> -       tv.bo = &rbo->tbo;
>> -       tv.num_shared = 1;
>> -       list_add(&tv.head, &list);
>> -
>> -       r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
>> -       if (r) {
>> -               dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
>> -               return r;
>> -       }
>> -
>> -       if (plane->type != DRM_PLANE_TYPE_CURSOR)
>> -               domain = amdgpu_display_supported_domains(adev, rbo->flags);
>> -       else
>> -               domain = AMDGPU_GEM_DOMAIN_VRAM;
>> -
>> -       r = amdgpu_bo_pin(rbo, domain);
>> -       if (unlikely(r != 0)) {
>> -               if (r != -ERESTARTSYS)
>> -                       DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
>> -               ttm_eu_backoff_reservation(&ticket, &list);
>> -               return r;
>> -       }
>> -
>> -       r = amdgpu_ttm_alloc_gart(&rbo->tbo);
>> -       if (unlikely(r != 0)) {
>> -               amdgpu_bo_unpin(rbo);
>> -               ttm_eu_backoff_reservation(&ticket, &list);
>> -               DRM_ERROR("%p bind failed\n", rbo);
>> -               return r;
>> -       }
>> -
>> -       ttm_eu_backoff_reservation(&ticket, &list);
>> -
>> -       afb->address = amdgpu_bo_gpu_offset(rbo);
>> -
>> -       amdgpu_bo_ref(rbo);
>> -
>> -       /**
>> -        * We don't do surface updates on planes that have been newly created,
>> -        * but we also don't have the afb->address during atomic check.
>> -        *
>> -        * Fill in buffer attributes depending on the address here, but only on
>> -        * newly created planes since they're not being used by DC yet and this
>> -        * won't modify global state.
>> -        */
>> -       dm_plane_state_old = to_dm_plane_state(plane->state);
>> -       dm_plane_state_new = to_dm_plane_state(new_state);
>> -
>> -       if (dm_plane_state_new->dc_state &&
>> -           dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
>> -               struct dc_plane_state *plane_state =
>> -                       dm_plane_state_new->dc_state;
>> -               bool force_disable_dcc = !plane_state->dcc.enable;
>> -
>> -               fill_plane_buffer_attributes(
>> -                       adev, afb, plane_state->format, plane_state->rotation,
>> -                       afb->tiling_flags,
>> -                       &plane_state->tiling_info, &plane_state->plane_size,
>> -                       &plane_state->dcc, &plane_state->address,
>> -                       afb->tmz_surface, force_disable_dcc);
>> -       }
>> -
>> -       return 0;
>> -}
>> -
>> -static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
>> -                                      struct drm_plane_state *old_state)
>> -{
>> -       struct amdgpu_bo *rbo;
>> -       int r;
>> -
>> -       if (!old_state->fb)
>> -               return;
>> -
>> -       rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
>> -       r = amdgpu_bo_reserve(rbo, false);
>> -       if (unlikely(r)) {
>> -               DRM_ERROR("failed to reserve rbo before unpin\n");
>> -               return;
>> -       }
>> -
>> -       amdgpu_bo_unpin(rbo);
>> -       amdgpu_bo_unreserve(rbo);
>> -       amdgpu_bo_unref(&rbo);
>> -}
>> -
>> -static int dm_plane_helper_check_state(struct drm_plane_state *state,
>> -                                      struct drm_crtc_state *new_crtc_state)
>> -{
>> -       struct drm_framebuffer *fb = state->fb;
>> -       int min_downscale, max_upscale;
>> -       int min_scale = 0;
>> -       int max_scale = INT_MAX;
>> -
>> -       /* Plane enabled? Validate viewport and get scaling factors from plane caps. */
>> -       if (fb && state->crtc) {
>> -               /* Validate viewport to cover the case when only the position changes */
>> -               if (state->plane->type != DRM_PLANE_TYPE_CURSOR) {
>> -                       int viewport_width = state->crtc_w;
>> -                       int viewport_height = state->crtc_h;
>> -
>> -                       if (state->crtc_x < 0)
>> -                               viewport_width += state->crtc_x;
>> -                       else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay)
>> -                               viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x;
>> -
>> -                       if (state->crtc_y < 0)
>> -                               viewport_height += state->crtc_y;
>> -                       else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
>> -                               viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
>> -
>> -                       if (viewport_width < 0 || viewport_height < 0) {
>> -                               DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
>> -                               return -EINVAL;
>> -                       } else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
>> -                               DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
>> -                               return -EINVAL;
>> -                       } else if (viewport_height < MIN_VIEWPORT_SIZE) {
>> -                               DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
>> -                               return -EINVAL;
>> -                       }
>> -
>> -               }
>> -
>> -               /* Get min/max allowed scaling factors from plane caps. */
>> -               get_min_max_dc_plane_scaling(state->crtc->dev, fb,
>> -                                            &min_downscale, &max_upscale);
>> -               /*
>> -                * Convert to drm convention: 16.16 fixed point, instead of dc's
>> -                * 1.0 == 1000. Also drm scaling is src/dst instead of dc's
>> -                * dst/src, so min_scale = 1.0 / max_upscale, etc.
>> -                */
>> -               min_scale = (1000 << 16) / max_upscale;
>> -               max_scale = (1000 << 16) / min_downscale;
>> -       }
>> -
>> -       return drm_atomic_helper_check_plane_state(
>> -               state, new_crtc_state, min_scale, max_scale, true, true);
>> -}
>> -
>> -static int dm_plane_atomic_check(struct drm_plane *plane,
>> -                                struct drm_atomic_state *state)
>> -{
>> -       struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> -                                                                                plane);
>> -       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> -       struct dc *dc = adev->dm.dc;
>> -       struct dm_plane_state *dm_plane_state;
>> -       struct dc_scaling_info scaling_info;
>> -       struct drm_crtc_state *new_crtc_state;
>> -       int ret;
>> -
>> -       trace_amdgpu_dm_plane_atomic_check(new_plane_state);
>> -
>> -       dm_plane_state = to_dm_plane_state(new_plane_state);
>> -
>> -       if (!dm_plane_state->dc_state)
>> -               return 0;
>> -
>> -       new_crtc_state =
>> -               drm_atomic_get_new_crtc_state(state,
>> -                                             new_plane_state->crtc);
>> -       if (!new_crtc_state)
>> -               return -EINVAL;
>> -
>> -       ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
>> -       if (ret)
>> -               return ret;
>> -
>> -       ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
>> -       if (ret)
>> -               return ret;
>> -
>> -       if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
>> -               return 0;
>> -
>> -       return -EINVAL;
>> -}
>> -
>> -static int dm_plane_atomic_async_check(struct drm_plane *plane,
>> -                                      struct drm_atomic_state *state)
>> -{
>> -       /* Only support async updates on cursor planes. */
>> -       if (plane->type != DRM_PLANE_TYPE_CURSOR)
>> -               return -EINVAL;
>> -
>> -       return 0;
>> -}
>> -
>> -static void dm_plane_atomic_async_update(struct drm_plane *plane,
>> -                                        struct drm_atomic_state *state)
>> -{
>> -       struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> -                                                                          plane);
>> -       struct drm_plane_state *old_state =
>> -               drm_atomic_get_old_plane_state(state, plane);
>> -
>> -       trace_amdgpu_dm_atomic_update_cursor(new_state);
>> -
>> -       swap(plane->state->fb, new_state->fb);
>> -
>> -       plane->state->src_x = new_state->src_x;
>> -       plane->state->src_y = new_state->src_y;
>> -       plane->state->src_w = new_state->src_w;
>> -       plane->state->src_h = new_state->src_h;
>> -       plane->state->crtc_x = new_state->crtc_x;
>> -       plane->state->crtc_y = new_state->crtc_y;
>> -       plane->state->crtc_w = new_state->crtc_w;
>> -       plane->state->crtc_h = new_state->crtc_h;
>> -
>> -       handle_cursor_update(plane, old_state);
>> -}
>> -
>> -static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
>> -       .prepare_fb = dm_plane_helper_prepare_fb,
>> -       .cleanup_fb = dm_plane_helper_cleanup_fb,
>> -       .atomic_check = dm_plane_atomic_check,
>> -       .atomic_async_check = dm_plane_atomic_async_check,
>> -       .atomic_async_update = dm_plane_atomic_async_update
>> -};
>> -
>> -/*
>> - * TODO: these are currently initialized to rgb formats only.
>> - * For future use cases we should either initialize them dynamically based on
>> - * plane capabilities, or initialize this array to all formats, so internal drm
>> - * check will succeed, and let DC implement proper check
>> - */
>> -static const uint32_t rgb_formats[] = {
>> -       DRM_FORMAT_XRGB8888,
>> -       DRM_FORMAT_ARGB8888,
>> -       DRM_FORMAT_RGBA8888,
>> -       DRM_FORMAT_XRGB2101010,
>> -       DRM_FORMAT_XBGR2101010,
>> -       DRM_FORMAT_ARGB2101010,
>> -       DRM_FORMAT_ABGR2101010,
>> -       DRM_FORMAT_XRGB16161616,
>> -       DRM_FORMAT_XBGR16161616,
>> -       DRM_FORMAT_ARGB16161616,
>> -       DRM_FORMAT_ABGR16161616,
>> -       DRM_FORMAT_XBGR8888,
>> -       DRM_FORMAT_ABGR8888,
>> -       DRM_FORMAT_RGB565,
>> -};
>> -
>> -static const uint32_t overlay_formats[] = {
>> -       DRM_FORMAT_XRGB8888,
>> -       DRM_FORMAT_ARGB8888,
>> -       DRM_FORMAT_RGBA8888,
>> -       DRM_FORMAT_XBGR8888,
>> -       DRM_FORMAT_ABGR8888,
>> -       DRM_FORMAT_RGB565
>> -};
>> -
>> -static const u32 cursor_formats[] = {
>> -       DRM_FORMAT_ARGB8888
>> -};
>> -
>> -static int get_plane_formats(const struct drm_plane *plane,
>> -                            const struct dc_plane_cap *plane_cap,
>> -                            uint32_t *formats, int max_formats)
>> -{
>> -       int i, num_formats = 0;
>> -
>> -       /*
>> -        * TODO: Query support for each group of formats directly from
>> -        * DC plane caps. This will require adding more formats to the
>> -        * caps list.
>> -        */
>> -
>> -       switch (plane->type) {
>> -       case DRM_PLANE_TYPE_PRIMARY:
>> -               for (i = 0; i < ARRAY_SIZE(rgb_formats); ++i) {
>> -                       if (num_formats >= max_formats)
>> -                               break;
>> -
>> -                       formats[num_formats++] = rgb_formats[i];
>> -               }
>> -
>> -               if (plane_cap && plane_cap->pixel_format_support.nv12)
>> -                       formats[num_formats++] = DRM_FORMAT_NV12;
>> -               if (plane_cap && plane_cap->pixel_format_support.p010)
>> -                       formats[num_formats++] = DRM_FORMAT_P010;
>> -               if (plane_cap && plane_cap->pixel_format_support.fp16) {
>> -                       formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
>> -                       formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
>> -                       formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
>> -                       formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
>> -               }
>> -               break;
>> -
>> -       case DRM_PLANE_TYPE_OVERLAY:
>> -               for (i = 0; i < ARRAY_SIZE(overlay_formats); ++i) {
>> -                       if (num_formats >= max_formats)
>> -                               break;
>> -
>> -                       formats[num_formats++] = overlay_formats[i];
>> -               }
>> -               break;
>> -
>> -       case DRM_PLANE_TYPE_CURSOR:
>> -               for (i = 0; i < ARRAY_SIZE(cursor_formats); ++i) {
>> -                       if (num_formats >= max_formats)
>> -                               break;
>> -
>> -                       formats[num_formats++] = cursor_formats[i];
>> -               }
>> -               break;
>> -       }
>> -
>> -       return num_formats;
>> -}
>> -
>> -static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
>> -                               struct drm_plane *plane,
>> -                               unsigned long possible_crtcs,
>> -                               const struct dc_plane_cap *plane_cap)
>> -{
>> -       uint32_t formats[32];
>> -       int num_formats;
>> -       int res = -EPERM;
>> -       unsigned int supported_rotations;
>> -       uint64_t *modifiers = NULL;
>> -
>> -       num_formats = get_plane_formats(plane, plane_cap, formats,
>> -                                       ARRAY_SIZE(formats));
>> -
>> -       res = get_plane_modifiers(dm->adev, plane->type, &modifiers);
>> -       if (res)
>> -               return res;
>> -
>> -       res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
>> -                                      &dm_plane_funcs, formats, num_formats,
>> -                                      modifiers, plane->type, NULL);
>> -       kfree(modifiers);
>> -       if (res)
>> -               return res;
>> -
>> -       if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
>> -           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);
>> -
>> -               drm_plane_create_alpha_property(plane);
>> -               drm_plane_create_blend_mode_property(plane, blend_caps);
>> -       }
>> -
>> -       if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
>> -           plane_cap &&
>> -           (plane_cap->pixel_format_support.nv12 ||
>> -            plane_cap->pixel_format_support.p010)) {
>> -               /* This only affects YUV formats. */
>> -               drm_plane_create_color_properties(
>> -                       plane,
>> -                       BIT(DRM_COLOR_YCBCR_BT601) |
>> -                       BIT(DRM_COLOR_YCBCR_BT709) |
>> -                       BIT(DRM_COLOR_YCBCR_BT2020),
>> -                       BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
>> -                       BIT(DRM_COLOR_YCBCR_FULL_RANGE),
>> -                       DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
>> -       }
>> -
>> -       supported_rotations =
>> -               DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
>> -               DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
>> -
>> -       if (dm->adev->asic_type >= CHIP_BONAIRE &&
>> -           plane->type != DRM_PLANE_TYPE_CURSOR)
>> -               drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
>> -                                                  supported_rotations);
>> -
>> -       drm_plane_helper_add(plane, &dm_plane_helper_funcs);
>> -
>> -       /* Create (reset) the plane state */
>> -       if (plane->funcs->reset)
>> -               plane->funcs->reset(plane);
>> -
>> -       return 0;
>> -}
>> -
>>   static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
>>                                 struct drm_plane *plane,
>>                                 uint32_t crtc_index)
>> @@ -9072,114 +7727,6 @@ static void remove_stream(struct amdgpu_device *adev,
>>          acrtc->enabled = false;
>>   }
>>
>> -static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
>> -                              struct dc_cursor_position *position)
>> -{
>> -       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
>> -       int x, y;
>> -       int xorigin = 0, yorigin = 0;
>> -
>> -       if (!crtc || !plane->state->fb)
>> -               return 0;
>> -
>> -       if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
>> -           (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
>> -               DRM_ERROR("%s: bad cursor width or height %d x %d\n",
>> -                         __func__,
>> -                         plane->state->crtc_w,
>> -                         plane->state->crtc_h);
>> -               return -EINVAL;
>> -       }
>> -
>> -       x = plane->state->crtc_x;
>> -       y = plane->state->crtc_y;
>> -
>> -       if (x <= -amdgpu_crtc->max_cursor_width ||
>> -           y <= -amdgpu_crtc->max_cursor_height)
>> -               return 0;
>> -
>> -       if (x < 0) {
>> -               xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
>> -               x = 0;
>> -       }
>> -       if (y < 0) {
>> -               yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
>> -               y = 0;
>> -       }
>> -       position->enable = true;
>> -       position->translate_by_source = true;
>> -       position->x = x;
>> -       position->y = y;
>> -       position->x_hotspot = xorigin;
>> -       position->y_hotspot = yorigin;
>> -
>> -       return 0;
>> -}
>> -
>> -static void handle_cursor_update(struct drm_plane *plane,
>> -                                struct drm_plane_state *old_plane_state)
>> -{
>> -       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> -       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
>> -       struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
>> -       struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
>> -       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
>> -       uint64_t address = afb ? afb->address : 0;
>> -       struct dc_cursor_position position = {0};
>> -       struct dc_cursor_attributes attributes;
>> -       int ret;
>> -
>> -       if (!plane->state->fb && !old_plane_state->fb)
>> -               return;
>> -
>> -       DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
>> -                     __func__,
>> -                     amdgpu_crtc->crtc_id,
>> -                     plane->state->crtc_w,
>> -                     plane->state->crtc_h);
>> -
>> -       ret = get_cursor_position(plane, crtc, &position);
>> -       if (ret)
>> -               return;
>> -
>> -       if (!position.enable) {
>> -               /* turn off cursor */
>> -               if (crtc_state && crtc_state->stream) {
>> -                       mutex_lock(&adev->dm.dc_lock);
>> -                       dc_stream_set_cursor_position(crtc_state->stream,
>> -                                                     &position);
>> -                       mutex_unlock(&adev->dm.dc_lock);
>> -               }
>> -               return;
>> -       }
>> -
>> -       amdgpu_crtc->cursor_width = plane->state->crtc_w;
>> -       amdgpu_crtc->cursor_height = plane->state->crtc_h;
>> -
>> -       memset(&attributes, 0, sizeof(attributes));
>> -       attributes.address.high_part = upper_32_bits(address);
>> -       attributes.address.low_part  = lower_32_bits(address);
>> -       attributes.width             = plane->state->crtc_w;
>> -       attributes.height            = plane->state->crtc_h;
>> -       attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
>> -       attributes.rotation_angle    = 0;
>> -       attributes.attribute_flags.value = 0;
>> -
>> -       attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
>> -
>> -       if (crtc_state->stream) {
>> -               mutex_lock(&adev->dm.dc_lock);
>> -               if (!dc_stream_set_cursor_attributes(crtc_state->stream,
>> -                                                        &attributes))
>> -                       DRM_ERROR("DC failed to set cursor attributes\n");
>> -
>> -               if (!dc_stream_set_cursor_position(crtc_state->stream,
>> -                                                  &position))
>> -                       DRM_ERROR("DC failed to set cursor position\n");
>> -               mutex_unlock(&adev->dm.dc_lock);
>> -       }
>> -}
>> -
>>   static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
>>   {
>>
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>> new file mode 100644
>> index 000000000000..e27621e11947
>> --- /dev/null
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
>> @@ -0,0 +1,1637 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright 2022 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + * Authors: AMD
>> + *
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drm_fourcc.h>
>> +
>> +#include "amdgpu.h"
>> +#include "dal_asic_id.h"
>> +#include "amdgpu_display.h"
>> +#include "amdgpu_dm_trace.h"
>> +#include "gc/gc_11_0_0_offset.h"
>> +#include "gc/gc_11_0_0_sh_mask.h"
>> +
>> +/*
>> + * TODO: these are currently initialized to rgb formats only.
>> + * For future use cases we should either initialize them dynamically based on
>> + * plane capabilities, or initialize this array to all formats, so internal drm
>> + * check will succeed, and let DC implement proper check
>> + */
>> +static const uint32_t rgb_formats[] = {
>> +       DRM_FORMAT_XRGB8888,
>> +       DRM_FORMAT_ARGB8888,
>> +       DRM_FORMAT_RGBA8888,
>> +       DRM_FORMAT_XRGB2101010,
>> +       DRM_FORMAT_XBGR2101010,
>> +       DRM_FORMAT_ARGB2101010,
>> +       DRM_FORMAT_ABGR2101010,
>> +       DRM_FORMAT_XRGB16161616,
>> +       DRM_FORMAT_XBGR16161616,
>> +       DRM_FORMAT_ARGB16161616,
>> +       DRM_FORMAT_ABGR16161616,
>> +       DRM_FORMAT_XBGR8888,
>> +       DRM_FORMAT_ABGR8888,
>> +       DRM_FORMAT_RGB565,
>> +};
>> +
>> +static const uint32_t overlay_formats[] = {
>> +       DRM_FORMAT_XRGB8888,
>> +       DRM_FORMAT_ARGB8888,
>> +       DRM_FORMAT_RGBA8888,
>> +       DRM_FORMAT_XBGR8888,
>> +       DRM_FORMAT_ABGR8888,
>> +       DRM_FORMAT_RGB565
>> +};
>> +
>> +static const u32 cursor_formats[] = {
>> +       DRM_FORMAT_ARGB8888
>> +};
>> +
>> +enum dm_micro_swizzle {
>> +       MICRO_SWIZZLE_Z = 0,
>> +       MICRO_SWIZZLE_S = 1,
>> +       MICRO_SWIZZLE_D = 2,
>> +       MICRO_SWIZZLE_R = 3
>> +};
>> +
>> +const struct drm_format_info *amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
>> +{
>> +       return amdgpu_lookup_format_info(cmd->pixel_format, cmd->modifier[0]);
>> +}
>> +
>> +void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
>> +                              bool *per_pixel_alpha, bool *pre_multiplied_alpha,
>> +                              bool *global_alpha, int *global_alpha_value)
>> +{
>> +       *per_pixel_alpha = false;
>> +       *pre_multiplied_alpha = true;
>> +       *global_alpha = false;
>> +       *global_alpha_value = 0xff;
>> +
>> +       if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
>> +               return;
>> +
>> +       if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
>> +               plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
>> +               static const uint32_t alpha_formats[] = {
>> +                       DRM_FORMAT_ARGB8888,
>> +                       DRM_FORMAT_RGBA8888,
>> +                       DRM_FORMAT_ABGR8888,
>> +               };
>> +               uint32_t format = plane_state->fb->format->format;
>> +               unsigned int i;
>> +
>> +               for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
>> +                       if (format == alpha_formats[i]) {
>> +                               *per_pixel_alpha = true;
>> +                               break;
>> +                       }
>> +               }
>> +
>> +               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
>> +                       *pre_multiplied_alpha = false;
>> +       }
>> +
>> +       if (plane_state->alpha < 0xffff) {
>> +               *global_alpha = true;
>> +               *global_alpha_value = plane_state->alpha >> 8;
>> +       }
>> +}
>> +
>> +static void add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod)
>> +{
>> +       if (!*mods)
>> +               return;
>> +
>> +       if (*cap - *size < 1) {
>> +               uint64_t new_cap = *cap * 2;
>> +               uint64_t *new_mods = kmalloc(new_cap * sizeof(uint64_t), GFP_KERNEL);
>> +
>> +               if (!new_mods) {
>> +                       kfree(*mods);
>> +                       *mods = NULL;
>> +                       return;
>> +               }
>> +
>> +               memcpy(new_mods, *mods, sizeof(uint64_t) * *size);
>> +               kfree(*mods);
>> +               *mods = new_mods;
>> +               *cap = new_cap;
>> +       }
>> +
>> +       (*mods)[*size] = mod;
>> +       *size += 1;
>> +}
>> +
>> +bool modifier_has_dcc(uint64_t modifier)
>> +{
>> +       return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier);
>> +}
>> +
>> +unsigned modifier_gfx9_swizzle_mode(uint64_t modifier)
>> +{
>> +       if (modifier == DRM_FORMAT_MOD_LINEAR)
>> +               return 0;
>> +
>> +       return AMD_FMT_MOD_GET(TILE, modifier);
>> +}
>> +
>> +static void fill_gfx8_tiling_info_from_flags(union dc_tiling_info *tiling_info,
>> +                                uint64_t tiling_flags)
>> +{
>> +       /* Fill GFX8 params */
>> +       if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
>> +               unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
>> +
>> +               bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
>> +               bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
>> +               mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
>> +               tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
>> +               num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
>> +
>> +               /* XXX fix me for VI */
>> +               tiling_info->gfx8.num_banks = num_banks;
>> +               tiling_info->gfx8.array_mode =
>> +                               DC_ARRAY_2D_TILED_THIN1;
>> +               tiling_info->gfx8.tile_split = tile_split;
>> +               tiling_info->gfx8.bank_width = bankw;
>> +               tiling_info->gfx8.bank_height = bankh;
>> +               tiling_info->gfx8.tile_aspect = mtaspect;
>> +               tiling_info->gfx8.tile_mode =
>> +                               DC_ADDR_SURF_MICRO_TILING_DISPLAY;
>> +       } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
>> +                       == DC_ARRAY_1D_TILED_THIN1) {
>> +               tiling_info->gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
>> +       }
>> +
>> +       tiling_info->gfx8.pipe_config =
>> +                       AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
>> +}
>> +
>> +static void fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev,
>> +                                 union dc_tiling_info *tiling_info)
>> +{
>> +       /* Fill GFX9 params */
>> +       tiling_info->gfx9.num_pipes =
>> +               adev->gfx.config.gb_addr_config_fields.num_pipes;
>> +       tiling_info->gfx9.num_banks =
>> +               adev->gfx.config.gb_addr_config_fields.num_banks;
>> +       tiling_info->gfx9.pipe_interleave =
>> +               adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
>> +       tiling_info->gfx9.num_shader_engines =
>> +               adev->gfx.config.gb_addr_config_fields.num_se;
>> +       tiling_info->gfx9.max_compressed_frags =
>> +               adev->gfx.config.gb_addr_config_fields.max_compress_frags;
>> +       tiling_info->gfx9.num_rb_per_se =
>> +               adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
>> +       tiling_info->gfx9.shaderEnable = 1;
>> +       if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
>> +               tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs;
>> +}
>> +
>> +static void fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev,
>> +                                   union dc_tiling_info *tiling_info,
>> +                                   uint64_t modifier)
>> +{
>> +       unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
>> +       unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
>> +       unsigned int pkrs_log2 = AMD_FMT_MOD_GET(PACKERS, modifier);
>> +       unsigned int pipes_log2;
>> +
>> +       pipes_log2 = min(5u, mod_pipe_xor_bits);
>> +
>> +       fill_gfx9_tiling_info_from_device(adev, tiling_info);
>> +
>> +       if (!IS_AMD_FMT_MOD(modifier))
>> +               return;
>> +
>> +       tiling_info->gfx9.num_pipes = 1u << pipes_log2;
>> +       tiling_info->gfx9.num_shader_engines = 1u << (mod_pipe_xor_bits - pipes_log2);
>> +
>> +       if (adev->family >= AMDGPU_FAMILY_NV) {
>> +               tiling_info->gfx9.num_pkrs = 1u << pkrs_log2;
>> +       } else {
>> +               tiling_info->gfx9.num_banks = 1u << mod_bank_xor_bits;
>> +
>> +               /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */
>> +       }
>> +}
>> +
>> +static int validate_dcc(struct amdgpu_device *adev,
>> +            const enum surface_pixel_format format,
>> +            const enum dc_rotation_angle rotation,
>> +            const union dc_tiling_info *tiling_info,
>> +            const struct dc_plane_dcc_param *dcc,
>> +            const struct dc_plane_address *address,
>> +            const struct plane_size *plane_size)
>> +{
>> +       struct dc *dc = adev->dm.dc;
>> +       struct dc_dcc_surface_param input;
>> +       struct dc_surface_dcc_cap output;
>> +
>> +       memset(&input, 0, sizeof(input));
>> +       memset(&output, 0, sizeof(output));
>> +
>> +       if (!dcc->enable)
>> +               return 0;
>> +
>> +       if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
>> +           !dc->cap_funcs.get_dcc_compression_cap)
>> +               return -EINVAL;
>> +
>> +       input.format = format;
>> +       input.surface_size.width = plane_size->surface_size.width;
>> +       input.surface_size.height = plane_size->surface_size.height;
>> +       input.swizzle_mode = tiling_info->gfx9.swizzle;
>> +
>> +       if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180)
>> +               input.scan = SCAN_DIRECTION_HORIZONTAL;
>> +       else if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270)
>> +               input.scan = SCAN_DIRECTION_VERTICAL;
>> +
>> +       if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output))
>> +               return -EINVAL;
>> +
>> +       if (!output.capable)
>> +               return -EINVAL;
>> +
>> +       if (dcc->independent_64b_blks == 0 &&
>> +           output.grph.rgb.independent_64b_blks != 0)
>> +               return -EINVAL;
>> +
>> +       return 0;
>> +}
>> +
>> +static int fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev,
>> +                                         const struct amdgpu_framebuffer *afb,
>> +                                         const enum surface_pixel_format format,
>> +                                         const enum dc_rotation_angle rotation,
>> +                                         const struct plane_size *plane_size,
>> +                                         union dc_tiling_info *tiling_info,
>> +                                         struct dc_plane_dcc_param *dcc,
>> +                                         struct dc_plane_address *address,
>> +                                         const bool force_disable_dcc)
>> +{
>> +       const uint64_t modifier = afb->base.modifier;
>> +       int ret = 0;
>> +
>> +       fill_gfx9_tiling_info_from_modifier(adev, tiling_info, modifier);
>> +       tiling_info->gfx9.swizzle = modifier_gfx9_swizzle_mode(modifier);
>> +
>> +       if (modifier_has_dcc(modifier) && !force_disable_dcc) {
>> +               uint64_t dcc_address = afb->address + afb->base.offsets[1];
>> +               bool independent_64b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier);
>> +               bool independent_128b_blks = AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier);
>> +
>> +               dcc->enable = 1;
>> +               dcc->meta_pitch = afb->base.pitches[1];
>> +               dcc->independent_64b_blks = independent_64b_blks;
>> +               if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) >= AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
>> +                       if (independent_64b_blks && independent_128b_blks)
>> +                               dcc->dcc_ind_blk = hubp_ind_block_64b_no_128bcl;
>> +                       else if (independent_128b_blks)
>> +                               dcc->dcc_ind_blk = hubp_ind_block_128b;
>> +                       else if (independent_64b_blks && !independent_128b_blks)
>> +                               dcc->dcc_ind_blk = hubp_ind_block_64b;
>> +                       else
>> +                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
>> +               } else {
>> +                       if (independent_64b_blks)
>> +                               dcc->dcc_ind_blk = hubp_ind_block_64b;
>> +                       else
>> +                               dcc->dcc_ind_blk = hubp_ind_block_unconstrained;
>> +               }
>> +
>> +               address->grph.meta_addr.low_part = lower_32_bits(dcc_address);
>> +               address->grph.meta_addr.high_part = upper_32_bits(dcc_address);
>> +       }
>> +
>> +       ret = validate_dcc(adev, format, rotation, tiling_info, dcc, address, plane_size);
>> +       if (ret)
>> +               drm_dbg_kms(adev_to_drm(adev), "validate_dcc: returned error: %d\n", ret);
>> +
>> +       return ret;
>> +}
>> +
>> +static void add_gfx10_1_modifiers(const struct amdgpu_device *adev,
>> +                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> +{
>> +       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits));
>> +
>> +
>> +       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> +}
>> +
>> +static void add_gfx9_modifiers(const struct amdgpu_device *adev,
>> +                  uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> +{
>> +       int pipes = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
>> +       int pipe_xor_bits = min(8, pipes +
>> +                               ilog2(adev->gfx.config.gb_addr_config_fields.num_se));
>> +       int bank_xor_bits = min(8 - pipe_xor_bits,
>> +                               ilog2(adev->gfx.config.gb_addr_config_fields.num_banks));
>> +       int rb = ilog2(adev->gfx.config.gb_addr_config_fields.num_se) +
>> +                ilog2(adev->gfx.config.gb_addr_config_fields.num_rb_per_se);
>> +
>> +
>> +       if (adev->family == AMDGPU_FAMILY_RV) {
>> +               /* Raven2 and later */
>> +               bool has_constant_encode = adev->asic_type > CHIP_RAVEN || adev->external_rev_id >= 0x81;
>> +
>> +               /*
>> +                * No _D DCC swizzles yet because we only allow 32bpp, which
>> +                * doesn't support _D on DCN
>> +                */
>> +
>> +               if (has_constant_encode) {
>> +                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> +                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> +                                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> +                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1));
>> +               }
>> +
>> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> +                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> +                           AMD_FMT_MOD_SET(DCC, 1) |
>> +                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> +                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0));
>> +
>> +               if (has_constant_encode) {
>> +                       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> +                                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> +                                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> +
>> +                                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                                   AMD_FMT_MOD_SET(RB, rb) |
>> +                                   AMD_FMT_MOD_SET(PIPE, pipes));
>> +               }
>> +
>> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> +                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits) |
>> +                           AMD_FMT_MOD_SET(DCC, 1) |
>> +                           AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> +                           AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                           AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B) |
>> +                           AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 0) |
>> +                           AMD_FMT_MOD_SET(RB, rb) |
>> +                           AMD_FMT_MOD_SET(PIPE, pipes));
>> +       }
>> +
>> +       /*
>> +        * Only supported for 64bpp on Raven, will be filtered on format in
>> +        * dm_plane_format_mod_supported.
>> +        */
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
>> +
>> +       if (adev->family == AMDGPU_FAMILY_RV) {
>> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) |
>> +                           AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                           AMD_FMT_MOD_SET(BANK_XOR_BITS, bank_xor_bits));
>> +       }
>> +
>> +       /*
>> +        * Only supported for 64bpp on Raven, will be filtered on format in
>> +        * dm_plane_format_mod_supported.
>> +        */
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> +
>> +       if (adev->family == AMDGPU_FAMILY_RV) {
>> +               add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                           AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
>> +                           AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> +       }
>> +}
>> +
>> +static void add_gfx10_3_modifiers(const struct amdgpu_device *adev,
>> +                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> +{
>> +       int pipe_xor_bits = ilog2(adev->gfx.config.gb_addr_config_fields.num_pipes);
>> +       int pkrs = ilog2(adev->gfx.config.gb_addr_config_fields.num_pkrs);
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> +                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> +                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> +                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(PACKERS, pkrs) |
>> +                   AMD_FMT_MOD_SET(DCC, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_RETILE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_CONSTANT_ENCODE, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> +                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_R_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(PACKERS, pkrs));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) |
>> +                   AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                   AMD_FMT_MOD_SET(PACKERS, pkrs));
>> +
>> +       /* Only supported for 64bpp, will be filtered in dm_plane_format_mod_supported */
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                   AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S) |
>> +                   AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9));
>> +}
>> +
>> +static void add_gfx11_modifiers(struct amdgpu_device *adev,
>> +                     uint64_t **mods, uint64_t *size, uint64_t *capacity)
>> +{
>> +       int num_pipes = 0;
>> +       int pipe_xor_bits = 0;
>> +       int num_pkrs = 0;
>> +       int pkrs = 0;
>> +       u32 gb_addr_config;
>> +       u8 i = 0;
>> +       unsigned swizzle_r_x;
>> +       uint64_t modifier_r_x;
>> +       uint64_t modifier_dcc_best;
>> +       uint64_t modifier_dcc_4k;
>> +
>> +       /* TODO: GFX11 IP HW init hasnt finish and we get zero if we read from
>> +        * adev->gfx.config.gb_addr_config_fields.num_{pkrs,pipes}
>> +        */
>> +       gb_addr_config = RREG32_SOC15(GC, 0, regGB_ADDR_CONFIG);
>> +       ASSERT(gb_addr_config != 0);
>> +
>> +       num_pkrs = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PKRS);
>> +       pkrs = ilog2(num_pkrs);
>> +       num_pipes = 1 << REG_GET_FIELD(gb_addr_config, GB_ADDR_CONFIG, NUM_PIPES);
>> +       pipe_xor_bits = ilog2(num_pipes);
>> +
>> +       for (i = 0; i < 2; i++) {
>> +               /* Insert the best one first. */
>> +               /* R_X swizzle modes are the best for rendering and DCC requires them. */
>> +               if (num_pipes > 16)
>> +                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX11_256K_R_X : AMD_FMT_MOD_TILE_GFX9_64K_R_X;
>> +               else
>> +                       swizzle_r_x = !i ? AMD_FMT_MOD_TILE_GFX9_64K_R_X : AMD_FMT_MOD_TILE_GFX11_256K_R_X;
>> +
>> +               modifier_r_x = AMD_FMT_MOD |
>> +                              AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
>> +                              AMD_FMT_MOD_SET(PIPE_XOR_BITS, pipe_xor_bits) |
>> +                              AMD_FMT_MOD_SET(TILE, swizzle_r_x) |
>> +                              AMD_FMT_MOD_SET(PACKERS, pkrs);
>> +
>> +               /* DCC_CONSTANT_ENCODE is not set because it can't vary with gfx11 (it's implied to be 1). */
>> +               modifier_dcc_best = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 0) |
>> +                                   AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> +                                   AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_128B);
>> +
>> +               /* DCC settings for 4K and greater resolutions. (required by display hw) */
>> +               modifier_dcc_4k = modifier_r_x | AMD_FMT_MOD_SET(DCC, 1) |
>> +                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_64B, 1) |
>> +                                 AMD_FMT_MOD_SET(DCC_INDEPENDENT_128B, 1) |
>> +                                 AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, AMD_FMT_MOD_DCC_BLOCK_64B);
>> +
>> +               add_modifier(mods, size, capacity, modifier_dcc_best);
>> +               add_modifier(mods, size, capacity, modifier_dcc_4k);
>> +
>> +               add_modifier(mods, size, capacity, modifier_dcc_best | AMD_FMT_MOD_SET(DCC_RETILE, 1));
>> +               add_modifier(mods, size, capacity, modifier_dcc_4k | AMD_FMT_MOD_SET(DCC_RETILE, 1));
>> +
>> +               add_modifier(mods, size, capacity, modifier_r_x);
>> +       }
>> +
>> +       add_modifier(mods, size, capacity, AMD_FMT_MOD |
>> +                       AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX11) |
>> +                       AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_D));
>> +}
>> +
>> +static int get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods)
>> +{
>> +       uint64_t size = 0, capacity = 128;
>> +       *mods = NULL;
>> +
>> +       /* We have not hooked up any pre-GFX9 modifiers. */
>> +       if (adev->family < AMDGPU_FAMILY_AI)
>> +               return 0;
>> +
>> +       *mods = kmalloc(capacity * sizeof(uint64_t), GFP_KERNEL);
>> +
>> +       if (plane_type == DRM_PLANE_TYPE_CURSOR) {
>> +               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
>> +               add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
>> +               return *mods ? 0 : -ENOMEM;
>> +       }
>> +
>> +       switch (adev->family) {
>> +       case AMDGPU_FAMILY_AI:
>> +       case AMDGPU_FAMILY_RV:
>> +               add_gfx9_modifiers(adev, mods, &size, &capacity);
>> +               break;
>> +       case AMDGPU_FAMILY_NV:
>> +       case AMDGPU_FAMILY_VGH:
>> +       case AMDGPU_FAMILY_YC:
>> +       case AMDGPU_FAMILY_GC_10_3_6:
>> +       case AMDGPU_FAMILY_GC_10_3_7:
>> +               if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
>> +                       add_gfx10_3_modifiers(adev, mods, &size, &capacity);
>> +               else
>> +                       add_gfx10_1_modifiers(adev, mods, &size, &capacity);
>> +               break;
>> +       case AMDGPU_FAMILY_GC_11_0_0:
>> +       case AMDGPU_FAMILY_GC_11_0_2:
>> +               add_gfx11_modifiers(adev, mods, &size, &capacity);
>> +               break;
>> +       }
>> +
>> +       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_LINEAR);
>> +
>> +       /* INVALID marks the end of the list. */
>> +       add_modifier(mods, &size, &capacity, DRM_FORMAT_MOD_INVALID);
>> +
>> +       if (!*mods)
>> +               return -ENOMEM;
>> +
>> +       return 0;
>> +}
>> +
>> +static int get_plane_formats(const struct drm_plane *plane,
>> +                            const struct dc_plane_cap *plane_cap,
>> +                            uint32_t *formats, int max_formats)
>> +{
>> +       int i, num_formats = 0;
>> +
>> +       /*
>> +        * TODO: Query support for each group of formats directly from
>> +        * DC plane caps. This will require adding more formats to the
>> +        * caps list.
>> +        */
>> +
>> +       switch (plane->type) {
>> +       case DRM_PLANE_TYPE_PRIMARY:
>> +               for (i = 0; i < ARRAY_SIZE(rgb_formats); ++i) {
>> +                       if (num_formats >= max_formats)
>> +                               break;
>> +
>> +                       formats[num_formats++] = rgb_formats[i];
>> +               }
>> +
>> +               if (plane_cap && plane_cap->pixel_format_support.nv12)
>> +                       formats[num_formats++] = DRM_FORMAT_NV12;
>> +               if (plane_cap && plane_cap->pixel_format_support.p010)
>> +                       formats[num_formats++] = DRM_FORMAT_P010;
>> +               if (plane_cap && plane_cap->pixel_format_support.fp16) {
>> +                       formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
>> +                       formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
>> +                       formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
>> +                       formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
>> +               }
>> +               break;
>> +
>> +       case DRM_PLANE_TYPE_OVERLAY:
>> +               for (i = 0; i < ARRAY_SIZE(overlay_formats); ++i) {
>> +                       if (num_formats >= max_formats)
>> +                               break;
>> +
>> +                       formats[num_formats++] = overlay_formats[i];
>> +               }
>> +               break;
>> +
>> +       case DRM_PLANE_TYPE_CURSOR:
>> +               for (i = 0; i < ARRAY_SIZE(cursor_formats); ++i) {
>> +                       if (num_formats >= max_formats)
>> +                               break;
>> +
>> +                       formats[num_formats++] = cursor_formats[i];
>> +               }
>> +               break;
>> +       }
>> +
>> +       return num_formats;
>> +}
>> +
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +static int attach_color_mgmt_properties(struct amdgpu_display_manager *dm, struct drm_plane *plane)
>> +{
>> +       drm_object_attach_property(&plane->base,
>> +                                  dm->degamma_lut_property,
>> +                                  0);
>> +       drm_object_attach_property(&plane->base,
>> +                                  dm->degamma_lut_size_property,
>> +                                  MAX_COLOR_LUT_ENTRIES);
>> +       drm_object_attach_property(&plane->base, dm->ctm_property,
>> +                                  0);
>> +       drm_object_attach_property(&plane->base, dm->sdr_boost_property,
>> +                                  DEFAULT_SDR_BOOST);
>> +
>> +       return 0;
>> +}
>> +#endif
>> +
>> +int fill_plane_buffer_attributes(struct amdgpu_device *adev,
>> +                            const struct amdgpu_framebuffer *afb,
>> +                            const enum surface_pixel_format format,
>> +                            const enum dc_rotation_angle rotation,
>> +                            const uint64_t tiling_flags,
>> +                            union dc_tiling_info *tiling_info,
>> +                            struct plane_size *plane_size,
>> +                            struct dc_plane_dcc_param *dcc,
>> +                            struct dc_plane_address *address,
>> +                            bool tmz_surface,
>> +                            bool force_disable_dcc)
>> +{
>> +       const struct drm_framebuffer *fb = &afb->base;
>> +       int ret;
>> +
>> +       memset(tiling_info, 0, sizeof(*tiling_info));
>> +       memset(plane_size, 0, sizeof(*plane_size));
>> +       memset(dcc, 0, sizeof(*dcc));
>> +       memset(address, 0, sizeof(*address));
>> +
>> +       address->tmz_surface = tmz_surface;
>> +
>> +       if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
>> +               uint64_t addr = afb->address + fb->offsets[0];
>> +
>> +               plane_size->surface_size.x = 0;
>> +               plane_size->surface_size.y = 0;
>> +               plane_size->surface_size.width = fb->width;
>> +               plane_size->surface_size.height = fb->height;
>> +               plane_size->surface_pitch =
>> +                       fb->pitches[0] / fb->format->cpp[0];
>> +
>> +               address->type = PLN_ADDR_TYPE_GRAPHICS;
>> +               address->grph.addr.low_part = lower_32_bits(addr);
>> +               address->grph.addr.high_part = upper_32_bits(addr);
>> +       } else if (format < SURFACE_PIXEL_FORMAT_INVALID) {
>> +               uint64_t luma_addr = afb->address + fb->offsets[0];
>> +               uint64_t chroma_addr = afb->address + fb->offsets[1];
>> +
>> +               plane_size->surface_size.x = 0;
>> +               plane_size->surface_size.y = 0;
>> +               plane_size->surface_size.width = fb->width;
>> +               plane_size->surface_size.height = fb->height;
>> +               plane_size->surface_pitch =
>> +                       fb->pitches[0] / fb->format->cpp[0];
>> +
>> +               plane_size->chroma_size.x = 0;
>> +               plane_size->chroma_size.y = 0;
>> +               /* TODO: set these based on surface format */
>> +               plane_size->chroma_size.width = fb->width / 2;
>> +               plane_size->chroma_size.height = fb->height / 2;
>> +
>> +               plane_size->chroma_pitch =
>> +                       fb->pitches[1] / fb->format->cpp[1];
>> +
>> +               address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
>> +               address->video_progressive.luma_addr.low_part =
>> +                       lower_32_bits(luma_addr);
>> +               address->video_progressive.luma_addr.high_part =
>> +                       upper_32_bits(luma_addr);
>> +               address->video_progressive.chroma_addr.low_part =
>> +                       lower_32_bits(chroma_addr);
>> +               address->video_progressive.chroma_addr.high_part =
>> +                       upper_32_bits(chroma_addr);
>> +       }
>> +
>> +       if (adev->family >= AMDGPU_FAMILY_AI) {
>> +               ret = fill_gfx9_plane_attributes_from_modifiers(adev, afb, format,
>> +                                                               rotation, plane_size,
>> +                                                               tiling_info, dcc,
>> +                                                               address,
>> +                                                               force_disable_dcc);
>> +               if (ret)
>> +                       return ret;
>> +       } else {
>> +               fill_gfx8_tiling_info_from_flags(tiling_info, tiling_flags);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
>> +                                     struct drm_plane_state *new_state)
>> +{
>> +       struct amdgpu_framebuffer *afb;
>> +       struct drm_gem_object *obj;
>> +       struct amdgpu_device *adev;
>> +       struct amdgpu_bo *rbo;
>> +       struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
>> +       struct list_head list;
>> +       struct ttm_validate_buffer tv;
>> +       struct ww_acquire_ctx ticket;
>> +       uint32_t domain;
>> +       int r;
>> +
>> +       if (!new_state->fb) {
>> +               DRM_DEBUG_KMS("No FB bound\n");
>> +               return 0;
>> +       }
>> +
>> +       afb = to_amdgpu_framebuffer(new_state->fb);
>> +       obj = new_state->fb->obj[0];
>> +       rbo = gem_to_amdgpu_bo(obj);
>> +       adev = amdgpu_ttm_adev(rbo->tbo.bdev);
>> +       INIT_LIST_HEAD(&list);
>> +
>> +       tv.bo = &rbo->tbo;
>> +       tv.num_shared = 1;
>> +       list_add(&tv.head, &list);
>> +
>> +       r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
>> +       if (r) {
>> +               dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
>> +               return r;
>> +       }
>> +
>> +       if (plane->type != DRM_PLANE_TYPE_CURSOR)
>> +               domain = amdgpu_display_supported_domains(adev, rbo->flags);
>> +       else
>> +               domain = AMDGPU_GEM_DOMAIN_VRAM;
>> +
>> +       r = amdgpu_bo_pin(rbo, domain);
>> +       if (unlikely(r != 0)) {
>> +               if (r != -ERESTARTSYS)
>> +                       DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
>> +               ttm_eu_backoff_reservation(&ticket, &list);
>> +               return r;
>> +       }
>> +
>> +       r = amdgpu_ttm_alloc_gart(&rbo->tbo);
>> +       if (unlikely(r != 0)) {
>> +               amdgpu_bo_unpin(rbo);
>> +               ttm_eu_backoff_reservation(&ticket, &list);
>> +               DRM_ERROR("%p bind failed\n", rbo);
>> +               return r;
>> +       }
>> +
>> +       ttm_eu_backoff_reservation(&ticket, &list);
>> +
>> +       afb->address = amdgpu_bo_gpu_offset(rbo);
>> +
>> +       amdgpu_bo_ref(rbo);
>> +
>> +       /**
>> +        * We don't do surface updates on planes that have been newly created,
>> +        * but we also don't have the afb->address during atomic check.
>> +        *
>> +        * Fill in buffer attributes depending on the address here, but only on
>> +        * newly created planes since they're not being used by DC yet and this
>> +        * won't modify global state.
>> +        */
>> +       dm_plane_state_old = to_dm_plane_state(plane->state);
>> +       dm_plane_state_new = to_dm_plane_state(new_state);
>> +
>> +       if (dm_plane_state_new->dc_state &&
>> +           dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
>> +               struct dc_plane_state *plane_state =
>> +                       dm_plane_state_new->dc_state;
>> +               bool force_disable_dcc = !plane_state->dcc.enable;
>> +
>> +               fill_plane_buffer_attributes(
>> +                       adev, afb, plane_state->format, plane_state->rotation,
>> +                       afb->tiling_flags,
>> +                       &plane_state->tiling_info, &plane_state->plane_size,
>> +                       &plane_state->dcc, &plane_state->address,
>> +                       afb->tmz_surface, force_disable_dcc);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
>> +                                      struct drm_plane_state *old_state)
>> +{
>> +       struct amdgpu_bo *rbo;
>> +       int r;
>> +
>> +       if (!old_state->fb)
>> +               return;
>> +
>> +       rbo = gem_to_amdgpu_bo(old_state->fb->obj[0]);
>> +       r = amdgpu_bo_reserve(rbo, false);
>> +       if (unlikely(r)) {
>> +               DRM_ERROR("failed to reserve rbo before unpin\n");
>> +               return;
>> +       }
>> +
>> +       amdgpu_bo_unpin(rbo);
>> +       amdgpu_bo_unreserve(rbo);
>> +       amdgpu_bo_unref(&rbo);
>> +}
>> +
>> +static void get_min_max_dc_plane_scaling(struct drm_device *dev,
>> +                                        struct drm_framebuffer *fb,
>> +                                        int *min_downscale, int *max_upscale)
>> +{
>> +       struct amdgpu_device *adev = drm_to_adev(dev);
>> +       struct dc *dc = adev->dm.dc;
>> +       /* Caps for all supported planes are the same on DCE and DCN 1 - 3 */
>> +       struct dc_plane_cap *plane_cap = &dc->caps.planes[0];
>> +
>> +       switch (fb->format->format) {
>> +       case DRM_FORMAT_P010:
>> +       case DRM_FORMAT_NV12:
>> +       case DRM_FORMAT_NV21:
>> +               *max_upscale = plane_cap->max_upscale_factor.nv12;
>> +               *min_downscale = plane_cap->max_downscale_factor.nv12;
>> +               break;
>> +
>> +       case DRM_FORMAT_XRGB16161616F:
>> +       case DRM_FORMAT_ARGB16161616F:
>> +       case DRM_FORMAT_XBGR16161616F:
>> +       case DRM_FORMAT_ABGR16161616F:
>> +               *max_upscale = plane_cap->max_upscale_factor.fp16;
>> +               *min_downscale = plane_cap->max_downscale_factor.fp16;
>> +               break;
>> +
>> +       default:
>> +               *max_upscale = plane_cap->max_upscale_factor.argb8888;
>> +               *min_downscale = plane_cap->max_downscale_factor.argb8888;
>> +               break;
>> +       }
>> +
>> +       /*
>> +        * A factor of 1 in the plane_cap means to not allow scaling, ie. use a
>> +        * scaling factor of 1.0 == 1000 units.
>> +        */
>> +       if (*max_upscale == 1)
>> +               *max_upscale = 1000;
>> +
>> +       if (*min_downscale == 1)
>> +               *min_downscale = 1000;
>> +}
>> +
>> +int dm_plane_helper_check_state(struct drm_plane_state *state,
>> +                                      struct drm_crtc_state *new_crtc_state)
>> +{
>> +       struct drm_framebuffer *fb = state->fb;
>> +       int min_downscale, max_upscale;
>> +       int min_scale = 0;
>> +       int max_scale = INT_MAX;
>> +
>> +       /* Plane enabled? Validate viewport and get scaling factors from plane caps. */
>> +       if (fb && state->crtc) {
>> +               /* Validate viewport to cover the case when only the position changes */
>> +               if (state->plane->type != DRM_PLANE_TYPE_CURSOR) {
>> +                       int viewport_width = state->crtc_w;
>> +                       int viewport_height = state->crtc_h;
>> +
>> +                       if (state->crtc_x < 0)
>> +                               viewport_width += state->crtc_x;
>> +                       else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay)
>> +                               viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x;
>> +
>> +                       if (state->crtc_y < 0)
>> +                               viewport_height += state->crtc_y;
>> +                       else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay)
>> +                               viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y;
>> +
>> +                       if (viewport_width < 0 || viewport_height < 0) {
>> +                               DRM_DEBUG_ATOMIC("Plane completely outside of screen\n");
>> +                               return -EINVAL;
>> +                       } else if (viewport_width < MIN_VIEWPORT_SIZE*2) { /* x2 for width is because of pipe-split. */
>> +                               DRM_DEBUG_ATOMIC("Viewport width %d smaller than %d\n", viewport_width, MIN_VIEWPORT_SIZE*2);
>> +                               return -EINVAL;
>> +                       } else if (viewport_height < MIN_VIEWPORT_SIZE) {
>> +                               DRM_DEBUG_ATOMIC("Viewport height %d smaller than %d\n", viewport_height, MIN_VIEWPORT_SIZE);
>> +                               return -EINVAL;
>> +                       }
>> +
>> +               }
>> +
>> +               /* Get min/max allowed scaling factors from plane caps. */
>> +               get_min_max_dc_plane_scaling(state->crtc->dev, fb,
>> +                                            &min_downscale, &max_upscale);
>> +               /*
>> +                * Convert to drm convention: 16.16 fixed point, instead of dc's
>> +                * 1.0 == 1000. Also drm scaling is src/dst instead of dc's
>> +                * dst/src, so min_scale = 1.0 / max_upscale, etc.
>> +                */
>> +               min_scale = (1000 << 16) / max_upscale;
>> +               max_scale = (1000 << 16) / min_downscale;
>> +       }
>> +
>> +       return drm_atomic_helper_check_plane_state(
>> +               state, new_crtc_state, min_scale, max_scale, true, true);
>> +}
>> +
>> +int fill_dc_scaling_info(struct amdgpu_device *adev,
>> +                               const struct drm_plane_state *state,
>> +                               struct dc_scaling_info *scaling_info)
>> +{
>> +       int scale_w, scale_h, min_downscale, max_upscale;
>> +
>> +       memset(scaling_info, 0, sizeof(*scaling_info));
>> +
>> +       /* Source is fixed 16.16 but we ignore mantissa for now... */
>> +       scaling_info->src_rect.x = state->src_x >> 16;
>> +       scaling_info->src_rect.y = state->src_y >> 16;
>> +
>> +       /*
>> +        * For reasons we don't (yet) fully understand a non-zero
>> +        * src_y coordinate into an NV12 buffer can cause a
>> +        * system hang on DCN1x.
>> +        * To avoid hangs (and maybe be overly cautious)
>> +        * let's reject both non-zero src_x and src_y.
>> +        *
>> +        * We currently know of only one use-case to reproduce a
>> +        * scenario with non-zero src_x and src_y for NV12, which
>> +        * is to gesture the YouTube Android app into full screen
>> +        * on ChromeOS.
>> +        */
>> +       if (((adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 0)) ||
>> +           (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(1, 0, 1))) &&
>> +           (state->fb && state->fb->format->format == DRM_FORMAT_NV12 &&
>> +           (scaling_info->src_rect.x != 0 || scaling_info->src_rect.y != 0)))
>> +               return -EINVAL;
>> +
>> +       scaling_info->src_rect.width = state->src_w >> 16;
>> +       if (scaling_info->src_rect.width == 0)
>> +               return -EINVAL;
>> +
>> +       scaling_info->src_rect.height = state->src_h >> 16;
>> +       if (scaling_info->src_rect.height == 0)
>> +               return -EINVAL;
>> +
>> +       scaling_info->dst_rect.x = state->crtc_x;
>> +       scaling_info->dst_rect.y = state->crtc_y;
>> +
>> +       if (state->crtc_w == 0)
>> +               return -EINVAL;
>> +
>> +       scaling_info->dst_rect.width = state->crtc_w;
>> +
>> +       if (state->crtc_h == 0)
>> +               return -EINVAL;
>> +
>> +       scaling_info->dst_rect.height = state->crtc_h;
>> +
>> +       /* DRM doesn't specify clipping on destination output. */
>> +       scaling_info->clip_rect = scaling_info->dst_rect;
>> +
>> +       /* Validate scaling per-format with DC plane caps */
>> +       if (state->plane && state->plane->dev && state->fb) {
>> +               get_min_max_dc_plane_scaling(state->plane->dev, state->fb,
>> +                                            &min_downscale, &max_upscale);
>> +       } else {
>> +               min_downscale = 250;
>> +               max_upscale = 16000;
>> +       }
>> +
>> +       scale_w = scaling_info->dst_rect.width * 1000 /
>> +                 scaling_info->src_rect.width;
>> +
>> +       if (scale_w < min_downscale || scale_w > max_upscale)
>> +               return -EINVAL;
>> +
>> +       scale_h = scaling_info->dst_rect.height * 1000 /
>> +                 scaling_info->src_rect.height;
>> +
>> +       if (scale_h < min_downscale || scale_h > max_upscale)
>> +               return -EINVAL;
>> +
>> +       /*
>> +        * The "scaling_quality" can be ignored for now, quality = 0 has DC
>> +        * assume reasonable defaults based on the format.
>> +        */
>> +
>> +       return 0;
>> +}
>> +
>> +static int dm_plane_atomic_check(struct drm_plane *plane,
>> +                                struct drm_atomic_state *state)
>> +{
>> +       struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
>> +                                                                                plane);
>> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> +       struct dc *dc = adev->dm.dc;
>> +       struct dm_plane_state *dm_plane_state;
>> +       struct dc_scaling_info scaling_info;
>> +       struct drm_crtc_state *new_crtc_state;
>> +       int ret;
>> +
>> +       trace_amdgpu_dm_plane_atomic_check(new_plane_state);
>> +
>> +       dm_plane_state = to_dm_plane_state(new_plane_state);
>> +
>> +       if (!dm_plane_state->dc_state)
>> +               return 0;
>> +
>> +       new_crtc_state =
>> +               drm_atomic_get_new_crtc_state(state,
>> +                                             new_plane_state->crtc);
>> +       if (!new_crtc_state)
>> +               return -EINVAL;
>> +
>> +       ret = dm_plane_helper_check_state(new_plane_state, new_crtc_state);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
>> +       if (ret)
>> +               return ret;
>> +
>> +       if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
>> +               return 0;
>> +
>> +       return -EINVAL;
>> +}
>> +
>> +static int dm_plane_atomic_async_check(struct drm_plane *plane,
>> +                                      struct drm_atomic_state *state)
>> +{
>> +       /* Only support async updates on cursor planes. */
>> +       if (plane->type != DRM_PLANE_TYPE_CURSOR)
>> +               return -EINVAL;
>> +
>> +       return 0;
>> +}
>> +
>> +static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
>> +                              struct dc_cursor_position *position)
>> +{
>> +       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
>> +       int x, y;
>> +       int xorigin = 0, yorigin = 0;
>> +
>> +       if (!crtc || !plane->state->fb)
>> +               return 0;
>> +
>> +       if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
>> +           (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
>> +               DRM_ERROR("%s: bad cursor width or height %d x %d\n",
>> +                         __func__,
>> +                         plane->state->crtc_w,
>> +                         plane->state->crtc_h);
>> +               return -EINVAL;
>> +       }
>> +
>> +       x = plane->state->crtc_x;
>> +       y = plane->state->crtc_y;
>> +
>> +       if (x <= -amdgpu_crtc->max_cursor_width ||
>> +           y <= -amdgpu_crtc->max_cursor_height)
>> +               return 0;
>> +
>> +       if (x < 0) {
>> +               xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
>> +               x = 0;
>> +       }
>> +       if (y < 0) {
>> +               yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
>> +               y = 0;
>> +       }
>> +       position->enable = true;
>> +       position->translate_by_source = true;
>> +       position->x = x;
>> +       position->y = y;
>> +       position->x_hotspot = xorigin;
>> +       position->y_hotspot = yorigin;
>> +
>> +       return 0;
>> +}
>> +
>> +void handle_cursor_update(struct drm_plane *plane,
>> +                                struct drm_plane_state *old_plane_state)
>> +{
>> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> +       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
>> +       struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
>> +       struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
>> +       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
>> +       uint64_t address = afb ? afb->address : 0;
>> +       struct dc_cursor_position position = {0};
>> +       struct dc_cursor_attributes attributes;
>> +       int ret;
>> +
>> +       if (!plane->state->fb && !old_plane_state->fb)
>> +               return;
>> +
>> +       DC_LOG_CURSOR("%s: crtc_id=%d with size %d to %d\n",
>> +                     __func__,
>> +                     amdgpu_crtc->crtc_id,
>> +                     plane->state->crtc_w,
>> +                     plane->state->crtc_h);
>> +
>> +       ret = get_cursor_position(plane, crtc, &position);
>> +       if (ret)
>> +               return;
>> +
>> +       if (!position.enable) {
>> +               /* turn off cursor */
>> +               if (crtc_state && crtc_state->stream) {
>> +                       mutex_lock(&adev->dm.dc_lock);
>> +                       dc_stream_set_cursor_position(crtc_state->stream,
>> +                                                     &position);
>> +                       mutex_unlock(&adev->dm.dc_lock);
>> +               }
>> +               return;
>> +       }
>> +
>> +       amdgpu_crtc->cursor_width = plane->state->crtc_w;
>> +       amdgpu_crtc->cursor_height = plane->state->crtc_h;
>> +
>> +       memset(&attributes, 0, sizeof(attributes));
>> +       attributes.address.high_part = upper_32_bits(address);
>> +       attributes.address.low_part  = lower_32_bits(address);
>> +       attributes.width             = plane->state->crtc_w;
>> +       attributes.height            = plane->state->crtc_h;
>> +       attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
>> +       attributes.rotation_angle    = 0;
>> +       attributes.attribute_flags.value = 0;
>> +
>> +       attributes.pitch = afb->base.pitches[0] / afb->base.format->cpp[0];
>> +
>> +       if (crtc_state->stream) {
>> +               mutex_lock(&adev->dm.dc_lock);
>> +               if (!dc_stream_set_cursor_attributes(crtc_state->stream,
>> +                                                        &attributes))
>> +                       DRM_ERROR("DC failed to set cursor attributes\n");
>> +
>> +               if (!dc_stream_set_cursor_position(crtc_state->stream,
>> +                                                  &position))
>> +                       DRM_ERROR("DC failed to set cursor position\n");
>> +               mutex_unlock(&adev->dm.dc_lock);
>> +       }
>> +}
>> +
>> +static void dm_plane_atomic_async_update(struct drm_plane *plane,
>> +                                        struct drm_atomic_state *state)
>> +{
>> +       struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
>> +                                                                          plane);
>> +       struct drm_plane_state *old_state =
>> +               drm_atomic_get_old_plane_state(state, plane);
>> +
>> +       trace_amdgpu_dm_atomic_update_cursor(new_state);
>> +
>> +       swap(plane->state->fb, new_state->fb);
>> +
>> +       plane->state->src_x = new_state->src_x;
>> +       plane->state->src_y = new_state->src_y;
>> +       plane->state->src_w = new_state->src_w;
>> +       plane->state->src_h = new_state->src_h;
>> +       plane->state->crtc_x = new_state->crtc_x;
>> +       plane->state->crtc_y = new_state->crtc_y;
>> +       plane->state->crtc_w = new_state->crtc_w;
>> +       plane->state->crtc_h = new_state->crtc_h;
>> +
>> +       handle_cursor_update(plane, old_state);
>> +}
>> +
>> +static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
>> +       .prepare_fb = dm_plane_helper_prepare_fb,
>> +       .cleanup_fb = dm_plane_helper_cleanup_fb,
>> +       .atomic_check = dm_plane_atomic_check,
>> +       .atomic_async_check = dm_plane_atomic_async_check,
>> +       .atomic_async_update = dm_plane_atomic_async_update
>> +};
>> +
>> +static void dm_drm_plane_reset(struct drm_plane *plane)
>> +{
>> +       struct dm_plane_state *amdgpu_state = NULL;
>> +
>> +       if (plane->state)
>> +               plane->funcs->atomic_destroy_state(plane, plane->state);
>> +
>> +       amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
>> +       WARN_ON(amdgpu_state == NULL);
>> +
>> +       if (amdgpu_state)
>> +               __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +       if (amdgpu_state)
>> +               amdgpu_state->sdr_boost = DEFAULT_SDR_BOOST;
>> +#endif
>> +}
>> +
>> +static struct drm_plane_state *
>> +dm_drm_plane_duplicate_state(struct drm_plane *plane)
>> +{
>> +       struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
>> +
>> +       old_dm_plane_state = to_dm_plane_state(plane->state);
>> +       dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
>> +       if (!dm_plane_state)
>> +               return NULL;
>> +
>> +       __drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
>> +
>> +       if (old_dm_plane_state->dc_state) {
>> +               dm_plane_state->dc_state = old_dm_plane_state->dc_state;
>> +               dc_plane_state_retain(dm_plane_state->dc_state);
>> +       }
>> +
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +       if (dm_plane_state->degamma_lut)
>> +               drm_property_blob_get(dm_plane_state->degamma_lut);
>> +       if (dm_plane_state->ctm)
>> +               drm_property_blob_get(dm_plane_state->ctm);
>> +
>> +       dm_plane_state->sdr_boost = old_dm_plane_state->sdr_boost;
>> +#endif
>> +
>> +       return &dm_plane_state->base;
>> +}
>> +
>> +static bool dm_plane_format_mod_supported(struct drm_plane *plane,
>> +                                         uint32_t format,
>> +                                         uint64_t modifier)
>> +{
>> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> +       const struct drm_format_info *info = drm_format_info(format);
>> +       struct hw_asic_id asic_id = adev->dm.dc->ctx->asic_id;
>> +
>> +       enum dm_micro_swizzle microtile = modifier_gfx9_swizzle_mode(modifier) & 3;
>> +
>> +       if (!info)
>> +               return false;
>> +
>> +       /*
>> +        * We always have to allow these modifiers:
>> +        * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers.
>> +        * 2. Not passing any modifiers is the same as explicitly passing INVALID.
>> +        */
>> +       if (modifier == DRM_FORMAT_MOD_LINEAR ||
>> +           modifier == DRM_FORMAT_MOD_INVALID) {
>> +               return true;
>> +       }
>> +
>> +       /* check if swizzle mode is supported by this version of DCN */
>> +       switch (asic_id.chip_family) {
>> +       case FAMILY_SI:
>> +       case FAMILY_CI:
>> +       case FAMILY_KV:
>> +       case FAMILY_CZ:
>> +       case FAMILY_VI:
>> +               /* asics before AI does not have modifier support */
>> +               return false;
>> +       case FAMILY_AI:
>> +       case FAMILY_RV:
>> +       case FAMILY_NV:
>> +       case FAMILY_VGH:
>> +       case FAMILY_YELLOW_CARP:
>> +       case AMDGPU_FAMILY_GC_10_3_6:
>> +       case AMDGPU_FAMILY_GC_10_3_7:
>> +               switch (AMD_FMT_MOD_GET(TILE, modifier)) {
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_D:
>> +                       return true;
>> +               default:
>> +                       return false;
>> +               }
>> +               break;
>> +       case AMDGPU_FAMILY_GC_11_0_0:
>> +               switch (AMD_FMT_MOD_GET(TILE, modifier)) {
>> +               case AMD_FMT_MOD_TILE_GFX11_256K_R_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
>> +               case AMD_FMT_MOD_TILE_GFX9_64K_D:
>> +                       return true;
>> +               default:
>> +                       return false;
>> +               }
>> +               break;
>> +       default:
>> +               ASSERT(0); /* Unknown asic */
>> +               break;
>> +       }
>> +
>> +       /*
>> +        * For D swizzle the canonical modifier depends on the bpp, so check
>> +        * it here.
>> +        */
>> +       if (AMD_FMT_MOD_GET(TILE_VERSION, modifier) == AMD_FMT_MOD_TILE_VER_GFX9 &&
>> +           adev->family >= AMDGPU_FAMILY_NV) {
>> +               if (microtile == MICRO_SWIZZLE_D && info->cpp[0] == 4)
>> +                       return false;
>> +       }
>> +
>> +       if (adev->family >= AMDGPU_FAMILY_RV && microtile == MICRO_SWIZZLE_D &&
>> +           info->cpp[0] < 8)
>> +               return false;
>> +
>> +       if (modifier_has_dcc(modifier)) {
>> +               /* Per radeonsi comments 16/64 bpp are more complicated. */
>> +               if (info->cpp[0] != 4)
>> +                       return false;
>> +               /* We support multi-planar formats, but not when combined with
>> +                * additional DCC metadata planes.
>> +                */
>> +               if (info->num_planes > 1)
>> +                       return false;
>> +       }
>> +
>> +       return true;
>> +}
>> +
>> +static void dm_drm_plane_destroy_state(struct drm_plane *plane,
>> +                               struct drm_plane_state *state)
>> +{
>> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
>> +
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +       drm_property_blob_put(dm_plane_state->degamma_lut);
>> +       drm_property_blob_put(dm_plane_state->ctm);
>> +#endif
>> +       if (dm_plane_state->dc_state)
>> +               dc_plane_state_release(dm_plane_state->dc_state);
>> +
>> +       drm_atomic_helper_plane_destroy_state(plane, state);
>> +}
>> +
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +/* copied from drm_atomic_uapi.c */
>> +static int atomic_replace_property_blob_from_id(struct drm_device *dev,
>> +                                        struct drm_property_blob **blob,
>> +                                        uint64_t blob_id,
>> +                                        ssize_t expected_size,
>> +                                        ssize_t expected_elem_size,
>> +                                        bool *replaced)
>> +{
>> +       struct drm_property_blob *new_blob = NULL;
>> +
>> +       if (blob_id != 0) {
>> +               new_blob = drm_property_lookup_blob(dev, blob_id);
>> +               if (new_blob == NULL)
>> +                       return -EINVAL;
>> +
>> +               if (expected_size > 0 &&
>> +                   new_blob->length != expected_size) {
>> +                       drm_property_blob_put(new_blob);
>> +                       return -EINVAL;
>> +               }
>> +               if (expected_elem_size > 0 &&
>> +                   new_blob->length % expected_elem_size != 0) {
>> +                       drm_property_blob_put(new_blob);
>> +                       return -EINVAL;
>> +               }
>> +       }
>> +
>> +       *replaced |= drm_property_replace_blob(blob, new_blob);
>> +       drm_property_blob_put(new_blob);
>> +
>> +       return 0;
>> +}
>> +
>> +int dm_drm_plane_set_property(struct drm_plane *plane,
>> +                             struct drm_plane_state *state,
>> +                             struct drm_property *property,
>> +                             uint64_t val)
>> +{
>> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
>> +       int ret = 0;
>> +       bool replaced;
>> +
>> +       if (property == adev->dm.degamma_lut_property) {
>> +               ret = atomic_replace_property_blob_from_id(adev_to_drm(adev),
>> +                               &dm_plane_state->degamma_lut,
>> +                               val, -1, sizeof(struct drm_color_lut),
>> +                               &replaced);
>> +       } else if (property == adev->dm.ctm_property) {
>> +               ret = atomic_replace_property_blob_from_id(adev_to_drm(adev),
>> +                               &dm_plane_state->ctm,
>> +                               val,
>> +                               sizeof(struct drm_color_ctm), -1,
>> +                               &replaced);
>> +       } else if (property == adev->dm.sdr_boost_property) {
>> +               dm_plane_state->sdr_boost = val;
>> +       } else {
>> +               return -EINVAL;
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +int dm_drm_plane_get_property(struct drm_plane *plane,
>> +                             const struct drm_plane_state *state,
>> +                             struct drm_property *property,
>> +                             uint64_t *val)
>> +{
>> +       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
>> +       struct amdgpu_device *adev = drm_to_adev(plane->dev);
>> +
>> +       if (property == adev->dm.degamma_lut_property) {
>> +               *val = (dm_plane_state->degamma_lut) ?
>> +                       dm_plane_state->degamma_lut->base.id : 0;
>> +       } else if (property == adev->dm.ctm_property) {
>> +               *val = (dm_plane_state->ctm) ? dm_plane_state->ctm->base.id : 0;
>> +       } else if (property == adev->dm.sdr_boost_property) {
>> +               *val = dm_plane_state->sdr_boost;
>> +       } else {
>> +               return -EINVAL;
>> +       }
>> +
>> +       return 0;
>> +}
>> +#endif
>> +
>> +static const struct drm_plane_funcs dm_plane_funcs = {
>> +       .update_plane   = drm_atomic_helper_update_plane,
>> +       .disable_plane  = drm_atomic_helper_disable_plane,
>> +       .destroy        = drm_primary_helper_destroy,
>> +       .reset = dm_drm_plane_reset,
>> +       .atomic_duplicate_state = dm_drm_plane_duplicate_state,
>> +       .atomic_destroy_state = dm_drm_plane_destroy_state,
>> +       .format_mod_supported = dm_plane_format_mod_supported,
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +       .atomic_set_property = dm_drm_plane_set_property,
>> +       .atomic_get_property = dm_drm_plane_get_property,
>> +#endif
>> +};
>> +
>> +int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
>> +                               struct drm_plane *plane,
>> +                               unsigned long possible_crtcs,
>> +                               const struct dc_plane_cap *plane_cap)
>> +{
>> +       uint32_t formats[32];
>> +       int num_formats;
>> +       int res = -EPERM;
>> +       unsigned int supported_rotations;
>> +       uint64_t *modifiers = NULL;
>> +
>> +       num_formats = get_plane_formats(plane, plane_cap, formats,
>> +                                       ARRAY_SIZE(formats));
>> +
>> +       res = get_plane_modifiers(dm->adev, plane->type, &modifiers);
>> +       if (res)
>> +               return res;
>> +
>> +       res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
>> +                                      &dm_plane_funcs, formats, num_formats,
>> +                                      modifiers, plane->type, NULL);
>> +       kfree(modifiers);
>> +       if (res)
>> +               return res;
>> +
>> +       if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
>> +           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);
>> +
>> +               drm_plane_create_alpha_property(plane);
>> +               drm_plane_create_blend_mode_property(plane, blend_caps);
>> +       }
>> +
>> +       if (plane->type == DRM_PLANE_TYPE_PRIMARY &&
>> +           plane_cap &&
>> +           (plane_cap->pixel_format_support.nv12 ||
>> +            plane_cap->pixel_format_support.p010)) {
>> +               /* This only affects YUV formats. */
>> +               drm_plane_create_color_properties(
>> +                       plane,
>> +                       BIT(DRM_COLOR_YCBCR_BT601) |
>> +                       BIT(DRM_COLOR_YCBCR_BT709) |
>> +                       BIT(DRM_COLOR_YCBCR_BT2020),
>> +                       BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
>> +                       BIT(DRM_COLOR_YCBCR_FULL_RANGE),
>> +                       DRM_COLOR_YCBCR_BT709, DRM_COLOR_YCBCR_LIMITED_RANGE);
>> +       }
>> +
>> +       supported_rotations =
>> +               DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
>> +               DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
>> +
>> +       if (dm->adev->asic_type >= CHIP_BONAIRE &&
>> +           plane->type != DRM_PLANE_TYPE_CURSOR)
>> +               drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
>> +                                                  supported_rotations);
>> +
>> +       drm_plane_helper_add(plane, &dm_plane_helper_funcs);
>> +
>> +#ifdef CONFIG_DRM_AMD_DC_HDR
>> +       attach_color_mgmt_properties(dm, plane);
>> +#endif
>> +       /* Create (reset) the plane state */
>> +       if (plane->funcs->reset)
>> +               plane->funcs->reset(plane);
>> +
>> +       return 0;
>> +}
>> +
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
>> new file mode 100644
>> index 000000000000..95168c2cfa6f
>> --- /dev/null
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h
>> @@ -0,0 +1,73 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * Copyright 2022 Advanced Micro Devices, Inc.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> + * Authors: AMD
>> + *
>> + */
>> +
>> +#ifndef __AMDGPU_DM_PLANE_H__
>> +#define __AMDGPU_DM_PLANE_H__
>> +
>> +#include "dc.h"
>> +
>> +void handle_cursor_update(struct drm_plane *plane,
>> +                         struct drm_plane_state *old_plane_state);
>> +
>> +int fill_dc_scaling_info(struct amdgpu_device *adev,
>> +                        const struct drm_plane_state *state,
>> +                        struct dc_scaling_info *scaling_info);
>> +
>> +void get_min_max_dc_plane_scaling(struct drm_device *dev,
>> +                                 struct drm_framebuffer *fb,
>> +                                 int *min_downscale, int *max_upscale);
>> +
>> +int dm_plane_helper_check_state(struct drm_plane_state *state,
>> +                               struct drm_crtc_state *new_crtc_state);
>> +
>> +bool modifier_has_dcc(uint64_t modifier);
>> +
>> +unsigned int modifier_gfx9_swizzle_mode(uint64_t modifier);
>> +
>> +int fill_plane_buffer_attributes(struct amdgpu_device *adev,
>> +                                const struct amdgpu_framebuffer *afb,
>> +                                const enum surface_pixel_format format,
>> +                                const enum dc_rotation_angle rotation,
>> +                                const uint64_t tiling_flags,
>> +                                union dc_tiling_info *tiling_info,
>> +                                struct plane_size *plane_size,
>> +                                struct dc_plane_dcc_param *dcc,
>> +                                struct dc_plane_address *address,
>> +                                bool tmz_surface,
>> +                                bool force_disable_dcc);
>> +
>> +int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
>> +                        struct drm_plane *plane,
>> +                        unsigned long possible_crtcs,
>> +                        const struct dc_plane_cap *plane_cap);
>> +
>> +const struct drm_format_info *amd_get_format_info(const struct drm_mode_fb_cmd2 *cmd);
>> +
>> +void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
>> +                                   bool *per_pixel_alpha, bool *pre_multiplied_alpha,
>> +                                   bool *global_alpha, int *global_alpha_value);
>> +
>> +#endif
>> --
>> 2.37.0
>>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 09/31] drm/amd/display: Create a file dedicated for CRTC
  2022-07-15 18:16 ` [PATCH 09/31] drm/amd/display: Create a file dedicated for CRTC Rodrigo Siqueira
@ 2022-07-20 17:36   ` André Almeida
  0 siblings, 0 replies; 36+ messages in thread
From: André Almeida @ 2022-07-20 17:36 UTC (permalink / raw)
  To: Rodrigo Siqueira
  Cc: stylon.wang, Alan Liu, Sunpeng.Li, Bhawanpreet.Lakha,
	qingqing.zhuo, roman.li, amd-gfx, solomon.chiu, Aurabindo.Pillai,
	wayne.lin, Harry.Wentland, agustin.gutierrez, pavle.kotarac

Hi Siqueira :)

Às 15:16 de 15/07/22, Rodrigo Siqueira escreveu:
> [Why]
> The amdgpu_dm file contains most of the code that works as an interface
> between DRM API and DC. As a result, this file becomes very large since
> it comprises multiple abstractions such as CRTC manipulation.
> 
> [How]
> This commit extracts the CRTC code to its specific file named
> amdgpu_dm_crtc. This change does not change anything inside the
> functions; the only exception is converting some static functions to a
> global function.
> 
> Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
> Acked-by: Alan Liu <HaoPing.Liu@amd.com>
> Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
> ---

[...]

> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> new file mode 100644
> index 000000000000..a9413acfe4dc
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
> @@ -0,0 +1,463 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright 2022 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: AMD
> + *
> + */
> +#include <drm/drm_vblank.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +#include "dc.h"
> +#include "amdgpu.h"
> +#include "amdgpu_dm_psr.h"
> +#include "amdgpu_dm_crtc.h"
> +#include "amdgpu_dm_plane.h"
> +#include "amdgpu_dm_trace.h"
> +#include "amdgpu_dm_debugfs.h"
> +

It's a good idea do keep includes ordered like

+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "amdgpu.h"
+#include "amdgpu_dm_crtc.h"
+#include "amdgpu_dm_debugfs.h"
+#include "amdgpu_dm_plane.h"
+#include "amdgpu_dm_psr.h"
+#include "amdgpu_dm_trace.h"
+#include "dc.h"

because it's easier to check for duplicates and prevents the need for
fixes like this in the future:
https://gitlab.freedesktop.org/agd5f/linux/-/commit/b7be3ae759160aa3355ebeb0583f67fb9bda4dae



^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2022-07-20 17:37 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-15 18:16 [PATCH 00/31] DC Patches July 15, 2022 Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 01/31] drm/amd/display: Support vertical interrupt 0 for all dcn ASIC Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 02/31] drm/amd/display: Remove unused variable Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 03/31] drm/amd/display: Update in dml Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 04/31] drm/amd/display: Expose function reset_cur_dp_mst_topology Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 05/31] drm/amd/display: fix trigger_hotplug to support mst case Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 06/31] drm/amd/display: Add is_mst_connector debugfs entry Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 07/31] drm/amd/display: Add tags for indicating mst progress status Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 08/31] drm/amd/display: Create a file dedicated to planes Rodrigo Siqueira
2022-07-18 14:29   ` Alex Deucher
2022-07-18 14:55     ` Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 09/31] drm/amd/display: Create a file dedicated for CRTC Rodrigo Siqueira
2022-07-20 17:36   ` André Almeida
2022-07-15 18:16 ` [PATCH 10/31] drm/amd/display: remove number of DSC slices override in DML Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 11/31] drm/amd/display: Fix hard hang if DSC is disabled Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 12/31] drm/amd/display: Don't set dram clock change requirement for SubVP Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 13/31] drm/amd/display: Update de-tile override to anticipate pipe splitting Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 14/31] drm/amd/display: Disable GPUVM in IP resource configuration Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 15/31] drm/amd/display: Loop through all pipes for DET allocation Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 16/31] drm/amd/display: Update Cursor Attribute MALL cache Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 17/31] drm/amd/display: Update DML logic for unbounded req handling Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 18/31] drm/amd/display: Drop FPU flags from dcn32_clk_mgr Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 19/31] drm/amd/display: Move populate phaton function to dml Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 20/31] drm/amd/display: Move predict pipe to dml fpu folder Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 21/31] drm/amd/display: Move insert entry table to the FPU code Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 22/31] drm/amd/display: Move phanton stream to " Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 23/31] drm/amd/display: Move SubVP functions to dcn32_fpu Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 24/31] drm/amd/display: Move wm and dlg calculation to FPU code Rodrigo Siqueira
2022-07-15 18:16 ` [PATCH 25/31] drm/amd/display: Move dlg params calculation Rodrigo Siqueira
2022-07-15 18:17 ` [PATCH 26/31] drm/amd/display: Move ntuple to insert entry Rodrigo Siqueira
2022-07-15 18:17 ` [PATCH 27/31] drm/amd/display: Move bounding box to FPU folder Rodrigo Siqueira
2022-07-15 18:17 ` [PATCH 28/31] drm/amd/display: Drop FPU flags from dcn32 Makefile Rodrigo Siqueira
2022-07-15 18:17 ` [PATCH 29/31] drm/amd/display: Create dcn321_fpu file Rodrigo Siqueira
2022-07-15 18:17 ` [PATCH 30/31] drm/amd/display: Drop FPU code from dcn321 resource Rodrigo Siqueira
2022-07-15 18:17 ` [PATCH 31/31] drm/amd/display: 3.2.195 Rodrigo Siqueira
2022-07-18 13:15 ` [PATCH 00/31] DC Patches July 15, 2022 Wheeler, Daniel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).