dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 00/14] add display port DSC feature
@ 2023-01-23 18:24 Kuogee Hsieh
  2023-01-23 18:24 ` [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability Kuogee Hsieh
                   ` (16 more replies)
  0 siblings, 17 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

This patch add DSC related supporting functions into to both dp controller and dpu enccoder

Kuogee Hsieh (14):
  drm/msm/dp: add dpcd read of both dsc and fec capability
  drm/msm/dp: add dsc factor into calculation of supported bpp
  drm/msm/dp: add configure mainlink_levels base on lane number
  drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
  drm/msm/dp: upgrade tu calculation base on newest algorithm
  drm/msm/dp: add display compression related struct
  drm/msm/dp: add dsc helper functions
  drm/msm/dp: add dsc supporting functions to DP controller
  drm/msm/dsi: export struct msm_compression_info to dpu encoder
  drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  drm/msm/disp/dpu1: add supports of new flush mechanism
  drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder
  drm/msm/disp/dpu1: add sc7280 dsc block and sub block

 drivers/gpu/drm/msm/Makefile                       |   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c     | 537 +++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h     |  25 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 341 +++++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   4 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   7 +-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  43 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c     |  50 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  74 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         |  43 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         |  21 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  23 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |  23 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c     | 371 +++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 ++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            |  10 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c                | 176 ++++-
 drivers/gpu/drm/msm/dp/dp_catalog.h                |  97 ++-
 drivers/gpu/drm/msm/dp/dp_ctrl.c                   | 839 ++++++++++++++-------
 drivers/gpu/drm/msm/dp/dp_display.c                |  61 +-
 drivers/gpu/drm/msm/dp/dp_link.c                   |  29 +-
 drivers/gpu/drm/msm/dp/dp_panel.c                  | 749 +++++++++++++++++-
 drivers/gpu/drm/msm/dp/dp_panel.h                  |  67 +-
 drivers/gpu/drm/msm/dp/dp_reg.h                    |  40 +-
 drivers/gpu/drm/msm/dsi/dsi.c                      |   3 +-
 drivers/gpu/drm/msm/dsi/dsi.h                      |   3 +-
 drivers/gpu/drm/msm/dsi/dsi_host.c                 |  14 +-
 drivers/gpu/drm/msm/msm_drv.h                      | 113 ++-
 32 files changed, 3429 insertions(+), 497 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:17   ` Dmitry Baryshkov
  2023-01-23 18:24 ` [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp Kuogee Hsieh
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

FEC is pre-requirement of DSC. Therefore FEC has to be enabled
before DSC enabled. This patch add functions to read sink's DSC
and FEC related DPCD and decode them and set enable flags
accordingly.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_panel.c | 91 ++++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/msm/dp/dp_panel.h | 20 ++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 1800d89..5078247 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -1,14 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #include "dp_panel.h"
 
+#include <drm/drm_fixed.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
 
+#define DSC_TGT_BPP 8
+
 struct dp_panel_private {
 	struct device *dev;
 	struct drm_device *drm_dev;
@@ -68,6 +72,9 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
 		goto end;
 	}
 
+	print_hex_dump_debug("[drm-dp] SINK DPCD: ",
+		DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
+
 	link_info->revision = dpcd[DP_DPCD_REV];
 	major = (link_info->revision >> 4) & 0x0f;
 	minor = link_info->revision & 0x0f;
@@ -154,6 +161,83 @@ static int dp_panel_update_modes(struct drm_connector *connector,
 	return rc;
 }
 
+static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel)
+{
+	if (dp_panel->dsc_dpcd[0]) {
+		dp_panel->sink_dsc_caps.dsc_capable = true;
+		dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1];
+		dp_panel->sink_dsc_caps.block_pred_en =
+				dp_panel->dsc_dpcd[6] ? true : false;
+		dp_panel->sink_dsc_caps.color_depth =
+				dp_panel->dsc_dpcd[10];
+
+		if (dp_panel->sink_dsc_caps.version >= 0x11)
+			dp_panel->dsc_en = true;
+	} else {
+		dp_panel->sink_dsc_caps.dsc_capable = false;
+		dp_panel->dsc_en = false;
+	}
+}
+
+static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel)
+{
+	int rlen;
+	struct dp_panel_private *panel;
+	int dpcd_rev;
+
+	if (!dp_panel) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	dpcd_rev = dp_panel->dpcd[DP_DPCD_REV];
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+	if (dpcd_rev >= 0x14) {
+		rlen = drm_dp_dpcd_read(panel->aux, DP_DSC_SUPPORT,
+			dp_panel->dsc_dpcd, (DP_DSC_RECEIVER_CAP_SIZE + 1));
+		if (rlen < (DP_DSC_RECEIVER_CAP_SIZE + 1)) {
+			drm_dbg_dp(panel->drm_dev, "dsc dpcd read failed, rlen=%d\n", rlen);
+			return;
+		}
+
+		print_hex_dump_debug("[drm-dp] SINK DSC DPCD: ",
+			DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen, false);
+
+		dp_panel_decode_dsc_dpcd(dp_panel);
+	}
+}
+
+static void dp_panel_read_sink_fec_caps(struct dp_panel *dp_panel)
+{
+	int rlen;
+	struct dp_panel_private *panel;
+	s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1);
+
+	if (!dp_panel) {
+		DRM_ERROR("invalid input\n");
+		return;
+	}
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+	rlen = drm_dp_dpcd_readb(panel->aux, DP_FEC_CAPABILITY,
+			&dp_panel->fec_dpcd);
+	if (rlen < 1) {
+		DRM_ERROR("fec capability read failed, rlen=%d\n", rlen);
+		return;
+	}
+
+	print_hex_dump_debug("[drm-dp] SINK FEC DPCD: ",
+		DUMP_PREFIX_NONE, 8, 1, &dp_panel->fec_dpcd, rlen, false);
+
+	dp_panel->fec_en = dp_panel->fec_dpcd & DP_FEC_CAPABLE;
+
+	if (dp_panel->fec_en)
+		fec_overhead_fp = drm_fixp_from_fraction(100000, 97582);
+
+	dp_panel->fec_overhead_fp = fec_overhead_fp;
+}
+
 int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
 	struct drm_connector *connector)
 {
@@ -224,6 +308,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
 		}
 		panel->aux_cfg_update_done = false;
 	}
+
+	dp_panel_read_sink_fec_caps(dp_panel);
+
+	if (dp_panel->fec_en)
+		dp_panel_read_sink_dsc_caps(dp_panel);
 end:
 	return rc;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index f04d021..fb30b92 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #ifndef _DP_PANEL_H_
@@ -11,6 +12,7 @@
 #include "dp_aux.h"
 #include "dp_link.h"
 #include "dp_hpd.h"
+#include "msm_drv.h"
 
 struct edid;
 
@@ -34,12 +36,21 @@ struct dp_panel_in {
 	struct dp_catalog *catalog;
 };
 
+struct dp_dsc_caps {
+	bool dsc_capable;
+	u8 version;
+	bool block_pred_en;
+	u8 color_depth;
+};
+
 struct dp_panel {
 	/* dpcd raw data */
 	u8 dpcd[DP_RECEIVER_CAP_SIZE + 1];
 	u8 ds_cap_info[DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE];
 	u32 ds_port_cnt;
 	u32 dfp_present;
+	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE + 1];
+	u8 fec_dpcd;
 
 	struct dp_link_info link_info;
 	struct drm_dp_desc desc;
@@ -53,6 +64,13 @@ struct dp_panel {
 	u32 max_dp_link_rate;
 
 	u32 max_bw_code;
+
+	struct dp_dsc_caps sink_dsc_caps;
+	bool dsc_feature_enable;
+	bool fec_feature_enable;
+	bool dsc_en;
+	bool fec_en;
+	s64 fec_overhead_fp;
 };
 
 int dp_panel_init_panel_info(struct dp_panel *dp_panel);
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
  2023-01-23 18:24 ` [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 23:38   ` kernel test robot
  2023-01-23 18:24 ` [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number Kuogee Hsieh
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

When FEC enabled, it introduces 2.5% overhead into link capacity.
This factor have to be considered into calculation supported bpp.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_panel.c | 45 +++++++++++++++++++++++++++++++++------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 5078247..36dad05 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -11,7 +11,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
 
-#define DSC_TGT_BPP 8
+#define DSC_TGT_BPP 10
 
 struct dp_panel_private {
 	struct device *dev;
@@ -122,20 +122,51 @@ static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel,
 		u32 mode_edid_bpp, u32 mode_pclk_khz)
 {
 	struct dp_link_info *link_info;
-	const u32 max_supported_bpp = 30, min_supported_bpp = 18;
-	u32 bpp = 0, data_rate_khz = 0;
+	struct dp_panel_private *panel;
+	const u32 max_supported_bpp = 30;
+	u32 min_supported_bpp = 18;
+	u32 bpp = 0, link_bitrate = 0, mode_bitrate;
+	s64 rate_fp = 0;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	if (dp_panel->dsc_en)
+		min_supported_bpp = 24;
 
 	bpp = min_t(u32, mode_edid_bpp, max_supported_bpp);
 
 	link_info = &dp_panel->link_info;
-	data_rate_khz = link_info->num_lanes * link_info->rate * 8;
 
-	while (bpp > min_supported_bpp) {
-		if (mode_pclk_khz * bpp <= data_rate_khz)
+	rate_fp = drm_int2fixp(link_info->num_lanes * link_info->rate * 8);
+
+	if (dp_panel->fec_en)
+		rate_fp = drm_fixp_div(rate_fp, dp_panel->fec_overhead_fp);
+
+	link_bitrate = drm_fixp2int(rate_fp);
+
+	for (; bpp > min_supported_bpp; bpp -= 6) {
+		if (dp_panel->dsc_en) {
+			if (bpp == 30 && !(dp_panel->sink_dsc_caps.color_depth & DP_DSC_10_BPC))
+				continue;
+			else if (bpp == 24 && !(dp_panel->sink_dsc_caps.color_depth & DP_DSC_8_BPC))
+				continue;
+
+			mode_bitrate = mode_pclk_khz * DSC_TGT_BPP;
+		} else {
+			mode_bitrate = mode_pclk_khz * bpp;
+		}
+
+		if (mode_bitrate <= link_bitrate)
 			break;
-		bpp -= 6;
 	}
 
+	if (bpp < min_supported_bpp)
+		DRM_ERROR("bpp %d is below minimum supported bpp %d\n", bpp,
+				min_supported_bpp);
+
+	if (dp_panel->dsc_en && bpp != 24 && bpp != 30 && bpp != 36)
+		DRM_ERROR("bpp %d is not supported when dsc is enabled\n", bpp);
+
 	return bpp;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
  2023-01-23 18:24 ` [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability Kuogee Hsieh
  2023-01-23 18:24 ` [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:34   ` Dmitry Baryshkov
  2023-01-23 18:24 ` [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0 Kuogee Hsieh
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

Mainlink_levels determined when two actions to take place by hardware,
a new BS sequence due to start of video and a static HW MVID is sent
to panel. This patch add function to configure mainlink level properly
base on lane number.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 37 ++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/msm/dp/dp_catalog.h |  4 +++-
 drivers/gpu/drm/msm/dp/dp_ctrl.c    |  4 ++++
 3 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..7ac37d8 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
@@ -359,6 +360,40 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog)
 			ln_mapping);
 }
 
+void dp_catalog_ctrl_mainlink_levels(struct dp_catalog *dp_catalog,
+					u8 lane_cnt)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	u32 mainlink_levels, safe_to_exit_level = 14;
+
+	switch (lane_cnt) {
+	case 1:
+		safe_to_exit_level = 14;
+		break;
+	case 2:
+		safe_to_exit_level = 8;
+		break;
+	case 4:
+		safe_to_exit_level = 5;
+		break;
+	default:
+		drm_dbg_dp(catalog->drm_dev, "setting the default safe_to_exit_level=%u\n",
+				safe_to_exit_level);
+		break;
+	}
+
+	mainlink_levels = dp_read_link(catalog, REG_DP_MAINLINK_LEVELS);
+	mainlink_levels &= 0xFE0;
+	mainlink_levels |= safe_to_exit_level;
+
+	drm_dbg_dp(catalog->drm_dev, "mainlink_level=0x%x, safe_to_exit_level=0x%x\n",
+		mainlink_levels, safe_to_exit_level);
+
+	dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, mainlink_levels);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
 						bool enable)
 {
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..990c162 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #ifndef _DP_CATALOG_H_
@@ -92,6 +93,7 @@ u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state);
 void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config);
 void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_mainlink_levels(struct dp_catalog *dp_catalog, u8 lane_cnt);
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable);
 void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index dd26ca6..959a78c 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -161,6 +161,8 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
 	u32 cc, tb;
 
 	dp_catalog_ctrl_lane_mapping(ctrl->catalog);
+	dp_catalog_ctrl_mainlink_levels(ctrl->catalog,
+				ctrl->link->link_params.num_lanes);
 	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
 
 	dp_ctrl_config_ctrl(ctrl);
@@ -1296,6 +1298,8 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
 {
 	int ret = 0;
 
+	dp_catalog_ctrl_mainlink_levels(ctrl->catalog,
+				ctrl->link->link_params.num_lanes);
 	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
 
 	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (2 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:41   ` Dmitry Baryshkov
  2023-01-24  0:49   ` kernel test robot
  2023-01-23 18:24 ` [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm Kuogee Hsieh
                   ` (12 subsequent siblings)
  16 siblings, 2 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

MSA MISC0 bit 1 to 7 contains Colorimetry Indicator Field. At current
implementation, Colorimetry Indicator Field of MISC0 is not configured
correctly. This patch add support of RGB formats Colorimetry.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c  |  5 +++--
 drivers/gpu/drm/msm/dp/dp_link.c  | 29 +++++++++++++++++++------
 drivers/gpu/drm/msm/dp/dp_panel.c | 45 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_panel.h |  1 +
 4 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 959a78c..d0d1848 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
@@ -169,7 +170,7 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
 
 	tb = dp_link_get_test_bits_depth(ctrl->link,
 		ctrl->panel->dp_mode.bpp);
-	cc = dp_link_get_colorimetry_config(ctrl->link);
+	cc = dp_panel_get_misc_colorimetry_val(ctrl->panel);
 	dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb);
 	dp_panel_timing_cfg(ctrl->panel);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index f1f1d64..e957948 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
@@ -12,6 +13,12 @@
 
 #define DP_TEST_REQUEST_MASK		0x7F
 
+enum dynamic_range {
+	DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
+	DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
+	DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF,
+};
+
 enum audio_sample_rate {
 	AUDIO_SAMPLE_RATE_32_KHZ	= 0x00,
 	AUDIO_SAMPLE_RATE_44_1_KHZ	= 0x01,
@@ -1079,6 +1086,7 @@ int dp_link_process_request(struct dp_link *dp_link)
 int dp_link_get_colorimetry_config(struct dp_link *dp_link)
 {
 	u32 cc;
+	enum dynamic_range dr;
 	struct dp_link_private *link;
 
 	if (!dp_link) {
@@ -1088,14 +1096,21 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link)
 
 	link = container_of(dp_link, struct dp_link_private, dp_link);
 
-	/*
-	 * Unless a video pattern CTS test is ongoing, use RGB_VESA
-	 * Only RGB_VESA and RGB_CEA supported for now
-	 */
+	/* unless a video pattern CTS test is ongoing, use CEA_VESA */
 	if (dp_link_is_video_pattern_requested(link))
-		cc = link->dp_link.test_video.test_dyn_range;
+		dr = link->dp_link.test_video.test_dyn_range;
 	else
-		cc = DP_TEST_DYNAMIC_RANGE_VESA;
+		dr = DP_DYNAMIC_RANGE_RGB_VESA;
+
+	/* Only RGB_VESA nd RGB_CEA supported for now */
+	switch (dr) {
+	case DP_DYNAMIC_RANGE_RGB_CEA:
+		cc = BIT(2);
+		break;
+	case DP_DYNAMIC_RANGE_RGB_VESA:
+	default:
+		cc = 0;
+	}
 
 	return cc;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 36dad05..55bb6b0 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -567,6 +567,51 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel)
 	return 0;
 }
 
+/**
+ * Mapper function which outputs colorimetry to be used for a
+ * given colorspace value when misc field of MSA is used to
+ * change the colorimetry. Currently only RGB formats have been
+ * added. This API will be extended to YUV once its supported on DP.
+ */
+u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel)
+{
+	u8 colorimetry;
+	u32 colorspace;
+	u32 cc;
+	struct dp_panel_private *panel;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	cc = dp_link_get_colorimetry_config(panel->link);
+	/*
+	 * If there is a non-zero value then compliance test-case
+	 * is going on, otherwise we can honor the colorspace setting
+	 */
+	if (cc)
+		return cc;
+
+	colorspace = dp_panel->connector->state->colorspace;
+	switch (colorspace) {
+	case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
+	case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
+		colorimetry = 0x7;
+		break;
+	case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED:
+		colorimetry = 0x3;
+		break;
+	case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT:
+		colorimetry = 0xb;
+		break;
+	case DRM_MODE_COLORIMETRY_OPRGB:
+		colorimetry = 0xc;
+		break;
+	default:
+		colorimetry = 0;
+	}
+
+	return colorimetry;
+}
+
 struct dp_panel *dp_panel_get(struct dp_panel_in *in)
 {
 	struct dp_panel_private *panel;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index fb30b92..1153e88 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -85,6 +85,7 @@ int dp_panel_get_modes(struct dp_panel *dp_panel,
 		struct drm_connector *connector);
 void dp_panel_handle_sink_request(struct dp_panel *dp_panel);
 void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable);
+u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel);
 
 /**
  * is_link_rate_valid() - validates the link rate
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (3 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0 Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 23:56   ` Dmitry Baryshkov
  2023-01-24  0:08   ` kernel test robot
  2023-01-23 18:24 ` [PATCH v1 06/14] drm/msm/dp: add display compression related struct Kuogee Hsieh
                   ` (11 subsequent siblings)
  16 siblings, 2 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

At display port, the pixel data is packed into TU (transfer units)
which is used to carry main video stream data during its horizontal active
period. TUs are mapping into the main-Link to facilitate the support of
various lane counts regardless of the pixel bit depth and colorimetry
format. Stuffing symbols are required if packed data rate less than link
symbol rate. TU size is calculated base on factors such as, pixel rate,
BPP, main link rate, main link lane and etc, and shall be 32 to 64
link symbols per lane. Each vendor has its own algorithm to calculate
TU size. This patch upgrade TU size calculation base on newest algorithm.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c | 702 +++++++++++++++++++++++----------------
 1 file changed, 416 insertions(+), 286 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index d0d1848..ae9c2b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -182,18 +182,24 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
  */
 struct tu_algo_data {
 	s64 lclk_fp;
+	s64 orig_lclk_fp;
 	s64 pclk_fp;
+	s64 orig_pclk_fp;
 	s64 lwidth;
 	s64 lwidth_fp;
+	int orig_lwidth;
 	s64 hbp_relative_to_pclk;
 	s64 hbp_relative_to_pclk_fp;
 	int nlanes;
+	int orig_hbp;
 	int bpp;
 	int pixelEnc;
 	int dsc_en;
 	int async_en;
+	int fec_en;
 	int bpc;
 
+	int rb2;
 	uint delay_start_link_extra_pixclk;
 	int extra_buffer_margin;
 	s64 ratio_fp;
@@ -250,19 +256,30 @@ struct tu_algo_data {
 	int even_distribution_BF;
 	int even_distribution_legacy;
 	int even_distribution;
+
+	int hbp_delayStartCheck;
+	int pre_tu_hw_pipe_delay;
+	int post_tu_hw_pipe_delay;
+	int link_config_hactive_time;
+	int delay_start_link_lclk;
+	int tu_active_cycles;
+	s64 parity_symbols;
+	int resolution_line_time;
+	int last_partial_lclk;
+
 	int min_hblank_violated;
 	s64 delay_start_time_fp;
 	s64 hbp_time_fp;
 	s64 hactive_time_fp;
 	s64 diff_abs_fp;
-
+	int second_loop_set;
 	s64 ratio;
 };
 
 static int _tu_param_compare(s64 a, s64 b)
 {
-	u32 a_sign;
-	u32 b_sign;
+	u32 a_int, a_frac, a_sign;
+	u32 b_int, b_frac, b_sign;
 	s64 a_temp, b_temp, minus_1;
 
 	if (a == b)
@@ -270,8 +287,12 @@ static int _tu_param_compare(s64 a, s64 b)
 
 	minus_1 = drm_fixp_from_fraction(-1, 1);
 
+	a_int = (a >> 32) & 0x7FFFFFFF;
+	a_frac = a & 0xFFFFFFFF;
 	a_sign = (a >> 32) & 0x80000000 ? 1 : 0;
 
+	b_int = (b >> 32) & 0x7FFFFFFF;
+	b_frac = b & 0xFFFFFFFF;
 	b_sign = (b >> 32) & 0x80000000 ? 1 : 0;
 
 	if (a_sign > b_sign)
@@ -295,6 +316,21 @@ static int _tu_param_compare(s64 a, s64 b)
 	}
 }
 
+static s64 fixp_subtract(s64 a, s64 b)
+{
+	s64 minus_1 = drm_fixp_from_fraction(-1, 1);
+
+	if (a >= b)
+		return a - b;
+
+	return drm_fixp_mul(b - a, minus_1);
+}
+
+static inline int fixp2int_ceil(s64 a)
+{
+	return a ? drm_fixp2int_ceil(a) : 0;
+}
+
 static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
 					struct tu_algo_data *tu)
 {
@@ -305,6 +341,7 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
 	s64 pclk_dsc_fp;
 	s64 dwidth_dsc_fp;
 	s64 hbp_dsc_fp;
+	s64 overhead_dsc;
 
 	int tot_num_eoc_symbols = 0;
 	int tot_num_hor_bytes   = 0;
@@ -315,16 +352,22 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
 	s64 temp1_fp, temp2_fp, temp3_fp;
 
 	tu->lclk_fp              = drm_fixp_from_fraction(in->lclk, 1);
+	tu->orig_lclk_fp         = tu->lclk_fp;
 	tu->pclk_fp              = drm_fixp_from_fraction(in->pclk_khz, 1000);
+	tu->orig_pclk_fp         = tu->pclk_fp;
 	tu->lwidth               = in->hactive;
 	tu->hbp_relative_to_pclk = in->hporch;
 	tu->nlanes               = in->nlanes;
 	tu->bpp                  = in->bpp;
 	tu->pixelEnc             = in->pixel_enc;
 	tu->dsc_en               = in->dsc_en;
+	tu->fec_en               = in->fec_en;
 	tu->async_en             = in->async_en;
 	tu->lwidth_fp            = drm_fixp_from_fraction(in->hactive, 1);
+	tu->orig_lwidth          = in->hactive;
 	tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1);
+	tu->orig_hbp             = in->hporch;
+	tu->rb2                  = (in->hporch <= 80) ? 1 : 0;
 
 	if (tu->pixelEnc == 420) {
 		temp1_fp = drm_fixp_from_fraction(2, 1);
@@ -378,6 +421,7 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
 	dwidth_dsc_bytes = (tot_num_hor_bytes +
 				tot_num_eoc_symbols +
 				(eoc_bytes == 0 ? 0 : tot_num_dummy_bytes));
+	overhead_dsc     = dwidth_dsc_bytes / tot_num_hor_bytes;
 
 	dwidth_dsc_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, 3);
 
@@ -409,12 +453,12 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
 	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
 
-	tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+	tu->new_valid_boundary_link = fixp2int_ceil(temp2_fp);
 
 	temp = (tu->i_upper_boundary_count *
 				tu->new_valid_boundary_link +
 				tu->i_lower_boundary_count *
-				(tu->new_valid_boundary_link-1));
+				(tu->new_valid_boundary_link - 1));
 	tu->average_valid2_fp = drm_fixp_from_fraction(temp,
 					(tu->i_upper_boundary_count +
 					tu->i_lower_boundary_count));
@@ -489,11 +533,11 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 
 	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
 	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
-	tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp;
+	tu->n_n_err_fp = fixp_subtract(tu->effective_valid_fp, temp2_fp);
 
 	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
 	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
-	tu->n_err_fp = tu->average_valid2_fp - temp2_fp;
+	tu->n_err_fp = fixp_subtract(tu->average_valid2_fp, temp2_fp);
 
 	tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
 
@@ -501,11 +545,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	temp2_fp = tu->lwidth_fp;
 	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
 	temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
-
-	if (temp2_fp)
-		tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp);
-	else
-		tu->n_tus_incl_last_incomplete_tu = 0;
+	tu->n_tus_incl_last_incomplete_tu = fixp2int_ceil(temp2_fp);
 
 	temp1 = 0;
 	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
@@ -513,9 +553,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	temp1_fp = tu->average_valid2_fp - temp2_fp;
 	temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1);
 	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
-
-	if (temp1_fp)
-		temp1 = drm_fixp2int_ceil(temp1_fp);
+	temp1 = fixp2int_ceil(temp1_fp);
 
 	temp = tu->i_upper_boundary_count * tu->nlanes;
 	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
@@ -524,32 +562,20 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	temp2_fp = temp1_fp - temp2_fp;
 	temp1_fp = drm_fixp_from_fraction(temp, 1);
 	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+	temp2 = fixp2int_ceil(temp2_fp);
 
-	if (temp2_fp)
-		temp2 = drm_fixp2int_ceil(temp2_fp);
-	else
-		temp2 = 0;
 	tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2);
 
 	temp1_fp = drm_fixp_from_fraction(8, tu->bpp);
 	temp2_fp = drm_fixp_from_fraction(
 	tu->extra_required_bytes_new_tmp, 1);
 	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
-
-	if (temp1_fp)
-		tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp);
-	else
-		tu->extra_pclk_cycles_tmp = 0;
+	tu->extra_pclk_cycles_tmp = fixp2int_ceil(temp1_fp);
 
 	temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1);
 	temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
 	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
-
-	if (temp1_fp)
-		tu->extra_pclk_cycles_in_link_clk_tmp =
-						drm_fixp2int_ceil(temp1_fp);
-	else
-		tu->extra_pclk_cycles_in_link_clk_tmp = 0;
+	tu->extra_pclk_cycles_in_link_clk_tmp = fixp2int_ceil(temp1_fp);
 
 	tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link;
 
@@ -562,6 +588,57 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1);
 	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
 
+	if (tu->rb2) {
+		temp1_fp = drm_fixp_mul(tu->delay_start_time_fp, tu->lclk_fp);
+		tu->delay_start_link_lclk = fixp2int_ceil(temp1_fp);
+
+		if (tu->remainder_tus > tu->i_upper_boundary_count) {
+			temp = (tu->remainder_tus - tu->i_upper_boundary_count) *
+							(tu->new_valid_boundary_link - 1);
+			temp += (tu->i_upper_boundary_count * tu->new_valid_boundary_link);
+			temp *= tu->nlanes;
+		} else {
+			temp = tu->nlanes * tu->remainder_tus * tu->new_valid_boundary_link;
+		}
+
+		temp1 = tu->i_lower_boundary_count * (tu->new_valid_boundary_link - 1);
+		temp1 += tu->i_upper_boundary_count * tu->new_valid_boundary_link;
+		temp1 *= tu->paired_tus * tu->nlanes;
+		temp1_fp = drm_fixp_from_fraction(tu->n_symbols - temp1 - temp, tu->nlanes);
+		tu->last_partial_lclk = fixp2int_ceil(temp1_fp);
+
+		tu->tu_active_cycles = (int)((tu->n_tus_per_lane * tu->tu_size) +
+								tu->last_partial_lclk);
+		tu->post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/;
+		temp = tu->pre_tu_hw_pipe_delay + tu->delay_start_link_lclk +
+					tu->tu_active_cycles + tu->post_tu_hw_pipe_delay;
+
+		if (tu->fec_en == 1) {
+			if (tu->nlanes == 1) {
+				temp1_fp = drm_fixp_from_fraction(temp, 500);
+				tu->parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1;
+			} else {
+				temp1_fp = drm_fixp_from_fraction(temp, 250);
+				tu->parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1;
+			}
+		} else { //no fec BW impact
+			tu->parity_symbols = 0;
+		}
+
+		tu->link_config_hactive_time = temp + tu->parity_symbols;
+
+		if (tu->resolution_line_time >= tu->link_config_hactive_time + 1 /*margin*/)
+			tu->hbp_delayStartCheck = 1;
+		else
+			tu->hbp_delayStartCheck = 0;
+	} else {
+		compare_result_3 = _tu_param_compare(tu->hbp_time_fp, tu->delay_start_time_fp);
+		if (compare_result_3 < 2)
+			tu->hbp_delayStartCheck = 1;
+		else
+			tu->hbp_delayStartCheck = 0;
+	}
+
 	compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp);
 	if (compare_result_1 == 2)
 		compare_result_1 = 1;
@@ -574,13 +651,6 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	else
 		compare_result_2 = 0;
 
-	compare_result_3 = _tu_param_compare(tu->hbp_time_fp,
-					tu->delay_start_time_fp);
-	if (compare_result_3 == 2)
-		compare_result_3 = 0;
-	else
-		compare_result_3 = 1;
-
 	if (((tu->even_distribution == 1) ||
 			((tu->even_distribution_BF == 0) &&
 			(tu->even_distribution_legacy == 0))) &&
@@ -588,7 +658,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 			compare_result_2 &&
 			(compare_result_1 || (tu->min_hblank_violated == 1)) &&
 			(tu->new_valid_boundary_link - 1) > 0 &&
-			compare_result_3 &&
+			(tu->hbp_delayStartCheck == 1) &&
 			(tu->delay_start_link_tmp <= 1023)) {
 		tu->upper_boundary_count = tu->i_upper_boundary_count;
 		tu->lower_boundary_count = tu->i_lower_boundary_count;
@@ -607,342 +677,402 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
 	}
 }
 
+static void _dp_calc_boundary(struct tu_algo_data *tu)
+{
+	s64 temp1_fp = 0, temp2_fp = 0;
+
+	do {
+		tu->err_fp = drm_fixp_from_fraction(1000, 1);
+
+		temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
+		temp2_fp = drm_fixp_from_fraction(
+				tu->delay_start_link_extra_pixclk, 1);
+		temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+		tu->extra_buffer_margin = fixp2int_ceil(temp1_fp);
+
+		temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
+		temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
+		tu->n_symbols = fixp2int_ceil(temp1_fp);
+
+		for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
+			for (tu->i_upper_boundary_count = 1;
+				tu->i_upper_boundary_count <= 15;
+				tu->i_upper_boundary_count++) {
+				for (tu->i_lower_boundary_count = 1;
+					tu->i_lower_boundary_count <= 15;
+					tu->i_lower_boundary_count++) {
+					_tu_valid_boundary_calc(tu);
+				}
+			}
+		}
+		tu->delay_start_link_extra_pixclk--;
+	} while (!tu->boundary_moderation_en &&
+		tu->boundary_mod_lower_err == 1 &&
+		tu->delay_start_link_extra_pixclk != 0 &&
+		((tu->second_loop_set == 0 && tu->rb2 == 1) || tu->rb2 == 0));
+}
+
+static void _dp_calc_extra_bytes(struct tu_algo_data *tu)
+{
+	u64 temp = 0;
+	s64 temp1_fp = 0, temp2_fp = 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
+	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+	temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
+	temp2_fp = temp1_fp - temp2_fp;
+	temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1);
+	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+
+	temp = drm_fixp2int(temp2_fp);
+	if (temp)
+		tu->extra_bytes = fixp2int_ceil(temp2_fp);
+	else
+		tu->extra_bytes = 0;
+
+	temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1);
+	temp2_fp = drm_fixp_from_fraction(8, tu->bpp);
+	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+	tu->extra_pclk_cycles = fixp2int_ceil(temp1_fp);
+
+	temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
+	temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1);
+	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+	tu->extra_pclk_cycles_in_link_clk = fixp2int_ceil(temp1_fp);
+}
+
+
 static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl,
 				struct dp_tu_calc_input *in,
 				struct dp_vc_tu_mapping_table *tu_table)
 {
-	struct tu_algo_data *tu;
+	struct tu_algo_data tu;
 	int compare_result_1, compare_result_2;
-	u64 temp = 0;
+	u64 temp = 0, temp1;
 	s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
 
 	s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */
-	s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */
-	s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */
 	s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000);
 
 	u8 DP_BRUTE_FORCE = 1;
 	s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */
 	uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
-	uint HBLANK_MARGIN = 4;
+	s64 HBLANK_MARGIN = drm_fixp_from_fraction(4, 1);
+	s64 HBLANK_MARGIN_EXTRA = 0;
 
-	tu = kzalloc(sizeof(*tu), GFP_KERNEL);
-	if (!tu)
-		return;
 
-	dp_panel_update_tu_timings(in, tu);
+	memset(&tu, 0, sizeof(tu));
 
-	tu->err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
+	dp_panel_update_tu_timings(in, &tu);
+
+	tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
 
 	temp1_fp = drm_fixp_from_fraction(4, 1);
-	temp2_fp = drm_fixp_mul(temp1_fp, tu->lclk_fp);
-	temp_fp = drm_fixp_div(temp2_fp, tu->pclk_fp);
-	tu->extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
+	temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
+	temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
+	tu.extra_buffer_margin = fixp2int_ceil(temp_fp);
 
-	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
-	temp2_fp = drm_fixp_mul(tu->pclk_fp, temp1_fp);
-	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
+	if (in->compress_ratio == 375 && tu.bpp == 30)
+		temp1_fp = drm_fixp_from_fraction(24, 8);
+	else
+		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+
+	temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
 	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
-	tu->ratio_fp = drm_fixp_div(temp2_fp, tu->lclk_fp);
-
-	tu->original_ratio_fp = tu->ratio_fp;
-	tu->boundary_moderation_en = false;
-	tu->upper_boundary_count = 0;
-	tu->lower_boundary_count = 0;
-	tu->i_upper_boundary_count = 0;
-	tu->i_lower_boundary_count = 0;
-	tu->valid_lower_boundary_link = 0;
-	tu->even_distribution_BF = 0;
-	tu->even_distribution_legacy = 0;
-	tu->even_distribution = 0;
-	tu->delay_start_time_fp = 0;
-
-	tu->err_fp = drm_fixp_from_fraction(1000, 1);
-	tu->n_err_fp = 0;
-	tu->n_n_err_fp = 0;
-
-	tu->ratio = drm_fixp2int(tu->ratio_fp);
-	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
-	div64_u64_rem(tu->lwidth_fp, temp1_fp, &temp2_fp);
-	if (temp2_fp != 0 &&
-			!tu->ratio && tu->dsc_en == 0) {
-		tu->ratio_fp = drm_fixp_mul(tu->ratio_fp, RATIO_SCALE_fp);
-		tu->ratio = drm_fixp2int(tu->ratio_fp);
-		if (tu->ratio)
-			tu->ratio_fp = drm_fixp_from_fraction(1, 1);
+	tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
+
+	tu.original_ratio_fp = tu.ratio_fp;
+	tu.boundary_moderation_en = false;
+	tu.upper_boundary_count = 0;
+	tu.lower_boundary_count = 0;
+	tu.i_upper_boundary_count = 0;
+	tu.i_lower_boundary_count = 0;
+	tu.valid_lower_boundary_link = 0;
+	tu.even_distribution_BF = 0;
+	tu.even_distribution_legacy = 0;
+	tu.even_distribution = 0;
+	tu.hbp_delayStartCheck = 0;
+	tu.pre_tu_hw_pipe_delay = 0;
+	tu.post_tu_hw_pipe_delay = 0;
+	tu.link_config_hactive_time = 0;
+	tu.delay_start_link_lclk = 0;
+	tu.tu_active_cycles = 0;
+	tu.resolution_line_time = 0;
+	tu.last_partial_lclk = 0;
+	tu.delay_start_time_fp = 0;
+	tu.second_loop_set = 0;
+
+	tu.err_fp = drm_fixp_from_fraction(1000, 1);
+	tu.n_err_fp = 0;
+	tu.n_n_err_fp = 0;
+
+	temp = drm_fixp2int(tu.lwidth_fp);
+	if ((((u32)temp % tu.nlanes) != 0) && (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 2)
+			&& (tu.dsc_en == 0)) {
+		tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
+		if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1)
+			tu.ratio_fp = DRM_FIXED_ONE;
 	}
 
-	if (tu->ratio > 1)
-		tu->ratio = 1;
+	if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1)
+		tu.ratio_fp = DRM_FIXED_ONE;
 
-	if (tu->ratio == 1)
-		goto tu_size_calc;
-
-	compare_result_1 = _tu_param_compare(tu->ratio_fp, const_p49_fp);
-	if (!compare_result_1 || compare_result_1 == 1)
-		compare_result_1 = 1;
-	else
-		compare_result_1 = 0;
-
-	compare_result_2 = _tu_param_compare(tu->ratio_fp, const_p56_fp);
-	if (!compare_result_2 || compare_result_2 == 2)
-		compare_result_2 = 1;
-	else
-		compare_result_2 = 0;
-
-	if (tu->dsc_en && compare_result_1 && compare_result_2) {
-		HBLANK_MARGIN += 4;
-		drm_dbg_dp(ctrl->drm_dev,
-			"increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN);
+	if (HBLANK_MARGIN_EXTRA != 0) {
+		HBLANK_MARGIN += HBLANK_MARGIN_EXTRA;
+		DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
+			HBLANK_MARGIN_EXTRA);
 	}
 
-tu_size_calc:
-	for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
-		temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
-		temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
-		temp = drm_fixp2int_ceil(temp2_fp);
+	for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
+		temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
+		temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+		temp = fixp2int_ceil(temp2_fp);
 		temp1_fp = drm_fixp_from_fraction(temp, 1);
-		tu->n_err_fp = temp1_fp - temp2_fp;
+		tu.n_err_fp = temp1_fp - temp2_fp;
 
-		if (tu->n_err_fp < tu->err_fp) {
-			tu->err_fp = tu->n_err_fp;
-			tu->tu_size_desired = tu->tu_size;
+		if (tu.n_err_fp < tu.err_fp) {
+			tu.err_fp = tu.n_err_fp;
+			tu.tu_size_desired = tu.tu_size;
 		}
 	}
 
-	tu->tu_size_minus1 = tu->tu_size_desired - 1;
+	tu.tu_size_minus1 = tu.tu_size_desired - 1;
 
-	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
-	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
-	tu->valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
+	tu.valid_boundary_link = fixp2int_ceil(temp2_fp);
 
-	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
-	temp2_fp = tu->lwidth_fp;
+	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+	temp2_fp = tu.lwidth_fp;
 	temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
 
-	temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
+	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
 	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
-	tu->n_tus = drm_fixp2int(temp2_fp);
+	tu.n_tus = drm_fixp2int(temp2_fp);
 	if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000)
-		tu->n_tus += 1;
-
-	tu->even_distribution_legacy = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
-
-	drm_dbg_dp(ctrl->drm_dev,
-			"n_sym = %d, num_of_tus = %d\n",
-			tu->valid_boundary_link, tu->n_tus);
-
-	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
-	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
-	temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
-	temp2_fp = temp1_fp - temp2_fp;
-	temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1);
-	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
-
-	temp = drm_fixp2int(temp2_fp);
-	if (temp && temp2_fp)
-		tu->extra_bytes = drm_fixp2int_ceil(temp2_fp);
-	else
-		tu->extra_bytes = 0;
-
-	temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1);
-	temp2_fp = drm_fixp_from_fraction(8, tu->bpp);
-	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+		tu.n_tus += 1;
 
-	if (temp && temp1_fp)
-		tu->extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
-	else
-		tu->extra_pclk_cycles = drm_fixp2int(temp1_fp);
+	tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
+	DRM_DEBUG("Info: n_sym = %d, num_of_tus = %d\n",
+		tu.valid_boundary_link, tu.n_tus);
 
-	temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
-	temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1);
-	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+	_dp_calc_extra_bytes(&tu);
 
-	if (temp1_fp)
-		tu->extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
-	else
-		tu->extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp);
+	tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
 
-	tu->filler_size = tu->tu_size_desired - tu->valid_boundary_link;
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
 
-	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
-	tu->ratio_by_tu_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
-
-	tu->delay_start_link = tu->extra_pclk_cycles_in_link_clk +
-				tu->filler_size + tu->extra_buffer_margin;
+	tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
+				tu.filler_size + tu.extra_buffer_margin;
 
-	tu->resulting_valid_fp =
-			drm_fixp_from_fraction(tu->valid_boundary_link, 1);
+	tu.resulting_valid_fp =
+			drm_fixp_from_fraction(tu.valid_boundary_link, 1);
 
-	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
-	temp2_fp = drm_fixp_div(tu->resulting_valid_fp, temp1_fp);
-	tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp;
+	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
+	temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
+	tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
 
-	temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1);
-	temp1_fp = tu->hbp_relative_to_pclk_fp - temp1_fp;
-	tu->hbp_time_fp = drm_fixp_div(temp1_fp, tu->pclk_fp);
+	temp1_fp = drm_fixp_from_fraction((tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1);
+	tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
 
-	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1);
-	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
+	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
 
-	compare_result_1 = _tu_param_compare(tu->hbp_time_fp,
-					tu->delay_start_time_fp);
-	if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */
-		tu->min_hblank_violated = 1;
+	compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
+					tu.delay_start_time_fp);
+	if (compare_result_1 == 2) /* hbp_time_fp < delay_start_time_fp */
+		tu.min_hblank_violated = 1;
 
-	tu->hactive_time_fp = drm_fixp_div(tu->lwidth_fp, tu->pclk_fp);
+	tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp);
 
-	compare_result_2 = _tu_param_compare(tu->hactive_time_fp,
-						tu->delay_start_time_fp);
+	compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
+						tu.delay_start_time_fp);
 	if (compare_result_2 == 2)
-		tu->min_hblank_violated = 1;
-
-	tu->delay_start_time_fp = 0;
+		tu.min_hblank_violated = 1;
 
 	/* brute force */
 
-	tu->delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
-	tu->diff_abs_fp = tu->resulting_valid_fp - tu->ratio_by_tu_fp;
+	tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
+	tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
 
-	temp = drm_fixp2int(tu->diff_abs_fp);
-	if (!temp && tu->diff_abs_fp <= 0xffff)
-		tu->diff_abs_fp = 0;
+	temp = drm_fixp2int(tu.diff_abs_fp);
+	if (!temp && tu.diff_abs_fp <= 0xffff)
+		tu.diff_abs_fp = 0;
 
 	/* if(diff_abs < 0) diff_abs *= -1 */
-	if (tu->diff_abs_fp < 0)
-		tu->diff_abs_fp = drm_fixp_mul(tu->diff_abs_fp, -1);
+	if (tu.diff_abs_fp < 0)
+		tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
+
+	tu.boundary_mod_lower_err = 0;
+
+	temp1_fp = drm_fixp_div(tu.orig_lclk_fp, tu.orig_pclk_fp);
+
+	temp2_fp = drm_fixp_from_fraction(tu.orig_lwidth + tu.orig_hbp, 2);
+	temp_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+	tu.resolution_line_time = drm_fixp2int(temp_fp);
+	tu.pre_tu_hw_pipe_delay = fixp2int_ceil(temp1_fp) + 2 /*cdc fifo write jitter+2*/
+				+ 3 /*pre-delay start cycles*/
+				+ 3 /*post-delay start cycles*/ + 1 /*BE on the link*/;
+	tu.post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/;
+
+	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+	temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
+	tu.n_symbols = fixp2int_ceil(temp1_fp);
+
+	if (tu.rb2) {
+		temp1_fp = drm_fixp_mul(tu.delay_start_time_fp, tu.lclk_fp);
+		tu.delay_start_link_lclk = fixp2int_ceil(temp1_fp);
+
+		tu.new_valid_boundary_link = tu.valid_boundary_link;
+		tu.i_upper_boundary_count = 1;
+		tu.i_lower_boundary_count = 0;
+
+		temp1 = tu.i_upper_boundary_count * tu.new_valid_boundary_link;
+		temp1 += tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1);
+		tu.average_valid2_fp = drm_fixp_from_fraction(temp1,
+				(tu.i_upper_boundary_count + tu.i_lower_boundary_count));
+
+		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+		temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
+		temp2_fp = drm_fixp_div(temp1_fp, tu.average_valid2_fp);
+		tu.n_tus = drm_fixp2int(temp2_fp);
+
+		tu.n_tus_per_lane = tu.n_tus / tu.nlanes;
+		tu.paired_tus = (int)((tu.n_tus_per_lane) /
+				(tu.i_upper_boundary_count + tu.i_lower_boundary_count));
+
+		tu.remainder_tus = tu.n_tus_per_lane - tu.paired_tus *
+				(tu.i_upper_boundary_count + tu.i_lower_boundary_count);
+
+		if (tu.remainder_tus > tu.i_upper_boundary_count) {
+			temp = (tu.remainder_tus - tu.i_upper_boundary_count) *
+							(tu.new_valid_boundary_link - 1);
+			temp += (tu.i_upper_boundary_count * tu.new_valid_boundary_link);
+			temp *= tu.nlanes;
+		} else {
+			temp = tu.nlanes * tu.remainder_tus * tu.new_valid_boundary_link;
+		}
 
-	tu->boundary_mod_lower_err = 0;
-	if ((tu->diff_abs_fp != 0 &&
-			((tu->diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
-			 (tu->even_distribution_legacy == 0) ||
-			 (DP_BRUTE_FORCE == 1))) ||
-			(tu->min_hblank_violated == 1)) {
-		do {
-			tu->err_fp = drm_fixp_from_fraction(1000, 1);
+		temp1 = tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1);
+		temp1 += tu.i_upper_boundary_count * tu.new_valid_boundary_link;
+		temp1 *= tu.paired_tus * tu.nlanes;
+		temp1_fp = drm_fixp_from_fraction(tu.n_symbols - temp1 - temp, tu.nlanes);
+		tu.last_partial_lclk = fixp2int_ceil(temp1_fp);
+
+		tu.tu_active_cycles = (int)((tu.n_tus_per_lane * tu.tu_size) +
+								tu.last_partial_lclk);
+
+		temp = tu.pre_tu_hw_pipe_delay + tu.delay_start_link_lclk +
+						tu.tu_active_cycles + tu.post_tu_hw_pipe_delay;
+
+		if (tu.fec_en == 1) {
+			if (tu.nlanes == 1) {
+				temp1_fp = drm_fixp_from_fraction(temp, 500);
+				tu.parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1;
+			} else {
+				temp1_fp = drm_fixp_from_fraction(temp, 250);
+				tu.parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1;
+			}
+		} else { //no fec BW impact
+			tu.parity_symbols = 0;
+		}
 
-			temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
-			temp2_fp = drm_fixp_from_fraction(
-					tu->delay_start_link_extra_pixclk, 1);
-			temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
+		tu.link_config_hactive_time = temp + tu.parity_symbols;
 
-			if (temp1_fp)
-				tu->extra_buffer_margin =
-					drm_fixp2int_ceil(temp1_fp);
-			else
-				tu->extra_buffer_margin = 0;
+		if (tu.link_config_hactive_time + 1 /*margin*/ >= tu.resolution_line_time)
+			tu.min_hblank_violated = 1;
+	}
 
-			temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
-			temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
+	tu.delay_start_time_fp = 0;
 
-			if (temp1_fp)
-				tu->n_symbols = drm_fixp2int_ceil(temp1_fp);
-			else
-				tu->n_symbols = 0;
-
-			for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
-				for (tu->i_upper_boundary_count = 1;
-					tu->i_upper_boundary_count <= 15;
-					tu->i_upper_boundary_count++) {
-					for (tu->i_lower_boundary_count = 1;
-						tu->i_lower_boundary_count <= 15;
-						tu->i_lower_boundary_count++) {
-						_tu_valid_boundary_calc(tu);
-					}
-				}
-			}
-			tu->delay_start_link_extra_pixclk--;
-		} while (tu->boundary_moderation_en != true &&
-			tu->boundary_mod_lower_err == 1 &&
-			tu->delay_start_link_extra_pixclk != 0);
+	if ((tu.diff_abs_fp != 0 &&
+			((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
+			 (tu.even_distribution_legacy == 0) ||
+			 (DP_BRUTE_FORCE == 1))) ||
+			(tu.min_hblank_violated == 1)) {
+		_dp_calc_boundary(&tu);
 
-		if (tu->boundary_moderation_en == true) {
+		if (tu.boundary_moderation_en) {
 			temp1_fp = drm_fixp_from_fraction(
-					(tu->upper_boundary_count *
-					tu->valid_boundary_link +
-					tu->lower_boundary_count *
-					(tu->valid_boundary_link - 1)), 1);
+					(tu.upper_boundary_count *
+					tu.valid_boundary_link +
+					tu.lower_boundary_count *
+					(tu.valid_boundary_link - 1)), 1);
 			temp2_fp = drm_fixp_from_fraction(
-					(tu->upper_boundary_count +
-					tu->lower_boundary_count), 1);
-			tu->resulting_valid_fp =
+					(tu.upper_boundary_count +
+					tu.lower_boundary_count), 1);
+			tu.resulting_valid_fp =
 					drm_fixp_div(temp1_fp, temp2_fp);
 
 			temp1_fp = drm_fixp_from_fraction(
-					tu->tu_size_desired, 1);
-			tu->ratio_by_tu_fp =
-				drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
+					tu.tu_size_desired, 1);
+			tu.ratio_by_tu_fp =
+				drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
 
-			tu->valid_lower_boundary_link =
-				tu->valid_boundary_link - 1;
+			tu.valid_lower_boundary_link =
+				tu.valid_boundary_link - 1;
 
-			temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
-			temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
+			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+			temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
 			temp2_fp = drm_fixp_div(temp1_fp,
-						tu->resulting_valid_fp);
-			tu->n_tus = drm_fixp2int(temp2_fp);
+						tu.resulting_valid_fp);
+			tu.n_tus = drm_fixp2int(temp2_fp);
 
-			tu->tu_size_minus1 = tu->tu_size_desired - 1;
-			tu->even_distribution_BF = 1;
+			tu.tu_size_minus1 = tu.tu_size_desired - 1;
+			tu.even_distribution_BF = 1;
 
 			temp1_fp =
-				drm_fixp_from_fraction(tu->tu_size_desired, 1);
+				drm_fixp_from_fraction(tu.tu_size_desired, 1);
 			temp2_fp =
-				drm_fixp_div(tu->resulting_valid_fp, temp1_fp);
-			tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp;
+				drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
+			tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
 		}
 	}
 
-	temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu->lwidth_fp);
+	if (tu.async_en) {
+		temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp);
+		temp = fixp2int_ceil(temp2_fp);
 
-	if (temp2_fp)
-		temp = drm_fixp2int_ceil(temp2_fp);
-	else
-		temp = 0;
-
-	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
-	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
-	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
-	temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
-	temp1_fp = drm_fixp_from_fraction(temp, 1);
-	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
-	temp = drm_fixp2int(temp2_fp);
+		temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
+		temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
+		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
+		temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
+		temp1_fp = drm_fixp_from_fraction(temp, 1);
+		temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+		temp = drm_fixp2int(temp2_fp);
 
-	if (tu->async_en)
-		tu->delay_start_link += (int)temp;
+		tu.delay_start_link += (int)temp;
+	}
 
-	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1);
-	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
+	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
+	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
 
 	/* OUTPUTS */
-	tu_table->valid_boundary_link       = tu->valid_boundary_link;
-	tu_table->delay_start_link          = tu->delay_start_link;
-	tu_table->boundary_moderation_en    = tu->boundary_moderation_en;
-	tu_table->valid_lower_boundary_link = tu->valid_lower_boundary_link;
-	tu_table->upper_boundary_count      = tu->upper_boundary_count;
-	tu_table->lower_boundary_count      = tu->lower_boundary_count;
-	tu_table->tu_size_minus1            = tu->tu_size_minus1;
-
-	drm_dbg_dp(ctrl->drm_dev, "TU: valid_boundary_link: %d\n",
-				tu_table->valid_boundary_link);
-	drm_dbg_dp(ctrl->drm_dev, "TU: delay_start_link: %d\n",
-				tu_table->delay_start_link);
-	drm_dbg_dp(ctrl->drm_dev, "TU: boundary_moderation_en: %d\n",
+	tu_table->valid_boundary_link       = tu.valid_boundary_link;
+	tu_table->delay_start_link          = tu.delay_start_link;
+	tu_table->boundary_moderation_en    = tu.boundary_moderation_en;
+	tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
+	tu_table->upper_boundary_count      = tu.upper_boundary_count;
+	tu_table->lower_boundary_count      = tu.lower_boundary_count;
+	tu_table->tu_size_minus1            = tu.tu_size_minus1;
+
+	DRM_DEBUG("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link);
+	DRM_DEBUG("TU: delay_start_link: %d\n", tu_table->delay_start_link);
+	DRM_DEBUG("TU: boundary_moderation_en: %d\n",
 			tu_table->boundary_moderation_en);
-	drm_dbg_dp(ctrl->drm_dev, "TU: valid_lower_boundary_link: %d\n",
+	DRM_DEBUG("TU: valid_lower_boundary_link: %d\n",
 			tu_table->valid_lower_boundary_link);
-	drm_dbg_dp(ctrl->drm_dev, "TU: upper_boundary_count: %d\n",
+	DRM_DEBUG("TU: upper_boundary_count: %d\n",
 			tu_table->upper_boundary_count);
-	drm_dbg_dp(ctrl->drm_dev, "TU: lower_boundary_count: %d\n",
+	DRM_DEBUG("TU: lower_boundary_count: %d\n",
 			tu_table->lower_boundary_count);
-	drm_dbg_dp(ctrl->drm_dev, "TU: tu_size_minus1: %d\n",
-			tu_table->tu_size_minus1);
-
-	kfree(tu);
+	DRM_DEBUG("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
 }
 
 static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
-		struct dp_vc_tu_mapping_table *tu_table)
+				struct dp_vc_tu_mapping_table *tu_table)
 {
 	struct dp_tu_calc_input in;
 	struct drm_display_mode *drm_mode;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 06/14] drm/msm/dp: add display compression related struct
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (4 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:46   ` Dmitry Baryshkov
  2023-01-24 15:15   ` Neil Armstrong
  2023-01-23 18:24 ` [PATCH v1 07/14] drm/msm/dp: add dsc helper functions Kuogee Hsieh
                   ` (10 subsequent siblings)
  16 siblings, 2 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

Add display compression related struct to support variant compression
mechanism. However, DSC is the only one supported at this moment.
VDC may be added later.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_panel.h | 42 ++++++++++++++++++
 drivers/gpu/drm/msm/msm_drv.h     | 89 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 1153e88..4c45d51 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -21,12 +21,54 @@ struct edid;
 #define DP_DOWNSTREAM_PORTS		4
 #define DP_DOWNSTREAM_CAP_SIZE		4
 
+
+#define DP_PANEL_CAPS_DSC	BIT(0)
+
+enum dp_output_format {
+	DP_OUTPUT_FORMAT_RGB,
+	DP_OUTPUT_FORMAT_YCBCR420,
+	DP_OUTPUT_FORMAT_YCBCR422,
+	DP_OUTPUT_FORMAT_YCBCR444,
+	DP_OUTPUT_FORMAT_INVALID,
+};
+
+
+struct dp_panel_info {
+	u32 h_active;
+	u32 v_active;
+	u32 h_back_porch;
+	u32 h_front_porch;
+	u32 h_sync_width;
+	u32 h_active_low;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 v_sync_width;
+	u32 v_active_low;
+	u32 h_skew;
+	u32 refresh_rate;
+	u32 pixel_clk_khz;
+	u32 bpp;
+	bool widebus_en;
+	struct msm_compression_info comp_info;
+	s64 dsc_overhead_fp;
+};
+
 struct dp_display_mode {
 	struct drm_display_mode drm_mode;
+	struct dp_panel_info timing;
 	u32 capabilities;
+	s64 fec_overhead_fp;
+	s64 dsc_overhead_fp;
 	u32 bpp;
 	u32 h_active_low;
 	u32 v_active_low;
+	/**
+	 * @output_format:
+	 *
+	 * This is used to indicate DP output format.
+	 * The output format can be read from drm_mode.
+	 */
+	enum dp_output_format output_format;
 };
 
 struct dp_panel_in {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 9f0c184..f155803 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  */
@@ -70,6 +71,16 @@ enum msm_dp_controller {
 #define MAX_H_TILES_PER_DISPLAY 2
 
 /**
+ * enum msm_display_compression_type - compression method used for pixel stream
+ * @MSM_DISPLAY_COMPRESSION_NONE:     Pixel data is not compressed
+ * @MSM_DISPLAY_COMPRESSION_DSC:      DSC compresison is used
+ */
+enum msm_display_compression_type {
+	MSM_DISPLAY_COMPRESSION_NONE,
+	MSM_DISPLAY_COMPRESSION_DSC,
+};
+
+/**
  * enum msm_event_wait - type of HW events to wait for
  * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
  * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
@@ -82,6 +93,84 @@ enum msm_event_wait {
 };
 
 /**
+ * struct msm_display_dsc_info - defines dsc configuration
+ * @config                   DSC encoder configuration
+ * @scr_rev:                 DSC revision.
+ * @initial_lines:           Number of initial lines stored in encoder.
+ * @pkt_per_line:            Number of packets per line.
+ * @bytes_in_slice:          Number of bytes in slice.
+ * @eol_byte_num:            Valid bytes at the end of line.
+ * @bytes_per_pkt            Number of bytes in DSI packet
+ * @pclk_per_line:           Compressed width.
+ * @slice_last_group_size:   Size of last group in pixels.
+ * @slice_per_pkt:           Number of slices per packet.
+ * @num_active_ss_per_enc:   Number of active soft slices per encoder.
+ * @source_color_space:      Source color space of DSC encoder
+ * @chroma_format:           Chroma_format of DSC encoder.
+ * @det_thresh_flatness:     Flatness threshold.
+ * @extra_width:             Extra width required in timing calculations.
+ * @pps_delay_ms:            Post PPS command delay in milliseconds.
+ * @dsc_4hsmerge_en:         Using DSC 4HS merge topology
+ * @dsc_4hsmerge_padding     4HS merge DSC pair padding value in bytes
+ * @dsc_4hsmerge_alignment   4HS merge DSC alignment value in bytes
+ * @half_panel_pu            True for single and dual dsc encoders if partial
+ *                           update sets the roi width to half of mode width
+ *                           False in all other cases
+ */
+struct msm_display_dsc_info {
+	struct drm_dsc_config drm_dsc;
+	u8 scr_rev;
+
+	int initial_lines;
+	int pkt_per_line;
+	int bytes_in_slice;
+	int bytes_per_pkt;
+	int eol_byte_num;
+	int pclk_per_line;
+	int slice_last_group_size;
+	int slice_per_pkt;
+	int num_active_ss_per_enc;
+	int source_color_space;
+	int chroma_format;
+	int det_thresh_flatness;
+	u32 extra_width;
+	u32 pps_delay_ms;
+	bool dsc_4hsmerge_en;
+	u32 dsc_4hsmerge_padding;
+	u32 dsc_4hsmerge_alignment;
+	bool half_panel_pu;
+};
+
+/*
+ * conver from struct drm_dsc_config to struct msm_display_dsc_info
+ */
+#define to_msm_dsc_info(dsc) container_of((dsc), struct msm_display_dsc_info, drm_dsc)
+
+/**
+ * Bits/pixel target >> 4  (removing the fractional bits)
+ * returns the integer bpp value from the drm_dsc_config struct
+ */
+#define DSC_BPP(config) ((config).bits_per_pixel >> 4)
+
+/**
+ * struct msm_compression_info - defined panel compression
+ * @enabled:          enabled/disabled
+ * @comp_type:        type of compression supported
+ * @comp_ratio:       compression ratio
+ * @src_bpp:          bits per pixel before compression
+ * @tgt_bpp:          bits per pixel after compression
+ * @msm_dsc_info:     msm dsc info if the compression supported is DSC
+ */
+struct msm_compression_info {
+	bool enabled;
+	enum msm_display_compression_type comp_type;
+	u32 comp_ratio;
+	u32 src_bpp;
+	u32 tgt_bpp;
+	struct msm_display_dsc_info msm_dsc_info;
+};
+
+/**
  * struct msm_display_topology - defines a display topology pipeline
  * @num_lm:       number of layer mixers used
  * @num_intf:     number of interfaces the panel is mounted on
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 07/14] drm/msm/dp: add dsc helper functions
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (5 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 06/14] drm/msm/dp: add display compression related struct Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:02   ` Dmitry Baryshkov
  2023-01-23 22:08   ` Marijn Suijten
  2023-01-23 18:24 ` [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller Kuogee Hsieh
                   ` (9 subsequent siblings)
  16 siblings, 2 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

Add DSC related supporting functions to calculate DSC related parameters.
In addition, DSC hardware encoder customized configuration parameters are
also included. Algorithms used to perform calculation are derived from
system engineer spreadsheet.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/Makefile                   |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c | 537 +++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h |  25 ++
 drivers/gpu/drm/msm/msm_drv.h                  |   4 +
 4 files changed, 567 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 7274c412..28cf52b 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
 	disp/dpu1/dpu_hw_catalog.o \
 	disp/dpu1/dpu_hw_ctl.o \
 	disp/dpu1/dpu_hw_dsc.o \
+	disp/dpu1/dpu_dsc_helper.o \
 	disp/dpu1/dpu_hw_interrupts.o \
 	disp/dpu1/dpu_hw_intf.o \
 	disp/dpu1/dpu_hw_lm.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
new file mode 100644
index 00000000..48cef23
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2023 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
+ */
+
+#include "msm_drv.h"
+#include "dpu_kms.h"
+#include "dpu_hw_dsc.h"
+#include "dpu_dsc_helper.h"
+
+
+#define DPU_DSC_PPS_SIZE       128
+
+enum dpu_dsc_ratio_type {
+	DSC_V11_8BPC_8BPP,
+	DSC_V11_10BPC_8BPP,
+	DSC_V11_10BPC_10BPP,
+	DSC_V11_SCR1_8BPC_8BPP,
+	DSC_V11_SCR1_10BPC_8BPP,
+	DSC_V11_SCR1_10BPC_10BPP,
+	DSC_V12_444_8BPC_8BPP = DSC_V11_SCR1_8BPC_8BPP,
+	DSC_V12_444_10BPC_8BPP = DSC_V11_SCR1_10BPC_8BPP,
+	DSC_V12_444_10BPC_10BPP = DSC_V11_SCR1_10BPC_10BPP,
+	DSC_V12_422_8BPC_7BPP,
+	DSC_V12_422_8BPC_8BPP,
+	DSC_V12_422_10BPC_7BPP,
+	DSC_V12_422_10BPC_10BPP,
+	DSC_V12_420_8BPC_6BPP,
+	DSC_V12_420_10BPC_6BPP,
+	DSC_V12_420_10BPC_7_5BPP,
+	DSC_RATIO_TYPE_MAX
+};
+
+
+static u16 dpu_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = {
+		0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
+		0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e
+};
+
+/*
+ * Rate control - Min QP values for each ratio type in dpu_dsc_ratio_type
+ */
+static char dpu_dsc_rc_range_min_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
+	/* DSC v1.1 */
+	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13},
+	{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17},
+	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
+	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
+	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12},
+	{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16},
+	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
+	/* DSC v1.2 YUV422 */
+	{0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11},
+	{0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10},
+	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
+	{0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12},
+	/* DSC v1.2 YUV420 */
+	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10},
+	{0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14},
+	{0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12},
+};
+
+/*
+ * Rate control - Max QP values for each ratio type in dpu_dsc_ratio_type
+ */
+static char dpu_dsc_rc_range_max_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
+	/* DSC v1.1 */
+	{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15},
+	{4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19},
+	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
+	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
+	{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13},
+	{8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17},
+	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
+	/* DSC v1.2 YUV422 */
+	{3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12},
+	{2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11},
+	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
+	{2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13},
+	/* DSC v1.2 YUV420 */
+	{2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 12},
+	{2, 5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15},
+	{2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13},
+	};
+
+/*
+ * Rate control - bpg offset values for each ratio type in dpu_dsc_ratio_type
+ */
+static char dpu_dsc_rc_range_bpg[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
+	/* DSC v1.1 */
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
+	/* DSC v1.1 SCR and DSC V1.2 RGB 444 */
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
+	/* DSC v1.2 YUV422 */
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
+	{10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12},
+	/* DSC v1.2 YUV420 */
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
+	{10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12},
+};
+
+static struct dpu_dsc_rc_init_params_lut {
+	u32 rc_quant_incr_limit0;
+	u32 rc_quant_incr_limit1;
+	u32 initial_fullness_offset;
+	u32 initial_xmit_delay;
+	u32 second_line_bpg_offset;
+	u32 second_line_offset_adj;
+	u32 flatness_min_qp;
+	u32 flatness_max_qp;
+}  dpu_dsc_rc_init_param_lut[] = {
+	/* DSC v1.1 */
+	{11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V11_8BPC_8BPP */
+	{15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V11_10BPC_8BPP */
+	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V11_10BPC_10BPP */
+	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
+	{11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V12_444_8BPC_8BPP or DSC_V11_SCR1_8BPC_8BPP */
+	{15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_8BPP or DSC_V11_SCR1_10BPC_8BPP */
+	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_10BPP or DSC_V11_SCR1_10BPC_10BPP */
+	/* DSC v1.2 YUV422 */
+	{11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */
+	{11, 11, 2048, 341, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_8BPP */
+	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_7BPP */
+	{15, 15, 2048, 273, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_10BPP */
+	/* DSC v1.2 YUV420 */
+	{11, 11, 5632, 410, 0, 0, 3, 12},    /* DSC_V12_422_8BPC_7BPP */
+	{11, 11, 2048, 341, 12, 512, 3, 12}, /* DSC_V12_420_8BPC_6BPP */
+	{15, 15, 2048, 341, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_6BPP */
+	{15, 15, 2048, 256, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_7_5BPP */
+};
+
+/**
+ * Maps to lookup the dpu_dsc_ratio_type index used in rate control tables
+ */
+static struct dpu_dsc_table_index_lut {
+	u32 fmt;
+	u32 scr_ver;
+	u32 minor_ver;
+	u32 bpc;
+	u32 bpp;
+	u32 type;
+} dpu_dsc_index_map[] = {
+	/* DSC 1.1 formats - scr version is considered */
+	{MSM_CHROMA_444, 0, 1, 8, 8, DSC_V11_8BPC_8BPP},
+	{MSM_CHROMA_444, 0, 1, 10, 8, DSC_V11_10BPC_8BPP},
+	{MSM_CHROMA_444, 0, 1, 10, 10, DSC_V11_10BPC_10BPP},
+
+	{MSM_CHROMA_444, 1, 1, 8, 8, DSC_V11_SCR1_8BPC_8BPP},
+	{MSM_CHROMA_444, 1, 1, 10, 8, DSC_V11_SCR1_10BPC_8BPP},
+	{MSM_CHROMA_444, 1, 1, 10, 10, DSC_V11_SCR1_10BPC_10BPP},
+
+	/* DSC 1.2 formats - scr version is no-op */
+	{MSM_CHROMA_444, -1, 2, 8, 8, DSC_V12_444_8BPC_8BPP},
+	{MSM_CHROMA_444, -1, 2, 10, 8, DSC_V12_444_10BPC_8BPP},
+	{MSM_CHROMA_444, -1, 2, 10, 10, DSC_V12_444_10BPC_10BPP},
+
+	{MSM_CHROMA_422, -1, 2, 8, 7, DSC_V12_422_8BPC_7BPP},
+	{MSM_CHROMA_422, -1, 2, 8, 8, DSC_V12_422_8BPC_8BPP},
+	{MSM_CHROMA_422, -1, 2, 10, 7, DSC_V12_422_10BPC_7BPP},
+	{MSM_CHROMA_422, -1, 2, 10, 10, DSC_V12_422_10BPC_10BPP},
+
+	{MSM_CHROMA_420, -1, 2, 8, 6, DSC_V12_420_8BPC_6BPP},
+	{MSM_CHROMA_420, -1, 2, 10, 6, DSC_V12_420_10BPC_6BPP},
+};
+
+static int _get_rc_table_index(struct drm_dsc_config *dsc, int scr_ver)
+{
+	u32 bpp, bpc, i, fmt = MSM_CHROMA_444;
+
+	if (dsc->dsc_version_major != 0x1) {
+		DPU_ERROR("unsupported major version %d\n",
+				dsc->dsc_version_major);
+		return -EINVAL;
+	}
+
+	bpc = dsc->bits_per_component;
+	bpp = DSC_BPP(*dsc);
+
+	if (dsc->native_422)
+		fmt = MSM_CHROMA_422;
+	else if (dsc->native_420)
+		fmt = MSM_CHROMA_420;
+
+
+	for (i = 0; i < ARRAY_SIZE(dpu_dsc_index_map); i++) {
+		if (dsc->dsc_version_minor == dpu_dsc_index_map[i].minor_ver &&
+				fmt ==  dpu_dsc_index_map[i].fmt &&
+				bpc == dpu_dsc_index_map[i].bpc &&
+				bpp == dpu_dsc_index_map[i].bpp &&
+				(dsc->dsc_version_minor != 0x1 ||
+					scr_ver == dpu_dsc_index_map[i].scr_ver))
+			return dpu_dsc_index_map[i].type;
+	}
+
+	DPU_ERROR("unsupported DSC v%d.%dr%d, bpc:%d, bpp:%d, fmt:0x%x\n",
+			dsc->dsc_version_major, dsc->dsc_version_minor,
+			scr_ver, bpc, bpp, fmt);
+	return -EINVAL;
+}
+
+u8 _get_dsc_v1_2_bpg_offset(struct drm_dsc_config *dsc)
+{
+	u8 bpg_offset = 0;
+	u8 uncompressed_bpg_rate;
+	u8 bpp = DSC_BPP(*dsc);
+
+	if (dsc->slice_height < 8)
+		bpg_offset = 2 * (dsc->slice_height - 1);
+	else if (dsc->slice_height < 20)
+		bpg_offset = 12;
+	else if (dsc->slice_height <= 30)
+		bpg_offset = 13;
+	else if (dsc->slice_height < 42)
+		bpg_offset = 14;
+	else
+		bpg_offset = 15;
+
+	if (dsc->native_422)
+		uncompressed_bpg_rate = 3 * bpp * 4;
+	else if (dsc->native_420)
+		uncompressed_bpg_rate = 3 * bpp;
+	else
+		uncompressed_bpg_rate = (3 * bpp + 2) * 3;
+
+	if (bpg_offset < (uncompressed_bpg_rate - (3 * bpp)))
+		return bpg_offset;
+	else
+		return (uncompressed_bpg_rate - (3 * bpp));
+}
+
+int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver)
+{
+	int bpp, bpc;
+	int groups_per_line, groups_total;
+	int min_rate_buffer_size;
+	int hrd_delay;
+	int pre_num_extra_mux_bits, num_extra_mux_bits;
+	int slice_bits;
+	int data;
+	int final_value, final_scale;
+	struct dpu_dsc_rc_init_params_lut *rc_param_lut;
+	u32 slice_width_mod;
+	int i, ratio_idx;
+
+	dsc->rc_model_size = 8192;
+
+	if ((dsc->dsc_version_major == 0x1) &&
+			(dsc->dsc_version_minor == 0x1)) {
+		if (scr_ver == 0x1)
+			dsc->first_line_bpg_offset = 15;
+		else
+			dsc->first_line_bpg_offset = 12;
+	} else if (dsc->dsc_version_minor == 0x2) {
+		dsc->first_line_bpg_offset = _get_dsc_v1_2_bpg_offset(dsc);
+	}
+
+	dsc->rc_edge_factor = 6;
+	dsc->rc_tgt_offset_high = 3;
+	dsc->rc_tgt_offset_low = 3;
+	dsc->simple_422 = 0;
+	dsc->convert_rgb = !(dsc->native_422 | dsc->native_420);
+	dsc->vbr_enable = 0;
+
+	bpp = DSC_BPP(*dsc);
+	bpc = dsc->bits_per_component;
+
+	ratio_idx = _get_rc_table_index(dsc, scr_ver);
+	if ((ratio_idx < 0) || (ratio_idx >= DSC_RATIO_TYPE_MAX))
+		return -EINVAL;
+
+
+	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
+		dsc->rc_buf_thresh[i] = dpu_dsc_rc_buf_thresh[i];
+
+	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+		dsc->rc_range_params[i].range_min_qp =
+			dpu_dsc_rc_range_min_qp[ratio_idx][i];
+		dsc->rc_range_params[i].range_max_qp =
+			dpu_dsc_rc_range_max_qp[ratio_idx][i];
+		dsc->rc_range_params[i].range_bpg_offset =
+			dpu_dsc_rc_range_bpg[ratio_idx][i];
+	}
+
+	rc_param_lut = &dpu_dsc_rc_init_param_lut[ratio_idx];
+	dsc->rc_quant_incr_limit0 = rc_param_lut->rc_quant_incr_limit0;
+	dsc->rc_quant_incr_limit1 = rc_param_lut->rc_quant_incr_limit1;
+	dsc->initial_offset = rc_param_lut->initial_fullness_offset;
+	dsc->initial_xmit_delay = rc_param_lut->initial_xmit_delay;
+	dsc->second_line_bpg_offset = rc_param_lut->second_line_bpg_offset;
+	dsc->second_line_offset_adj = rc_param_lut->second_line_offset_adj;
+	dsc->flatness_min_qp = rc_param_lut->flatness_min_qp;
+	dsc->flatness_max_qp = rc_param_lut->flatness_max_qp;
+
+	slice_width_mod = dsc->slice_width;
+	if (dsc->native_422 || dsc->native_420) {
+		slice_width_mod = dsc->slice_width / 2;
+		bpp = bpp * 2;
+	}
+
+	dsc->line_buf_depth = bpc + 1;
+	dsc->mux_word_size = bpc > 10 ? DSC_MUX_WORD_SIZE_12_BPC : DSC_MUX_WORD_SIZE_8_10_BPC;
+
+	if ((dsc->dsc_version_minor == 0x2) && (dsc->native_420))
+		dsc->nsl_bpg_offset = (2048 * (DIV_ROUND_UP(dsc->second_line_bpg_offset,
+				(dsc->slice_height - 1))));
+
+	groups_per_line = DIV_ROUND_UP(slice_width_mod, 3);
+
+	dsc->slice_chunk_size = slice_width_mod * bpp / 8;
+	if ((slice_width_mod * bpp) % 8)
+		dsc->slice_chunk_size++;
+
+	/* rbs-min */
+	min_rate_buffer_size =  dsc->rc_model_size - dsc->initial_offset +
+			dsc->initial_xmit_delay * bpp +
+			groups_per_line * dsc->first_line_bpg_offset;
+
+	hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp);
+
+	dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
+
+	dsc->initial_scale_value = 8 * dsc->rc_model_size /
+			(dsc->rc_model_size - dsc->initial_offset);
+
+	slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height;
+
+	groups_total = groups_per_line * dsc->slice_height;
+
+	data = dsc->first_line_bpg_offset * 2048;
+
+	dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
+
+	if (dsc->native_422)
+		pre_num_extra_mux_bits = 4 * dsc->mux_word_size + (4 * bpc + 4) + (3 * 4 * bpc) - 2;
+	else if (dsc->native_420)
+		pre_num_extra_mux_bits = 3 * dsc->mux_word_size + (4 * bpc + 4) + (2 * 4 * bpc) - 2;
+	else
+		pre_num_extra_mux_bits = 3 * (dsc->mux_word_size + (4 * bpc + 4) - 2);
+
+	num_extra_mux_bits = pre_num_extra_mux_bits - (dsc->mux_word_size -
+		((slice_bits - pre_num_extra_mux_bits) % dsc->mux_word_size));
+
+	data = 2048 * (dsc->rc_model_size - dsc->initial_offset
+		+ num_extra_mux_bits);
+	dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
+
+	data = dsc->initial_xmit_delay * bpp;
+	final_value =  dsc->rc_model_size - data + num_extra_mux_bits;
+
+	final_scale = 8 * dsc->rc_model_size /
+		(dsc->rc_model_size - final_value);
+
+	dsc->final_offset = final_value;
+
+	data = (final_scale - 9) * (dsc->nfl_bpg_offset +
+		dsc->slice_bpg_offset);
+	dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
+
+	dsc->scale_decrement_interval = groups_per_line /
+		(dsc->initial_scale_value - 8);
+
+	return 0;
+}
+
+bool dpu_dsc_ich_reset_override_needed(bool pu_en,
+		struct msm_display_dsc_info *dsc_info)
+{
+	/*
+	 * As per the DSC spec, ICH_RESET can be either end of the slice line
+	 * or at the end of the slice. HW internally generates ich_reset at
+	 * end of the slice line if DSC_MERGE is used or encoder has two
+	 * soft slices. However, if encoder has only 1 soft slice and DSC_MERGE
+	 * is not used then it will generate ich_reset at the end of slice.
+	 *
+	 * Now as per the spec, during one PPS session, position where
+	 * ich_reset is generated should not change. Now if full-screen frame
+	 * has more than 1 soft slice then HW will automatically generate
+	 * ich_reset at the end of slice_line. But for the same panel, if
+	 * partial frame is enabled and only 1 encoder is used with 1 slice,
+	 * then HW will generate ich_reset at end of the slice. This is a
+	 * mismatch. Prevent this by overriding HW's decision.
+	 */
+	return pu_en && dsc_info && (dsc_info->drm_dsc.slice_count > 1) &&
+		(dsc_info->drm_dsc.slice_width == dsc_info->drm_dsc.pic_width);
+}
+
+int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc_info,
+				int enc_ip_width, int dsc_cmn_mode)
+{
+	int max_ssm_delay, max_se_size, max_muxword_size;
+	int compress_bpp_group, obuf_latency, input_ssm_out_latency;
+	int base_hs_latency, chunk_bits, ob_data_width;
+	int output_rate_extra_budget_bits, multi_hs_extra_budget_bits;
+	int multi_hs_extra_latency,  mux_word_size;
+	int ob_data_width_4comps, ob_data_width_3comps;
+	int output_rate_ratio_complement, container_slice_width;
+	int rtl_num_components, multi_hs_c, multi_hs_d;
+
+	int bpc = dsc_info->drm_dsc.bits_per_component;
+	int bpp = DSC_BPP(dsc_info->drm_dsc);
+	bool native_422 = dsc_info->drm_dsc.native_422;
+	bool native_420 = dsc_info->drm_dsc.native_420;
+
+	/* Hardent core config */
+	int multiplex_mode_enable = 0, split_panel_enable = 0;
+	int rtl_max_bpc = 10, rtl_output_data_width = 64;
+	int pipeline_latency = 28;
+
+	if (dsc_cmn_mode & DSC_MODE_MULTIPLEX)
+		multiplex_mode_enable = 1;
+	if (dsc_cmn_mode & DSC_MODE_SPLIT_PANEL)
+		split_panel_enable = 1;
+	container_slice_width = (native_422 ?
+			dsc_info->drm_dsc.slice_width / 2 : dsc_info->drm_dsc.slice_width);
+	max_muxword_size = (rtl_max_bpc >= 12) ? 64 : 48;
+	max_se_size = 4 * (rtl_max_bpc + 1);
+	max_ssm_delay = max_se_size + max_muxword_size - 1;
+	mux_word_size = (bpc >= 12) ? 64 : 48;
+	compress_bpp_group = native_422 ? (2 * bpp) : bpp;
+	input_ssm_out_latency = pipeline_latency + 3 * (max_ssm_delay + 2)
+			* dsc_info->num_active_ss_per_enc;
+	rtl_num_components = (native_420 || native_422) ? 4 : 3;
+	ob_data_width_4comps = (rtl_output_data_width >= (2 *
+			max_muxword_size)) ?
+			rtl_output_data_width :
+			(2 * rtl_output_data_width);
+	ob_data_width_3comps = (rtl_output_data_width >= max_muxword_size) ?
+			rtl_output_data_width : 2 * rtl_output_data_width;
+	ob_data_width = (rtl_num_components == 4) ?
+			ob_data_width_4comps : ob_data_width_3comps;
+	obuf_latency = DIV_ROUND_UP((9 * ob_data_width + mux_word_size),
+			compress_bpp_group) + 1;
+	base_hs_latency = dsc_info->drm_dsc.initial_xmit_delay +
+		input_ssm_out_latency + obuf_latency;
+	chunk_bits = 8 * dsc_info->drm_dsc.slice_chunk_size;
+	output_rate_ratio_complement = ob_data_width - compress_bpp_group;
+	output_rate_extra_budget_bits =
+		(output_rate_ratio_complement * chunk_bits) >>
+		((ob_data_width == 128) ? 7 : 6);
+	multi_hs_c = split_panel_enable * multiplex_mode_enable;
+	multi_hs_d = (dsc_info->num_active_ss_per_enc > 1) * (ob_data_width > compress_bpp_group);
+	multi_hs_extra_budget_bits = multi_hs_c ?
+				chunk_bits : (multi_hs_d ? chunk_bits :
+					output_rate_extra_budget_bits);
+	multi_hs_extra_latency = DIV_ROUND_UP(multi_hs_extra_budget_bits,
+			compress_bpp_group);
+	dsc_info->initial_lines = DIV_ROUND_UP((base_hs_latency +
+				multi_hs_extra_latency),
+			container_slice_width);
+
+	return 0;
+}
+
+int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
+					int intf_width)
+{
+	int  mod_offset;
+	int slice_per_pkt, slice_per_intf;
+	int bytes_in_slice, total_bytes_per_intf;
+	u16 bpp;
+	u32 bytes_in_dsc_pair;
+	u32 total_bytes_in_dsc_pair;
+
+	if (!dsc_info || !dsc_info->drm_dsc.slice_width ||
+			!dsc_info->drm_dsc.slice_height ||
+			intf_width < dsc_info->drm_dsc.slice_width) {
+		DPU_ERROR("invalid input, intf_width=%d slice_width=%d\n",
+			intf_width, dsc_info ? dsc_info->drm_dsc.slice_width :
+			-1);
+		return -EINVAL;
+	}
+
+	mod_offset = dsc_info->drm_dsc.slice_width % 3;
+
+
+	switch (mod_offset) {
+	case 0:
+		dsc_info->slice_last_group_size = 2;
+		break;
+	case 1:
+		dsc_info->slice_last_group_size = 0;
+		break;
+	case 2:
+		dsc_info->slice_last_group_size = 1;
+		break;
+	default:
+		break;
+	}
+
+	dsc_info->det_thresh_flatness =
+		2 << (dsc_info->drm_dsc.bits_per_component - 8);
+
+	slice_per_pkt = dsc_info->slice_per_pkt;
+	slice_per_intf = DIV_ROUND_UP(intf_width,
+			dsc_info->drm_dsc.slice_width);
+
+
+	/*
+	 * If slice_per_pkt is greater than slice_per_intf then default to 1.
+	 * This can happen during partial update.
+	 */
+	if (slice_per_pkt > slice_per_intf)
+		slice_per_pkt = 1;
+
+	bpp = DSC_BPP(dsc_info->drm_dsc);
+	bytes_in_slice = DIV_ROUND_UP(dsc_info->drm_dsc.slice_width * bpp, 8);
+	total_bytes_per_intf = bytes_in_slice * slice_per_intf;
+
+
+	dsc_info->eol_byte_num = total_bytes_per_intf % 3;
+	dsc_info->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
+	dsc_info->bytes_in_slice = bytes_in_slice;
+	dsc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
+	dsc_info->pkt_per_line = slice_per_intf / slice_per_pkt;
+
+
+	bytes_in_dsc_pair = DIV_ROUND_UP(bytes_in_slice * 2, 3);
+	if (bytes_in_dsc_pair % 8) {
+		dsc_info->dsc_4hsmerge_padding = 8 - (bytes_in_dsc_pair % 8);
+		total_bytes_in_dsc_pair = bytes_in_dsc_pair +
+				dsc_info->dsc_4hsmerge_padding;
+		if (total_bytes_in_dsc_pair % 16)
+			dsc_info->dsc_4hsmerge_alignment = 16 -
+					(total_bytes_in_dsc_pair % 16);
+	}
+
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
new file mode 100644
index 00000000..9f26455
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 - 2023 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
+ */
+
+#ifndef __DPU_DSC_HELPER_H__
+#define __DPU_DSC_HELPER_H__
+
+#include "msm_drv.h"
+
+#define DSC_1_1_PPS_PARAMETER_SET_ELEMENTS   88
+
+int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver);
+
+int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
+					int intf_width);
+
+bool dpu_dsc_ich_reset_override_needed(bool pu_en, struct msm_display_dsc_info *dsc);
+
+int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc,
+				int enc_ip_width, int dsc_cmn_mode);
+
+#endif /* __DPU_DSC_HELPER_H__ */
+
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index f155803..cf4eb8d 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -57,6 +57,10 @@ struct msm_disp_state;
 #define MAX_CRTCS      8
 #define MAX_BRIDGES    8
 
+#define MSM_CHROMA_444 0x0
+#define MSM_CHROMA_422 0x1
+#define MSM_CHROMA_420 0x2
+
 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
 
 enum msm_dp_controller {
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (6 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 07/14] drm/msm/dp: add dsc helper functions Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:30   ` Dmitry Baryshkov
  2023-01-23 18:24 ` [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Kuogee Hsieh
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

This patch provides DSC required functions at DP controller to
complete DSC feature. those functions include enable fec, configure
dsc, configure dto, transmit pps and finally flush hardware registers.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 139 ++++++++-
 drivers/gpu/drm/msm/dp/dp_catalog.h |  93 ++++++
 drivers/gpu/drm/msm/dp/dp_ctrl.c    | 132 ++++++++-
 drivers/gpu/drm/msm/dp/dp_display.c |  61 +++-
 drivers/gpu/drm/msm/dp/dp_panel.c   | 570 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/msm/dp/dp_panel.h   |   4 +
 drivers/gpu/drm/msm/dp/dp_reg.h     |  40 ++-
 drivers/gpu/drm/msm/msm_drv.h       |  16 +
 8 files changed, 1033 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 7ac37d8..20a86e7 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -48,6 +48,11 @@
 #define DP_INTERRUPT_STATUS2_MASK \
 	(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+enum dp_flush_bit {
+	DP_PPS_FLUSH,
+	DP_DHDR_FLUSH,
+};
+
 struct dp_catalog_private {
 	struct device *dev;
 	struct drm_device *drm_dev;
@@ -277,6 +282,30 @@ static void dump_regs(void __iomem *base, int len)
 	}
 }
 
+void dp_catalog_fec_config(struct dp_catalog *dp_catalog, bool enable)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+		struct dp_catalog_private, dp_catalog);
+	u32 reg;
+
+	reg = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+	/*
+	 * fec_en = BIT(12)
+	 * fec_seq_mode = BIT(22)
+	 * sde_flush = BIT(23) | BIT(24)
+	 * fb_boundary_sel = BIT(25)
+	 */
+	if (enable)
+		reg |= BIT(12) | BIT(22) | BIT(23) | BIT(24) | BIT(25);
+	else
+		reg &= ~BIT(12);
+
+	dp_write_link(catalog, REG_DP_MAINLINK_CTRL, reg);
+	/* make sure mainlink configuration is updated with fec sequence */
+	wmb();
+}
+
 void dp_catalog_dump_regs(struct dp_catalog *dp_catalog)
 {
 	struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -344,6 +373,54 @@ void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 cfg)
 	dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
 }
 
+void dp_catalog_config_dsc_dto(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data;
+	u32 reg;
+
+	dp_write_p0(catalog, MMSS_DP_DSC_DTO_COUNT, dsc_data->dto_count);
+
+	reg = dp_read_p0(catalog, MMSS_DP_DSC_DTO);
+
+	if (dsc_data->dto_en) {
+		reg |= BIT(0);
+		reg |= BIT(3);
+		reg |= (dsc_data->dto_n << 8);
+		reg |= (dsc_data->dto_d << 16);
+	}
+
+	dp_write_p0(catalog, MMSS_DP_DSC_DTO, reg);
+
+	reg = 0;
+	if (dsc_data->dsc_en) {
+		reg = BIT(0);
+		reg |= (dsc_data->eol_byte_num << 3);
+		reg |= (dsc_data->slice_per_pkt << 5);
+		reg |= (dsc_data->bytes_per_pkt << 16);
+		reg |= (dsc_data->be_in_lane << 10);
+	}
+	dp_write_link(catalog, DP_COMPRESSION_MODE_CTRL, reg);
+
+	drm_dbg_dp(catalog->drm_dev, "compression:0x%x\n", reg);
+}
+
+void dp_catalog_override_ack_dto(struct dp_catalog *dp_catalog, bool not_ack)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+        u32 dsc_dto;
+
+	dsc_dto = dp_read_p0(catalog, MMSS_DP_DSC_DTO);
+        if (not_ack)
+                dsc_dto &= ~BIT(1);
+        else
+                dsc_dto = BIT(1);
+
+	dp_write_p0(catalog, MMSS_DP_DSC_DTO, dsc_dto);
+}
+
 void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog)
 {
 	struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -429,6 +506,15 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
 	}
 }
 
+static void dp_catalog_sdp_update( struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+	dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+}
+
 void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog,
 					u32 colorimetry_cfg,
 					u32 test_bits_depth)
@@ -504,7 +590,6 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
 	drm_dbg_dp(catalog->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid);
 	dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid);
 	dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid);
-	dp_write_p0(catalog, MMSS_DP_DSC_DTO, 0x0);
 }
 
 int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog,
@@ -918,6 +1003,58 @@ void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog)
 	dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0);
 }
 
+void dp_catalog_dsc_commit_pps(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data;
+	int i;
+
+	dp_write_link(catalog, DP_PPS_HB_0_3, 0x7F1000);
+	dp_write_link(catalog, DP_PPS_PB_0_3, 0xA22300);
+
+	for (i = 0; i < dsc_data->parity_word_len; i++)
+		dp_write_link(catalog, DP_PPS_PB_4_7 + (i << 2),
+				dsc_data->parity_word[i]);
+
+	for (i = 0; i < dsc_data->pps_word_len; i++)
+		dp_write_link(catalog, DP_PPS_PPS_0_3 + (i << 2),
+				dsc_data->pps_word[i]);
+}
+
+static void dp_catalog_dp_flush(struct dp_catalog *dp_catalog,
+		enum dp_flush_bit flush_bit)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+	u32 dp_flush;
+	struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data;
+
+	dp_flush = dp_read_link(catalog, MMSS_DP_FLUSH);
+
+	dsc_data->continuous_pps = true;
+
+	if ((flush_bit == DP_PPS_FLUSH) && dsc_data->continuous_pps)
+		dp_flush &= ~BIT(2);
+
+	dp_flush |= BIT(flush_bit);
+	dp_write_link(catalog, MMSS_DP_FLUSH, dp_flush);
+
+	/*
+	 * TODO: no dp_config_sdp_update() required?
+	 */
+	dp_catalog_sdp_update(dp_catalog);
+}
+
+void dp_catalog_pps_flush(struct dp_catalog *dp_catalog)
+{
+	struct dp_catalog_private *catalog = container_of(dp_catalog,
+				struct dp_catalog_private, dp_catalog);
+
+	dp_catalog_dp_flush(dp_catalog, DP_PPS_FLUSH);
+	drm_dbg_dp(catalog->drm_dev, "pps flush\n");
+}
+
 struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
 {
 	struct dp_catalog_private *catalog;
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 990c162..537fb8d 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -62,6 +62,27 @@ enum dp_catalog_audio_header_type {
 	DP_AUDIO_SDP_HEADER_MAX,
 };
 
+struct dp_dsc_cfg_data {
+	bool dsc_en;
+	bool continuous_pps;
+	char pps[128];
+	u32 pps_len;
+	u32 pps_word[32];
+	u32 pps_word_len;
+	u8 parity[32];
+	u8 parity_len;
+	u32 parity_word[8];
+	u32 parity_word_len;
+	u32 slice_per_pkt;
+	u32 bytes_per_pkt;
+	u32 eol_byte_num;
+	u32 be_in_lane;
+	u32 dto_en;
+	u32 dto_n;
+	u32 dto_d;
+	u32 dto_count;
+};
+
 struct dp_catalog {
 	u32 aux_data;
 	u32 total;
@@ -72,8 +93,74 @@ struct dp_catalog {
 	enum dp_catalog_audio_header_type sdp_header;
 	u32 audio_data;
 	bool wide_bus_en;
+	struct dp_dsc_cfg_data dsc_data;
 };
 
+static inline u8 dp_ecc_get_g0_value(u8 data)
+{
+	u8 c[4];
+	u8 g[4];
+	u8 ret_data = 0;
+	u8 i;
+
+	for (i = 0; i < 4; i++)
+		c[i] = (data >> i) & 0x01;
+
+	g[0] = c[3];
+	g[1] = c[0] ^ c[3];
+	g[2] = c[1];
+	g[3] = c[2];
+
+	for (i = 0; i < 4; i++)
+		ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+	return ret_data;
+}
+
+static inline u8 dp_ecc_get_g1_value(u8 data)
+{
+	u8 c[4];
+	u8 g[4];
+	u8 ret_data = 0;
+	u8 i;
+
+	for (i = 0; i < 4; i++)
+		c[i] = (data >> i) & 0x01;
+
+	g[0] = c[0] ^ c[3];
+	g[1] = c[0] ^ c[1] ^ c[3];
+	g[2] = c[1] ^ c[2];
+	g[3] = c[2] ^ c[3];
+
+	for (i = 0; i < 4; i++)
+		ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+	return ret_data;
+}
+
+static inline u8 dp_header_get_parity(u32 data)
+{
+	u8 x0 = 0;
+	u8 x1 = 0;
+	u8 ci = 0;
+	u8 iData = 0;
+	u8 i = 0;
+	u8 parity_byte;
+	u8 num_byte = (data > 0xFF) ? 8 : 2;
+
+	for (i = 0; i < num_byte; i++) {
+		iData = (data >> i*4) & 0xF;
+
+		ci = iData ^ x1;
+		x1 = x0 ^ dp_ecc_get_g1_value(ci);
+		x0 = dp_ecc_get_g0_value(ci);
+	}
+
+	parity_byte = x1 | (x0 << 4);
+
+	return parity_byte;
+}
+
 /* Debug module */
 void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *disp_state);
 
@@ -137,4 +224,10 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *catalog);
 void dp_catalog_audio_init(struct dp_catalog *catalog);
 void dp_catalog_audio_sfe_level(struct dp_catalog *catalog);
 
+void dp_catalog_fec_config(struct dp_catalog *dp_catalog, bool enable);
+void dp_catalog_dsc_commit_pps(struct dp_catalog *catalog);
+void dp_catalog_config_dsc_dto(struct dp_catalog *catalog);
+void dp_catalog_override_ack_dto(struct dp_catalog *dp_catalog, bool not_ack);
+void dp_catalog_pps_flush(struct dp_catalog *catalog);
+
 #endif /* _DP_CATALOG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index ae9c2b8..b315bf3 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -134,9 +134,13 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
 	tbd = dp_link_get_test_bits_depth(ctrl->link,
 			ctrl->panel->dp_mode.bpp);
 
-	if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) {
+	/*
+	 * since dsc encoder output byte stream to dp controller,
+	 * 8 bits bpc should be used as long as dsc eanabled
+	 */ 
+	if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN || ctrl->panel->dsc_en) {
 		pr_debug("BIT_DEPTH not set. Configure default\n");
-		tbd = DP_TEST_BIT_DEPTH_8;
+		tbd = DP_TEST_BIT_DEPTH_8 >> DP_TEST_BIT_DEPTH_SHIFT;
 	}
 
 	config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
@@ -366,8 +370,8 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
 	tu->lwidth_fp            = drm_fixp_from_fraction(in->hactive, 1);
 	tu->orig_lwidth          = in->hactive;
 	tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1);
-	tu->orig_hbp             = in->hporch;
-	tu->rb2                  = (in->hporch <= 80) ? 1 : 0;
+        tu->orig_hbp             = in->hporch;
+	tu->rb2                  = (in->hporch < 160) ? 1 : 0;
 
 	if (tu->pixelEnc == 420) {
 		temp1_fp = drm_fixp_from_fraction(2, 1);
@@ -399,6 +403,8 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
 	if (!in->dsc_en)
 		goto fec_check;
 
+	tu->bpp = 24; /* hardcode to 24 if DSC is enabled */
+
 	temp1_fp = drm_fixp_from_fraction(in->compress_ratio, 100);
 	temp2_fp = drm_fixp_from_fraction(in->bpp, 1);
 	temp3_fp = drm_fixp_div(temp2_fp, temp1_fp);
@@ -1076,6 +1082,11 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
 {
 	struct dp_tu_calc_input in;
 	struct drm_display_mode *drm_mode;
+	struct dp_panel_info *timing;
+	struct msm_compression_info *comp_info;
+
+	timing = &ctrl->panel->dp_mode.timing;
+	comp_info = &timing->comp_info;
 
 	drm_mode = &ctrl->panel->dp_mode.drm_mode;
 
@@ -1086,12 +1097,22 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
 	in.nlanes = ctrl->link->link_params.num_lanes;
 	in.bpp = ctrl->panel->dp_mode.bpp;
 	in.pixel_enc = 444;
-	in.dsc_en = 0;
+	in.dsc_en = ctrl->panel->dsc_en;
 	in.async_en = 0;
-	in.fec_en = 0;
+	in.fec_en = ctrl->panel->fec_en;
 	in.num_of_dsc_slices = 0;
 	in.compress_ratio = 100;
 
+
+	/*
+	 * TODO: only one dsc slice supported for now
+	 */
+	if (ctrl->panel->dsc_en) {
+		in.num_of_dsc_slices = 1;
+		in.compress_ratio = mult_frac(100, comp_info->src_bpp,
+                                comp_info->tgt_bpp);
+	}
+
 	_dp_ctrl_calc_tu(ctrl, &in, tu_table);
 }
 
@@ -1424,6 +1445,74 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
 	return ret;
 }
 
+static void dp_ctrl_sink_fec_enable(struct dp_ctrl_private *ctrl)
+{
+	int rlen;
+
+	rlen = drm_dp_dpcd_writeb(ctrl->aux, DP_FEC_CONFIGURATION, 0x07);
+	if (rlen < 1)
+		DRM_ERROR("failed to enable sink fec\n");
+
+
+}
+
+static void dp_ctrl_host_fec_start(struct dp_ctrl_private *ctrl)
+{
+	u8 fec_sts = 0;
+	int i, max_retries = 3;
+	bool fec_en_detected = false;
+
+	if (!ctrl->panel->fec_en)
+		return;
+
+	/* Need to try to enable multiple times due to BS symbols collisions */
+	for (i = 0; i < max_retries; i++) {
+		dp_catalog_fec_config(ctrl->catalog, true);
+
+		/* wait for controller to start fec sequence */
+		usleep_range(900, 1000);
+
+		/* read back FEC status and check if it is enabled */
+		drm_dp_dpcd_readb(ctrl->aux, DP_FEC_STATUS, &fec_sts);
+		if (fec_sts & DP_FEC_DECODE_EN_DETECTED) {
+			fec_en_detected = true;
+			break;
+		}
+	}
+
+	drm_dbg_dp(ctrl->drm_dev, "retries %d, fec_en_detected %d\n",
+				i, fec_en_detected);
+
+	if (!fec_en_detected)
+		DRM_ERROR("failed to enable sink fec\n");
+}
+
+static void dp_ctrl_host_fec_stop(struct dp_ctrl_private *ctrl)
+{
+	dp_catalog_fec_config(ctrl->catalog, false);
+}
+
+static void dp_ctrl_sink_dsc_enable(struct dp_ctrl_private *ctrl)
+{
+	int rlen;
+	u32 dsc_enable;
+	u8 xx = 0;
+
+
+	if (!ctrl->panel->fec_en)
+		return;
+
+	dsc_enable = ctrl->panel->dsc_en ? 1 : 0;
+	rlen = drm_dp_dpcd_writeb(ctrl->aux, DP_DSC_ENABLE, dsc_enable);
+	if (rlen < 1)
+		DRM_ERROR("failed to enable sink dsc\n");
+
+
+	dsc_enable = 0;
+	drm_dp_dpcd_readb(ctrl->aux, DP_DSC_ENABLE, &xx);
+
+}
+
 static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
 			int *training_step)
 {
@@ -1442,6 +1531,9 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
 	 * a link training pattern, we have to first do soft reset.
 	 */
 
+	if (ctrl->panel->fec_en)
+		dp_ctrl_sink_fec_enable(ctrl);
+
 	ret = dp_ctrl_link_train(ctrl, training_step);
 
 	return ret;
@@ -1986,14 +2078,25 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
 	 */
 	reinit_completion(&ctrl->video_comp);
 
+	if (ctrl->panel->dsc_en)
+		dp_panel_config_dsc(ctrl->panel, true);
+
 	dp_ctrl_configure_source_params(ctrl);
 
 	dp_catalog_ctrl_config_msa(ctrl->catalog,
 		ctrl->link->link_params.rate,
 		pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
 
+	if (ctrl->panel->dsc_en) {
+		dp_catalog_config_dsc_dto(ctrl->catalog);
+		dp_catalog_dsc_commit_pps(ctrl->catalog);
+		dp_catalog_pps_flush(ctrl->catalog);
+	}
+
 	dp_ctrl_setup_tr_unit(ctrl);
 
+	dp_catalog_override_ack_dto(ctrl->catalog, true);
+
 	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
 
 	ret = dp_ctrl_wait4video_ready(ctrl);
@@ -2004,6 +2107,12 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
 	drm_dbg_dp(ctrl->drm_dev,
 		"mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
 
+	if (ctrl->panel->dsc_en) {
+		/* wait for link training completion before fec config as per spec */
+		dp_ctrl_host_fec_start(ctrl);
+		dp_ctrl_sink_dsc_enable(ctrl);
+	}
+
 end:
 	return ret;
 }
@@ -2019,6 +2128,9 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
 	dp_io = &ctrl->parser->io;
 	phy = dp_io->phy;
 
+	if (ctrl->panel->dsc_en)
+		dp_panel_config_dsc(ctrl->panel, false);
+
 	/* set dongle to D3 (power off) mode */
 	dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
 
@@ -2093,6 +2205,14 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
 	dp_io = &ctrl->parser->io;
 	phy = dp_io->phy;
 
+	if (ctrl->panel->dsc_en) {
+		dp_ctrl_host_fec_stop(ctrl);
+		dp_panel_config_dsc(ctrl->panel, false);
+		dp_catalog_config_dsc_dto(ctrl->catalog);
+	}
+
+	dp_catalog_override_ack_dto(ctrl->catalog, false);
+
 	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
 
 	dp_catalog_ctrl_reset(ctrl->catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index bde1a7c..da59d13 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved 
  */
 
 #include <linux/module.h>
@@ -99,7 +100,7 @@ struct dp_display_private {
 	struct dp_debug   *debug;
 
 	struct dp_usbpd_cb usbpd_cb;
-	struct dp_display_mode dp_mode;
+	struct dp_display_mode *dp_mode;
 	struct msm_dp dp_display;
 
 	/* wait for audio signaling */
@@ -831,6 +832,9 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
 		goto error_link;
 	}
 
+	/* both dp_display and dp_panel shared same dp_mode */
+	dp->dp_mode = &dp->panel->dp_mode;
+
 	dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,
 			       dp->power, dp->catalog, dp->parser);
 	if (IS_ERR(dp->ctrl)) {
@@ -1662,7 +1666,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
 	bool force_link_train = false;
 
 	dp_display = container_of(dp, struct dp_display_private, dp_display);
-	if (!dp_display->dp_mode.drm_mode.clock) {
+	if (!dp_display->dp_mode->drm_mode.clock) {
 		DRM_ERROR("invalid params\n");
 		return;
 	}
@@ -1678,7 +1682,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
 		return;
 	}
 
-	rc = dp_display_set_mode(dp, &dp_display->dp_mode);
+	rc = dp_display_set_mode(dp, dp_display->dp_mode);
 	if (rc) {
 		DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
 		mutex_unlock(&dp_display->event_mutex);
@@ -1744,6 +1748,10 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
 	if (state == ST_DISCONNECT_PENDING) {
 		/* completed disconnection */
 		dp_display->hpd_state = ST_DISCONNECTED;
+		if (dp_display->panel->dsc_en) {
+			dp_display->dp_mode->timing.comp_info.enabled = false;
+			dp_display->panel->dsc_en = false;
+		}
 	} else {
 		dp_display->hpd_state = ST_DISPLAY_OFF;
 	}
@@ -1762,23 +1770,50 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
 
 	dp_display = container_of(dp, struct dp_display_private, dp_display);
 
-	memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
+	memset(dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
 
 	if (dp_display_check_video_test(dp))
-		dp_display->dp_mode.bpp = dp_display_get_test_bpp(dp);
+		dp_display->dp_mode->bpp = dp_display_get_test_bpp(dp);
 	else /* Default num_components per pixel = 3 */
-		dp_display->dp_mode.bpp = dp->connector->display_info.bpc * 3;
+		dp_display->dp_mode->bpp = dp->connector->display_info.bpc * 3;
+
+	if (!dp_display->dp_mode->bpp)
+		dp_display->dp_mode->bpp = 24; /* Default bpp */
+
+	drm_mode_copy(&dp_display->dp_mode->drm_mode, adjusted_mode);
+
+	dp_display->dp_mode->v_active_low =
+		!!(dp_display->dp_mode->drm_mode.flags & DRM_MODE_FLAG_NVSYNC);
+
+	dp_display->dp_mode->h_active_low =
+		!!(dp_display->dp_mode->drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+
+
+	if (dp_display->panel->dsc_en) {
+		dp_display->dp_mode->capabilities |= DP_PANEL_CAPS_DSC;
+		dp_panel_convert_to_dp_mode(dp_display->panel, dp_display->dp_mode);
+	}
+}
 
-	if (!dp_display->dp_mode.bpp)
-		dp_display->dp_mode.bpp = 24; /* Default bpp */
+void msm_dp_bridge_mode_set(struct drm_bridge *bridge,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{ 
+	dp_bridge_mode_set(bridge, mode, adjusted_mode);
+}
 
-	drm_mode_copy(&dp_display->dp_mode.drm_mode, adjusted_mode);
+struct msm_compression_info *msm_dp_bridge_get_compression(struct drm_bridge *drm_bridge)
+{
+	struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
+	struct msm_dp *dp_display = dp_bridge->dp_display;
+	struct dp_display_private *dp;
+
+	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
-	dp_display->dp_mode.v_active_low =
-		!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC);
+	if (!dp->panel->dsc_en)
+		return NULL;
 
-	dp_display->dp_mode.h_active_low =
-		!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+	return &dp->dp_mode->timing.comp_info;
 }
 
 void dp_bridge_hpd_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 55bb6b0..19e2f07 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -5,11 +5,12 @@
  */
 
 #include "dp_panel.h"
-
+#include "dpu_dsc_helper.h"
 #include <drm/drm_fixed.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_print.h>
+#include <drm/display/drm_dsc_helper.h>
 
 #define DSC_TGT_BPP 10
 
@@ -612,6 +613,573 @@ u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel)
 	return colorimetry;
 }
 
+static inline int fixp2int_ceil(s64 a)
+{
+	return (a ? drm_fixp2int_ceil(a) : 0);
+}
+
+struct dp_dsc_slices_per_line {
+	u32 min_ppr;
+	u32 max_ppr;
+	u8 num_slices;
+};
+
+struct dp_dsc_peak_throughput {
+	u32 index;
+	u32 peak_throughput;
+};
+
+struct dp_dsc_slice_caps_bit_map {
+	u32 num_slices;
+	u32 bit_index;
+};
+
+const struct dp_dsc_slices_per_line slice_per_line_tbl[] = {
+	{0,     340,    1   },
+	{340,   680,    2   },
+	{680,   1360,   4   },
+	{1360,  3200,   8   },
+	{3200,  4800,   12  },
+	{4800,  6400,   16  },
+	{6400,  8000,   20  },
+	{8000,  9600,   24  }
+};
+
+const struct dp_dsc_peak_throughput peak_throughput_mode_0_tbl[] = {
+	{0, 0},
+	{1, 340},
+	{2, 400},
+	{3, 450},
+	{4, 500},
+	{5, 550},
+	{6, 600},
+	{7, 650},
+	{8, 700},
+	{9, 750},
+	{10, 800},
+	{11, 850},
+	{12, 900},
+	{13, 950},
+	{14, 1000},
+};
+
+const struct dp_dsc_slice_caps_bit_map slice_caps_bit_map_tbl[] = {
+	{1, 0},
+	{2, 1},
+	{4, 3},
+	{6, 4},
+	{8, 5},
+	{10, 6},
+	{12, 7},
+	{16, 0},
+	{20, 1},
+	{24, 2},
+};
+
+static bool dp_panel_check_slice_support(u32 num_slices, u32 raw_data_1,
+		u32 raw_data_2)
+{
+	const struct dp_dsc_slice_caps_bit_map *bcap;
+	u32 raw_data;
+	int i;
+
+	if (num_slices <= 12)
+		raw_data = raw_data_1;
+	else
+		raw_data = raw_data_2;
+
+	for (i = 0; i < ARRAY_SIZE(slice_caps_bit_map_tbl); i++) {
+		bcap = &slice_caps_bit_map_tbl[i];
+
+		if (bcap->num_slices == num_slices) {
+			raw_data &= (1 << bcap->bit_index);
+
+			if (raw_data)
+				return true;
+			else
+				return false;
+		}
+	}
+
+	return false;
+}
+
+static int dp_panel_dsc_prepare_basic_params(
+		struct msm_compression_info *comp_info,
+		const struct dp_display_mode *dp_mode,
+		struct dp_panel *dp_panel)
+{
+	struct dp_panel_private *panel;
+	struct drm_dsc_config *dsc;
+	int i;
+	const struct dp_dsc_slices_per_line *rec;
+	const struct dp_dsc_peak_throughput *tput;
+	u32 slice_width;
+	u32 ppr = dp_mode->timing.pixel_clk_khz/1000;
+	u32 max_slice_width;
+	u32 ppr_max_index;
+	u32 peak_throughput;
+	u32 ppr_per_slice;
+	u32 slice_caps_1;
+	u32 slice_caps_2;
+	u32 dsc_version_major, dsc_version_minor;
+	bool dsc_version_supported = false;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	dsc_version_major = dp_panel->sink_dsc_caps.version & 0xF;
+	dsc_version_minor = (dp_panel->sink_dsc_caps.version >> 4) & 0xF;
+	dsc_version_supported = (dsc_version_major == 0x1 &&
+			(dsc_version_minor == 0x1 || dsc_version_minor == 0x2))
+			? true : false;
+
+	drm_dbg_dp(panel->drm_dev, "DSC version: %d.%d, dpcd value: %x\n",
+			dsc_version_major, dsc_version_minor,
+			dp_panel->sink_dsc_caps.version);
+
+	if (!dsc_version_supported) {
+		dsc_version_major = 1;
+		dsc_version_minor = 1;
+		DRM_ERROR("invalid sink DSC version, fallback to %d.%d\n",
+				dsc_version_major, dsc_version_minor);
+	}
+
+	dsc = &comp_info->msm_dsc_info.drm_dsc;
+	dsc->dsc_version_major = dsc_version_major;
+	dsc->dsc_version_minor = dsc_version_minor;
+	comp_info->msm_dsc_info.scr_rev = 0x0;
+
+
+	comp_info->msm_dsc_info.slice_per_pkt = 0;
+	for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) {
+		rec = &slice_per_line_tbl[i];
+		if ((ppr > rec->min_ppr) && (ppr <= rec->max_ppr)) {
+			comp_info->msm_dsc_info.slice_per_pkt = rec->num_slices;
+			i++;
+			break;
+		}
+	}
+
+	if (comp_info->msm_dsc_info.slice_per_pkt == 0)
+		return -EINVAL;
+
+	ppr_max_index = dp_panel->dsc_dpcd[11] &= 0xf;
+	if (!ppr_max_index || ppr_max_index >= 15) {
+		drm_dbg_dp(panel->drm_dev, 
+				"Throughput mode 0 not supported");
+		return -EINVAL;
+	}
+
+	tput = &peak_throughput_mode_0_tbl[ppr_max_index];
+	peak_throughput = tput->peak_throughput;
+
+	max_slice_width = dp_panel->dsc_dpcd[12] * 320;
+	slice_width = (dp_mode->timing.h_active /
+				comp_info->msm_dsc_info.slice_per_pkt);
+
+	ppr_per_slice = ppr/comp_info->msm_dsc_info.slice_per_pkt;
+
+	slice_caps_1 = dp_panel->dsc_dpcd[4];
+	slice_caps_2 = dp_panel->dsc_dpcd[13] & 0x7;
+
+	/*
+	 * There are 3 conditions to check for sink support:
+	 * 1. The slice width cannot exceed the maximum.
+	 * 2. The ppr per slice cannot exceed the maximum.
+	 * 3. The number of slices must be explicitly supported.
+	 */
+	while (slice_width >= max_slice_width ||
+			ppr_per_slice > peak_throughput ||
+			!dp_panel_check_slice_support(
+			comp_info->msm_dsc_info.slice_per_pkt, slice_caps_1,
+			slice_caps_2)) {
+		if (i == ARRAY_SIZE(slice_per_line_tbl))
+			return -EINVAL;
+
+		rec = &slice_per_line_tbl[i];
+		comp_info->msm_dsc_info.slice_per_pkt = rec->num_slices;
+		slice_width = (dp_mode->timing.h_active /
+				comp_info->msm_dsc_info.slice_per_pkt);
+		ppr_per_slice = ppr/comp_info->msm_dsc_info.slice_per_pkt;
+		i++;
+	}
+
+	dsc->block_pred_enable = dp_panel->sink_dsc_caps.block_pred_en;
+
+	dsc->pic_width = dp_mode->timing.h_active;
+	dsc->pic_height = dp_mode->timing.v_active;
+	dsc->slice_width = slice_width;
+
+	if (dsc->pic_height % 108 == 0)
+		dsc->slice_height = 108;
+	else if (dsc->pic_height % 16 == 0)
+		dsc->slice_height = 16;
+	else if (dsc->pic_height % 12 == 0)
+		dsc->slice_height = 12;
+	else
+		dsc->slice_height = 15;
+
+	dsc->bits_per_component = (dp_mode->timing.bpp / 3);
+	dsc->bits_per_pixel = DSC_TGT_BPP << 4;
+	dsc->slice_count = DIV_ROUND_UP(dp_mode->timing.h_active, slice_width);
+
+	comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC;
+	comp_info->tgt_bpp = DSC_TGT_BPP;
+	comp_info->src_bpp = dp_mode->timing.bpp;
+	comp_info->comp_ratio = dp_mode->timing.bpp / DSC_TGT_BPP;
+	comp_info->enabled = true;
+
+	return 0;
+}
+
+static void dp_panel_get_dto_params(u32 src_bpp, u32 tgt_bpp, u32 *num, u32 *denom)
+{
+	if ((tgt_bpp == 12) && (src_bpp == 24)) {
+		*num = 1;
+		*denom = 2;
+	} else if ((tgt_bpp == 15) && (src_bpp == 30)) {
+		*num = 5;
+		*denom = 8;
+	} else if ((tgt_bpp == 8) && ((src_bpp == 24) || (src_bpp == 30))) {
+		*num = 1;
+		*denom = 3;
+	} else if ((tgt_bpp == 10) && (src_bpp == 30)) {
+		*num = 5;
+		*denom = 12;
+	} else {
+		DRM_ERROR("dto params not found\n");
+		*num = 0;
+		*denom = 1;
+	}
+}
+
+static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel)
+{
+	struct dp_panel_private *panel;
+	struct dp_dsc_cfg_data *dsc_data;
+	u8 *pps, *parity;
+	u32 *pps_word, *parity_word;
+	int i, index_4;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	dsc_data = &panel->catalog->dsc_data;
+	pps = dsc_data->pps;
+	pps_word = dsc_data->pps_word;
+	parity = dsc_data->parity;
+	parity_word = dsc_data->parity_word;
+
+	memset(parity, 0, sizeof(dsc_data->parity));
+
+	dsc_data->pps_word_len = dsc_data->pps_len >> 2;
+	dsc_data->parity_len = dsc_data->pps_word_len;
+	dsc_data->parity_word_len = (dsc_data->parity_len >> 2) + 1;
+
+	for (i = 0; i < dsc_data->pps_word_len; i++) {
+		index_4 = i << 2;
+		pps_word[i] = pps[index_4 + 0] << 0 |
+				pps[index_4 + 1] << 8 |
+				pps[index_4 + 2] << 16 |
+				pps[index_4 + 3] << 24;
+
+		parity[i] = dp_header_get_parity(pps_word[i]);
+	}
+
+	for (i = 0; i < dsc_data->parity_word_len; i++) {
+		index_4 = i << 2;
+		parity_word[i] = parity[index_4 + 0] << 0 |
+				   parity[index_4 + 1] << 8 |
+				   parity[index_4 + 2] << 16 |
+				   parity[index_4 + 3] << 24;
+	}
+}
+
+void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable)
+{
+	struct dp_panel_private *panel;
+	struct dp_panel_info *timing;
+	struct msm_compression_info *comp_info;
+	struct dp_dsc_cfg_data *dsc_data;
+	struct drm_dsc_picture_parameter_set *pps_payload;
+	struct drm_dsc_config *dsc;
+
+	if (!dp_panel->dsc_en)
+		return;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	dsc_data = &panel->catalog->dsc_data;
+	timing = &dp_panel->dp_mode.timing;
+	comp_info = &timing->comp_info;
+	dsc = &comp_info->msm_dsc_info.drm_dsc;
+
+	if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) {
+		memset(dsc_data->pps, 0, sizeof(dsc_data->pps));
+		pps_payload = (struct drm_dsc_picture_parameter_set *)dsc_data->pps;
+		drm_dsc_pps_payload_pack(pps_payload, dsc);
+
+		dsc_data->pps_len = DSC_1_1_PPS_PARAMETER_SET_ELEMENTS;
+		dp_panel_dsc_prepare_pps_packet(dp_panel);
+
+		dsc_data->slice_per_pkt = comp_info->msm_dsc_info.slice_per_pkt - 1;
+		dsc_data->bytes_per_pkt = comp_info->msm_dsc_info.bytes_per_pkt;
+		dsc_data->bytes_per_pkt /= comp_info->msm_dsc_info.slice_per_pkt;
+		dsc_data->eol_byte_num = comp_info->msm_dsc_info.eol_byte_num;
+		dsc_data->dto_count = comp_info->msm_dsc_info.pclk_per_line;
+		dsc_data->be_in_lane = 10;
+		dsc_data->dsc_en = true;
+		dsc_data->dto_en = true;
+		dp_panel_get_dto_params(comp_info->src_bpp, comp_info->tgt_bpp, &dsc_data->dto_n,
+				&dsc_data->dto_d);
+	} else {
+		dsc_data->dsc_en = false;
+		dsc_data->dto_en = false;
+		dsc_data->dto_n = 0;
+		dsc_data->dto_d = 0;
+		dsc_data->continuous_pps = false;
+	}
+}
+
+static void _dp_panel_dsc_get_num_extra_pclk(struct msm_compression_info *comp_info)
+{
+	unsigned int dto_n = 0, dto_d = 0, remainder;
+	int ack_required, last_few_ack_required, accum_ack;
+	int last_few_pclk, last_few_pclk_required;
+	struct msm_display_dsc_info *dsc_info = &comp_info->msm_dsc_info;
+	int start, temp, line_width = dsc_info->drm_dsc.pic_width/2;
+	s64 temp1_fp, temp2_fp;
+
+	dp_panel_get_dto_params(comp_info->src_bpp, comp_info->tgt_bpp, &dto_n, &dto_d);
+
+	ack_required = dsc_info->pclk_per_line;
+
+	/* number of pclk cycles left outside of the complete DTO set */
+	last_few_pclk = line_width % dto_d;
+
+	/* number of pclk cycles outside of the complete dto */
+	temp1_fp = drm_fixp_from_fraction(line_width, dto_d);
+	temp2_fp = drm_fixp_from_fraction(dto_n, 1);
+	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+	temp = drm_fixp2int(temp1_fp);
+	last_few_ack_required = ack_required - temp;
+
+	/*
+	 * check how many more pclk is needed to
+	 * accommodate the last few ack required
+	 */
+	remainder = dto_n;
+	accum_ack = 0;
+	last_few_pclk_required = 0;
+	while (accum_ack < last_few_ack_required) {
+		last_few_pclk_required++;
+
+		if (remainder >= dto_n)
+			start = remainder;
+		else
+			start = remainder + dto_d;
+
+		remainder = start - dto_n;
+		if (remainder < dto_n)
+			accum_ack++;
+	}
+
+	/* if fewer pclk than required */
+	if (last_few_pclk < last_few_pclk_required)
+		dsc_info->extra_width = last_few_pclk_required - last_few_pclk;
+	else
+		dsc_info->extra_width = 0;
+}
+
+static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel,
+		struct msm_display_dsc_info *dsc_info,
+		struct dp_display_mode *dp_mode, u32 dsc_byte_cnt)
+{
+	int num_slices, tot_num_eoc_symbols;
+	int tot_num_hor_bytes, tot_num_dummy_bytes;
+	int dwidth_dsc_bytes, eoc_bytes;
+	u32 num_lanes;
+	struct dp_panel_private *panel;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	num_lanes = panel->link->link_params.num_lanes;
+	num_slices = dsc_info->slice_per_pkt;
+
+	eoc_bytes = dsc_byte_cnt % num_lanes;
+	tot_num_eoc_symbols = num_lanes * num_slices;
+	tot_num_hor_bytes = dsc_byte_cnt * num_slices;
+	tot_num_dummy_bytes = (num_lanes - eoc_bytes) * num_slices;
+
+	if (!eoc_bytes)
+		tot_num_dummy_bytes = 0;
+
+	dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols +
+				tot_num_dummy_bytes;
+
+	drm_dbg_dp(panel->drm_dev, "dwidth_dsc_bytes:%d, tot_num_hor_bytes:%d\n",
+			dwidth_dsc_bytes, tot_num_hor_bytes);
+
+	dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes,
+			tot_num_hor_bytes);
+
+	dp_mode->timing.dsc_overhead_fp = dp_mode->dsc_overhead_fp;
+}
+
+static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel,
+		struct msm_compression_info *comp_info,
+		struct dp_display_mode *dp_mode)
+{
+	int comp_ratio = 100, intf_width;
+	int slice_per_pkt, slice_per_intf;
+	s64 temp1_fp, temp2_fp;
+	s64 numerator_fp, denominator_fp;
+	s64 dsc_byte_count_fp;
+	u32 dsc_byte_count, temp1, temp2;
+	struct msm_display_dsc_info *dsc_info = &comp_info->msm_dsc_info;
+
+	intf_width = dp_mode->timing.h_active;
+	if (!dsc_info || !dsc_info->drm_dsc.slice_width || !dsc_info->slice_per_pkt ||
+			 (intf_width < dsc_info->drm_dsc.slice_width))
+		return;
+
+	slice_per_pkt = dsc_info->slice_per_pkt;
+	slice_per_intf = DIV_ROUND_UP(intf_width,
+			dsc_info->drm_dsc.slice_width);
+
+	comp_ratio = mult_frac(100, comp_info->src_bpp, comp_info->tgt_bpp);
+
+	temp1_fp = drm_fixp_from_fraction(comp_ratio, 100);
+	temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1);
+	denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp);
+	numerator_fp = drm_fixp_from_fraction(
+			intf_width * dsc_info->drm_dsc.bits_per_component * 3, 1);
+	dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp);
+	dsc_byte_count = fixp2int_ceil(dsc_byte_count_fp);
+
+	temp1 = dsc_byte_count * slice_per_intf;
+	temp2 = temp1;
+	if (temp1 % 3 != 0)
+		temp1 += 3 - (temp1 % 3);
+
+	dsc_info->eol_byte_num = temp1 - temp2;
+
+	temp1_fp = drm_fixp_from_fraction(slice_per_intf, 6);
+	temp2_fp = drm_fixp_mul(dsc_byte_count_fp, temp1_fp);
+	dsc_info->pclk_per_line = fixp2int_ceil(temp2_fp);
+
+	_dp_panel_dsc_get_num_extra_pclk(comp_info);
+	dsc_info->pclk_per_line--;
+
+	_dp_panel_dsc_bw_overhead_calc(dp_panel, dsc_info, dp_mode, dsc_byte_count);
+}
+
+void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
+		struct dp_display_mode *dp_mode)
+{
+	struct dp_panel_private *panel;
+	const u32 num_components = 3, default_bpp = 24;
+	struct drm_display_mode *drm_mode;
+	struct dp_panel_info *timing;
+	struct msm_compression_info *comp_info;
+	bool dsc_cap = (dp_mode->capabilities & DP_PANEL_CAPS_DSC) ?
+				true : false;
+	int rc;
+
+	if (!dp_panel->dsc_en)
+		return;
+
+	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+	drm_mode = &dp_mode->drm_mode;
+	timing = &dp_mode->timing;
+
+	timing->h_active = drm_mode->hdisplay;
+	timing->h_back_porch = drm_mode->htotal - drm_mode->hsync_end;
+	timing->h_sync_width = drm_mode->htotal -
+                        (drm_mode->hsync_start + dp_mode->timing.h_back_porch);
+
+	timing->h_front_porch = drm_mode->hsync_start -
+					 drm_mode->hdisplay;
+	timing->h_skew = drm_mode->hskew;
+
+	timing->v_active = drm_mode->vdisplay;
+	timing->v_back_porch = drm_mode->vtotal - drm_mode->vsync_end;
+	timing->v_sync_width = drm_mode->vtotal -
+                (drm_mode->vsync_start + dp_mode->timing.v_back_porch);
+
+	timing->v_front_porch = drm_mode->vsync_start - drm_mode->vdisplay;
+
+	timing->refresh_rate = drm_mode_vrefresh(drm_mode);
+	timing->pixel_clk_khz = drm_mode->clock;
+
+	timing->v_active_low =
+		!!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC);
+
+	timing->h_active_low =
+		!!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	timing->bpp =
+		dp_panel->connector->display_info.bpc * num_components;
+	if (!timing->bpp)
+		timing->bpp = default_bpp;
+
+	timing->widebus_en = dp_panel->widebus_en;
+	timing->dsc_overhead_fp = 0;
+
+	comp_info = &timing->comp_info;
+	comp_info->src_bpp = default_bpp;
+	comp_info->tgt_bpp = default_bpp;
+	comp_info->comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+	comp_info->comp_ratio = 1;
+	comp_info->enabled = false;
+
+	/* As YUV was not supported now, so set the default format to RGB */
+	dp_mode->output_format = DP_OUTPUT_FORMAT_RGB;
+	/*
+	 * If a given videomode can be only supported in YCBCR420, set
+	 * the output format to YUV420. While now our driver did not
+	 * support YUV display over DP, so just place this flag here.
+	 * When we want to support YUV, we can use this flag to do
+	 * a lot of settings, like CDM, CSC and pixel_clock.
+	 */
+	if (drm_mode_is_420_only(&dp_panel->connector->display_info,
+			drm_mode)) {
+		dp_mode->output_format = DP_OUTPUT_FORMAT_YCBCR420;
+		drm_dbg_dp(panel->drm_dev, "YCBCR420 was not supported");
+	}
+
+	timing->bpp = dp_panel_get_mode_bpp(dp_panel,
+			timing->bpp, timing->pixel_clk_khz);
+
+
+	if (dp_panel->dsc_en && dsc_cap) {
+		if (dp_panel_dsc_prepare_basic_params(comp_info,
+					dp_mode, dp_panel)) {
+			drm_dbg_dp(panel->drm_dev,
+					"prepare DSC basic params failed\n");
+			return;
+		}
+
+		rc = dpu_dsc_populate_dsc_config(&comp_info->msm_dsc_info.drm_dsc, 0);
+		if (rc) {
+			drm_dbg_dp(panel->drm_dev,
+					"failed populating dsc params \n");
+			return;
+		}
+
+		rc = dpu_dsc_populate_dsc_private_params(&comp_info->msm_dsc_info,
+				dp_mode->timing.h_active);
+		if (rc) {
+			drm_dbg_dp(panel->drm_dev,
+					"failed populating other dsc params\n");
+			return;
+		}
+
+		dp_panel_dsc_pclk_param_calc(dp_panel, comp_info, dp_mode);
+	}
+	dp_mode->fec_overhead_fp = dp_panel->fec_overhead_fp;
+}
+
 struct dp_panel *dp_panel_get(struct dp_panel_in *in)
 {
 	struct dp_panel_private *panel;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 4c45d51..576056c 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -112,6 +112,7 @@ struct dp_panel {
 	bool fec_feature_enable;
 	bool dsc_en;
 	bool fec_en;
+	bool widebus_en;
 	s64 fec_overhead_fp;
 };
 
@@ -128,6 +129,9 @@ int dp_panel_get_modes(struct dp_panel *dp_panel,
 void dp_panel_handle_sink_request(struct dp_panel *dp_panel);
 void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable);
 u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel);
+void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable);
+void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
+		struct dp_display_mode *dp_mode);
 
 /**
  * is_link_rate_valid() - validates the link rate
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 2686028..96d48d0c 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #ifndef _DP_REG_H_
@@ -167,7 +168,38 @@
 #define MMSS_DP_PSR_CRC_RG			(0x00000154)
 #define MMSS_DP_PSR_CRC_B			(0x00000158)
 
-#define REG_DP_COMPRESSION_MODE_CTRL		(0x00000180)
+#define DP_COMPRESSION_MODE_CTRL		(0x00000180)
+#define DP_PPS_HB_0_3				(0x00000184)
+#define DP_PPS_PB_0_3				(0x00000188)
+#define DP_PPS_PB_4_7				(0x0000018C)
+#define DP_PPS_PB_8_11				(0x00000190)
+#define DP_PPS_PB_12_15				(0x00000194)
+#define DP_PPS_PB_16_19				(0x00000198)
+#define DP_PPS_PB_20_23				(0x0000019C)
+#define DP_PPS_PB_24_27				(0x000001A0)
+#define DP_PPS_PB_28_31				(0x000001A4)
+#define DP_PPS_PPS_0_3				(0x000001A8)
+#define DP_PPS_PPS_4_7				(0x000001AC)
+#define DP_PPS_PPS_8_11				(0x000001B0)
+#define DP_PPS_PPS_12_15			(0x000001B4)
+#define DP_PPS_PPS_16_19			(0x000001B8)
+#define DP_PPS_PPS_20_23			(0x000001BC)
+#define DP_PPS_PPS_24_27			(0x000001C0)
+#define DP_PPS_PPS_28_31			(0x000001C4)
+#define DP_PPS_PPS_32_35			(0x000001C8)
+#define DP_PPS_PPS_36_39			(0x000001CC)
+#define DP_PPS_PPS_40_43			(0x000001D0)
+#define DP_PPS_PPS_44_47			(0x000001D4)
+#define DP_PPS_PPS_48_51			(0x000001D8)
+#define DP_PPS_PPS_52_55			(0x000001DC)
+#define DP_PPS_PPS_56_59			(0x000001E0)
+#define DP_PPS_PPS_60_63			(0x000001E4)
+#define DP_PPS_PPS_64_67			(0x000001E8)
+#define DP_PPS_PPS_68_71			(0x000001EC)
+#define DP_PPS_PPS_72_75			(0x000001F0)
+#define DP_PPS_PPS_76_79			(0x000001F4)
+#define DP_PPS_PPS_80_83			(0x000001F8)
+#define DP_PPS_PPS_84_87			(0x000001FC)
 
 #define MMSS_DP_AUDIO_CFG			(0x00000200)
 #define MMSS_DP_AUDIO_STATUS			(0x00000204)
@@ -178,6 +210,8 @@
 
 #define MMSS_DP_SDP_CFG				(0x00000228)
 #define MMSS_DP_SDP_CFG2			(0x0000022C)
+#define MMSS_DP_SDP_CFG3			(0x0000024C)
+#define MMSS_DP_SDP_CFG4			(0x000004EC)
 #define MMSS_DP_AUDIO_TIMESTAMP_0		(0x00000230)
 #define MMSS_DP_AUDIO_TIMESTAMP_1		(0x00000234)
 
@@ -210,6 +244,9 @@
 #define MMSS_DP_AUDIO_INFOFRAME_1		(0x000002AC)
 #define MMSS_DP_AUDIO_INFOFRAME_2		(0x000002B0)
 
+#define MMSS_DP_FLUSH				(0x000002F8)
+#define MMSS_DP1_FLUSH				(0x000002FC)
+
 #define MMSS_DP_GENERIC0_0			(0x00000300)
 #define MMSS_DP_GENERIC0_1			(0x00000304)
 #define MMSS_DP_GENERIC0_2			(0x00000308)
@@ -268,6 +305,7 @@
 
 #define MMSS_DP_TPG_MAIN_CONTROL		(0x00000060)
 #define MMSS_DP_DSC_DTO				(0x0000007C)
+#define MMSS_DP_DSC_DTO_COUNT			(0x00000084)
 #define DP_TPG_CHECKERED_RECT_PATTERN		(0x00000100)
 
 #define MMSS_DP_TPG_VIDEO_CONFIG		(0x00000064)
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index cf4eb8d..6a46ed7 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -476,6 +476,11 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_displa
 
 void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor);
 bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);
+struct msm_compression_info *msm_dp_bridge_get_compression(struct drm_bridge *drm_bridge);
+
+void msm_dp_bridge_mode_set(struct drm_bridge *bridge,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
 
 #else
 static inline int __init msm_dp_register(void)
@@ -510,6 +515,17 @@ static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
 	return false;
 }
 
+static inline struct msm_compression_info *msm_dp_bridge_get_compression(
+				struct drm_bridge *drm_bridge)
+{
+	return NULL;
+}
+static inline void msm_dp_bridge_mode_set(struct drm_bridge *bridge,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+
+}
 #endif
 
 #ifdef CONFIG_DRM_MSM_MDP4
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (7 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 22:06   ` Dmitry Baryshkov
                     ` (2 more replies)
  2023-01-23 18:24 ` [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Kuogee Hsieh
                   ` (7 subsequent siblings)
  16 siblings, 3 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

struct msm_compression_info is used to support several different
compression mechanisms. It also contains customized info required
to configure DSC encoder engine. This patch also make changes DSI
module to have DSI exports struct msm_compreion_info to dpu encoder
instead of struct drm_dsc_config.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  7 +++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 ++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 10 ++++++++--
 drivers/gpu/drm/msm/dsi/dsi.c               |  3 ++-
 drivers/gpu/drm/msm/dsi/dsi.h               |  3 ++-
 drivers/gpu/drm/msm/dsi/dsi_host.c          | 14 ++++++++++++--
 drivers/gpu/drm/msm/msm_drv.h               |  4 ++--
 7 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 758261e..7f4a439 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2013 Red Hat
  * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Author: Rob Clark <robdclark@gmail.com>
  */
@@ -210,6 +210,7 @@ struct dpu_encoder_virt {
 
 	/* DSC configuration */
 	struct drm_dsc_config *dsc;
+	struct msm_compression_info *comp_info;
 };
 
 #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base)
@@ -2275,7 +2276,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
 		dpu_enc->idle_pc_supported =
 				dpu_kms->catalog->caps->has_idle_pc;
 
-	dpu_enc->dsc = disp_info->dsc;
+	dpu_enc->comp_info = disp_info->comp_info;
+	if (dpu_enc->comp_info)
+		dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc;
 
 	mutex_lock(&dpu_enc->enc_lock);
 	for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) {
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 9e7236e..bd2da5e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
@@ -36,7 +36,7 @@ struct msm_display_info {
 	uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
 	bool is_cmd_mode;
 	bool is_te_using_watchdog_timer;
-	struct drm_dsc_config *dsc;
+	struct msm_compression_info *comp_info;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index d612419..70a74ed 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -2,7 +2,7 @@
 /*
  * Copyright (C) 2013 Red Hat
  * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Author: Rob Clark <robdclark@gmail.com>
  */
@@ -570,7 +570,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
 		info.h_tile_instance[info.num_of_h_tiles++] = i;
 		info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);
 
-		info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]);
+		info.comp_info = msm_dsi_get_dsc_config(priv->dsi[i]);
 
 		if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) {
 			rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder);
@@ -622,6 +622,8 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
 		info.num_of_h_tiles = 1;
 		info.h_tile_instance[0] = i;
 		info.intf_type = encoder->encoder_type;
+		info.is_cmd_mode = 0; /* dp always video mode */
+		info.comp_info = NULL;
 		rc = dpu_encoder_setup(dev, encoder, &info);
 		if (rc) {
 			DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
@@ -892,6 +894,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
 
 	pm_runtime_get_sync(&dpu_kms->pdev->dev);
 
+	for (i = 0; i < cat->dsc_count; i++)
+		msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len,
+				dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i);
+
 	/* dump CTL sub-blocks HW regs info */
 	for (i = 0; i < cat->ctl_count; i++)
 		msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len,
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 31fdee2..52b7e33 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #include "dsi.h"
@@ -13,7 +14,7 @@ bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
 	return !(host_flags & MIPI_DSI_MODE_VIDEO);
 }
 
-struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
+struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
 {
 	return msm_dsi_host_get_dsc_config(msm_dsi->host);
 }
diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
index bd3763a..79ada54 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #ifndef __DSI_CONNECTOR_H__
@@ -133,7 +134,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
 int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
 void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host);
 void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host);
-struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
+struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
 
 /* dsi phy */
 struct msm_dsi_phy;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 18fa30e..6188f4b 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #include <linux/clk.h>
@@ -163,6 +164,7 @@ struct msm_dsi_host {
 
 	struct drm_display_mode *mode;
 	struct drm_dsc_config *dsc;
+	struct msm_compression_info comp_info;
 
 	/* connected device info */
 	unsigned int channel;
@@ -2600,9 +2602,17 @@ void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host)
 				DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER);
 }
 
-struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
+struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
 {
 	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
+	struct msm_compression_info *comp_info = NULL;
 
-	return msm_host->dsc;
+	if (msm_host->dsc) {
+		comp_info = &msm_host->comp_info;
+		comp_info->msm_dsc_info.drm_dsc = *msm_host->dsc;
+		comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC;
+		comp_info->enabled = true;
+	}
+
+	return comp_info;
 }
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 6a46ed7..eab0901 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -430,7 +430,7 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi
 bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi);
 bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi);
 bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi);
-struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
+struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
 #else
 static inline void __init msm_dsi_register(void)
 {
@@ -460,7 +460,7 @@ static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)
 	return false;
 }
 
-static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
+static inline struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
 {
 	return NULL;
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (8 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 20:11   ` Marijn Suijten
                     ` (2 more replies)
  2023-01-23 18:24 ` [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism Kuogee Hsieh
                   ` (6 subsequent siblings)
  16 siblings, 3 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

DSC V1.2 encoder engine is newly added hardware module. This patch
add support functions to configure and enable DSC V1.2 encoder engine.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/Makefile                   |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  60 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c     |  23 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h     |  23 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 371 +++++++++++++++++++++++++
 6 files changed, 463 insertions(+), 17 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 28cf52b..271c29a15 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
 	disp/dpu1/dpu_hw_catalog.o \
 	disp/dpu1/dpu_hw_ctl.o \
 	disp/dpu1/dpu_hw_dsc.o \
+	disp/dpu1/dpu_hw_dsc_1_2.o \
 	disp/dpu1/dpu_dsc_helper.o \
 	disp/dpu1/dpu_hw_interrupts.o \
 	disp/dpu1/dpu_hw_intf.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 7f4a439..901e317 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1821,7 +1821,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
 				     u32 initial_lines)
 {
 	if (hw_dsc->ops.dsc_config)
-		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines);
+		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);
 
 	if (hw_dsc->ops.dsc_config_thresh)
 		hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 978e3bd..7b0b092 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
  */
 
@@ -11,6 +11,7 @@
 #include <linux/bug.h>
 #include <linux/bitmap.h>
 #include <linux/err.h>
+#include "dpu_hw_mdss.h"
 
 /**
  * Max hardware block count: For ex: max 12 SSPP pipes or
@@ -182,6 +183,7 @@ enum {
  * @DPU_PINGPONG_TE2        Additional tear check block for split pipes
  * @DPU_PINGPONG_SPLIT      PP block supports split fifo
  * @DPU_PINGPONG_SLAVE      PP block is a suitable slave for split fifo
+ * @DPU_PINGPONG_DSC,       Display stream compression blocks
  * @DPU_PINGPONG_DITHER,    Dither blocks
  * @DPU_PINGPONG_MAX
  */
@@ -190,10 +192,32 @@ enum {
 	DPU_PINGPONG_TE2,
 	DPU_PINGPONG_SPLIT,
 	DPU_PINGPONG_SLAVE,
+	DPU_PINGPONG_DSC,
 	DPU_PINGPONG_DITHER,
 	DPU_PINGPONG_MAX
 };
 
+
+/** DSC sub-blocks/features
+ * @DPU_DSC_OUTPUT_CTRL         Supports the control of the pp id which gets
+ *                              the pixel output from this DSC.
+ * @DPU_DSC_HW_REV_1_1          dsc block supports dsc 1.1 only
+ * @DPU_DSC_HW_REV_1_2          dsc block supports dsc 1.1 and 1.2
+ * @DPU_DSC_NATIVE_422_EN,      Supports native422 and native420 encoding
+ * @DPU_DSC_ENC,                DSC encoder sub block
+ * @DPU_DSC_CTL,                DSC ctl sub block
+ * @DPU_DSC_MAX
+ */
+enum {
+	DPU_DSC_OUTPUT_CTRL = 0x1,
+	DPU_DSC_HW_REV_1_1,
+	DPU_DSC_HW_REV_1_2,
+	DPU_DSC_NATIVE_422_EN,
+	DPU_DSC_ENC,
+	DPU_DSC_CTL,
+	DPU_DSC_MAX
+};
+
 /**
  * CTL sub-blocks
  * @DPU_CTL_SPLIT_DISPLAY:	CTL supports video mode split display
@@ -276,15 +300,6 @@ enum {
 };
 
 /**
- * DSC features
- * @DPU_DSC_OUTPUT_CTRL       Configure which PINGPONG block gets
- *                            the pixel output from this DSC.
- */
-enum {
-	DPU_DSC_OUTPUT_CTRL = 0x1,
-};
-
-/**
  * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
  * @name:              string name for debug purposes
  * @id:                enum identifying this block
@@ -346,6 +361,14 @@ struct dpu_pp_blk {
 };
 
 /**
+ * struct dpu_dsc_blk : DSC Encoder sub-blk information
+ * @info:   HW register and features supported by this sub-blk
+ */
+struct dpu_dsc_blk {
+	DPU_HW_SUBBLK_INFO;
+};
+
+/**
  * enum dpu_qos_lut_usage - define QoS LUT use cases
  */
 enum dpu_qos_lut_usage {
@@ -403,6 +426,7 @@ struct dpu_rotation_cfg {
  * @pixel_ram_size     size of latency hiding and de-tiling buffer in bytes
  * @max_hdeci_exp      max horizontal decimation supported (max is 2^value)
  * @max_vdeci_exp      max vertical decimation supported (max is 2^value)
+ * @max_dsc_width      max dsc line width support.
  */
 struct dpu_caps {
 	u32 max_mixer_width;
@@ -419,6 +443,7 @@ struct dpu_caps {
 	u32 pixel_ram_size;
 	u32 max_hdeci_exp;
 	u32 max_vdeci_exp;
+	u32 max_dsc_width;
 };
 
 /**
@@ -494,9 +519,20 @@ struct dpu_dspp_sub_blks {
 struct dpu_pingpong_sub_blks {
 	struct dpu_pp_blk te;
 	struct dpu_pp_blk te2;
+	struct dpu_pp_blk dsc;
 	struct dpu_pp_blk dither;
 };
 
+
+/**
+ * struct dpu_dsc_sub_blks : DSC sub-blks
+ *
+ */
+struct dpu_dsc_sub_blks {
+	struct dpu_dsc_blk enc;
+	struct dpu_dsc_blk ctl;
+};
+
 /**
  * dpu_clk_ctrl_type - Defines top level clock control signals
  */
@@ -641,10 +677,14 @@ struct dpu_merge_3d_cfg  {
  * struct dpu_dsc_cfg - information of DSC blocks
  * @id                 enum identifying this block
  * @base               register offset of this block
+ * @len:               length of hardware block
  * @features           bit mask identifying sub-blocks/features
+ * @dsc_pair_mask:     Bitmask of DSCs that can be controlled by same CTL
  */
 struct dpu_dsc_cfg {
 	DPU_HW_BLK_INFO;
+	DECLARE_BITMAP(dsc_pair_mask, DSC_MAX);
+	const struct dpu_dsc_sub_blks *sblk;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
index 619926d..51e8890 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2020-2022, Linaro Limited
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
  */
 
 #include "dpu_kms.h"
@@ -41,10 +42,11 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
 static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
 			      struct drm_dsc_config *dsc,
 			      u32 mode,
-			      u32 initial_lines)
+			      u32 initial_lines,
+			      bool ich_reset_override)
 {
 	struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
-	u32 data;
+	u32 data, lsb, bpp;
 	u32 slice_last_group_size;
 	u32 det_thresh_flatness;
 	bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
@@ -58,7 +60,14 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
 	data = (initial_lines << 20);
 	data |= ((slice_last_group_size - 1) << 18);
 	/* bpp is 6.4 format, 4 LSBs bits are for fractional part */
-	data |= (dsc->bits_per_pixel << 8);
+	data |= dsc->bits_per_pixel << 12;
+	lsb = dsc->bits_per_pixel % 4;
+	bpp = dsc->bits_per_pixel / 4;
+	bpp *= 4;
+	bpp <<= 4;
+	bpp |= lsb;
+
+	data |= bpp << 8;
 	data |= (dsc->block_pred_enable << 7);
 	data |= (dsc->line_buf_depth << 3);
 	data |= (dsc->simple_422 << 2);
@@ -221,7 +230,13 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
 
 	c->idx = idx;
 	c->caps = cfg;
-	_setup_dsc_ops(&c->ops, c->caps->features);
+
+	if (test_bit(DPU_DSC_HW_REV_1_1, &c->caps->features))
+		_setup_dsc_ops(&c->ops, c->caps->features);
+	else if (test_bit(DPU_DSC_HW_REV_1_2, &c->caps->features))
+		dpu_dsc_1_2_setup_ops(&c->ops, c->caps->features);
+	else
+		_setup_dsc_ops(&c->ops, c->caps->features);
 
 	return c;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
index ae9b5db..a48f572 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2020-2022, Linaro Limited */
+/*
+ * Copyright (c) 2020-2022, Linaro Limited
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
+ */
 
 #ifndef _DPU_HW_DSC_H
 #define _DPU_HW_DSC_H
@@ -33,7 +36,8 @@ struct dpu_hw_dsc_ops {
 	void (*dsc_config)(struct dpu_hw_dsc *hw_dsc,
 			   struct drm_dsc_config *dsc,
 			   u32 mode,
-			   u32 initial_lines);
+			   u32 initial_lines,
+			   bool ich_reset_override);
 
 	/**
 	 * dsc_config_thresh - programs panel thresholds
@@ -43,6 +47,12 @@ struct dpu_hw_dsc_ops {
 	void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
 				  struct drm_dsc_config *dsc);
 
+	/**
+	 * bind_pingpong_blk - enable/disable the connection with pp
+	 * @hw_dsc: Pointer to dsc context
+	 * @enable: enable/disable connection
+	 * @pp: pingpong blk id
+	 */
 	void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc,
 				  bool enable,
 				  enum dpu_pingpong pp);
@@ -51,6 +61,7 @@ struct dpu_hw_dsc_ops {
 struct dpu_hw_dsc {
 	struct dpu_hw_blk base;
 	struct dpu_hw_blk_reg_map hw;
+	struct dpu_hw_ctl *hw_ctl;
 
 	/* dsc */
 	enum dpu_dsc idx;
@@ -76,9 +87,17 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
  */
 void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc);
 
+/**
+ * dpu_hw_dsc - convert base object dpu_hw_base to container
+ * @hw: Pointer to base hardware block
+ * return: Pointer to hardware block container
+ */
 static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw)
 {
 	return container_of(hw, struct dpu_hw_dsc, base);
 }
 
+void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
+		const unsigned long features);
+
 #endif /* _DPU_HW_DSC_H */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
new file mode 100644
index 00000000..2be74ae
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
+ */
+
+#include "dpu_kms.h"
+#include "dpu_hw_catalog.h"
+#include "dpu_hwio.h"
+#include "dpu_hw_mdss.h"
+#include "dpu_hw_dsc.h"
+
+
+#define DSC_CMN_MAIN_CNF           0x00
+
+/* DPU_DSC_ENC register offsets */
+#define ENC_DF_CTRL                0x00
+#define ENC_GENERAL_STATUS         0x04
+#define ENC_HSLICE_STATUS          0x08
+#define ENC_OUT_STATUS             0x0C
+#define ENC_INT_STAT               0x10
+#define ENC_INT_CLR                0x14
+#define ENC_INT_MASK               0x18
+#define DSC_MAIN_CONF              0x30
+#define DSC_PICTURE_SIZE           0x34
+#define DSC_SLICE_SIZE             0x38
+#define DSC_MISC_SIZE              0x3C
+#define DSC_HRD_DELAYS             0x40
+#define DSC_RC_SCALE               0x44
+#define DSC_RC_SCALE_INC_DEC       0x48
+#define DSC_RC_OFFSETS_1           0x4C
+#define DSC_RC_OFFSETS_2           0x50
+#define DSC_RC_OFFSETS_3           0x54
+#define DSC_RC_OFFSETS_4           0x58
+#define DSC_FLATNESS_QP            0x5C
+#define DSC_RC_MODEL_SIZE          0x60
+#define DSC_RC_CONFIG              0x64
+#define DSC_RC_BUF_THRESH_0        0x68
+#define DSC_RC_BUF_THRESH_1        0x6C
+#define DSC_RC_BUF_THRESH_2        0x70
+#define DSC_RC_BUF_THRESH_3        0x74
+#define DSC_RC_MIN_QP_0            0x78
+#define DSC_RC_MIN_QP_1            0x7C
+#define DSC_RC_MIN_QP_2            0x80
+#define DSC_RC_MAX_QP_0            0x84
+#define DSC_RC_MAX_QP_1            0x88
+#define DSC_RC_MAX_QP_2             0x8C
+#define DSC_RC_RANGE_BPG_OFFSETS_0  0x90
+#define DSC_RC_RANGE_BPG_OFFSETS_1  0x94
+#define DSC_RC_RANGE_BPG_OFFSETS_2  0x98
+
+/* DPU_DSC_CTL register offsets */
+#define DSC_CTL                    0x00
+#define DSC_CFG                    0x04
+#define DSC_DATA_IN_SWAP           0x08
+#define DSC_CLK_CTRL               0x0C
+
+
+static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss)
+{
+	enum dpu_dsc idx;
+
+	idx = hw_dsc->idx;
+
+	if (!(hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))) {
+		if (num_ss == 1)
+			return 2399;
+		else if (num_ss == 2)
+			return 1199;
+	} else {
+		if (num_ss == 1)
+			return 1199;
+		else if (num_ss == 2)
+			return 599;
+	}
+	return 0;
+}
+
+static inline int _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id,
+		u32 *idx)
+{
+	const struct dpu_dsc_sub_blks *sblk;
+
+	if (!hw_dsc)
+		return -EINVAL;
+
+	*idx = 0;
+
+	sblk = hw_dsc->caps->sblk;
+
+	switch (s_id) {
+
+	case DPU_DSC_ENC:
+		*idx = sblk->enc.base;
+		break;
+	case DPU_DSC_CTL:
+		*idx = sblk->ctl.base;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc)
+{
+	struct dpu_hw_blk_reg_map *hw;
+	u32 idx;
+
+	if (!hw_dsc)
+		return;
+
+	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
+		return;
+
+	hw = &hw_dsc->hw;
+	DPU_REG_WRITE(hw, DSC_CFG + idx, 0);
+
+	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
+		return;
+
+	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, 0);
+	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, 0);
+}
+
+static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc,
+		struct drm_dsc_config *dsc, u32 mode,
+		u32 initial_lines, bool ich_reset_override)
+{
+	struct dpu_hw_blk_reg_map *hw;
+	struct msm_display_dsc_info *dsc_info;
+	u32 idx;
+	u32 data = 0;
+	u32 bpp;
+	void __iomem *off;
+
+	if (!hw_dsc || !dsc)
+		return;
+
+	hw = &hw_dsc->hw;
+
+	dsc_info = to_msm_dsc_info(dsc);
+
+	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
+		return;
+
+	if (mode & DSC_MODE_SPLIT_PANEL)
+		data |= BIT(0);
+
+	if (mode & DSC_MODE_MULTIPLEX)
+		data |= BIT(1);
+
+	data |= (dsc_info->num_active_ss_per_enc & 0x3) << 7;
+
+	DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data);
+
+	data = (dsc_info->initial_lines & 0xff);
+	data |= ((mode & DSC_MODE_VIDEO) ? 1 : 0) << 9;
+	if (ich_reset_override)
+		data |= 0xC00; // set bit 10 and 11
+	data |= (_dsc_calc_ob_max_addr(hw_dsc, dsc_info->num_active_ss_per_enc) << 18);
+
+	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, data);
+
+	data = (dsc->dsc_version_minor & 0xf) << 28;
+	if (dsc->dsc_version_minor == 0x2) {
+		if (dsc->native_422)
+			data |= BIT(22);
+		if (dsc->native_420)
+			data |= BIT(21);
+	}
+
+	bpp = dsc->bits_per_pixel;
+	/* as per hw requirement bpp should be programmed
+	 * twice the actual value in case of 420 or 422 encoding
+	 */
+	if (dsc->native_422 || dsc->native_420)
+		bpp = 2 * bpp;
+	data |= (dsc->block_pred_enable ? 1 : 0) << 20;
+	data |= (bpp << 10);
+	data |= (dsc->line_buf_depth & 0xf) << 6;
+	data |= dsc->convert_rgb << 4;
+	data |= dsc->bits_per_component & 0xf;
+
+	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, data);
+
+	data = (dsc->pic_width & 0xffff) |
+		((dsc->pic_height & 0xffff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_PICTURE_SIZE + idx, data);
+
+	data = (dsc->slice_width & 0xffff) |
+		((dsc->slice_height & 0xffff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_SLICE_SIZE + idx, data);
+
+	DPU_REG_WRITE(hw, DSC_MISC_SIZE + idx,
+			(dsc->slice_chunk_size) & 0xffff);
+
+	data = (dsc->initial_xmit_delay & 0xffff) |
+		((dsc->initial_dec_delay & 0xffff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_HRD_DELAYS + idx, data);
+
+	DPU_REG_WRITE(hw, DSC_RC_SCALE + idx,
+			dsc->initial_scale_value & 0x3f);
+
+	data = (dsc->scale_increment_interval & 0xffff) |
+		((dsc->scale_decrement_interval & 0x7ff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_RC_SCALE_INC_DEC + idx, data);
+
+	data = (dsc->first_line_bpg_offset & 0x1f) |
+		((dsc->second_line_bpg_offset & 0x1f) << 5);
+
+	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_1 + idx, data);
+
+	data = (dsc->nfl_bpg_offset & 0xffff) |
+		((dsc->slice_bpg_offset & 0xffff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_2 + idx, data);
+
+	data = (dsc->initial_offset & 0xffff) |
+		((dsc->final_offset & 0xffff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_3 + idx, data);
+
+	data = (dsc->nsl_bpg_offset & 0xffff) |
+		((dsc->second_line_offset_adj & 0xffff) << 16);
+
+	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_4 + idx, data);
+
+	data = (dsc->flatness_min_qp & 0x1f);
+	data |= (dsc->flatness_max_qp & 0x1f) << 5;
+	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
+
+	DPU_REG_WRITE(hw, DSC_FLATNESS_QP + idx, data);
+
+	DPU_REG_WRITE(hw, DSC_RC_MODEL_SIZE + idx,
+			(dsc->rc_model_size) & 0xffff);
+
+	data = dsc->rc_edge_factor & 0xf;
+	data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8;
+	data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13;
+	data |= (dsc->rc_tgt_offset_high & 0xf) << 20;
+	data |= (dsc->rc_tgt_offset_low & 0xf) << 24;
+
+	DPU_REG_WRITE(hw, DSC_RC_CONFIG + idx, data);
+
+	/* program the dsc wrapper */
+	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
+		return;
+
+	off = hw->blk_addr + idx;
+
+	data = BIT(0); /* encoder enable */
+	if (dsc->native_422)
+		data |= BIT(8);
+	else if (dsc->native_420)
+		data |= BIT(9);
+	if (!dsc->convert_rgb)
+		data |= BIT(10);
+	if (dsc->bits_per_component == 8)
+		data |= BIT(11);
+	if (mode & DSC_MODE_SPLIT_PANEL)
+		data |= BIT(12);
+	if (mode & DSC_MODE_MULTIPLEX)
+		data |= BIT(13);
+	if (!(mode & DSC_MODE_VIDEO))
+		data |= BIT(17);
+
+	if (dsc_info->dsc_4hsmerge_en) {
+		data |= dsc_info->dsc_4hsmerge_padding << 18;
+		data |= dsc_info->dsc_4hsmerge_alignment << 22;
+		data |= BIT(16);
+	}
+
+	DPU_REG_WRITE(hw, DSC_CFG + idx, data);
+
+//	DPU_REG_WRITE(hw, DSC_DATA_IN_SWAP + idx, 0x14e5);
+}
+
+static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc,
+		struct drm_dsc_config *dsc)
+{
+	struct dpu_hw_blk_reg_map *hw;
+	struct msm_display_dsc_info *dsc_info;
+	u32 idx, off;
+	int i, j = 0;
+	struct drm_dsc_rc_range_parameters *rc;
+	u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0;
+
+	if (!hw_dsc || !dsc)
+		return;
+
+	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
+		return;
+
+	hw = &hw_dsc->hw;
+
+	dsc_info = to_msm_dsc_info(dsc);
+
+	rc = dsc->rc_range_params;
+
+	off = 0;
+	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
+		data |= dsc->rc_buf_thresh[i] << (8*j);
+		j++;
+		if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) {
+			DPU_REG_WRITE(hw, DSC_RC_BUF_THRESH_0 + idx + off,
+					data);
+			off += 4;
+			j = 0;
+			data = 0;
+		}
+	}
+
+	off = 0;
+	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
+		min_qp |= (rc[i].range_min_qp & 0x1f) << 5*j;
+		max_qp |= (rc[i].range_max_qp & 0x1f) << 5*j;
+		bpg_off |= (rc[i].range_bpg_offset & 0x3f) << 6*j;
+		j++;
+		if (j == 5) {
+			DPU_REG_WRITE(hw, DSC_RC_MIN_QP_0 + idx + off,
+					min_qp);
+			DPU_REG_WRITE(hw, DSC_RC_MAX_QP_0 + idx + off,
+					max_qp);
+			DPU_REG_WRITE(hw,
+					DSC_RC_RANGE_BPG_OFFSETS_0 + idx + off,
+					bpg_off);
+			off += 4;
+			j = 0;
+			min_qp = 0;
+			max_qp = 0;
+			bpg_off = 0;
+		}
+	}
+}
+
+static void dpu_hw_dsc_bind_pingpong_blk_1_2(
+		struct dpu_hw_dsc *hw_dsc,
+		bool enable,
+		const enum dpu_pingpong pp)
+{
+	struct dpu_hw_blk_reg_map *hw;
+	int idx;
+	int mux_cfg = 0xF; /* Disabled */
+
+	if (!hw_dsc)
+		return;
+
+	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
+		return;
+
+	hw = &hw_dsc->hw;
+	if (enable)
+		mux_cfg = (pp - PINGPONG_0) & 0x7;
+
+	DPU_REG_WRITE(hw, DSC_CTL + idx, mux_cfg);
+}
+
+void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
+		const unsigned long features)
+{
+	ops->dsc_disable = dpu_hw_dsc_disable_1_2;
+	ops->dsc_config = dpu_hw_dsc_config_1_2;
+	ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2;
+	ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2;
+}
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (9 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 21:43   ` Dmitry Baryshkov
  2023-01-23 18:24 ` [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC Kuogee Hsieh
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

A new flushing mechanism is introduced to decouple peripheral metadata
flushing from timing engine related flush. This patch add peripheral
flushing functions.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 24 ++++++++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  2 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  7 ++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         | 43 ++++++++++++++++++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         | 21 +++++++++++
 5 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 901e317..d2625b3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1472,6 +1472,12 @@ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
 	if (extra_flush_bits && ctl->ops.update_pending_flush)
 		ctl->ops.update_pending_flush(ctl, extra_flush_bits);
 
+	if (phys->hw_intf->cap->type == INTF_DP &&
+		phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
+						phys->comp_ratio) {
+		ctl->ops.update_pending_flush_periph(ctl, phys->hw_intf->idx);
+	}
+
 	ctl->ops.trigger_flush(ctl);
 
 	if (ctl->ops.get_pending_flush)
@@ -1814,12 +1820,18 @@ dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc,
 	return DIV_ROUND_UP(total_pixels, dsc->slice_width);
 }
 
-static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
+static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
+				     struct dpu_hw_dsc *hw_dsc,
 				     struct dpu_hw_pingpong *hw_pp,
 				     struct drm_dsc_config *dsc,
 				     u32 common_mode,
 				     u32 initial_lines)
 {
+	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
+	struct dpu_hw_ctl *ctl;
+
+	ctl = cur_master->hw_ctl;
+
 	if (hw_dsc->ops.dsc_config)
 		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);
 
@@ -1834,6 +1846,10 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
 
 	if (hw_pp->ops.enable_dsc)
 		hw_pp->ops.enable_dsc(hw_pp);
+
+	if (ctl->ops.update_pending_flush_dsc)
+		ctl->ops.update_pending_flush_dsc(ctl, hw_dsc->idx);
+
 }
 
 static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
@@ -1877,8 +1893,10 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
 	enc_ip_w = intf_ip_w / 2;
 	initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
 
-	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
-		dpu_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], dsc, dsc_common_mode, initial_lines);
+	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc,
+					dsc_common_mode, initial_lines);
+	}
 }
 
 void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 1d434b2..0569b36 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -200,6 +200,8 @@ struct dpu_encoder_phys {
 	atomic_t pending_kickoff_cnt;
 	wait_queue_head_t pending_kickoff_wq;
 	int irq[INTR_IDX_MAX];
+	enum msm_display_compression_type comp_type;
+	u32 comp_ratio;
 };
 
 static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 48c4810..2d864f9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -427,6 +428,12 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
 	if (ctl->ops.update_pending_flush_merge_3d && phys_enc->hw_pp->merge_3d)
 		ctl->ops.update_pending_flush_merge_3d(ctl, phys_enc->hw_pp->merge_3d->idx);
 
+	if (phys_enc->hw_intf->cap->type == INTF_DP &&
+		phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
+					phys_enc->comp_ratio) {
+		ctl->ops.update_pending_flush_periph(ctl, phys_enc->hw_intf->idx);
+	}
+
 skip_flush:
 	DPU_DEBUG_VIDENC(phys_enc,
 		"update pending flush ctl %d intf %d\n",
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index b88a2f3..1891c57 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -33,6 +33,7 @@
 #define   CTL_DSC_FLUSH                0x104
 #define   CTL_WB_FLUSH                  0x108
 #define   CTL_INTF_FLUSH                0x110
+#define   CTL_PERIPH_FLUSH              0x128
 #define   CTL_INTF_MASTER               0x134
 #define   CTL_FETCH_PIPE_ACTIVE         0x0FC
 
@@ -42,11 +43,13 @@
 #define DPU_REG_RESET_TIMEOUT_US        2000
 #define  MERGE_3D_IDX   23
 #define  DSC_IDX        22
+#define  PERIPH_IDX     30
 #define  INTF_IDX       31
 #define WB_IDX          16
 #define CTL_INVALID_BIT                 0xffff
 #define CTL_DEFAULT_GROUP_ID		0xf
 
+
 static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19,
 	CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0,
 	1, 2, 3, CTL_INVALID_BIT, CTL_INVALID_BIT};
@@ -123,6 +126,7 @@ static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx,
 	trace_dpu_hw_ctl_update_pending_flush(flushbits,
 					      ctx->pending_flush_mask);
 	ctx->pending_flush_mask |= flushbits;
+
 }
 
 static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
@@ -142,6 +146,15 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
 		DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
 				ctx->pending_wb_flush_mask);
 
+	if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+		DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH,
+				ctx->pending_periph_flush_mask);
+
+	if (ctx->pending_flush_mask & BIT(DSC_IDX)) {
+		DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH,
+				ctx->pending_dsc_flush_mask);
+	}
+
 	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 }
 
@@ -281,6 +294,13 @@ static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
 	ctx->pending_flush_mask |= BIT(INTF_IDX);
 }
 
+static void dpu_hw_ctl_update_pending_flush_periph(struct dpu_hw_ctl *ctx,
+		enum dpu_intf intf)
+{
+	ctx->pending_periph_flush_mask |= BIT(intf - INTF_0);
+	ctx->pending_flush_mask |= BIT(PERIPH_IDX);
+}
+
 static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
 		enum dpu_merge_3d merge_3d)
 {
@@ -288,6 +308,13 @@ static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
 	ctx->pending_flush_mask |= BIT(MERGE_3D_IDX);
 }
 
+static void dpu_hw_ctl_update_pending_flush_dsc_v1(struct dpu_hw_ctl *ctx,
+		enum dpu_dsc dsc_num)
+{
+	ctx->pending_dsc_flush_mask |= BIT(dsc_num - DSC_0);
+	ctx->pending_flush_mask |= BIT(DSC_IDX);
+}
+
 static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx,
 	enum dpu_dspp dspp)
 {
@@ -472,6 +499,7 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 	u32 intf_active = 0;
 	u32 wb_active = 0;
 	u32 mode_sel = 0;
+	u32 dsc_active = 0;
 
 	/* CTL_TOP[31:28] carries group_id to collate CTL paths
 	 * per VM. Explicitly disable it until VM support is
@@ -502,9 +530,11 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 	if (cfg->merge_3d)
 		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
 			      BIT(cfg->merge_3d - MERGE_3D_0));
-	if (cfg->dsc) {
-		DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, DSC_IDX);
-		DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc);
+
+	if (cfg->dsc_num) {
+		dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE);
+		dsc_active |= BIT(cfg->dsc_num - DSC_0);
+		DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active);
 	}
 }
 
@@ -605,9 +635,16 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
 		ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
 		ops->update_pending_flush_intf =
 			dpu_hw_ctl_update_pending_flush_intf_v1;
+
+		ops->update_pending_flush_periph =
+			dpu_hw_ctl_update_pending_flush_periph;
+
 		ops->update_pending_flush_merge_3d =
 			dpu_hw_ctl_update_pending_flush_merge_3d_v1;
 		ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
+
+		ops->update_pending_flush_dsc =
+			dpu_hw_ctl_update_pending_flush_dsc_v1;
 	} else {
 		ops->trigger_flush = dpu_hw_ctl_trigger_flush;
 		ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
index 96c012e..d3faa0b1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -48,6 +48,7 @@ struct dpu_hw_intf_cfg {
 	enum dpu_3d_blend_mode mode_3d;
 	enum dpu_merge_3d merge_3d;
 	enum dpu_ctl_mode_sel intf_mode_sel;
+	enum dpu_dsc dsc_num;
 	int stream_sel;
 	unsigned int dsc;
 };
@@ -121,6 +122,15 @@ struct dpu_hw_ctl_ops {
 		enum dpu_intf blk);
 
 	/**
+	 * OR in the given flushbits to the cached pending_(periph_)flush_mask
+	 * No effect on hardware
+	 * @ctx       : ctl path ctx pointer
+	 * @blk       : interface block index
+	 */
+	void (*update_pending_flush_periph)(struct dpu_hw_ctl *ctx,
+		enum dpu_intf blk);
+
+	/**
 	 * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask
 	 * No effect on hardware
 	 * @ctx       : ctl path ctx pointer
@@ -156,6 +166,15 @@ struct dpu_hw_ctl_ops {
 	void (*update_pending_flush_dspp)(struct dpu_hw_ctl *ctx,
 		enum dpu_dspp blk);
 	/**
+	 * OR in the given flushbits to the cached pending_(dsc_)flush_mask
+	 * No effect on hardware
+	 * @ctx       : ctl path ctx pointer
+	 * @blk       : interface block index
+	 */
+	void (*update_pending_flush_dsc)(struct dpu_hw_ctl *ctx,
+		enum dpu_dsc blk);
+
+	/**
 	 * Write the value of the pending_flush_mask to hardware
 	 * @ctx       : ctl path ctx pointer
 	 */
@@ -241,7 +260,9 @@ struct dpu_hw_ctl {
 	u32 pending_flush_mask;
 	u32 pending_intf_flush_mask;
 	u32 pending_wb_flush_mask;
+	u32 pending_periph_flush_mask;
 	u32 pending_merge_3d_flush_mask;
+	u32 pending_dsc_flush_mask;
 
 	/* ops */
 	struct dpu_hw_ctl_ops ops;
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (10 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 21:39   ` Dmitry Baryshkov
  2023-01-24  9:11   ` Dmitry Baryshkov
  2023-01-23 18:24 ` [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder Kuogee Hsieh
                   ` (4 subsequent siblings)
  16 siblings, 2 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

Current implementation timing engine programming does not consider
compression factors. This patch add consideration of DSC factors
while programming timing engine.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  14 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 +++++++++++++--------
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
 5 files changed, 110 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 2d864f9..3330e185 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -279,6 +279,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
 	if (phys_enc->hw_pp->merge_3d)
 		intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
 
+	phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev;
+
 	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
 	phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
 			&timing_params, fmt);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 7b0b092..c6ee789 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -43,16 +43,22 @@
 #define DPU_HW_VER_500	DPU_HW_VER(5, 0, 0) /* sm8150 v1.0 */
 #define DPU_HW_VER_501	DPU_HW_VER(5, 0, 1) /* sm8150 v2.0 */
 #define DPU_HW_VER_510	DPU_HW_VER(5, 1, 1) /* sc8180 */
-#define DPU_HW_VER_600	DPU_HW_VER(6, 0, 0) /* sm8250 */
+#define DPU_HW_VER_600	DPU_HW_VER(6, 0, 0) /* sm8250, kona */
 #define DPU_HW_VER_620	DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */
 #define DPU_HW_VER_630	DPU_HW_VER(6, 3, 0) /* sm6115|sm4250 */
 #define DPU_HW_VER_650	DPU_HW_VER(6, 5, 0) /* qcm2290|sm4125 */
-#define DPU_HW_VER_700	DPU_HW_VER(7, 0, 0) /* sm8350 */
+#define DPU_HW_VER_700	DPU_HW_VER(7, 0, 0) /* sm8350, lahaina */
 #define DPU_HW_VER_720	DPU_HW_VER(7, 2, 0) /* sc7280 */
 #define DPU_HW_VER_800	DPU_HW_VER(8, 0, 0) /* sc8280xp */
-#define DPU_HW_VER_810	DPU_HW_VER(8, 1, 0) /* sm8450 */
+#define DPU_HW_VER_810	DPU_HW_VER(8, 1, 0) /* sm8450, waipio */
 #define DPU_HW_VER_900	DPU_HW_VER(9, 0, 0) /* sm8550 */
 
+/* Avoid using below IS_XXX macros outside catalog, use feature bit instead */
+#define IS_DPU_MAJOR_SAME(rev1, rev2)   \
+		(DPU_HW_MAJOR((rev1)) == DPU_HW_MAJOR((rev2)))
+#define IS_DPU_MAJOR_MINOR_SAME(rev1, rev2)   \
+		(DPU_HW_MAJOR_MINOR((rev1)) == DPU_HW_MAJOR_MINOR((rev2)))
+
 #define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170)
 #define IS_MSM8998_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_300)
 #define IS_SDM845_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_400)
@@ -240,6 +246,7 @@ enum {
  * @DPU_INTF_INPUT_CTRL         Supports the setting of pp block from which
  *                              pixel data arrives to this INTF
  * @DPU_INTF_TE                 INTF block has TE configuration support
+ * @DPU_INTF_TE_ALIGN_VSYNC     INTF block has POMS Align vsync support
  * @DPU_DATA_HCTL_EN            Allows data to be transferred at different rate
                                 than video timing
  * @DPU_INTF_MAX
@@ -247,6 +254,7 @@ enum {
 enum {
 	DPU_INTF_INPUT_CTRL = 0x1,
 	DPU_INTF_TE,
+	DPU_INTF_TE_ALIGN_VSYNC,
 	DPU_DATA_HCTL_EN,
 	DPU_INTF_MAX
 };
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..238efdb 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  */
 
@@ -44,6 +44,7 @@
 #define   INTF_DEFLICKER_STRNG_COEFF    0x0F4
 #define   INTF_DEFLICKER_WEAK_COEFF     0x0F8
 
+#define   INTF_REG_SPLIT_LINK           0x080
 #define   INTF_DSI_CMD_MODE_TRIGGER_EN  0x084
 #define   INTF_PANEL_FORMAT             0x090
 #define   INTF_TPG_ENABLE               0x100
@@ -65,9 +66,9 @@
 
 #define INTF_CFG_ACTIVE_H_EN	BIT(29)
 #define INTF_CFG_ACTIVE_V_EN	BIT(30)
-
 #define INTF_CFG2_DATABUS_WIDEN	BIT(0)
 #define INTF_CFG2_DATA_HCTL_EN	BIT(4)
+#define INTF_CFG2_ALIGN_VSYNC_TO_TE BIT(16)
 
 #define INTF_MISR_CTRL			0x180
 #define INTF_MISR_SIGNATURE		0x184
@@ -91,6 +92,16 @@ static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
 	return ERR_PTR(-EINVAL);
 }
 
+static inline void _check_and_set_comp_bit(struct dpu_hw_intf *ctx,
+		bool dsc_4hs_merge, bool compression_en, u32 *intf_cfg2)
+{
+	if (((DPU_HW_MAJOR(ctx->hw_rev) >= DPU_HW_MAJOR(DPU_HW_VER_700)) && compression_en)
+		|| (IS_DPU_MAJOR_SAME(ctx->hw_rev, DPU_HW_VER_600) && dsc_4hs_merge))
+		(*intf_cfg2) |= BIT(12);
+	else if (!compression_en)
+		(*intf_cfg2) &= ~BIT(12);
+}
+
 static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
 		const struct intf_timing_params *p,
 		const struct dpu_format *fmt)
@@ -113,82 +124,96 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
 	/* read interface_cfg */
 	intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
 
-	if (ctx->cap->type == INTF_DP)
+	if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)
 		dp_intf = true;
 
 	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
-	p->h_front_porch;
+			p->h_front_porch;
 	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
-	p->v_front_porch;
+			p->v_front_porch;
 
 	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
-	hsync_period) + p->hsync_skew;
+			hsync_period) + p->hsync_skew;
 	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
-	p->hsync_skew - 1;
+			p->hsync_skew - 1;
+
+	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
 
 	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
 	hsync_end_x = hsync_period - p->h_front_porch - 1;
 
-	if (p->width != p->xres) { /* border fill added */
-		active_h_start = hsync_start_x;
-		active_h_end = active_h_start + p->xres - 1;
-	} else {
-		active_h_start = 0;
-		active_h_end = 0;
-	}
-
-	if (p->height != p->yres) { /* border fill added */
-		active_v_start = display_v_start;
-		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
-	} else {
-		active_v_start = 0;
-		active_v_end = 0;
-	}
-
-	if (active_h_end) {
-		active_hctl = (active_h_end << 16) | active_h_start;
-		intf_cfg |= INTF_CFG_ACTIVE_H_EN;
-	} else {
-		active_hctl = 0;
-	}
-
-	if (active_v_end)
-		intf_cfg |= INTF_CFG_ACTIVE_V_EN;
-
-	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
-	display_hctl = (hsync_end_x << 16) | hsync_start_x;
-
 	/*
 	 * DATA_HCTL_EN controls data timing which can be different from
 	 * video timing. It is recommended to enable it for all cases, except
 	 * if compression is enabled in 1 pixel per clock mode
 	 */
+	if (!p->compression_en || p->wide_bus_en)
+		intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
+
 	if (p->wide_bus_en)
-		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
+		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
 
+	/*
+	 * If widebus is disabled:
+	 * For uncompressed stream, the data is valid for the entire active
+	 * window period.
+	 * For compressed stream, data is valid for a shorter time period
+	 * inside the active window depending on the compression ratio.
+	 *
+	 * If widebus is enabled:
+	 * For uncompressed stream, data is valid for only half the active
+	 * window, since the data rate is doubled in this mode.
+	 * p->width holds the adjusted width for DP but unadjusted width for DSI
+	 * For compressed stream, data validity window needs to be adjusted for
+	 * compression ratio and then further halved.
+	 */
 	data_width = p->width;
 
+	if (p->compression_en) {
+		if (p->wide_bus_en)
+			data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6);
+		else
+			data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
+	} else if (!dp_intf && p->wide_bus_en) {
+		data_width = p->width >> 1;
+	} else {
+		data_width = p->width;
+	}
+
 	hsync_data_start_x = hsync_start_x;
 	hsync_data_end_x =  hsync_start_x + data_width - 1;
 
+	display_hctl = (hsync_end_x << 16) | hsync_start_x;
 	display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
 
 	if (dp_intf) {
 		/* DP timing adjustment */
 		display_v_start += p->hsync_pulse_width + p->h_back_porch;
 		display_v_end   -= p->h_front_porch;
+	}
+
+	intf_cfg |= INTF_CFG_ACTIVE_H_EN;
+	intf_cfg |= INTF_CFG_ACTIVE_V_EN;
+	active_h_start = hsync_start_x;
+	active_h_end = active_h_start + p->xres - 1;
+	active_v_start = display_v_start;
+	active_v_end = active_v_start + (p->yres * hsync_period) - 1;
 
-		active_h_start = hsync_start_x;
-		active_h_end = active_h_start + p->xres - 1;
-		active_v_start = display_v_start;
-		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
+	active_hctl = (active_h_end << 16) | active_h_start;
 
-		active_hctl = (active_h_end << 16) | active_h_start;
+	if (dp_intf) {
 		display_hctl = active_hctl;
 
-		intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
+		if (p->compression_en) {
+			active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16;
+			active_data_hctl += hsync_start_x;
+
+			display_data_hctl = active_data_hctl;
+		}
 	}
 
+	_check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en, &intf_cfg2);
+
 	den_polarity = 0;
 	if (ctx->cap->type == INTF_HDMI) {
 		hsync_polarity = p->yres >= 720 ? 0 : 1;
@@ -202,7 +227,7 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
 	}
 	polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
 		(vsync_polarity << 1) | /* VSYNC Polarity */
-		(hsync_polarity << 0);  /* HSYNC Polarity */
+		 (hsync_polarity << 0);  /* HSYNC Polarity */
 
 	if (!DPU_FORMAT_IS_YUV(fmt))
 		panel_format = (fmt->bits[C0_G_Y] |
@@ -216,6 +241,17 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
 				(COLOR_8BIT << 4) |
 				(0x21 << 8));
 
+	if (p->wide_bus_en)
+		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
+
+	/* Synchronize timing engine enable to TE */
+	if ((ctx->cap->features & BIT(DPU_INTF_TE_ALIGN_VSYNC))
+			&& p->poms_align_vsync)
+		intf_cfg2 |= INTF_CFG2_ALIGN_VSYNC_TO_TE;
+
+	if (ctx->cfg.split_link_en)
+		DPU_REG_WRITE(c, INTF_REG_SPLIT_LINK, 0x3);
+
 	DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
 	DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
 	DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
@@ -233,11 +269,9 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
 	DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
 	DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
 	DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
-	if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) {
-		DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
-		DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
-		DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
-	}
+	DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
+	DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
+	DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
 }
 
 static void dpu_hw_intf_enable_timing_engine(
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
index 643dd10..57be86d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  */
 
@@ -10,6 +10,7 @@
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_mdss.h"
 #include "dpu_hw_util.h"
+#include "dpu_hw_top.h"
 
 struct dpu_hw_intf;
 
@@ -33,6 +34,11 @@ struct intf_timing_params {
 	u32 hsync_skew;
 
 	bool wide_bus_en;
+	bool compression_en;
+	u32 extra_dto_cycles;   /* for DP only */
+	bool dsc_4hs_merge;     /* DSC 4HS merge */
+	bool poms_align_vsync;  /* poms with vsync aligned */
+	u32 dce_bytes_per_line;
 };
 
 struct intf_prog_fetch {
@@ -86,11 +92,13 @@ struct dpu_hw_intf_ops {
 
 struct dpu_hw_intf {
 	struct dpu_hw_blk_reg_map hw;
+	u32 hw_rev;	/* mdss hw_rev */
 
 	/* intf */
 	enum dpu_intf idx;
 	const struct dpu_intf_cfg *cap;
 	const struct dpu_mdss_cfg *mdss;
+	struct split_pipe_cfg cfg;
 
 	/* ops */
 	struct dpu_hw_intf_ops ops;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
index a1a9e44..1212fa2 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _DPU_HW_TOP_H
@@ -34,12 +36,14 @@ struct traffic_shaper_cfg {
  * @intf      : Interface id for main control path
  * @split_flush_en: Allows both the paths to be flushed when master path is
  *              flushed
+ * @split_link_en:  Check if split link is enabled
  */
 struct split_pipe_cfg {
 	bool en;
 	enum dpu_intf_mode mode;
 	enum dpu_intf intf;
 	bool split_flush_en;
+	bool split_link_en;
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (11 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-25  9:01   ` Neil Armstrong
  2023-01-23 18:24 ` [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block Kuogee Hsieh
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

Since display Port is an external peripheral, runtime compression
detection is added to handle plug in and unplugged events. Currently
only DSC compression supported. Once DSC compression detected, topology
is static added and used to allocate system resources to accommodate
DSC requirement. DSC related parameters are calculated and committed to
DSC encoder. Also compression information are propagated to phy and
committed to timing engine at video mode. This patch completes DSC
implementation.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 314 ++++++++++++++++-----
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   5 +-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  34 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
 5 files changed, 292 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index d2625b3..d7f5f93 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -15,6 +15,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_file.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_bridge.h>
 
 #include "msm_drv.h"
 #include "dpu_kms.h"
@@ -30,6 +31,7 @@
 #include "dpu_crtc.h"
 #include "dpu_trace.h"
 #include "dpu_core_irq.h"
+#include "dpu_dsc_helper.h"
 #include "disp/msm_disp_snapshot.h"
 
 #define DPU_DEBUG_ENC(e, fmt, ...) DRM_DEBUG_ATOMIC("enc%d " fmt,\
@@ -542,12 +544,12 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc)
 	return (num_dsc > 0) && (num_dsc > intf_count);
 }
 
-static struct msm_display_topology dpu_encoder_get_topology(
+static void dpu_encoder_get_topology(
 			struct dpu_encoder_virt *dpu_enc,
 			struct dpu_kms *dpu_kms,
-			struct drm_display_mode *mode)
+			struct drm_display_mode *mode,
+			struct msm_display_topology *topology)
 {
-	struct msm_display_topology topology = {0};
 	int i, intf_count = 0;
 
 	for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++)
@@ -567,19 +569,19 @@ static struct msm_display_topology dpu_encoder_get_topology(
 	 * sufficient number
 	 */
 	if (intf_count == 2)
-		topology.num_lm = 2;
+		topology->num_lm = 2;
 	else if (!dpu_kms->catalog->caps->has_3d_merge)
-		topology.num_lm = 1;
+		topology->num_lm = 1;
 	else
-		topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
+		topology->num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
 
 	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) {
 		if (dpu_kms->catalog->dspp &&
-			(dpu_kms->catalog->dspp_count >= topology.num_lm))
-			topology.num_dspp = topology.num_lm;
+			(dpu_kms->catalog->dspp_count >= topology->num_lm))
+			topology->num_dspp = topology->num_lm;
 	}
 
-	topology.num_intf = intf_count;
+	topology->num_intf = intf_count;
 
 	if (dpu_enc->dsc) {
 		/*
@@ -588,12 +590,31 @@ static struct msm_display_topology dpu_encoder_get_topology(
 		 * this is power optimal and can drive up to (including) 4k
 		 * screens
 		 */
-		topology.num_dsc = 2;
-		topology.num_lm = 2;
-		topology.num_intf = 1;
+		topology->num_dsc = 2;
+		topology->num_intf = 1;
+		topology->num_lm = 2;
 	}
 
-	return topology;
+	/*
+	 * default topology for display port DSC implementation.
+	 * TODO:
+	 *	change to runtime resource calculation
+	 */
+	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
+		topology->num_dsc = 0;
+		topology->num_intf = intf_count;
+
+		if (dpu_enc->comp_info) {
+			/* In case of Display Stream Compression (DSC), we would use
+			 * 2 encoders, 2 layer mixers and 1 interface
+			 * this is power optimal and can drive up to (including) 4k
+			 * screens
+			 */
+			topology->num_dsc = 1;
+			topology->num_intf = 1;
+			topology->num_lm = 1;
+		}
+	}
 }
 
 static int dpu_encoder_virt_atomic_check(
@@ -605,7 +626,7 @@ static int dpu_encoder_virt_atomic_check(
 	struct msm_drm_private *priv;
 	struct dpu_kms *dpu_kms;
 	struct drm_display_mode *adj_mode;
-	struct msm_display_topology topology;
+	struct msm_display_topology *topology;
 	struct dpu_global_state *global_state;
 	int i = 0;
 	int ret = 0;
@@ -642,7 +663,27 @@ static int dpu_encoder_virt_atomic_check(
 		}
 	}
 
-	topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
+	/*
+	 * For display port, at this moment we know panel had been plugged in
+	 * and dsc supported is detected.
+	 * however we do not know the details of resolution will be used
+	 * until mode_set had been done.
+	 *
+	 * use default topology to reserve system resource for dsc
+	 *
+	 * TODO: run time calculation of topology instead of hardcode it now
+	 */
+	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
+		struct drm_bridge *bridge;
+
+		if (!dpu_enc->comp_info) {
+			bridge = drm_bridge_chain_get_first_bridge(drm_enc);
+			dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge);
+		}
+	}
+
+	topology = &dpu_enc->topology;
+	dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, topology);
 
 	/* Reserve dynamic resources now. */
 	if (!ret) {
@@ -655,7 +696,7 @@ static int dpu_encoder_virt_atomic_check(
 
 			if (!crtc_state->active_changed || crtc_state->active)
 				ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
-						drm_enc, crtc_state, topology);
+						drm_enc, crtc_state, *topology);
 		}
 	}
 
@@ -1009,7 +1050,37 @@ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
 
 		if (phys->ops.cleanup_wb_job)
 			phys->ops.cleanup_wb_job(phys, job);
+	}
+}
+
+static void dpu_encoder_populate_encoder_phys(struct drm_encoder *drm_enc,
+					struct dpu_encoder_virt *dpu_enc)
+{
+	struct msm_compression_info *comp_info;
+	struct msm_display_dsc_info *dsc_info;
+	int i;
+
+	if (!dpu_enc->comp_info)
+		return;
+
+	comp_info = dpu_enc->comp_info;
+	dsc_info = &comp_info->msm_dsc_info;
+
+	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+		if (!phys)
+			continue;
+
+		phys->comp_type = comp_info->comp_type;
+		phys->comp_ratio = comp_info->comp_ratio;
 
+		if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) {
+			phys->dsc_extra_pclk_cycle_cnt = dsc_info->pclk_per_line;
+			phys->dsc_extra_disp_width = dsc_info->extra_width;
+			phys->dce_bytes_per_line =
+				dsc_info->bytes_per_pkt * dsc_info->pkt_per_line;
+		}
 	}
 }
 
@@ -1050,6 +1121,24 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 
 	trace_dpu_enc_mode_set(DRMID(drm_enc));
 
+	/*
+	 * For display port, msm_dp_bridge_mode_set() will conver panel info
+	 * into dp_mode. This including detail dsc information if it is enabled.
+	 * after that, msm_dp_bridge_get_compression() will return detail
+	 * dsc compression info
+	 */
+	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
+		struct drm_display_mode *mode, *adjusted_mode;
+		struct drm_bridge *bridge;
+
+		mode = &crtc_state->mode;
+		adjusted_mode = &crtc_state->adjusted_mode;
+		bridge = drm_bridge_chain_get_first_bridge(drm_enc);
+		msm_dp_bridge_mode_set(bridge, mode, adjusted_mode);
+
+		dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge);
+	}
+
 	/* Query resource that have been reserved in atomic check step. */
 	num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
 		drm_enc->base.id, DPU_HW_BLK_PINGPONG, hw_pp,
@@ -1061,19 +1150,18 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 	dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
 		drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp,
 		ARRAY_SIZE(hw_dspp));
+	num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
+		drm_enc->base.id, DPU_HW_BLK_DSC,
+		hw_dsc, ARRAY_SIZE(hw_dsc));
 
 	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
 		dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i])
 						: NULL;
 
-	if (dpu_enc->dsc) {
-		num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
-							drm_enc->base.id, DPU_HW_BLK_DSC,
-							hw_dsc, ARRAY_SIZE(hw_dsc));
-		for (i = 0; i < num_dsc; i++) {
-			dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]);
-			dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0);
-		}
+	for (i = 0; i < num_dsc; i++) {
+		dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]);
+		dpu_enc->hw_pp[i]->dsc = dpu_enc->hw_dsc[i]; /* bind dsc to pp */
+		dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0);
 	}
 
 	dpu_enc->dsc_mask = dsc_mask;
@@ -1110,10 +1198,22 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 		phys->hw_pp = dpu_enc->hw_pp[i];
 		phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
 
+		if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
+			phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
+
+		/* phys->hw_intf populated at dpu_encoder_setup_display() */
+		if (!phys->hw_intf) {
+			DPU_ERROR_ENC(dpu_enc,
+				"no intf block assigned at idx: %d\n", i);
+			return;
+		}
+
 		phys->cached_mode = crtc_state->adjusted_mode;
 		if (phys->ops.atomic_mode_set)
 			phys->ops.atomic_mode_set(phys, crtc_state, conn_state);
 	}
+
+	dpu_encoder_populate_encoder_phys(drm_enc, dpu_enc);
 }
 
 static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
@@ -1208,6 +1308,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
 	mutex_unlock(&dpu_enc->enc_lock);
 }
 
+static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc);
+
 static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
 {
 	struct dpu_encoder_virt *dpu_enc = NULL;
@@ -1233,6 +1335,10 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
 			phys->ops.disable(phys);
 	}
 
+	if (dpu_enc->comp_info && (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS)) {
+		dpu_encoder_unprep_dsc(dpu_enc);
+		dpu_enc->comp_info = NULL;
+	}
 
 	/* after phys waits for frame-done, should be no more frames pending */
 	if (atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) {
@@ -1795,40 +1901,16 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work)
 			nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
 }
 
-static u32
-dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc,
-				  u32 enc_ip_width)
-{
-	int ssm_delay, total_pixels, soft_slice_per_enc;
-
-	soft_slice_per_enc = enc_ip_width / dsc->slice_width;
-
-	/*
-	 * minimum number of initial line pixels is a sum of:
-	 * 1. sub-stream multiplexer delay (83 groups for 8bpc,
-	 *    91 for 10 bpc) * 3
-	 * 2. for two soft slice cases, add extra sub-stream multiplexer * 3
-	 * 3. the initial xmit delay
-	 * 4. total pipeline delay through the "lock step" of encoder (47)
-	 * 5. 6 additional pixels as the output of the rate buffer is
-	 *    48 bits wide
-	 */
-	ssm_delay = ((dsc->bits_per_component < 10) ? 84 : 92);
-	total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47;
-	if (soft_slice_per_enc > 1)
-		total_pixels += (ssm_delay * 3);
-	return DIV_ROUND_UP(total_pixels, dsc->slice_width);
-}
-
 static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
 				     struct dpu_hw_dsc *hw_dsc,
 				     struct dpu_hw_pingpong *hw_pp,
-				     struct drm_dsc_config *dsc,
+				     struct msm_display_dsc_info *dsc_info,
 				     u32 common_mode,
 				     u32 initial_lines)
 {
 	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
 	struct dpu_hw_ctl *ctl;
+	struct drm_dsc_config *dsc = &dsc_info->drm_dsc;
 
 	ctl = cur_master->hw_ctl;
 
@@ -1852,51 +1934,137 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
 
 }
 
+static void dpu_encoder_dsc_disable(struct dpu_encoder_virt *dpu_enc,
+				     struct dpu_hw_dsc *hw_dsc,
+				     struct dpu_hw_pingpong *hw_pp)
+{
+	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
+	struct dpu_hw_ctl *ctl;
+
+	ctl = cur_master->hw_ctl;
+
+	if (hw_dsc->ops.dsc_disable)
+		hw_dsc->ops.dsc_disable(hw_dsc);
+
+	if (hw_pp->ops.disable_dsc)
+		hw_pp->ops.disable_dsc(hw_pp);
+
+}
+
 static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
-				 struct drm_dsc_config *dsc)
+				 struct msm_display_dsc_info *dsc_info)
 {
 	/* coding only for 2LM, 2enc, 1 dsc config */
 	struct dpu_encoder_phys *enc_master = dpu_enc->cur_master;
 	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
 	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
+	struct msm_display_topology *topology = &dpu_enc->topology;
+	enum dpu_3d_blend_mode mode_3d;
 	int this_frame_slices;
 	int intf_ip_w, enc_ip_w;
-	int dsc_common_mode;
-	int pic_width;
-	u32 initial_lines;
+	int dsc_common_mode = 0;
+	int dsc_pic_width;
+	int num_lm, num_dsc, num_intf;
+	bool dsc_merge, merge_3d, dsc_4hsmerge;
+	bool disable_merge_3d = false;
+	int ich_res;
 	int i;
 
 	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
 		hw_pp[i] = dpu_enc->hw_pp[i];
 		hw_dsc[i] = dpu_enc->hw_dsc[i];
+	}
 
-		if (!hw_pp[i] || !hw_dsc[i]) {
-			DPU_ERROR_ENC(dpu_enc, "invalid params for DSC\n");
-			return;
-		}
+	num_lm = topology->num_lm;
+	num_dsc = topology->num_dsc;
+	num_intf = topology->num_intf;
+
+
+	mode_3d = (num_lm > num_dsc) ? BLEND_3D_H_ROW_INT : BLEND_3D_NONE;
+	merge_3d = ((mode_3d != BLEND_3D_NONE) && !(enc_master->hw_intf->cfg.split_link_en)) ?
+			true : false;
+
+	dsc_merge = ((num_dsc > num_intf) && !dsc_info->half_panel_pu &&
+			!(enc_master->hw_intf->cfg.split_link_en)) ? true : false;
+	disable_merge_3d = (merge_3d && dsc_info->half_panel_pu) ?  false : true;
+	dsc_4hsmerge = (dsc_merge && num_dsc == 4 && num_intf == 1) ?  true : false;
+
+	/*
+	 * If this encoder is driving more than one DSC encoder, they
+	 * operate in tandem, same pic dimension needs to be used by
+	 * each of them.(pp-split is assumed to be not supported)
+	 *
+	 * If encoder is driving more than 2 DSCs, each DSC pair will operate
+	 * on half of the picture in tandem.
+	 */
+	dsc_pic_width = dsc_info->drm_dsc.pic_width;
+
+	if (num_dsc > 2) {
+		dsc_pic_width /= 2;
+		dsc_info->dsc_4hsmerge_en = dsc_4hsmerge;
 	}
 
-	dsc_common_mode = 0;
-	pic_width = dsc->pic_width;
+	this_frame_slices = dsc_pic_width / dsc_info->drm_dsc.slice_width;
+	intf_ip_w = this_frame_slices * dsc_info->drm_dsc.slice_width;
+	enc_ip_w = intf_ip_w;
+
+	if (!dsc_info->half_panel_pu)
+		intf_ip_w /= num_intf;
+	if (!dsc_info->half_panel_pu && (num_dsc > 1))
+		dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
+	if (dsc_merge) {
+		dsc_common_mode |= DSC_MODE_MULTIPLEX;
+		/*
+		 * in dsc merge case: when using 2 encoders for the same
+		 * stream, no. of slices need to be same on both the
+		 * encoders.
+		 */
+		enc_ip_w = intf_ip_w / 2;
+	}
 
-	dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL;
 	if (enc_master->intf_mode == INTF_MODE_VIDEO)
 		dsc_common_mode |= DSC_MODE_VIDEO;
 
-	this_frame_slices = pic_width / dsc->slice_width;
-	intf_ip_w = this_frame_slices * dsc->slice_width;
+	dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count;
+
+	if (dsc_info->dsc_4hsmerge_en)
+		dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 2;
+	else if ((dsc_common_mode & DSC_MODE_MULTIPLEX) || (dsc_info->half_panel_pu))
+		dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 1;
+
+	dpu_dsc_populate_dsc_private_params(dsc_info, intf_ip_w);
+
+	dpu_dsc_initial_line_calc(dsc_info, enc_ip_w, dsc_common_mode);
 
 	/*
 	 * dsc merge case: when using 2 encoders for the same stream,
 	 * no. of slices need to be same on both the encoders.
 	 */
-	enc_ip_w = intf_ip_w / 2;
-	initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
+	ich_res = dpu_dsc_ich_reset_override_needed(dsc_info->half_panel_pu, dsc_info);
+
+	for (i = 0; i < num_dsc; i++) {
+		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc_info,
+					dsc_common_mode, 0);
+	}
+}
+
+static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc)
+{
+	/* coding only for 2LM, 2enc, 1 dsc config */
+	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
+	struct msm_display_topology *topology = &dpu_enc->topology;
+	int i, num_dsc;
 
 	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
-		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc,
-					dsc_common_mode, initial_lines);
+		hw_pp[i] = dpu_enc->hw_pp[i];
+		hw_dsc[i] = dpu_enc->hw_dsc[i];
 	}
+
+	num_dsc = topology->num_dsc;
+
+	for (i = 0; i < num_dsc; i++)
+		dpu_encoder_dsc_disable(dpu_enc, hw_dsc[i], hw_pp[i]);
 }
 
 void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
@@ -1904,6 +2072,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
 	struct dpu_encoder_virt *dpu_enc;
 	struct dpu_encoder_phys *phys;
 	bool needs_hw_reset = false;
+	bool needs_phy_enable = false;
 	unsigned int i;
 
 	dpu_enc = to_dpu_encoder_virt(drm_enc);
@@ -1918,6 +2087,9 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
 			phys->ops.prepare_for_kickoff(phys);
 		if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET)
 			needs_hw_reset = true;
+
+		if (phys->enable_state == DPU_ENC_ENABLING)
+			needs_phy_enable = true;
 	}
 	DPU_ATRACE_END("enc_prepare_for_kickoff");
 
@@ -1931,8 +2103,10 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
 		}
 	}
 
-	if (dpu_enc->dsc)
-		dpu_encoder_prep_dsc(dpu_enc, dpu_enc->dsc);
+	if (needs_phy_enable && dpu_enc->comp_info)
+		dpu_encoder_prep_dsc(dpu_enc, &dpu_enc->comp_info->msm_dsc_info);
+
+
 }
 
 bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc)
@@ -2295,7 +2469,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
 				dpu_kms->catalog->caps->has_idle_pc;
 
 	dpu_enc->comp_info = disp_info->comp_info;
-	if (dpu_enc->comp_info)
+	if (dpu_enc->comp_info && dpu_enc->comp_info->enabled)
 		dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc;
 
 	mutex_lock(&dpu_enc->enc_lock);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 0569b36..ae4f6a8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
  */
 
@@ -202,6 +202,9 @@ struct dpu_encoder_phys {
 	int irq[INTR_IDX_MAX];
 	enum msm_display_compression_type comp_type;
 	u32 comp_ratio;
+	u32 dsc_extra_pclk_cycle_cnt;
+	u32 dsc_extra_disp_width;
+	u32 dce_bytes_per_line;
 };
 
 static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 3330e185..6c7d791 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -86,6 +86,11 @@ static void drm_mode_to_intf_timing_params(
 	timing->underflow_clr = 0xff;
 	timing->hsync_skew = mode->hskew;
 
+	if (phys_enc->comp_type != MSM_DISPLAY_COMPRESSION_NONE) {
+		timing->compression_en = true;
+		timing->dce_bytes_per_line = phys_enc->dce_bytes_per_line;
+	}
+
 	/* DSI controller cannot handle active-low sync signals. */
 	if (phys_enc->hw_intf->cap->type == INTF_DSI) {
 		timing->hsync_polarity = 0;
@@ -104,14 +109,36 @@ static void drm_mode_to_intf_timing_params(
 
 	/*
 	 * for DP, divide the horizonal parameters by 2 when
-	 * widebus is enabled
+	 * widebus or compression is enabled, irrespective of
+	 * compression ratio
 	 */
-	if (phys_enc->hw_intf->cap->type == INTF_DP && timing->wide_bus_en) {
+	if (phys_enc->hw_intf->cap->type == INTF_DP &&
+		(timing->wide_bus_en || (phys_enc->comp_ratio > 1))) {
 		timing->width = timing->width >> 1;
 		timing->xres = timing->xres >> 1;
 		timing->h_back_porch = timing->h_back_porch >> 1;
 		timing->h_front_porch = timing->h_front_porch >> 1;
 		timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
+
+		if (phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
+				(phys_enc->comp_ratio > 1)) {
+			timing->extra_dto_cycles =
+					phys_enc->dsc_extra_pclk_cycle_cnt;
+			timing->width += phys_enc->dsc_extra_disp_width;
+			timing->h_back_porch +=
+					phys_enc->dsc_extra_disp_width;
+		}
+	}
+
+	/*
+	 * for DSI, if compression is enabled, then divide the horizonal active
+	 * timing parameters by compression ratio.
+	 */
+	if ((phys_enc->hw_intf->cap->type != INTF_DP) &&
+			((phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC))) {
+		// adjust active dimensions
+		timing->width = DIV_ROUND_UP(timing->width, phys_enc->comp_ratio);
+		timing->xres = DIV_ROUND_UP(timing->xres, phys_enc->comp_ratio);
 	}
 }
 
@@ -281,6 +308,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
 
 	phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev;
 
+	if (phys_enc->hw_pp->dsc)
+		intf_cfg.dsc_num = phys_enc->hw_pp->dsc->idx;
+
 	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
 	phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
 			&timing_params, fmt);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
index c002234..ee71cee 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _DPU_HW_PINGPONG_H
@@ -8,6 +9,7 @@
 #include "dpu_hw_catalog.h"
 #include "dpu_hw_mdss.h"
 #include "dpu_hw_util.h"
+#include "dpu_hw_dsc.h"
 
 #define DITHER_MATRIX_SZ 16
 
@@ -149,6 +151,7 @@ struct dpu_hw_pingpong {
 	enum dpu_pingpong idx;
 	const struct dpu_pingpong_cfg *caps;
 	struct dpu_hw_merge_3d *merge_3d;
+	struct dpu_hw_dsc *dsc;
 
 	/* ops */
 	struct dpu_hw_pingpong_ops ops;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 396429e..bb22ec8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s] " fmt, __func__
@@ -246,6 +247,11 @@ int dpu_rm_init(struct dpu_rm *rm,
 		struct dpu_hw_dsc *hw;
 		const struct dpu_dsc_cfg *dsc = &cat->dsc[i];
 
+		if (dsc->id < DSC_0 || dsc->id >= DSC_MAX) {
+			DPU_ERROR("skip dsc %d with invalid id\n", dsc->id);
+			continue;
+		}
+
 		hw = dpu_hw_dsc_init(dsc->id, mmio, cat);
 		if (IS_ERR_OR_NULL(hw)) {
 			rc = PTR_ERR(hw);
@@ -535,8 +541,10 @@ static int _dpu_rm_make_reservation(
 	}
 
 	ret  = _dpu_rm_reserve_dsc(rm, global_state, enc, &reqs->topology);
-	if (ret)
+	if (ret) {
+		DPU_ERROR("unable to find appropriate DSC\n");
 		return ret;
+	}
 
 	return ret;
 }
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (12 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder Kuogee Hsieh
@ 2023-01-23 18:24 ` Kuogee Hsieh
  2023-01-23 20:19   ` Marijn Suijten
  2023-01-23 18:34 ` [PATCH v1 00/14] add display port DSC feature Marijn Suijten
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-23 18:24 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, linux-kernel,
	Kuogee Hsieh, freedreno

This patch add DSC block and sub block to support new DSC v1.2 hardware
encoder. Also sc7280 DSC related hardware information are added to allow
sc7280 DSC feature be enabled at sc7280 platform.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 50 +++++++++++++++++++-------
 1 file changed, 38 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 7deffc9f9..2c78a46 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -476,6 +476,7 @@ static const struct dpu_caps sc7280_dpu_caps = {
 	.has_idle_pc = true,
 	.max_linewidth = 2400,
 	.pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
+	.max_dsc_width = 2560,
 };
 
 static const struct dpu_mdp_cfg msm8998_mdp[] = {
@@ -1707,7 +1708,7 @@ static const struct dpu_pingpong_cfg sm8350_pp[] = {
 };
 
 static const struct dpu_pingpong_cfg sc7280_pp[] = {
-	PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1),
+	PP_BLK("pingpong_0", PINGPONG_0, 0x69000, 0, sc7280_pp_sblk, -1, -1),
 	PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
 	PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1),
 	PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1),
@@ -1814,25 +1815,48 @@ static const struct dpu_merge_3d_cfg sm8550_merge_3d[] = {
 /*************************************************************
  * DSC sub blocks config
  *************************************************************/
-#define DSC_BLK(_name, _id, _base, _features) \
+#define DSC_BLK_HW_1_1(_name, _id, _base, _features) \
 	{\
 	.name = _name, .id = _id, \
 	.base = _base, .len = 0x140, \
-	.features = _features, \
+	.features = BIT(DPU_DSC_HW_REV_1_1) | _features, \
+	}
+
+#define DSC_BLK_HW_1_2(_name, _id, _base, _features, _sblk) \
+	{\
+	.name = _name, .id = _id, \
+	.base = _base, .len = 0x140, \
+	.features = BIT(DPU_DSC_HW_REV_1_2) | _features, \
+	.sblk = &_sblk, \
 	}
 
 static struct dpu_dsc_cfg sdm845_dsc[] = {
-	DSC_BLK("dsc_0", DSC_0, 0x80000, 0),
-	DSC_BLK("dsc_1", DSC_1, 0x80400, 0),
-	DSC_BLK("dsc_2", DSC_2, 0x80800, 0),
-	DSC_BLK("dsc_3", DSC_3, 0x80c00, 0),
+	DSC_BLK_HW_1_1("dsc_0", DSC_0, 0x80000, 0),
+	DSC_BLK_HW_1_1("dsc_1", DSC_1, 0x80400, 0),
+	DSC_BLK_HW_1_1("dsc_2", DSC_2, 0x80800, 0),
+	DSC_BLK_HW_1_1("dsc_3", DSC_3, 0x80c00, 0),
 };
 
 static struct dpu_dsc_cfg sm8150_dsc[] = {
-	DSC_BLK("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)),
-	DSC_BLK("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)),
-	DSC_BLK("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)),
-	DSC_BLK("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)),
+	DSC_BLK_HW_1_1("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)),
+	DSC_BLK_HW_1_1("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)),
+	DSC_BLK_HW_1_1("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)),
+	DSC_BLK_HW_1_1("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)),
+};
+
+static struct dpu_dsc_sub_blks sc7280_dsc_sblk_0 = {
+	.enc = {.base = 0x100, .len = 0x100},
+	.ctl = {.base = 0xF00, .len = 0x10},
+};
+
+static struct dpu_dsc_sub_blks sc7280_dsc_sblk_1 = {
+	.enc = {.base = 0x200, .len = 0x100},
+	.ctl = {.base = 0xF80, .len = 0x10},
+};
+
+static struct dpu_dsc_cfg sc7280_dsc[] = {
+	DSC_BLK_HW_1_2("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_NATIVE_422_EN), sc7280_dsc_sblk_0),
+	DSC_BLK_HW_1_2("dsc_1", DSC_1, 0x80000, BIT(DPU_DSC_NATIVE_422_EN), sc7280_dsc_sblk_1),
 };
 
 /*************************************************************
@@ -2809,6 +2833,8 @@ static const struct dpu_mdss_cfg sc7280_dpu_cfg = {
 	.pingpong_count = ARRAY_SIZE(sc7280_pp),
 	.pingpong = sc7280_pp,
 	.intf_count = ARRAY_SIZE(sc7280_intf),
+	.dsc_count = ARRAY_SIZE(sc7280_dsc),
+	.dsc = sc7280_dsc,
 	.intf = sc7280_intf,
 	.vbif_count = ARRAY_SIZE(sdm845_vbif),
 	.vbif = sdm845_vbif,
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


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

* Re: [PATCH v1 00/14] add display port DSC feature
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (13 preceding siblings ...)
  2023-01-23 18:24 ` [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block Kuogee Hsieh
@ 2023-01-23 18:34 ` Marijn Suijten
  2023-01-24  0:10 ` Dmitry Baryshkov
  2023-01-25  0:28 ` Abhinav Kumar
  16 siblings, 0 replies; 50+ messages in thread
From: Marijn Suijten @ 2023-01-23 18:34 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel

DisplayPort is a name, and I think you should spell it as such in both
the cover letter title and individual patch descriptions (capital D and
P, no space in between).

On 2023-01-23 10:24:20, Kuogee Hsieh wrote:
> This patch add DSC related supporting functions into to both dp controller and dpu enccoder
> 
> Kuogee Hsieh (14):
>   drm/msm/dp: add dpcd read of both dsc and fec capability
>   drm/msm/dp: add dsc factor into calculation of supported bpp
>   drm/msm/dp: add configure mainlink_levels base on lane number
>   drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
>   drm/msm/dp: upgrade tu calculation base on newest algorithm
>   drm/msm/dp: add display compression related struct
>   drm/msm/dp: add dsc helper functions
>   drm/msm/dp: add dsc supporting functions to DP controller
>   drm/msm/dsi: export struct msm_compression_info to dpu encoder
>   drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
>   drm/msm/disp/dpu1: add supports of new flush mechanism
>   drm/msm/disp/dpu1: revise timing engine programming to work for DSC
>   drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder
>   drm/msm/disp/dpu1: add sc7280 dsc block and sub block

For DSC, capitalize it everywhere instead of the current free-form lower
and uppercase mixup in patch titles.

Still asking around for the subsystem tag, I've seen:

    drm/msm/dpu
    drm/msm/dpu1
    drm/msm/disp/dpu
    drm/msm/disp/dpu1

And you're already mixing two of them.

Aside that, thanks for sending this series!  Been looking forward to DSC
1.2 for a while, but for DSI!

- Marijn

>  drivers/gpu/drm/msm/Makefile                       |   2 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c     | 537 +++++++++++++
>  drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h     |  25 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 341 +++++++--
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   4 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   7 +-
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  43 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c     |  50 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  74 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         |  43 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         |  21 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  23 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |  23 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c     | 371 +++++++++
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 ++--
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            |  10 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
>  drivers/gpu/drm/msm/dp/dp_catalog.c                | 176 ++++-
>  drivers/gpu/drm/msm/dp/dp_catalog.h                |  97 ++-
>  drivers/gpu/drm/msm/dp/dp_ctrl.c                   | 839 ++++++++++++++-------
>  drivers/gpu/drm/msm/dp/dp_display.c                |  61 +-
>  drivers/gpu/drm/msm/dp/dp_link.c                   |  29 +-
>  drivers/gpu/drm/msm/dp/dp_panel.c                  | 749 +++++++++++++++++-
>  drivers/gpu/drm/msm/dp/dp_panel.h                  |  67 +-
>  drivers/gpu/drm/msm/dp/dp_reg.h                    |  40 +-
>  drivers/gpu/drm/msm/dsi/dsi.c                      |   3 +-
>  drivers/gpu/drm/msm/dsi/dsi.h                      |   3 +-
>  drivers/gpu/drm/msm/dsi/dsi_host.c                 |  14 +-
>  drivers/gpu/drm/msm/msm_drv.h                      | 113 ++-
>  32 files changed, 3429 insertions(+), 497 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
>  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
>  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> 
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-23 18:24 ` [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Kuogee Hsieh
@ 2023-01-23 20:11   ` Marijn Suijten
  2023-01-24 23:52     ` Kuogee Hsieh
  2023-01-24  7:44   ` Dmitry Baryshkov
  2023-01-24 15:18   ` Neil Armstrong
  2 siblings, 1 reply; 50+ messages in thread
From: Marijn Suijten @ 2023-01-23 20:11 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel

add support for*

drm/msm/dpu*

On 2023-01-23 10:24:30, Kuogee Hsieh wrote:
> DSC V1.2 encoder engine is newly added hardware module. This patch
> add support functions to configure and enable DSC V1.2 encoder engine.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>  drivers/gpu/drm/msm/Makefile                   |   1 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    |   2 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  60 +++-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c     |  23 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h     |  23 +-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 371 +++++++++++++++++++++++++
>  6 files changed, 463 insertions(+), 17 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 28cf52b..271c29a15 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>  	disp/dpu1/dpu_hw_catalog.o \
>  	disp/dpu1/dpu_hw_ctl.o \
>  	disp/dpu1/dpu_hw_dsc.o \
> +	disp/dpu1/dpu_hw_dsc_1_2.o \
>  	disp/dpu1/dpu_dsc_helper.o \
>  	disp/dpu1/dpu_hw_interrupts.o \
>  	disp/dpu1/dpu_hw_intf.o \
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 7f4a439..901e317 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -1821,7 +1821,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
>  				     u32 initial_lines)
>  {
>  	if (hw_dsc->ops.dsc_config)
> -		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines);
> +		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);

As usual, an enum is better: readers have no idea what a free-floating
bool means.

>  
>  	if (hw_dsc->ops.dsc_config_thresh)
>  		hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> index 978e3bd..7b0b092 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> @@ -1,6 +1,6 @@
>  /* SPDX-License-Identifier: GPL-2.0-only */
>  /*
> - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>   * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
>   */
>  
> @@ -11,6 +11,7 @@
>  #include <linux/bug.h>
>  #include <linux/bitmap.h>
>  #include <linux/err.h>
> +#include "dpu_hw_mdss.h"

Unused if you remove the unused DECLARE_BITMAP(dsc_pair_mask, DSC_MAX).

>  
>  /**
>   * Max hardware block count: For ex: max 12 SSPP pipes or
> @@ -182,6 +183,7 @@ enum {
>   * @DPU_PINGPONG_TE2        Additional tear check block for split pipes
>   * @DPU_PINGPONG_SPLIT      PP block supports split fifo
>   * @DPU_PINGPONG_SLAVE      PP block is a suitable slave for split fifo
> + * @DPU_PINGPONG_DSC,       Display stream compression blocks
>   * @DPU_PINGPONG_DITHER,    Dither blocks
>   * @DPU_PINGPONG_MAX
>   */
> @@ -190,10 +192,32 @@ enum {
>  	DPU_PINGPONG_TE2,
>  	DPU_PINGPONG_SPLIT,
>  	DPU_PINGPONG_SLAVE,
> +	DPU_PINGPONG_DSC,

This is not used.

>  	DPU_PINGPONG_DITHER,
>  	DPU_PINGPONG_MAX
>  };
>  
> +
> +/** DSC sub-blocks/features

Newline between /** and the text.

> + * @DPU_DSC_OUTPUT_CTRL         Supports the control of the pp id which gets
> + *                              the pixel output from this DSC.

The original comment is much more concise, can we keep it?

> + * @DPU_DSC_HW_REV_1_1          dsc block supports dsc 1.1 only
> + * @DPU_DSC_HW_REV_1_2          dsc block supports dsc 1.1 and 1.2

Capitalize DSC just like elsewhere.

> + * @DPU_DSC_NATIVE_422_EN,      Supports native422 and native420 encoding
> + * @DPU_DSC_ENC,                DSC encoder sub block
> + * @DPU_DSC_CTL,                DSC ctl sub block

No need for trailing commas in doc comments; if anything replace them
with colons?

> + * @DPU_DSC_MAX
> + */
> +enum {
> +	DPU_DSC_OUTPUT_CTRL = 0x1,
> +	DPU_DSC_HW_REV_1_1,
> +	DPU_DSC_HW_REV_1_2,
> +	DPU_DSC_NATIVE_422_EN,
> +	DPU_DSC_ENC,
> +	DPU_DSC_CTL,

These two enum values only have a meaning within the dpu_hw_dsc_1_2.c
file, and have nothing to do with the other feature flags/block
description.  Please move them there (and give _dsc_subblk_offset a
proper enum type).

> +	DPU_DSC_MAX
> +};
> +
>  /**
>   * CTL sub-blocks
>   * @DPU_CTL_SPLIT_DISPLAY:	CTL supports video mode split display
> @@ -276,15 +300,6 @@ enum {
>  };
>  
>  /**
> - * DSC features
> - * @DPU_DSC_OUTPUT_CTRL       Configure which PINGPONG block gets
> - *                            the pixel output from this DSC.
> - */
> -enum {
> -	DPU_DSC_OUTPUT_CTRL = 0x1,

Did this have to move?

> -};
> -
> -/**
>   * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
>   * @name:              string name for debug purposes
>   * @id:                enum identifying this block
> @@ -346,6 +361,14 @@ struct dpu_pp_blk {
>  };
>  
>  /**
> + * struct dpu_dsc_blk : DSC Encoder sub-blk information

Use a hyphen here and everywhere else:
https://docs.kernel.org/doc-guide/kernel-doc.html

> + * @info:   HW register and features supported by this sub-blk
> + */
> +struct dpu_dsc_blk {
> +	DPU_HW_SUBBLK_INFO;
> +};
> +
> +/**
>   * enum dpu_qos_lut_usage - define QoS LUT use cases
>   */
>  enum dpu_qos_lut_usage {
> @@ -403,6 +426,7 @@ struct dpu_rotation_cfg {
>   * @pixel_ram_size     size of latency hiding and de-tiling buffer in bytes
>   * @max_hdeci_exp      max horizontal decimation supported (max is 2^value)
>   * @max_vdeci_exp      max vertical decimation supported (max is 2^value)
> + * @max_dsc_width      max dsc line width support.

DSC*

>   */
>  struct dpu_caps {
>  	u32 max_mixer_width;
> @@ -419,6 +443,7 @@ struct dpu_caps {
>  	u32 pixel_ram_size;
>  	u32 max_hdeci_exp;
>  	u32 max_vdeci_exp;
> +	u32 max_dsc_width;

This is never read.

>  };
>  
>  /**
> @@ -494,9 +519,20 @@ struct dpu_dspp_sub_blks {
>  struct dpu_pingpong_sub_blks {
>  	struct dpu_pp_blk te;
>  	struct dpu_pp_blk te2;
> +	struct dpu_pp_blk dsc;

Unused.

>  	struct dpu_pp_blk dither;
>  };
>  
> +
> +/**
> + * struct dpu_dsc_sub_blks : DSC sub-blks
> + *

A sub-block of sub-blocks?  Use the documentation to explain what this
is for, describe @enc and @ctl.

> + */
> +struct dpu_dsc_sub_blks {
> +	struct dpu_dsc_blk enc;
> +	struct dpu_dsc_blk ctl;
> +};
> +
>  /**
>   * dpu_clk_ctrl_type - Defines top level clock control signals
>   */
> @@ -641,10 +677,14 @@ struct dpu_merge_3d_cfg  {
>   * struct dpu_dsc_cfg - information of DSC blocks
>   * @id                 enum identifying this block
>   * @base               register offset of this block
> + * @len:               length of hardware block
>   * @features           bit mask identifying sub-blocks/features
> + * @dsc_pair_mask:     Bitmask of DSCs that can be controlled by same CTL
>   */
>  struct dpu_dsc_cfg {
>  	DPU_HW_BLK_INFO;
> +	DECLARE_BITMAP(dsc_pair_mask, DSC_MAX);

This bitmask is unused.

> +	const struct dpu_dsc_sub_blks *sblk;
>  };
>  
>  /**
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> index 619926d..51e8890 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /*
>   * Copyright (c) 2020-2022, Linaro Limited
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>   */
>  
>  #include "dpu_kms.h"
> @@ -41,10 +42,11 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
>  static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>  			      struct drm_dsc_config *dsc,
>  			      u32 mode,
> -			      u32 initial_lines)
> +			      u32 initial_lines,
> +			      bool ich_reset_override)
>  {
>  	struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
> -	u32 data;
> +	u32 data, lsb, bpp;
>  	u32 slice_last_group_size;
>  	u32 det_thresh_flatness;
>  	bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
> @@ -58,7 +60,14 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>  	data = (initial_lines << 20);
>  	data |= ((slice_last_group_size - 1) << 18);
>  	/* bpp is 6.4 format, 4 LSBs bits are for fractional part */
> -	data |= (dsc->bits_per_pixel << 8);
> +	data |= dsc->bits_per_pixel << 12;
> +	lsb = dsc->bits_per_pixel % 4;
> +	bpp = dsc->bits_per_pixel / 4;
> +	bpp *= 4;
> +	bpp <<= 4;
> +	bpp |= lsb;
> +
> +	data |= bpp << 8;

Why are you re-adding this nonsense?  It was removed in [1] _and_ does
not account for bits_per_pixel _already being in x.4 format_. This will
regress existing hardware.

[1]: https://lore.kernel.org/linux-arm-msm/20221026182824.876933-10-marijn.suijten@somainline.org/

>  	data |= (dsc->block_pred_enable << 7);
>  	data |= (dsc->line_buf_depth << 3);
>  	data |= (dsc->simple_422 << 2);
> @@ -221,7 +230,13 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>  
>  	c->idx = idx;
>  	c->caps = cfg;
> -	_setup_dsc_ops(&c->ops, c->caps->features);
> +
> +	if (test_bit(DPU_DSC_HW_REV_1_1, &c->caps->features))
> +		_setup_dsc_ops(&c->ops, c->caps->features);
> +	else if (test_bit(DPU_DSC_HW_REV_1_2, &c->caps->features))
> +		dpu_dsc_1_2_setup_ops(&c->ops, c->caps->features);
> +	else
> +		_setup_dsc_ops(&c->ops, c->caps->features);
>  
>  	return c;
>  }
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> index ae9b5db..a48f572 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> @@ -1,5 +1,8 @@
>  /* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (c) 2020-2022, Linaro Limited */
> +/*
> + * Copyright (c) 2020-2022, Linaro Limited
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
> + */
>  
>  #ifndef _DPU_HW_DSC_H
>  #define _DPU_HW_DSC_H
> @@ -33,7 +36,8 @@ struct dpu_hw_dsc_ops {
>  	void (*dsc_config)(struct dpu_hw_dsc *hw_dsc,
>  			   struct drm_dsc_config *dsc,
>  			   u32 mode,
> -			   u32 initial_lines);
> +			   u32 initial_lines,
> +			   bool ich_reset_override);
>  
>  	/**
>  	 * dsc_config_thresh - programs panel thresholds
> @@ -43,6 +47,12 @@ struct dpu_hw_dsc_ops {
>  	void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
>  				  struct drm_dsc_config *dsc);
>  
> +	/**
> +	 * bind_pingpong_blk - enable/disable the connection with pp

Inherit docs from the enum.

> +	 * @hw_dsc: Pointer to dsc context

DSC*

> +	 * @enable: enable/disable connection
> +	 * @pp: pingpong blk id

It's documentation, write out block fully.

> +	 */
>  	void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc,
>  				  bool enable,
>  				  enum dpu_pingpong pp);
> @@ -51,6 +61,7 @@ struct dpu_hw_dsc_ops {
>  struct dpu_hw_dsc {
>  	struct dpu_hw_blk base;
>  	struct dpu_hw_blk_reg_map hw;
> +	struct dpu_hw_ctl *hw_ctl;

Unused.

>  
>  	/* dsc */
>  	enum dpu_dsc idx;
> @@ -76,9 +87,17 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>   */
>  void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc);
>  
> +/**
> + * dpu_hw_dsc - convert base object dpu_hw_base to container
> + * @hw: Pointer to base hardware block
> + * return: Pointer to hardware block container
> + */
>  static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw)
>  {
>  	return container_of(hw, struct dpu_hw_dsc, base);
>  }
>  
> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
> +		const unsigned long features);
> +
>  #endif /* _DPU_HW_DSC_H */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> new file mode 100644
> index 00000000..2be74ae
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#include "dpu_kms.h"
> +#include "dpu_hw_catalog.h"
> +#include "dpu_hwio.h"
> +#include "dpu_hw_mdss.h"
> +#include "dpu_hw_dsc.h"
> +
> +
> +#define DSC_CMN_MAIN_CNF           0x00
> +
> +/* DPU_DSC_ENC register offsets */
> +#define ENC_DF_CTRL                0x00
> +#define ENC_GENERAL_STATUS         0x04
> +#define ENC_HSLICE_STATUS          0x08
> +#define ENC_OUT_STATUS             0x0C
> +#define ENC_INT_STAT               0x10
> +#define ENC_INT_CLR                0x14
> +#define ENC_INT_MASK               0x18
> +#define DSC_MAIN_CONF              0x30
> +#define DSC_PICTURE_SIZE           0x34
> +#define DSC_SLICE_SIZE             0x38
> +#define DSC_MISC_SIZE              0x3C
> +#define DSC_HRD_DELAYS             0x40
> +#define DSC_RC_SCALE               0x44
> +#define DSC_RC_SCALE_INC_DEC       0x48
> +#define DSC_RC_OFFSETS_1           0x4C
> +#define DSC_RC_OFFSETS_2           0x50
> +#define DSC_RC_OFFSETS_3           0x54
> +#define DSC_RC_OFFSETS_4           0x58
> +#define DSC_FLATNESS_QP            0x5C
> +#define DSC_RC_MODEL_SIZE          0x60
> +#define DSC_RC_CONFIG              0x64
> +#define DSC_RC_BUF_THRESH_0        0x68
> +#define DSC_RC_BUF_THRESH_1        0x6C
> +#define DSC_RC_BUF_THRESH_2        0x70
> +#define DSC_RC_BUF_THRESH_3        0x74
> +#define DSC_RC_MIN_QP_0            0x78
> +#define DSC_RC_MIN_QP_1            0x7C
> +#define DSC_RC_MIN_QP_2            0x80
> +#define DSC_RC_MAX_QP_0            0x84
> +#define DSC_RC_MAX_QP_1            0x88
> +#define DSC_RC_MAX_QP_2             0x8C
> +#define DSC_RC_RANGE_BPG_OFFSETS_0  0x90
> +#define DSC_RC_RANGE_BPG_OFFSETS_1  0x94
> +#define DSC_RC_RANGE_BPG_OFFSETS_2  0x98

Reindent to line this back up.

> +
> +/* DPU_DSC_CTL register offsets */
> +#define DSC_CTL                    0x00
> +#define DSC_CFG                    0x04
> +#define DSC_DATA_IN_SWAP           0x08
> +#define DSC_CLK_CTRL               0x0C
> +
> +
> +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss)
> +{
> +	enum dpu_dsc idx;
> +
> +	idx = hw_dsc->idx;
> +
> +	if (!(hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))) {

Why not swap the bodies instead of inverting this.

> +		if (num_ss == 1)
> +			return 2399;
> +		else if (num_ss == 2)
> +			return 1199;
> +	} else {
> +		if (num_ss == 1)
> +			return 1199;
> +		else if (num_ss == 2)
> +			return 599;
> +	}
> +	return 0;
> +}
> +
> +static inline int _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id,
> +		u32 *idx)
> +{
> +	const struct dpu_dsc_sub_blks *sblk;
> +
> +	if (!hw_dsc)
> +		return -EINVAL;
> +
> +	*idx = 0;
> +
> +	sblk = hw_dsc->caps->sblk;
> +
> +	switch (s_id) {
> +
> +	case DPU_DSC_ENC:
> +		*idx = sblk->enc.base;
> +		break;
> +	case DPU_DSC_CTL:
> +		*idx = sblk->ctl.base;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	u32 idx;

Can we rename these to offset or subblk_offset or something more clear?

> +
> +	if (!hw_dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;

These error checks are excessive: you pass in a non-null hw_dsc and
known enum constant - _dsc_subblk_offset should perhaps not return
errors at all.

> +
> +	hw = &hw_dsc->hw;
> +	DPU_REG_WRITE(hw, DSC_CFG + idx, 0);

Swap the arguments to + so that it's clear that DSC_CFG is a register on
the subblock offset denoted by "idx", not the other way around.

> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, 0);
> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, 0);
> +}
> +
> +static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc,
> +		struct drm_dsc_config *dsc, u32 mode,
> +		u32 initial_lines, bool ich_reset_override)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	struct msm_display_dsc_info *dsc_info;
> +	u32 idx;
> +	u32 data = 0;
> +	u32 bpp;
> +	void __iomem *off;
> +
> +	if (!hw_dsc || !dsc)
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +
> +	dsc_info = to_msm_dsc_info(dsc);
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	if (mode & DSC_MODE_SPLIT_PANEL)
> +		data |= BIT(0);
> +
> +	if (mode & DSC_MODE_MULTIPLEX)
> +		data |= BIT(1);

These are well known bitwise definitions for a reason, data |= mode will
do (or out DSC_MODE_VIDEO since you have to shift that one at BIT(9).

> +
> +	data |= (dsc_info->num_active_ss_per_enc & 0x3) << 7;
> +
> +	DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data);
> +
> +	data = (dsc_info->initial_lines & 0xff);

You already get initial_lines passed as function argument, but ignore
it?

> +	data |= ((mode & DSC_MODE_VIDEO) ? 1 : 0) << 9;

Yuck. if (mode & DSC_MODE_VIDEO) data |= BIT(9);.

> +	if (ich_reset_override)
> +		data |= 0xC00; // set bit 10 and 11

Instead of a comment, make this self-describing BIT(10) | BIT(11) code.

> +	data |= (_dsc_calc_ob_max_addr(hw_dsc, dsc_info->num_active_ss_per_enc) << 18);
> +
> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, data);
> +
> +	data = (dsc->dsc_version_minor & 0xf) << 28;
> +	if (dsc->dsc_version_minor == 0x2) {
> +		if (dsc->native_422)
> +			data |= BIT(22);
> +		if (dsc->native_420)
> +			data |= BIT(21);
> +	}
> +
> +	bpp = dsc->bits_per_pixel;

As above, don't forget to read the documentation on this field:

    Target bits per pixel with 4 fractional bits, bits_per_pixel << 4

> +	/* as per hw requirement bpp should be programmed
> +	 * twice the actual value in case of 420 or 422 encoding
> +	 */
> +	if (dsc->native_422 || dsc->native_420)
> +		bpp = 2 * bpp;
> +	data |= (dsc->block_pred_enable ? 1 : 0) << 20;
> +	data |= (bpp << 10);

Either wrap everything or nothing in ().

> +	data |= (dsc->line_buf_depth & 0xf) << 6;
> +	data |= dsc->convert_rgb << 4;
> +	data |= dsc->bits_per_component & 0xf;
> +
> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, data);
> +
> +	data = (dsc->pic_width & 0xffff) |
> +		((dsc->pic_height & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_PICTURE_SIZE + idx, data);
> +
> +	data = (dsc->slice_width & 0xffff) |
> +		((dsc->slice_height & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_SLICE_SIZE + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_MISC_SIZE + idx,
> +			(dsc->slice_chunk_size) & 0xffff);
> +
> +	data = (dsc->initial_xmit_delay & 0xffff) |
> +		((dsc->initial_dec_delay & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_HRD_DELAYS + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_SCALE + idx,
> +			dsc->initial_scale_value & 0x3f);
> +
> +	data = (dsc->scale_increment_interval & 0xffff) |
> +		((dsc->scale_decrement_interval & 0x7ff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_SCALE_INC_DEC + idx, data);
> +
> +	data = (dsc->first_line_bpg_offset & 0x1f) |
> +		((dsc->second_line_bpg_offset & 0x1f) << 5);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_1 + idx, data);
> +
> +	data = (dsc->nfl_bpg_offset & 0xffff) |
> +		((dsc->slice_bpg_offset & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_2 + idx, data);
> +
> +	data = (dsc->initial_offset & 0xffff) |
> +		((dsc->final_offset & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_3 + idx, data);
> +
> +	data = (dsc->nsl_bpg_offset & 0xffff) |
> +		((dsc->second_line_offset_adj & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_4 + idx, data);
> +
> +	data = (dsc->flatness_min_qp & 0x1f);
> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;

dpu_hw_dsc.c computes this on the fly.  After removing that, and
using initial_lines from the function parameters, only
dsc_info->num_active_ss_per_enc remains.  Do you really need that
msm_display_dsc_info struct here, do you need it at all?

> +
> +	DPU_REG_WRITE(hw, DSC_FLATNESS_QP + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_MODEL_SIZE + idx,
> +			(dsc->rc_model_size) & 0xffff);
> +
> +	data = dsc->rc_edge_factor & 0xf;
> +	data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8;
> +	data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13;
> +	data |= (dsc->rc_tgt_offset_high & 0xf) << 20;
> +	data |= (dsc->rc_tgt_offset_low & 0xf) << 24;
> +
> +	DPU_REG_WRITE(hw, DSC_RC_CONFIG + idx, data);
> +
> +	/* program the dsc wrapper */
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	off = hw->blk_addr + idx;
> +
> +	data = BIT(0); /* encoder enable */
> +	if (dsc->native_422)
> +		data |= BIT(8);
> +	else if (dsc->native_420)
> +		data |= BIT(9);
> +	if (!dsc->convert_rgb)
> +		data |= BIT(10);
> +	if (dsc->bits_per_component == 8)
> +		data |= BIT(11);
> +	if (mode & DSC_MODE_SPLIT_PANEL)
> +		data |= BIT(12);
> +	if (mode & DSC_MODE_MULTIPLEX)
> +		data |= BIT(13);
> +	if (!(mode & DSC_MODE_VIDEO))
> +		data |= BIT(17);
> +
> +	if (dsc_info->dsc_4hsmerge_en) {
> +		data |= dsc_info->dsc_4hsmerge_padding << 18;
> +		data |= dsc_info->dsc_4hsmerge_alignment << 22;
> +		data |= BIT(16);
> +	}
> +
> +	DPU_REG_WRITE(hw, DSC_CFG + idx, data);
> +
> +//	DPU_REG_WRITE(hw, DSC_DATA_IN_SWAP + idx, 0x14e5);

No commented-out code please, especially not with //

> +}
> +
> +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc,
> +		struct drm_dsc_config *dsc)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	struct msm_display_dsc_info *dsc_info;
> +	u32 idx, off;
> +	int i, j = 0;
> +	struct drm_dsc_rc_range_parameters *rc;
> +	u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0;
> +
> +	if (!hw_dsc || !dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +
> +	dsc_info = to_msm_dsc_info(dsc);
> +
> +	rc = dsc->rc_range_params;
> +
> +	off = 0;
> +	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
> +		data |= dsc->rc_buf_thresh[i] << (8*j);

Lack of spaces does not make this multiplication any prettier to read.

* has precedence over << but it's better to replicate the () below as
well.

> +		j++;
> +		if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) {
> +			DPU_REG_WRITE(hw, DSC_RC_BUF_THRESH_0 + idx + off,
> +					data);
> +			off += 4;
> +			j = 0;
> +			data = 0;
> +		}
> +	}
> +
> +	off = 0;
> +	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
> +		min_qp |= (rc[i].range_min_qp & 0x1f) << 5*j;
> +		max_qp |= (rc[i].range_max_qp & 0x1f) << 5*j;
> +		bpg_off |= (rc[i].range_bpg_offset & 0x3f) << 6*j;

These values _must_ already be masked to be useful in
drm_dsc_compute_rc_parameters(), no need to mask them again just like
the v1.1 block implementation.

> +		j++;
> +		if (j == 5) {
> +			DPU_REG_WRITE(hw, DSC_RC_MIN_QP_0 + idx + off,
> +					min_qp);
> +			DPU_REG_WRITE(hw, DSC_RC_MAX_QP_0 + idx + off,
> +					max_qp);
> +			DPU_REG_WRITE(hw,
> +					DSC_RC_RANGE_BPG_OFFSETS_0 + idx + off,
> +					bpg_off);
> +			off += 4;
> +			j = 0;
> +			min_qp = 0;
> +			max_qp = 0;
> +			bpg_off = 0;
> +		}
> +	}
> +}
> +
> +static void dpu_hw_dsc_bind_pingpong_blk_1_2(
> +		struct dpu_hw_dsc *hw_dsc,
> +		bool enable,
> +		const enum dpu_pingpong pp)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	int idx;
> +	int mux_cfg = 0xF; /* Disabled */

Lowercase hex (and anywhere else if I skipped any).

> +
> +	if (!hw_dsc)
> +		return;

As with the v1.1 implementation, we don't check this, and your function
below also checks it (but it does not need to).

> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +	if (enable)
> +		mux_cfg = (pp - PINGPONG_0) & 0x7;
> +
> +	DPU_REG_WRITE(hw, DSC_CTL + idx, mux_cfg);
> +}
> +
> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
> +		const unsigned long features)
> +{
> +	ops->dsc_disable = dpu_hw_dsc_disable_1_2;
> +	ops->dsc_config = dpu_hw_dsc_config_1_2;
> +	ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2;
> +	ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2;
> +}
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

All in all you really need to revise and clean your patches before
sending them to the lists; these are already far too many comments and
nits, and massively take away from reviewing code behaviour which I have
not even started with after looking at 1 out of 14 patches :(

- Marijn

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

* Re: [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block
  2023-01-23 18:24 ` [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block Kuogee Hsieh
@ 2023-01-23 20:19   ` Marijn Suijten
  0 siblings, 0 replies; 50+ messages in thread
From: Marijn Suijten @ 2023-01-23 20:19 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel

On 2023-01-23 10:24:34, Kuogee Hsieh wrote:
> This patch add DSC block and sub block to support new DSC v1.2 hardware
> encoder. Also sc7280 DSC related hardware information are added to allow
> sc7280 DSC feature be enabled at sc7280 platform.

You're not adding support (that happened in previous patches), you're
only describing SC7280 DSC blocks.  Drop the first sentence.

> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 50 +++++++++++++++++++-------
>  1 file changed, 38 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
> index 7deffc9f9..2c78a46 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
> - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>   */
>  
>  #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
> @@ -476,6 +476,7 @@ static const struct dpu_caps sc7280_dpu_caps = {
>  	.has_idle_pc = true,
>  	.max_linewidth = 2400,
>  	.pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE,
> +	.max_dsc_width = 2560,
>  };
>  
>  static const struct dpu_mdp_cfg msm8998_mdp[] = {
> @@ -1707,7 +1708,7 @@ static const struct dpu_pingpong_cfg sm8350_pp[] = {
>  };
>  
>  static const struct dpu_pingpong_cfg sc7280_pp[] = {
> -	PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1),
> +	PP_BLK("pingpong_0", PINGPONG_0, 0x69000, 0, sc7280_pp_sblk, -1, -1),

This should go in a separate Fixes: patch.

>  	PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
>  	PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1),
>  	PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1),
> @@ -1814,25 +1815,48 @@ static const struct dpu_merge_3d_cfg sm8550_merge_3d[] = {
>  /*************************************************************
>   * DSC sub blocks config
>   *************************************************************/
> -#define DSC_BLK(_name, _id, _base, _features) \
> +#define DSC_BLK_HW_1_1(_name, _id, _base, _features) \

Not sure if HW_ is necessary here, DSC_BLK_1_1 seems cleaner.

>  	{\
>  	.name = _name, .id = _id, \
>  	.base = _base, .len = 0x140, \
> -	.features = _features, \
> +	.features = BIT(DPU_DSC_HW_REV_1_1) | _features, \
> +	}
> +
> +#define DSC_BLK_HW_1_2(_name, _id, _base, _features, _sblk) \
> +	{\
> +	.name = _name, .id = _id, \
> +	.base = _base, .len = 0x140, \
> +	.features = BIT(DPU_DSC_HW_REV_1_2) | _features, \
> +	.sblk = &_sblk, \
>  	}
>  
>  static struct dpu_dsc_cfg sdm845_dsc[] = {
> -	DSC_BLK("dsc_0", DSC_0, 0x80000, 0),
> -	DSC_BLK("dsc_1", DSC_1, 0x80400, 0),
> -	DSC_BLK("dsc_2", DSC_2, 0x80800, 0),
> -	DSC_BLK("dsc_3", DSC_3, 0x80c00, 0),
> +	DSC_BLK_HW_1_1("dsc_0", DSC_0, 0x80000, 0),
> +	DSC_BLK_HW_1_1("dsc_1", DSC_1, 0x80400, 0),
> +	DSC_BLK_HW_1_1("dsc_2", DSC_2, 0x80800, 0),
> +	DSC_BLK_HW_1_1("dsc_3", DSC_3, 0x80c00, 0),
>  };
>  
>  static struct dpu_dsc_cfg sm8150_dsc[] = {
> -	DSC_BLK("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)),
> -	DSC_BLK("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)),
> -	DSC_BLK("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)),
> -	DSC_BLK("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)),
> +	DSC_BLK_HW_1_1("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_OUTPUT_CTRL)),
> +	DSC_BLK_HW_1_1("dsc_1", DSC_1, 0x80400, BIT(DPU_DSC_OUTPUT_CTRL)),
> +	DSC_BLK_HW_1_1("dsc_2", DSC_2, 0x80800, BIT(DPU_DSC_OUTPUT_CTRL)),
> +	DSC_BLK_HW_1_1("dsc_3", DSC_3, 0x80c00, BIT(DPU_DSC_OUTPUT_CTRL)),
> +};
> +
> +static struct dpu_dsc_sub_blks sc7280_dsc_sblk_0 = {
> +	.enc = {.base = 0x100, .len = 0x100},
> +	.ctl = {.base = 0xF00, .len = 0x10},
> +};
> +
> +static struct dpu_dsc_sub_blks sc7280_dsc_sblk_1 = {
> +	.enc = {.base = 0x200, .len = 0x100},
> +	.ctl = {.base = 0xF80, .len = 0x10},
> +};
> +
> +static struct dpu_dsc_cfg sc7280_dsc[] = {
> +	DSC_BLK_HW_1_2("dsc_0", DSC_0, 0x80000, BIT(DPU_DSC_NATIVE_422_EN), sc7280_dsc_sblk_0),
> +	DSC_BLK_HW_1_2("dsc_1", DSC_1, 0x80000, BIT(DPU_DSC_NATIVE_422_EN), sc7280_dsc_sblk_1),

Bit scary that the blocks have the same address, because it is purely
driven by the sub-blocks with non-overlapping offsets/ranges.  Should we
clarify that with a comment?

While at it, in v1.1 we use a hacky DSC_CTL() macro to bind a pingpong
block via a register in this magical "CTL" range at (0x1800 - 0x3FC * (m
- DSC_0)), can and/or should we represent that CTL sub-block explicitly
in the catalog for v1.1 hardware as well?

- Marijn

>  };
>  
>  /*************************************************************
> @@ -2809,6 +2833,8 @@ static const struct dpu_mdss_cfg sc7280_dpu_cfg = {
>  	.pingpong_count = ARRAY_SIZE(sc7280_pp),
>  	.pingpong = sc7280_pp,
>  	.intf_count = ARRAY_SIZE(sc7280_intf),
> +	.dsc_count = ARRAY_SIZE(sc7280_dsc),
> +	.dsc = sc7280_dsc,
>  	.intf = sc7280_intf,
>  	.vbif_count = ARRAY_SIZE(sdm845_vbif),
>  	.vbif = sdm845_vbif,
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

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

* Re: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-23 18:24 ` [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC Kuogee Hsieh
@ 2023-01-23 21:39   ` Dmitry Baryshkov
  2023-01-24  9:11   ` Dmitry Baryshkov
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 21:39 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> Current implementation timing engine programming does not consider
> compression factors. This patch add consideration of DSC factors
> while programming timing engine.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |   2 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  14 ++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 +++++++++++++--------
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>   5 files changed, 110 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> index 2d864f9..3330e185 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> @@ -279,6 +279,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
>   	if (phys_enc->hw_pp->merge_3d)
>   		intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
>   
> +	phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev;
> +
>   	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
>   	phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
>   			&timing_params, fmt);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> index 7b0b092..c6ee789 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> @@ -43,16 +43,22 @@
>   #define DPU_HW_VER_500	DPU_HW_VER(5, 0, 0) /* sm8150 v1.0 */
>   #define DPU_HW_VER_501	DPU_HW_VER(5, 0, 1) /* sm8150 v2.0 */
>   #define DPU_HW_VER_510	DPU_HW_VER(5, 1, 1) /* sc8180 */
> -#define DPU_HW_VER_600	DPU_HW_VER(6, 0, 0) /* sm8250 */
> +#define DPU_HW_VER_600	DPU_HW_VER(6, 0, 0) /* sm8250, kona */
>   #define DPU_HW_VER_620	DPU_HW_VER(6, 2, 0) /* sc7180 v1.0 */
>   #define DPU_HW_VER_630	DPU_HW_VER(6, 3, 0) /* sm6115|sm4250 */
>   #define DPU_HW_VER_650	DPU_HW_VER(6, 5, 0) /* qcm2290|sm4125 */
> -#define DPU_HW_VER_700	DPU_HW_VER(7, 0, 0) /* sm8350 */
> +#define DPU_HW_VER_700	DPU_HW_VER(7, 0, 0) /* sm8350, lahaina */
>   #define DPU_HW_VER_720	DPU_HW_VER(7, 2, 0) /* sc7280 */
>   #define DPU_HW_VER_800	DPU_HW_VER(8, 0, 0) /* sc8280xp */
> -#define DPU_HW_VER_810	DPU_HW_VER(8, 1, 0) /* sm8450 */
> +#define DPU_HW_VER_810	DPU_HW_VER(8, 1, 0) /* sm8450, waipio */
>   #define DPU_HW_VER_900	DPU_HW_VER(9, 0, 0) /* sm8550 */

No.

>   
> +/* Avoid using below IS_XXX macros outside catalog, use feature bit instead */
> +#define IS_DPU_MAJOR_SAME(rev1, rev2)   \
> +		(DPU_HW_MAJOR((rev1)) == DPU_HW_MAJOR((rev2)))
> +#define IS_DPU_MAJOR_MINOR_SAME(rev1, rev2)   \
> +		(DPU_HW_MAJOR_MINOR((rev1)) == DPU_HW_MAJOR_MINOR((rev2)))
> +
>   #define IS_MSM8996_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_170)
>   #define IS_MSM8998_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_300)
>   #define IS_SDM845_TARGET(rev) IS_DPU_MAJOR_MINOR_SAME((rev), DPU_HW_VER_400)
> @@ -240,6 +246,7 @@ enum {
>    * @DPU_INTF_INPUT_CTRL         Supports the setting of pp block from which
>    *                              pixel data arrives to this INTF
>    * @DPU_INTF_TE                 INTF block has TE configuration support
> + * @DPU_INTF_TE_ALIGN_VSYNC     INTF block has POMS Align vsync support
>    * @DPU_DATA_HCTL_EN            Allows data to be transferred at different rate
>                                   than video timing
>    * @DPU_INTF_MAX
> @@ -247,6 +254,7 @@ enum {
>   enum {
>   	DPU_INTF_INPUT_CTRL = 0x1,
>   	DPU_INTF_TE,
> +	DPU_INTF_TE_ALIGN_VSYNC,
>   	DPU_DATA_HCTL_EN,
>   	DPU_INTF_MAX
>   };
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
> index 7ce66bf..238efdb 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
> @@ -1,6 +1,6 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
>    */
>   
> @@ -44,6 +44,7 @@
>   #define   INTF_DEFLICKER_STRNG_COEFF    0x0F4
>   #define   INTF_DEFLICKER_WEAK_COEFF     0x0F8
>   
> +#define   INTF_REG_SPLIT_LINK           0x080
>   #define   INTF_DSI_CMD_MODE_TRIGGER_EN  0x084
>   #define   INTF_PANEL_FORMAT             0x090
>   #define   INTF_TPG_ENABLE               0x100
> @@ -65,9 +66,9 @@
>   
>   #define INTF_CFG_ACTIVE_H_EN	BIT(29)
>   #define INTF_CFG_ACTIVE_V_EN	BIT(30)
> -
>   #define INTF_CFG2_DATABUS_WIDEN	BIT(0)
>   #define INTF_CFG2_DATA_HCTL_EN	BIT(4)
> +#define INTF_CFG2_ALIGN_VSYNC_TO_TE BIT(16)
>   
>   #define INTF_MISR_CTRL			0x180
>   #define INTF_MISR_SIGNATURE		0x184
> @@ -91,6 +92,16 @@ static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
>   	return ERR_PTR(-EINVAL);
>   }
>   
> +static inline void _check_and_set_comp_bit(struct dpu_hw_intf *ctx,
> +		bool dsc_4hs_merge, bool compression_en, u32 *intf_cfg2)
> +{
> +	if (((DPU_HW_MAJOR(ctx->hw_rev) >= DPU_HW_MAJOR(DPU_HW_VER_700)) && compression_en)
> +		|| (IS_DPU_MAJOR_SAME(ctx->hw_rev, DPU_HW_VER_600) && dsc_4hs_merge))
> +		(*intf_cfg2) |= BIT(12);
> +	else if (!compression_en)
> +		(*intf_cfg2) &= ~BIT(12);

NAK. Make this into a sensible API rather than poking at DPU revision. 
Not to mention that this BIT(12) should be defined somewhere.

> +}
> +
>   static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>   		const struct intf_timing_params *p,
>   		const struct dpu_format *fmt)
> @@ -113,82 +124,96 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>   	/* read interface_cfg */
>   	intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
>   
> -	if (ctx->cap->type == INTF_DP)
> +	if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)

You remember, we have been here. INTF_EDP is for old (msm8974,  apq8084) 
eDP.

>   		dp_intf = true;
>   
>   	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
> -	p->h_front_porch;
> +			p->h_front_porch;
>   	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
> -	p->v_front_porch;
> +			p->v_front_porch;
>   
>   	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
> -	hsync_period) + p->hsync_skew;
> +			hsync_period) + p->hsync_skew;
>   	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
> -	p->hsync_skew - 1;
> +			p->hsync_skew - 1;

As usual. A mixture of formatting changes and data changes. Please turn 
this into reviewable changes. Split them into atomic commits. Rewriting 
the whole function is not revieweable and has no way to go in.

> +
> +	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
>   
>   	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
>   	hsync_end_x = hsync_period - p->h_front_porch - 1;
>   
> -	if (p->width != p->xres) { /* border fill added */
> -		active_h_start = hsync_start_x;
> -		active_h_end = active_h_start + p->xres - 1;
> -	} else {
> -		active_h_start = 0;
> -		active_h_end = 0;
> -	}
> -
> -	if (p->height != p->yres) { /* border fill added */
> -		active_v_start = display_v_start;
> -		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
> -	} else {
> -		active_v_start = 0;
> -		active_v_end = 0;
> -	}
> -
> -	if (active_h_end) {
> -		active_hctl = (active_h_end << 16) | active_h_start;
> -		intf_cfg |= INTF_CFG_ACTIVE_H_EN;
> -	} else {
> -		active_hctl = 0;
> -	}
> -
> -	if (active_v_end)
> -		intf_cfg |= INTF_CFG_ACTIVE_V_EN;
> -
> -	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
> -	display_hctl = (hsync_end_x << 16) | hsync_start_x;
> -
>   	/*
>   	 * DATA_HCTL_EN controls data timing which can be different from
>   	 * video timing. It is recommended to enable it for all cases, except
>   	 * if compression is enabled in 1 pixel per clock mode
>   	 */
> +	if (!p->compression_en || p->wide_bus_en)
> +		intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
> +
>   	if (p->wide_bus_en)
> -		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
> +		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
>   
> +	/*
> +	 * If widebus is disabled:
> +	 * For uncompressed stream, the data is valid for the entire active
> +	 * window period.
> +	 * For compressed stream, data is valid for a shorter time period
> +	 * inside the active window depending on the compression ratio.
> +	 *
> +	 * If widebus is enabled:
> +	 * For uncompressed stream, data is valid for only half the active
> +	 * window, since the data rate is doubled in this mode.
> +	 * p->width holds the adjusted width for DP but unadjusted width for DSI
> +	 * For compressed stream, data validity window needs to be adjusted for
> +	 * compression ratio and then further halved.
> +	 */
>   	data_width = p->width;
>   
> +	if (p->compression_en) {
> +		if (p->wide_bus_en)
> +			data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6);
> +		else
> +			data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
> +	} else if (!dp_intf && p->wide_bus_en) {
> +		data_width = p->width >> 1;
> +	} else {
> +		data_width = p->width;
> +	}
> +
>   	hsync_data_start_x = hsync_start_x;
>   	hsync_data_end_x =  hsync_start_x + data_width - 1;
>   
> +	display_hctl = (hsync_end_x << 16) | hsync_start_x;
>   	display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
>   
>   	if (dp_intf) {
>   		/* DP timing adjustment */
>   		display_v_start += p->hsync_pulse_width + p->h_back_porch;
>   		display_v_end   -= p->h_front_porch;
> +	}
> +
> +	intf_cfg |= INTF_CFG_ACTIVE_H_EN;
> +	intf_cfg |= INTF_CFG_ACTIVE_V_EN;
> +	active_h_start = hsync_start_x;
> +	active_h_end = active_h_start + p->xres - 1;
> +	active_v_start = display_v_start;
> +	active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>   
> -		active_h_start = hsync_start_x;
> -		active_h_end = active_h_start + p->xres - 1;
> -		active_v_start = display_v_start;
> -		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
> +	active_hctl = (active_h_end << 16) | active_h_start;
>   
> -		active_hctl = (active_h_end << 16) | active_h_start;
> +	if (dp_intf) {
>   		display_hctl = active_hctl;
>   
> -		intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
> +		if (p->compression_en) {
> +			active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16;
> +			active_data_hctl += hsync_start_x;
> +
> +			display_data_hctl = active_data_hctl;
> +		}
>   	}
>   
> +	_check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en, &intf_cfg2);
> +
>   	den_polarity = 0;
>   	if (ctx->cap->type == INTF_HDMI) {
>   		hsync_polarity = p->yres >= 720 ? 0 : 1;
> @@ -202,7 +227,7 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>   	}
>   	polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
>   		(vsync_polarity << 1) | /* VSYNC Polarity */
> -		(hsync_polarity << 0);  /* HSYNC Polarity */
> +		 (hsync_polarity << 0);  /* HSYNC Polarity */
>   
>   	if (!DPU_FORMAT_IS_YUV(fmt))
>   		panel_format = (fmt->bits[C0_G_Y] |
> @@ -216,6 +241,17 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>   				(COLOR_8BIT << 4) |
>   				(0x21 << 8));
>   
> +	if (p->wide_bus_en)
> +		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
> +
> +	/* Synchronize timing engine enable to TE */
> +	if ((ctx->cap->features & BIT(DPU_INTF_TE_ALIGN_VSYNC))
> +			&& p->poms_align_vsync)
> +		intf_cfg2 |= INTF_CFG2_ALIGN_VSYNC_TO_TE;
> +
> +	if (ctx->cfg.split_link_en)
> +		DPU_REG_WRITE(c, INTF_REG_SPLIT_LINK, 0x3);
> +
>   	DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
>   	DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
>   	DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
> @@ -233,11 +269,9 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>   	DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
>   	DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
>   	DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
> -	if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) {
> -		DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
> -		DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
> -		DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
> -	}
> +	DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
> +	DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
> +	DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
>   }
>   
>   static void dpu_hw_intf_enable_timing_engine(
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
> index 643dd10..57be86d 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
>    */
>   
> @@ -10,6 +10,7 @@
>   #include "dpu_hw_catalog.h"
>   #include "dpu_hw_mdss.h"
>   #include "dpu_hw_util.h"
> +#include "dpu_hw_top.h"
>   
>   struct dpu_hw_intf;
>   
> @@ -33,6 +34,11 @@ struct intf_timing_params {
>   	u32 hsync_skew;
>   
>   	bool wide_bus_en;
> +	bool compression_en;
> +	u32 extra_dto_cycles;   /* for DP only */
> +	bool dsc_4hs_merge;     /* DSC 4HS merge */
> +	bool poms_align_vsync;  /* poms with vsync aligned */
> +	u32 dce_bytes_per_line;
>   };
>   
>   struct intf_prog_fetch {
> @@ -86,11 +92,13 @@ struct dpu_hw_intf_ops {
>   
>   struct dpu_hw_intf {
>   	struct dpu_hw_blk_reg_map hw;
> +	u32 hw_rev;	/* mdss hw_rev */
>   
>   	/* intf */
>   	enum dpu_intf idx;
>   	const struct dpu_intf_cfg *cap;
>   	const struct dpu_mdss_cfg *mdss;
> +	struct split_pipe_cfg cfg;
>   
>   	/* ops */
>   	struct dpu_hw_intf_ops ops;
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
> index a1a9e44..1212fa2 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
> @@ -1,5 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
> +/*
> + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #ifndef _DPU_HW_TOP_H
> @@ -34,12 +36,14 @@ struct traffic_shaper_cfg {
>    * @intf      : Interface id for main control path
>    * @split_flush_en: Allows both the paths to be flushed when master path is
>    *              flushed
> + * @split_link_en:  Check if split link is enabled
>    */
>   struct split_pipe_cfg {
>   	bool en;
>   	enum dpu_intf_mode mode;
>   	enum dpu_intf intf;
>   	bool split_flush_en;
> +	bool split_link_en;
>   };
>   
>   /**

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism
  2023-01-23 18:24 ` [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism Kuogee Hsieh
@ 2023-01-23 21:43   ` Dmitry Baryshkov
  0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 21:43 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> A new flushing mechanism is introduced to decouple peripheral metadata
> flushing from timing engine related flush. This patch add peripheral
> flushing functions.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 24 ++++++++++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  2 +
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  7 ++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         | 43 ++++++++++++++++++++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         | 21 +++++++++++
>   5 files changed, 91 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 901e317..d2625b3 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -1472,6 +1472,12 @@ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
>   	if (extra_flush_bits && ctl->ops.update_pending_flush)
>   		ctl->ops.update_pending_flush(ctl, extra_flush_bits);
>   
> +	if (phys->hw_intf->cap->type == INTF_DP &&
> +		phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
> +						phys->comp_ratio) {

Do you really need to know comp_ratio here? And the comp_type?

> +		ctl->ops.update_pending_flush_periph(ctl, phys->hw_intf->idx);
> +	}
> +
>   	ctl->ops.trigger_flush(ctl);
>   
>   	if (ctl->ops.get_pending_flush)
> @@ -1814,12 +1820,18 @@ dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc,
>   	return DIV_ROUND_UP(total_pixels, dsc->slice_width);
>   }
>   
> -static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
> +static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
> +				     struct dpu_hw_dsc *hw_dsc,
>   				     struct dpu_hw_pingpong *hw_pp,
>   				     struct drm_dsc_config *dsc,
>   				     u32 common_mode,
>   				     u32 initial_lines)
>   {
> +	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
> +	struct dpu_hw_ctl *ctl;
> +
> +	ctl = cur_master->hw_ctl;
> +
>   	if (hw_dsc->ops.dsc_config)
>   		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);
>   
> @@ -1834,6 +1846,10 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
>   
>   	if (hw_pp->ops.enable_dsc)
>   		hw_pp->ops.enable_dsc(hw_pp);
> +
> +	if (ctl->ops.update_pending_flush_dsc)
> +		ctl->ops.update_pending_flush_dsc(ctl, hw_dsc->idx);
> +
>   }
>   
>   static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
> @@ -1877,8 +1893,10 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
>   	enc_ip_w = intf_ip_w / 2;
>   	initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
>   
> -	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
> -		dpu_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], dsc, dsc_common_mode, initial_lines);
> +	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
> +		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc,
> +					dsc_common_mode, initial_lines);
> +	}
>   }
>   
>   void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> index 1d434b2..0569b36 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> @@ -200,6 +200,8 @@ struct dpu_encoder_phys {
>   	atomic_t pending_kickoff_cnt;
>   	wait_queue_head_t pending_kickoff_wq;
>   	int irq[INTR_IDX_MAX];
> +	enum msm_display_compression_type comp_type;
> +	u32 comp_ratio;
>   };
>   
>   static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> index 48c4810..2d864f9 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> @@ -1,5 +1,6 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /* Copyright (c) 2015-2018, 2020-2021 The Linux Foundation. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
> @@ -427,6 +428,12 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
>   	if (ctl->ops.update_pending_flush_merge_3d && phys_enc->hw_pp->merge_3d)
>   		ctl->ops.update_pending_flush_merge_3d(ctl, phys_enc->hw_pp->merge_3d->idx);
>   
> +	if (phys_enc->hw_intf->cap->type == INTF_DP &&
> +		phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
> +					phys_enc->comp_ratio) {
> +		ctl->ops.update_pending_flush_periph(ctl, phys_enc->hw_intf->idx);
> +	}
> +
>   skip_flush:
>   	DPU_DEBUG_VIDENC(phys_enc,
>   		"update pending flush ctl %d intf %d\n",
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> index b88a2f3..1891c57 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
> @@ -33,6 +33,7 @@
>   #define   CTL_DSC_FLUSH                0x104
>   #define   CTL_WB_FLUSH                  0x108
>   #define   CTL_INTF_FLUSH                0x110
> +#define   CTL_PERIPH_FLUSH              0x128
>   #define   CTL_INTF_MASTER               0x134
>   #define   CTL_FETCH_PIPE_ACTIVE         0x0FC
>   
> @@ -42,11 +43,13 @@
>   #define DPU_REG_RESET_TIMEOUT_US        2000
>   #define  MERGE_3D_IDX   23
>   #define  DSC_IDX        22
> +#define  PERIPH_IDX     30
>   #define  INTF_IDX       31
>   #define WB_IDX          16
>   #define CTL_INVALID_BIT                 0xffff
>   #define CTL_DEFAULT_GROUP_ID		0xf
>   
> +

No extra empty lines please.

>   static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19,
>   	CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0,
>   	1, 2, 3, CTL_INVALID_BIT, CTL_INVALID_BIT};
> @@ -123,6 +126,7 @@ static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx,
>   	trace_dpu_hw_ctl_update_pending_flush(flushbits,
>   					      ctx->pending_flush_mask);
>   	ctx->pending_flush_mask |= flushbits;
> +
>   }
>   
>   static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
> @@ -142,6 +146,15 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
>   		DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
>   				ctx->pending_wb_flush_mask);
>   
> +	if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
> +		DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH,
> +				ctx->pending_periph_flush_mask);
> +
> +	if (ctx->pending_flush_mask & BIT(DSC_IDX)) {
> +		DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH,
> +				ctx->pending_dsc_flush_mask);
> +	}
> +
>   	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
>   }
>   
> @@ -281,6 +294,13 @@ static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
>   	ctx->pending_flush_mask |= BIT(INTF_IDX);
>   }
>   
> +static void dpu_hw_ctl_update_pending_flush_periph(struct dpu_hw_ctl *ctx,
> +		enum dpu_intf intf)
> +{
> +	ctx->pending_periph_flush_mask |= BIT(intf - INTF_0);
> +	ctx->pending_flush_mask |= BIT(PERIPH_IDX);
> +}
> +
>   static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
>   		enum dpu_merge_3d merge_3d)
>   {
> @@ -288,6 +308,13 @@ static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
>   	ctx->pending_flush_mask |= BIT(MERGE_3D_IDX);
>   }
>   
> +static void dpu_hw_ctl_update_pending_flush_dsc_v1(struct dpu_hw_ctl *ctx,
> +		enum dpu_dsc dsc_num)
> +{
> +	ctx->pending_dsc_flush_mask |= BIT(dsc_num - DSC_0);
> +	ctx->pending_flush_mask |= BIT(DSC_IDX);
> +}
> +
>   static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx,
>   	enum dpu_dspp dspp)
>   {
> @@ -472,6 +499,7 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
>   	u32 intf_active = 0;
>   	u32 wb_active = 0;
>   	u32 mode_sel = 0;
> +	u32 dsc_active = 0;
>   
>   	/* CTL_TOP[31:28] carries group_id to collate CTL paths
>   	 * per VM. Explicitly disable it until VM support is
> @@ -502,9 +530,11 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
>   	if (cfg->merge_3d)
>   		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
>   			      BIT(cfg->merge_3d - MERGE_3D_0));
> -	if (cfg->dsc) {
> -		DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, DSC_IDX);
> -		DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc);
> +
> +	if (cfg->dsc_num) {
> +		dsc_active = DPU_REG_READ(c, CTL_DSC_ACTIVE);
> +		dsc_active |= BIT(cfg->dsc_num - DSC_0);
> +		DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active);

This deserves a separate patch with Fixed tag.

>   	}
>   }
>   
> @@ -605,9 +635,16 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
>   		ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
>   		ops->update_pending_flush_intf =
>   			dpu_hw_ctl_update_pending_flush_intf_v1;
> +
> +		ops->update_pending_flush_periph =
> +			dpu_hw_ctl_update_pending_flush_periph;
> +
>   		ops->update_pending_flush_merge_3d =
>   			dpu_hw_ctl_update_pending_flush_merge_3d_v1;
>   		ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
> +
> +		ops->update_pending_flush_dsc =
> +			dpu_hw_ctl_update_pending_flush_dsc_v1;
>   	} else {
>   		ops->trigger_flush = dpu_hw_ctl_trigger_flush;
>   		ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg;
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> index 96c012e..d3faa0b1 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
> @@ -48,6 +48,7 @@ struct dpu_hw_intf_cfg {
>   	enum dpu_3d_blend_mode mode_3d;
>   	enum dpu_merge_3d merge_3d;
>   	enum dpu_ctl_mode_sel intf_mode_sel;
> +	enum dpu_dsc dsc_num;
>   	int stream_sel;
>   	unsigned int dsc;
>   };
> @@ -121,6 +122,15 @@ struct dpu_hw_ctl_ops {
>   		enum dpu_intf blk);
>   
>   	/**
> +	 * OR in the given flushbits to the cached pending_(periph_)flush_mask
> +	 * No effect on hardware
> +	 * @ctx       : ctl path ctx pointer
> +	 * @blk       : interface block index
> +	 */
> +	void (*update_pending_flush_periph)(struct dpu_hw_ctl *ctx,
> +		enum dpu_intf blk);
> +
> +	/**
>   	 * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask
>   	 * No effect on hardware
>   	 * @ctx       : ctl path ctx pointer
> @@ -156,6 +166,15 @@ struct dpu_hw_ctl_ops {
>   	void (*update_pending_flush_dspp)(struct dpu_hw_ctl *ctx,
>   		enum dpu_dspp blk);
>   	/**
> +	 * OR in the given flushbits to the cached pending_(dsc_)flush_mask
> +	 * No effect on hardware
> +	 * @ctx       : ctl path ctx pointer
> +	 * @blk       : interface block index
> +	 */
> +	void (*update_pending_flush_dsc)(struct dpu_hw_ctl *ctx,
> +		enum dpu_dsc blk);
> +
> +	/**
>   	 * Write the value of the pending_flush_mask to hardware
>   	 * @ctx       : ctl path ctx pointer
>   	 */
> @@ -241,7 +260,9 @@ struct dpu_hw_ctl {
>   	u32 pending_flush_mask;
>   	u32 pending_intf_flush_mask;
>   	u32 pending_wb_flush_mask;
> +	u32 pending_periph_flush_mask;
>   	u32 pending_merge_3d_flush_mask;
> +	u32 pending_dsc_flush_mask;
>   
>   	/* ops */
>   	struct dpu_hw_ctl_ops ops;

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 07/14] drm/msm/dp: add dsc helper functions
  2023-01-23 18:24 ` [PATCH v1 07/14] drm/msm/dp: add dsc helper functions Kuogee Hsieh
@ 2023-01-23 22:02   ` Dmitry Baryshkov
  2023-01-23 22:08   ` Marijn Suijten
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:02 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> Add DSC related supporting functions to calculate DSC related parameters.
> In addition, DSC hardware encoder customized configuration parameters are
> also included. Algorithms used to perform calculation are derived from
> system engineer spreadsheet.

Overall impression. First rewrite this patch to use existing data 
structures and helpers. Then move the remnants to the 
drm/display/drm_dsc_helper.c.

> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/Makefile                   |   1 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c | 537 +++++++++++++++++++++++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h |  25 ++
>   drivers/gpu/drm/msm/msm_drv.h                  |   4 +
>   4 files changed, 567 insertions(+)
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 7274c412..28cf52b 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>   	disp/dpu1/dpu_hw_catalog.o \
>   	disp/dpu1/dpu_hw_ctl.o \
>   	disp/dpu1/dpu_hw_dsc.o \
> +	disp/dpu1/dpu_dsc_helper.o \
>   	disp/dpu1/dpu_hw_interrupts.o \
>   	disp/dpu1/dpu_hw_intf.o \
>   	disp/dpu1/dpu_hw_lm.o \
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
> new file mode 100644
> index 00000000..48cef23
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
> @@ -0,0 +1,537 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2012-2023 The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#include "msm_drv.h"
> +#include "dpu_kms.h"
> +#include "dpu_hw_dsc.h"
> +#include "dpu_dsc_helper.h"
> +
> +
> +#define DPU_DSC_PPS_SIZE       128

doesn't sizeof(drm_dsc_picture_parameter_set) work instead?

> +
> +enum dpu_dsc_ratio_type {
> +	DSC_V11_8BPC_8BPP,
> +	DSC_V11_10BPC_8BPP,
> +	DSC_V11_10BPC_10BPP,
> +	DSC_V11_SCR1_8BPC_8BPP,
> +	DSC_V11_SCR1_10BPC_8BPP,
> +	DSC_V11_SCR1_10BPC_10BPP,
> +	DSC_V12_444_8BPC_8BPP = DSC_V11_SCR1_8BPC_8BPP,
> +	DSC_V12_444_10BPC_8BPP = DSC_V11_SCR1_10BPC_8BPP,
> +	DSC_V12_444_10BPC_10BPP = DSC_V11_SCR1_10BPC_10BPP,
> +	DSC_V12_422_8BPC_7BPP,
> +	DSC_V12_422_8BPC_8BPP,
> +	DSC_V12_422_10BPC_7BPP,
> +	DSC_V12_422_10BPC_10BPP,
> +	DSC_V12_420_8BPC_6BPP,
> +	DSC_V12_420_10BPC_6BPP,
> +	DSC_V12_420_10BPC_7_5BPP,
> +	DSC_RATIO_TYPE_MAX
> +};
> +
> +
> +static u16 dpu_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = {
> +		0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
> +		0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e
> +};
> +
> +/*
> + * Rate control - Min QP values for each ratio type in dpu_dsc_ratio_type
> + */
> +static char dpu_dsc_rc_range_min_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
> +	/* DSC v1.1 */
> +	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13},
> +	{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17},
> +	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
> +	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
> +	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12},
> +	{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16},
> +	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
> +	/* DSC v1.2 YUV422 */
> +	{0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11},
> +	{0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10},
> +	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
> +	{0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12},
> +	/* DSC v1.2 YUV420 */
> +	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10},
> +	{0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14},
> +	{0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12},
> +};
> +
> +/*
> + * Rate control - Max QP values for each ratio type in dpu_dsc_ratio_type
> + */
> +static char dpu_dsc_rc_range_max_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
> +	/* DSC v1.1 */
> +	{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15},
> +	{4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19},
> +	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
> +	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
> +	{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13},
> +	{8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17},
> +	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
> +	/* DSC v1.2 YUV422 */
> +	{3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12},
> +	{2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11},
> +	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
> +	{2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13},
> +	/* DSC v1.2 YUV420 */
> +	{2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 12},
> +	{2, 5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15},
> +	{2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13},
> +	};
> +
> +/*
> + * Rate control - bpg offset values for each ratio type in dpu_dsc_ratio_type
> + */
> +static char dpu_dsc_rc_range_bpg[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
> +	/* DSC v1.1 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	/* DSC v1.1 SCR and DSC V1.2 RGB 444 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	/* DSC v1.2 YUV422 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	{10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12},
> +	/* DSC v1.2 YUV420 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12},
> +};
> +
> +static struct dpu_dsc_rc_init_params_lut {
> +	u32 rc_quant_incr_limit0;
> +	u32 rc_quant_incr_limit1;
> +	u32 initial_fullness_offset;
> +	u32 initial_xmit_delay;
> +	u32 second_line_bpg_offset;
> +	u32 second_line_offset_adj;
> +	u32 flatness_min_qp;
> +	u32 flatness_max_qp;
> +}  dpu_dsc_rc_init_param_lut[] = {
> +	/* DSC v1.1 */
> +	{11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V11_8BPC_8BPP */
> +	{15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V11_10BPC_8BPP */
> +	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V11_10BPC_10BPP */
> +	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
> +	{11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V12_444_8BPC_8BPP or DSC_V11_SCR1_8BPC_8BPP */
> +	{15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_8BPP or DSC_V11_SCR1_10BPC_8BPP */
> +	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_10BPP or DSC_V11_SCR1_10BPC_10BPP */
> +	/* DSC v1.2 YUV422 */
> +	{11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */
> +	{11, 11, 2048, 341, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_8BPP */
> +	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_7BPP */
> +	{15, 15, 2048, 273, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_10BPP */
> +	/* DSC v1.2 YUV420 */
> +	{11, 11, 5632, 410, 0, 0, 3, 12},    /* DSC_V12_422_8BPC_7BPP */
> +	{11, 11, 2048, 341, 12, 512, 3, 12}, /* DSC_V12_420_8BPC_6BPP */
> +	{15, 15, 2048, 341, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_6BPP */
> +	{15, 15, 2048, 256, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_7_5BPP */
> +};
> +
> +/**
> + * Maps to lookup the dpu_dsc_ratio_type index used in rate control tables
> + */
> +static struct dpu_dsc_table_index_lut {
> +	u32 fmt;
> +	u32 scr_ver;
> +	u32 minor_ver;
> +	u32 bpc;
> +	u32 bpp;
> +	u32 type;
> +} dpu_dsc_index_map[] = {
> +	/* DSC 1.1 formats - scr version is considered */
> +	{MSM_CHROMA_444, 0, 1, 8, 8, DSC_V11_8BPC_8BPP},
> +	{MSM_CHROMA_444, 0, 1, 10, 8, DSC_V11_10BPC_8BPP},
> +	{MSM_CHROMA_444, 0, 1, 10, 10, DSC_V11_10BPC_10BPP},
> +
> +	{MSM_CHROMA_444, 1, 1, 8, 8, DSC_V11_SCR1_8BPC_8BPP},
> +	{MSM_CHROMA_444, 1, 1, 10, 8, DSC_V11_SCR1_10BPC_8BPP},
> +	{MSM_CHROMA_444, 1, 1, 10, 10, DSC_V11_SCR1_10BPC_10BPP},
> +
> +	/* DSC 1.2 formats - scr version is no-op */

Such distinctions begs to split this table into a pair or three of them.

> +	{MSM_CHROMA_444, -1, 2, 8, 8, DSC_V12_444_8BPC_8BPP},
> +	{MSM_CHROMA_444, -1, 2, 10, 8, DSC_V12_444_10BPC_8BPP},
> +	{MSM_CHROMA_444, -1, 2, 10, 10, DSC_V12_444_10BPC_10BPP},
> +
> +	{MSM_CHROMA_422, -1, 2, 8, 7, DSC_V12_422_8BPC_7BPP},
> +	{MSM_CHROMA_422, -1, 2, 8, 8, DSC_V12_422_8BPC_8BPP},
> +	{MSM_CHROMA_422, -1, 2, 10, 7, DSC_V12_422_10BPC_7BPP},
> +	{MSM_CHROMA_422, -1, 2, 10, 10, DSC_V12_422_10BPC_10BPP},
> +
> +	{MSM_CHROMA_420, -1, 2, 8, 6, DSC_V12_420_8BPC_6BPP},
> +	{MSM_CHROMA_420, -1, 2, 10, 6, DSC_V12_420_10BPC_6BPP},
> +};
> +
> +static int _get_rc_table_index(struct drm_dsc_config *dsc, int scr_ver)
> +{
> +	u32 bpp, bpc, i, fmt = MSM_CHROMA_444;
> +
> +	if (dsc->dsc_version_major != 0x1) {
> +		DPU_ERROR("unsupported major version %d\n",
> +				dsc->dsc_version_major);
> +		return -EINVAL;
> +	}
> +
> +	bpc = dsc->bits_per_component;
> +	bpp = DSC_BPP(*dsc);
> +
> +	if (dsc->native_422)
> +		fmt = MSM_CHROMA_422;
> +	else if (dsc->native_420)
> +		fmt = MSM_CHROMA_420;
> +
> +
> +	for (i = 0; i < ARRAY_SIZE(dpu_dsc_index_map); i++) {
> +		if (dsc->dsc_version_minor == dpu_dsc_index_map[i].minor_ver &&
> +				fmt ==  dpu_dsc_index_map[i].fmt &&
> +				bpc == dpu_dsc_index_map[i].bpc &&
> +				bpp == dpu_dsc_index_map[i].bpp &&
> +				(dsc->dsc_version_minor != 0x1 ||
> +					scr_ver == dpu_dsc_index_map[i].scr_ver))
> +			return dpu_dsc_index_map[i].type;
> +	}
> +
> +	DPU_ERROR("unsupported DSC v%d.%dr%d, bpc:%d, bpp:%d, fmt:0x%x\n",
> +			dsc->dsc_version_major, dsc->dsc_version_minor,
> +			scr_ver, bpc, bpp, fmt);
> +	return -EINVAL;
> +}
> +
> +u8 _get_dsc_v1_2_bpg_offset(struct drm_dsc_config *dsc)
> +{
> +	u8 bpg_offset = 0;
> +	u8 uncompressed_bpg_rate;
> +	u8 bpp = DSC_BPP(*dsc);
> +
> +	if (dsc->slice_height < 8)
> +		bpg_offset = 2 * (dsc->slice_height - 1);
> +	else if (dsc->slice_height < 20)
> +		bpg_offset = 12;
> +	else if (dsc->slice_height <= 30)
> +		bpg_offset = 13;
> +	else if (dsc->slice_height < 42)
> +		bpg_offset = 14;
> +	else
> +		bpg_offset = 15;
> +
> +	if (dsc->native_422)
> +		uncompressed_bpg_rate = 3 * bpp * 4;
> +	else if (dsc->native_420)
> +		uncompressed_bpg_rate = 3 * bpp;
> +	else
> +		uncompressed_bpg_rate = (3 * bpp + 2) * 3;
> +
> +	if (bpg_offset < (uncompressed_bpg_rate - (3 * bpp)))
> +		return bpg_offset;
> +	else
> +		return (uncompressed_bpg_rate - (3 * bpp));
> +}
> +
> +int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver)
> +{
> +	int bpp, bpc;
> +	int groups_per_line, groups_total;
> +	int min_rate_buffer_size;
> +	int hrd_delay;
> +	int pre_num_extra_mux_bits, num_extra_mux_bits;
> +	int slice_bits;
> +	int data;
> +	int final_value, final_scale;
> +	struct dpu_dsc_rc_init_params_lut *rc_param_lut;
> +	u32 slice_width_mod;
> +	int i, ratio_idx;

We just got rid of a duplicate of drm_dsc_compute_rc_parameters(), so we 
are not going to introduce another one. Please use that function to 
compute relevant parameters.

> +
> +	dsc->rc_model_size = 8192;
> +
> +	if ((dsc->dsc_version_major == 0x1) &&
> +			(dsc->dsc_version_minor == 0x1)) {
> +		if (scr_ver == 0x1)
> +			dsc->first_line_bpg_offset = 15;
> +		else
> +			dsc->first_line_bpg_offset = 12;
> +	} else if (dsc->dsc_version_minor == 0x2) {
> +		dsc->first_line_bpg_offset = _get_dsc_v1_2_bpg_offset(dsc);
> +	}
> +
> +	dsc->rc_edge_factor = 6;
> +	dsc->rc_tgt_offset_high = 3;
> +	dsc->rc_tgt_offset_low = 3;
> +	dsc->simple_422 = 0;
> +	dsc->convert_rgb = !(dsc->native_422 | dsc->native_420);
> +	dsc->vbr_enable = 0;
> +
> +	bpp = DSC_BPP(*dsc);
> +	bpc = dsc->bits_per_component;
> +
> +	ratio_idx = _get_rc_table_index(dsc, scr_ver);
> +	if ((ratio_idx < 0) || (ratio_idx >= DSC_RATIO_TYPE_MAX))
> +		return -EINVAL;
> +
> +
> +	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
> +		dsc->rc_buf_thresh[i] = dpu_dsc_rc_buf_thresh[i];
> +
> +	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
> +		dsc->rc_range_params[i].range_min_qp =
> +			dpu_dsc_rc_range_min_qp[ratio_idx][i];
> +		dsc->rc_range_params[i].range_max_qp =
> +			dpu_dsc_rc_range_max_qp[ratio_idx][i];
> +		dsc->rc_range_params[i].range_bpg_offset =
> +			dpu_dsc_rc_range_bpg[ratio_idx][i];
> +	}
> +
> +	rc_param_lut = &dpu_dsc_rc_init_param_lut[ratio_idx];
> +	dsc->rc_quant_incr_limit0 = rc_param_lut->rc_quant_incr_limit0;
> +	dsc->rc_quant_incr_limit1 = rc_param_lut->rc_quant_incr_limit1;
> +	dsc->initial_offset = rc_param_lut->initial_fullness_offset;
> +	dsc->initial_xmit_delay = rc_param_lut->initial_xmit_delay;
> +	dsc->second_line_bpg_offset = rc_param_lut->second_line_bpg_offset;
> +	dsc->second_line_offset_adj = rc_param_lut->second_line_offset_adj;
> +	dsc->flatness_min_qp = rc_param_lut->flatness_min_qp;
> +	dsc->flatness_max_qp = rc_param_lut->flatness_max_qp;
> +
> +	slice_width_mod = dsc->slice_width;
> +	if (dsc->native_422 || dsc->native_420) {
> +		slice_width_mod = dsc->slice_width / 2;
> +		bpp = bpp * 2;
> +	}
> +
> +	dsc->line_buf_depth = bpc + 1;
> +	dsc->mux_word_size = bpc > 10 ? DSC_MUX_WORD_SIZE_12_BPC : DSC_MUX_WORD_SIZE_8_10_BPC;
> +
> +	if ((dsc->dsc_version_minor == 0x2) && (dsc->native_420))
> +		dsc->nsl_bpg_offset = (2048 * (DIV_ROUND_UP(dsc->second_line_bpg_offset,
> +				(dsc->slice_height - 1))));
> +
> +	groups_per_line = DIV_ROUND_UP(slice_width_mod, 3);
> +
> +	dsc->slice_chunk_size = slice_width_mod * bpp / 8;
> +	if ((slice_width_mod * bpp) % 8)
> +		dsc->slice_chunk_size++;
> +
> +	/* rbs-min */
> +	min_rate_buffer_size =  dsc->rc_model_size - dsc->initial_offset +
> +			dsc->initial_xmit_delay * bpp +
> +			groups_per_line * dsc->first_line_bpg_offset;
> +
> +	hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp);
> +
> +	dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
> +
> +	dsc->initial_scale_value = 8 * dsc->rc_model_size /
> +			(dsc->rc_model_size - dsc->initial_offset);
> +
> +	slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height;
> +
> +	groups_total = groups_per_line * dsc->slice_height;
> +
> +	data = dsc->first_line_bpg_offset * 2048;
> +
> +	dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
> +
> +	if (dsc->native_422)
> +		pre_num_extra_mux_bits = 4 * dsc->mux_word_size + (4 * bpc + 4) + (3 * 4 * bpc) - 2;
> +	else if (dsc->native_420)
> +		pre_num_extra_mux_bits = 3 * dsc->mux_word_size + (4 * bpc + 4) + (2 * 4 * bpc) - 2;
> +	else
> +		pre_num_extra_mux_bits = 3 * (dsc->mux_word_size + (4 * bpc + 4) - 2);
> +
> +	num_extra_mux_bits = pre_num_extra_mux_bits - (dsc->mux_word_size -
> +		((slice_bits - pre_num_extra_mux_bits) % dsc->mux_word_size));
> +
> +	data = 2048 * (dsc->rc_model_size - dsc->initial_offset
> +		+ num_extra_mux_bits);
> +	dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
> +
> +	data = dsc->initial_xmit_delay * bpp;
> +	final_value =  dsc->rc_model_size - data + num_extra_mux_bits;
> +
> +	final_scale = 8 * dsc->rc_model_size /
> +		(dsc->rc_model_size - final_value);
> +
> +	dsc->final_offset = final_value;
> +
> +	data = (final_scale - 9) * (dsc->nfl_bpg_offset +
> +		dsc->slice_bpg_offset);
> +	dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
> +
> +	dsc->scale_decrement_interval = groups_per_line /
> +		(dsc->initial_scale_value - 8);
> +
> +	return 0;
> +}
> +
> +bool dpu_dsc_ich_reset_override_needed(bool pu_en,
> +		struct msm_display_dsc_info *dsc_info)
> +{
> +	/*
> +	 * As per the DSC spec, ICH_RESET can be either end of the slice line
> +	 * or at the end of the slice. HW internally generates ich_reset at
> +	 * end of the slice line if DSC_MERGE is used or encoder has two
> +	 * soft slices. However, if encoder has only 1 soft slice and DSC_MERGE
> +	 * is not used then it will generate ich_reset at the end of slice.
> +	 *
> +	 * Now as per the spec, during one PPS session, position where
> +	 * ich_reset is generated should not change. Now if full-screen frame
> +	 * has more than 1 soft slice then HW will automatically generate
> +	 * ich_reset at the end of slice_line. But for the same panel, if
> +	 * partial frame is enabled and only 1 encoder is used with 1 slice,
> +	 * then HW will generate ich_reset at end of the slice. This is a
> +	 * mismatch. Prevent this by overriding HW's decision.
> +	 */
> +	return pu_en && dsc_info && (dsc_info->drm_dsc.slice_count > 1) &&
> +		(dsc_info->drm_dsc.slice_width == dsc_info->drm_dsc.pic_width);
> +}
> +
> +int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc_info,
> +				int enc_ip_width, int dsc_cmn_mode)
> +{
> +	int max_ssm_delay, max_se_size, max_muxword_size;
> +	int compress_bpp_group, obuf_latency, input_ssm_out_latency;
> +	int base_hs_latency, chunk_bits, ob_data_width;
> +	int output_rate_extra_budget_bits, multi_hs_extra_budget_bits;
> +	int multi_hs_extra_latency,  mux_word_size;
> +	int ob_data_width_4comps, ob_data_width_3comps;
> +	int output_rate_ratio_complement, container_slice_width;
> +	int rtl_num_components, multi_hs_c, multi_hs_d;
> +
> +	int bpc = dsc_info->drm_dsc.bits_per_component;
> +	int bpp = DSC_BPP(dsc_info->drm_dsc);
> +	bool native_422 = dsc_info->drm_dsc.native_422;
> +	bool native_420 = dsc_info->drm_dsc.native_420;
> +
> +	/* Hardent core config */
> +	int multiplex_mode_enable = 0, split_panel_enable = 0;
> +	int rtl_max_bpc = 10, rtl_output_data_width = 64;
> +	int pipeline_latency = 28;
> +
> +	if (dsc_cmn_mode & DSC_MODE_MULTIPLEX)
> +		multiplex_mode_enable = 1;
> +	if (dsc_cmn_mode & DSC_MODE_SPLIT_PANEL)
> +		split_panel_enable = 1;
> +	container_slice_width = (native_422 ?
> +			dsc_info->drm_dsc.slice_width / 2 : dsc_info->drm_dsc.slice_width);
> +	max_muxword_size = (rtl_max_bpc >= 12) ? 64 : 48;
> +	max_se_size = 4 * (rtl_max_bpc + 1);
> +	max_ssm_delay = max_se_size + max_muxword_size - 1;
> +	mux_word_size = (bpc >= 12) ? 64 : 48;
> +	compress_bpp_group = native_422 ? (2 * bpp) : bpp;
> +	input_ssm_out_latency = pipeline_latency + 3 * (max_ssm_delay + 2)
> +			* dsc_info->num_active_ss_per_enc;
> +	rtl_num_components = (native_420 || native_422) ? 4 : 3;
> +	ob_data_width_4comps = (rtl_output_data_width >= (2 *
> +			max_muxword_size)) ?
> +			rtl_output_data_width :
> +			(2 * rtl_output_data_width);
> +	ob_data_width_3comps = (rtl_output_data_width >= max_muxword_size) ?
> +			rtl_output_data_width : 2 * rtl_output_data_width;
> +	ob_data_width = (rtl_num_components == 4) ?
> +			ob_data_width_4comps : ob_data_width_3comps;
> +	obuf_latency = DIV_ROUND_UP((9 * ob_data_width + mux_word_size),
> +			compress_bpp_group) + 1;
> +	base_hs_latency = dsc_info->drm_dsc.initial_xmit_delay +
> +		input_ssm_out_latency + obuf_latency;
> +	chunk_bits = 8 * dsc_info->drm_dsc.slice_chunk_size;
> +	output_rate_ratio_complement = ob_data_width - compress_bpp_group;
> +	output_rate_extra_budget_bits =
> +		(output_rate_ratio_complement * chunk_bits) >>
> +		((ob_data_width == 128) ? 7 : 6);
> +	multi_hs_c = split_panel_enable * multiplex_mode_enable;
> +	multi_hs_d = (dsc_info->num_active_ss_per_enc > 1) * (ob_data_width > compress_bpp_group);
> +	multi_hs_extra_budget_bits = multi_hs_c ?
> +				chunk_bits : (multi_hs_d ? chunk_bits :
> +					output_rate_extra_budget_bits);
> +	multi_hs_extra_latency = DIV_ROUND_UP(multi_hs_extra_budget_bits,
> +			compress_bpp_group);
> +	dsc_info->initial_lines = DIV_ROUND_UP((base_hs_latency +
> +				multi_hs_extra_latency),
> +			container_slice_width);
> +
> +	return 0;
> +}
> +
> +int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
> +					int intf_width)
> +{
> +	int  mod_offset;
> +	int slice_per_pkt, slice_per_intf;
> +	int bytes_in_slice, total_bytes_per_intf;
> +	u16 bpp;
> +	u32 bytes_in_dsc_pair;
> +	u32 total_bytes_in_dsc_pair;
> +
> +	if (!dsc_info || !dsc_info->drm_dsc.slice_width ||
> +			!dsc_info->drm_dsc.slice_height ||
> +			intf_width < dsc_info->drm_dsc.slice_width) {
> +		DPU_ERROR("invalid input, intf_width=%d slice_width=%d\n",
> +			intf_width, dsc_info ? dsc_info->drm_dsc.slice_width :
> +			-1);
> +		return -EINVAL;
> +	}
> +
> +	mod_offset = dsc_info->drm_dsc.slice_width % 3;
> +
> +
> +	switch (mod_offset) {
> +	case 0:
> +		dsc_info->slice_last_group_size = 2;
> +		break;
> +	case 1:
> +		dsc_info->slice_last_group_size = 0;
> +		break;
> +	case 2:
> +		dsc_info->slice_last_group_size = 1;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	dsc_info->det_thresh_flatness =
> +		2 << (dsc_info->drm_dsc.bits_per_component - 8);
> +
> +	slice_per_pkt = dsc_info->slice_per_pkt;
> +	slice_per_intf = DIV_ROUND_UP(intf_width,
> +			dsc_info->drm_dsc.slice_width);
> +
> +
> +	/*
> +	 * If slice_per_pkt is greater than slice_per_intf then default to 1.
> +	 * This can happen during partial update.
> +	 */
> +	if (slice_per_pkt > slice_per_intf)
> +		slice_per_pkt = 1;
> +
> +	bpp = DSC_BPP(dsc_info->drm_dsc);
> +	bytes_in_slice = DIV_ROUND_UP(dsc_info->drm_dsc.slice_width * bpp, 8);
> +	total_bytes_per_intf = bytes_in_slice * slice_per_intf;
> +
> +
> +	dsc_info->eol_byte_num = total_bytes_per_intf % 3;
> +	dsc_info->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
> +	dsc_info->bytes_in_slice = bytes_in_slice;
> +	dsc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
> +	dsc_info->pkt_per_line = slice_per_intf / slice_per_pkt;
> +
> +
> +	bytes_in_dsc_pair = DIV_ROUND_UP(bytes_in_slice * 2, 3);
> +	if (bytes_in_dsc_pair % 8) {
> +		dsc_info->dsc_4hsmerge_padding = 8 - (bytes_in_dsc_pair % 8);
> +		total_bytes_in_dsc_pair = bytes_in_dsc_pair +
> +				dsc_info->dsc_4hsmerge_padding;
> +		if (total_bytes_in_dsc_pair % 16)
> +			dsc_info->dsc_4hsmerge_alignment = 16 -
> +					(total_bytes_in_dsc_pair % 16);
> +	}
> +
> +	return 0;
> +}
> +
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
> new file mode 100644
> index 00000000..9f26455
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
> @@ -0,0 +1,25 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020 - 2023 The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#ifndef __DPU_DSC_HELPER_H__
> +#define __DPU_DSC_HELPER_H__
> +
> +#include "msm_drv.h"
> +
> +#define DSC_1_1_PPS_PARAMETER_SET_ELEMENTS   88

Where is this used?

> +
> +int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver);
> +
> +int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
> +					int intf_width);
> +
> +bool dpu_dsc_ich_reset_override_needed(bool pu_en, struct msm_display_dsc_info *dsc);
> +
> +int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc,
> +				int enc_ip_width, int dsc_cmn_mode);
> +
> +#endif /* __DPU_DSC_HELPER_H__ */
> +
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index f155803..cf4eb8d 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -57,6 +57,10 @@ struct msm_disp_state;
>   #define MAX_CRTCS      8
>   #define MAX_BRIDGES    8
>   
> +#define MSM_CHROMA_444 0x0
> +#define MSM_CHROMA_422 0x1
> +#define MSM_CHROMA_420 0x2

enum?

> +
>   #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
>   
>   enum msm_dp_controller {

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder
  2023-01-23 18:24 ` [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Kuogee Hsieh
@ 2023-01-23 22:06   ` Dmitry Baryshkov
  2023-01-24 15:06   ` Neil Armstrong
  2023-01-30 20:27   ` Marijn Suijten
  2 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:06 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> struct msm_compression_info is used to support several different
> compression mechanisms. It also contains customized info required
> to configure DSC encoder engine. This patch also make changes DSI
> module to have DSI exports struct msm_compreion_info to dpu encoder
> instead of struct drm_dsc_config.

Let's see how patch 07 evolves first. But generally I don't like the 
idea of passing around another wrapper structure.

> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  7 +++++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 ++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 10 ++++++++--
>   drivers/gpu/drm/msm/dsi/dsi.c               |  3 ++-
>   drivers/gpu/drm/msm/dsi/dsi.h               |  3 ++-
>   drivers/gpu/drm/msm/dsi/dsi_host.c          | 14 ++++++++++++--
>   drivers/gpu/drm/msm/msm_drv.h               |  4 ++--
>   7 files changed, 33 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 758261e..7f4a439 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -2,7 +2,7 @@
>   /*
>    * Copyright (C) 2013 Red Hat
>    * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved.
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    *
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
> @@ -210,6 +210,7 @@ struct dpu_encoder_virt {
>   
>   	/* DSC configuration */
>   	struct drm_dsc_config *dsc;
> +	struct msm_compression_info *comp_info;
>   };
>   
>   #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base)
> @@ -2275,7 +2276,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>   		dpu_enc->idle_pc_supported =
>   				dpu_kms->catalog->caps->has_idle_pc;
>   
> -	dpu_enc->dsc = disp_info->dsc;
> +	dpu_enc->comp_info = disp_info->comp_info;
> +	if (dpu_enc->comp_info)
> +		dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc;
>   
>   	mutex_lock(&dpu_enc->enc_lock);
>   	for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) {
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> index 9e7236e..bd2da5e 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
>    * Copyright (C) 2013 Red Hat
>    * Author: Rob Clark <robdclark@gmail.com>
> @@ -36,7 +36,7 @@ struct msm_display_info {
>   	uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
>   	bool is_cmd_mode;
>   	bool is_te_using_watchdog_timer;
> -	struct drm_dsc_config *dsc;
> +	struct msm_compression_info *comp_info;
>   };
>   
>   /**
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index d612419..70a74ed 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -2,7 +2,7 @@
>   /*
>    * Copyright (C) 2013 Red Hat
>    * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    *
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
> @@ -570,7 +570,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
>   		info.h_tile_instance[info.num_of_h_tiles++] = i;
>   		info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);
>   
> -		info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]);
> +		info.comp_info = msm_dsi_get_dsc_config(priv->dsi[i]);
>   
>   		if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) {
>   			rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder);
> @@ -622,6 +622,8 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
>   		info.num_of_h_tiles = 1;
>   		info.h_tile_instance[0] = i;
>   		info.intf_type = encoder->encoder_type;
> +		info.is_cmd_mode = 0; /* dp always video mode */
> +		info.comp_info = NULL;
>   		rc = dpu_encoder_setup(dev, encoder, &info);
>   		if (rc) {
>   			DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
> @@ -892,6 +894,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
>   
>   	pm_runtime_get_sync(&dpu_kms->pdev->dev);
>   
> +	for (i = 0; i < cat->dsc_count; i++)
> +		msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len,
> +				dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i);
> +

unrelated, isn't it?

>   	/* dump CTL sub-blocks HW regs info */
>   	for (i = 0; i < cat->ctl_count; i++)
>   		msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len,
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> index 31fdee2..52b7e33 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include "dsi.h"
> @@ -13,7 +14,7 @@ bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>   	return !(host_flags & MIPI_DSI_MODE_VIDEO);
>   }
>   
> -struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
> +struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
>   {
>   	return msm_dsi_host_get_dsc_config(msm_dsi->host);
>   }
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index bd3763a..79ada54 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
>    * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #ifndef __DSI_CONNECTOR_H__
> @@ -133,7 +134,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
>   int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host);
>   void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host);
> -struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
> +struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
>   
>   /* dsi phy */
>   struct msm_dsi_phy;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> index 18fa30e..6188f4b 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include <linux/clk.h>
> @@ -163,6 +164,7 @@ struct msm_dsi_host {
>   
>   	struct drm_display_mode *mode;
>   	struct drm_dsc_config *dsc;
> +	struct msm_compression_info comp_info;
>   
>   	/* connected device info */
>   	unsigned int channel;
> @@ -2600,9 +2602,17 @@ void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host)
>   				DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER);
>   }
>   
> -struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
> +struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
>   {
>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> +	struct msm_compression_info *comp_info = NULL;
>   
> -	return msm_host->dsc;
> +	if (msm_host->dsc) {
> +		comp_info = &msm_host->comp_info;
> +		comp_info->msm_dsc_info.drm_dsc = *msm_host->dsc;
> +		comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC;
> +		comp_info->enabled = true;
> +	}
> +
> +	return comp_info;
>   }
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index 6a46ed7..eab0901 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -430,7 +430,7 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi
>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi);
>   bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi);
>   bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi);
> -struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
> +struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
>   #else
>   static inline void __init msm_dsi_register(void)
>   {
> @@ -460,7 +460,7 @@ static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)
>   	return false;
>   }
>   
> -static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
> +static inline struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
>   {
>   	return NULL;
>   }

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 07/14] drm/msm/dp: add dsc helper functions
  2023-01-23 18:24 ` [PATCH v1 07/14] drm/msm/dp: add dsc helper functions Kuogee Hsieh
  2023-01-23 22:02   ` Dmitry Baryshkov
@ 2023-01-23 22:08   ` Marijn Suijten
  1 sibling, 0 replies; 50+ messages in thread
From: Marijn Suijten @ 2023-01-23 22:08 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel

This has nothing to do with /dp, make it /dpu


On 2023-01-23 10:24:27, Kuogee Hsieh wrote:
> Add DSC related supporting functions to calculate DSC related parameters.
> In addition, DSC hardware encoder customized configuration parameters are
> also included. Algorithms used to perform calculation are derived from
> system engineer spreadsheet.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>  drivers/gpu/drm/msm/Makefile                   |   1 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c | 537 +++++++++++++++++++++++++
>  drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h |  25 ++
>  drivers/gpu/drm/msm/msm_drv.h                  |   4 +
>  4 files changed, 567 insertions(+)
>  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
>  create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 7274c412..28cf52b 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>  	disp/dpu1/dpu_hw_catalog.o \
>  	disp/dpu1/dpu_hw_ctl.o \
>  	disp/dpu1/dpu_hw_dsc.o \
> +	disp/dpu1/dpu_dsc_helper.o \
>  	disp/dpu1/dpu_hw_interrupts.o \
>  	disp/dpu1/dpu_hw_intf.o \
>  	disp/dpu1/dpu_hw_lm.o \
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
> new file mode 100644
> index 00000000..48cef23
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
> @@ -0,0 +1,537 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2012-2023 The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#include "msm_drv.h"
> +#include "dpu_kms.h"
> +#include "dpu_hw_dsc.h"
> +#include "dpu_dsc_helper.h"
> +
> +
> +#define DPU_DSC_PPS_SIZE       128
> +
> +enum dpu_dsc_ratio_type {
> +	DSC_V11_8BPC_8BPP,
> +	DSC_V11_10BPC_8BPP,
> +	DSC_V11_10BPC_10BPP,
> +	DSC_V11_SCR1_8BPC_8BPP,
> +	DSC_V11_SCR1_10BPC_8BPP,
> +	DSC_V11_SCR1_10BPC_10BPP,
> +	DSC_V12_444_8BPC_8BPP = DSC_V11_SCR1_8BPC_8BPP,
> +	DSC_V12_444_10BPC_8BPP = DSC_V11_SCR1_10BPC_8BPP,
> +	DSC_V12_444_10BPC_10BPP = DSC_V11_SCR1_10BPC_10BPP,
> +	DSC_V12_422_8BPC_7BPP,
> +	DSC_V12_422_8BPC_8BPP,
> +	DSC_V12_422_10BPC_7BPP,
> +	DSC_V12_422_10BPC_10BPP,
> +	DSC_V12_420_8BPC_6BPP,
> +	DSC_V12_420_10BPC_6BPP,
> +	DSC_V12_420_10BPC_7_5BPP,
> +	DSC_RATIO_TYPE_MAX
> +};
> +
> +
> +static u16 dpu_dsc_rc_buf_thresh[DSC_NUM_BUF_RANGES - 1] = {
> +		0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
> +		0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e
> +};
> +
> +/*
> + * Rate control - Min QP values for each ratio type in dpu_dsc_ratio_type
> + */
> +static char dpu_dsc_rc_range_min_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
> +	/* DSC v1.1 */
> +	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13},
> +	{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17},
> +	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
> +	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
> +	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12},
> +	{0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16},
> +	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
> +	/* DSC v1.2 YUV422 */
> +	{0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11},
> +	{0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10},
> +	{0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15},
> +	{0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12},
> +	/* DSC v1.2 YUV420 */
> +	{0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10},
> +	{0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14},
> +	{0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12},
> +};
> +
> +/*
> + * Rate control - Max QP values for each ratio type in dpu_dsc_ratio_type
> + */
> +static char dpu_dsc_rc_range_max_qp[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
> +	/* DSC v1.1 */
> +	{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15},
> +	{4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19},
> +	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
> +	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
> +	{4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13},
> +	{8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17},
> +	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
> +	/* DSC v1.2 YUV422 */
> +	{3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12},
> +	{2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11},
> +	{7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16},
> +	{2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13},
> +	/* DSC v1.2 YUV420 */
> +	{2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 12},
> +	{2, 5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15},
> +	{2, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13},
> +	};
> +
> +/*
> + * Rate control - bpg offset values for each ratio type in dpu_dsc_ratio_type
> + */
> +static char dpu_dsc_rc_range_bpg[DSC_RATIO_TYPE_MAX][DSC_NUM_BUF_RANGES] = {
> +	/* DSC v1.1 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	/* DSC v1.1 SCR and DSC V1.2 RGB 444 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	/* DSC v1.2 YUV422 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -10, -12, -12, -12},
> +	{10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12},
> +	/* DSC v1.2 YUV420 */
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{2, 0, 0, -2, -4, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12},
> +	{10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12},
> +};
> +
> +static struct dpu_dsc_rc_init_params_lut {
> +	u32 rc_quant_incr_limit0;
> +	u32 rc_quant_incr_limit1;
> +	u32 initial_fullness_offset;
> +	u32 initial_xmit_delay;
> +	u32 second_line_bpg_offset;
> +	u32 second_line_offset_adj;
> +	u32 flatness_min_qp;
> +	u32 flatness_max_qp;
> +}  dpu_dsc_rc_init_param_lut[] = {
> +	/* DSC v1.1 */
> +	{11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V11_8BPC_8BPP */
> +	{15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V11_10BPC_8BPP */
> +	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V11_10BPC_10BPP */
> +	/* DSC v1.1 SCR and DSC v1.2 RGB 444 */
> +	{11, 11, 6144, 512, 0, 0, 3, 12}, /* DSC_V12_444_8BPC_8BPP or DSC_V11_SCR1_8BPC_8BPP */
> +	{15, 15, 6144, 512, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_8BPP or DSC_V11_SCR1_10BPC_8BPP */
> +	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_444_10BPC_10BPP or DSC_V11_SCR1_10BPC_10BPP */
> +	/* DSC v1.2 YUV422 */
> +	{11, 11, 5632, 410, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_7BPP */
> +	{11, 11, 2048, 341, 0, 0, 3, 12}, /* DSC_V12_422_8BPC_8BPP */
> +	{15, 15, 5632, 410, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_7BPP */
> +	{15, 15, 2048, 273, 0, 0, 7, 16}, /* DSC_V12_422_10BPC_10BPP */
> +	/* DSC v1.2 YUV420 */
> +	{11, 11, 5632, 410, 0, 0, 3, 12},    /* DSC_V12_422_8BPC_7BPP */
> +	{11, 11, 2048, 341, 12, 512, 3, 12}, /* DSC_V12_420_8BPC_6BPP */
> +	{15, 15, 2048, 341, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_6BPP */
> +	{15, 15, 2048, 256, 12, 512, 7, 16}, /* DSC_V12_420_10BPC_7_5BPP */
> +};
> +
> +/**
> + * Maps to lookup the dpu_dsc_ratio_type index used in rate control tables
> + */
> +static struct dpu_dsc_table_index_lut {
> +	u32 fmt;
> +	u32 scr_ver;
> +	u32 minor_ver;
> +	u32 bpc;
> +	u32 bpp;
> +	u32 type;
> +} dpu_dsc_index_map[] = {
> +	/* DSC 1.1 formats - scr version is considered */
> +	{MSM_CHROMA_444, 0, 1, 8, 8, DSC_V11_8BPC_8BPP},
> +	{MSM_CHROMA_444, 0, 1, 10, 8, DSC_V11_10BPC_8BPP},
> +	{MSM_CHROMA_444, 0, 1, 10, 10, DSC_V11_10BPC_10BPP},
> +
> +	{MSM_CHROMA_444, 1, 1, 8, 8, DSC_V11_SCR1_8BPC_8BPP},
> +	{MSM_CHROMA_444, 1, 1, 10, 8, DSC_V11_SCR1_10BPC_8BPP},
> +	{MSM_CHROMA_444, 1, 1, 10, 10, DSC_V11_SCR1_10BPC_10BPP},
> +
> +	/* DSC 1.2 formats - scr version is no-op */
> +	{MSM_CHROMA_444, -1, 2, 8, 8, DSC_V12_444_8BPC_8BPP},
> +	{MSM_CHROMA_444, -1, 2, 10, 8, DSC_V12_444_10BPC_8BPP},
> +	{MSM_CHROMA_444, -1, 2, 10, 10, DSC_V12_444_10BPC_10BPP},
> +
> +	{MSM_CHROMA_422, -1, 2, 8, 7, DSC_V12_422_8BPC_7BPP},
> +	{MSM_CHROMA_422, -1, 2, 8, 8, DSC_V12_422_8BPC_8BPP},
> +	{MSM_CHROMA_422, -1, 2, 10, 7, DSC_V12_422_10BPC_7BPP},
> +	{MSM_CHROMA_422, -1, 2, 10, 10, DSC_V12_422_10BPC_10BPP},
> +
> +	{MSM_CHROMA_420, -1, 2, 8, 6, DSC_V12_420_8BPC_6BPP},
> +	{MSM_CHROMA_420, -1, 2, 10, 6, DSC_V12_420_10BPC_6BPP},
> +};
> +
> +static int _get_rc_table_index(struct drm_dsc_config *dsc, int scr_ver)
> +{
> +	u32 bpp, bpc, i, fmt = MSM_CHROMA_444;
> +
> +	if (dsc->dsc_version_major != 0x1) {
> +		DPU_ERROR("unsupported major version %d\n",
> +				dsc->dsc_version_major);
> +		return -EINVAL;
> +	}
> +
> +	bpc = dsc->bits_per_component;
> +	bpp = DSC_BPP(*dsc);
> +
> +	if (dsc->native_422)
> +		fmt = MSM_CHROMA_422;
> +	else if (dsc->native_420)
> +		fmt = MSM_CHROMA_420;
> +
> +
> +	for (i = 0; i < ARRAY_SIZE(dpu_dsc_index_map); i++) {
> +		if (dsc->dsc_version_minor == dpu_dsc_index_map[i].minor_ver &&
> +				fmt ==  dpu_dsc_index_map[i].fmt &&
> +				bpc == dpu_dsc_index_map[i].bpc &&
> +				bpp == dpu_dsc_index_map[i].bpp &&
> +				(dsc->dsc_version_minor != 0x1 ||
> +					scr_ver == dpu_dsc_index_map[i].scr_ver))
> +			return dpu_dsc_index_map[i].type;
> +	}
> +
> +	DPU_ERROR("unsupported DSC v%d.%dr%d, bpc:%d, bpp:%d, fmt:0x%x\n",
> +			dsc->dsc_version_major, dsc->dsc_version_minor,
> +			scr_ver, bpc, bpp, fmt);
> +	return -EINVAL;
> +}
> +
> +u8 _get_dsc_v1_2_bpg_offset(struct drm_dsc_config *dsc)
> +{
> +	u8 bpg_offset = 0;
> +	u8 uncompressed_bpg_rate;
> +	u8 bpp = DSC_BPP(*dsc);
> +
> +	if (dsc->slice_height < 8)
> +		bpg_offset = 2 * (dsc->slice_height - 1);
> +	else if (dsc->slice_height < 20)
> +		bpg_offset = 12;
> +	else if (dsc->slice_height <= 30)
> +		bpg_offset = 13;
> +	else if (dsc->slice_height < 42)
> +		bpg_offset = 14;
> +	else
> +		bpg_offset = 15;
> +
> +	if (dsc->native_422)
> +		uncompressed_bpg_rate = 3 * bpp * 4;
> +	else if (dsc->native_420)
> +		uncompressed_bpg_rate = 3 * bpp;
> +	else
> +		uncompressed_bpg_rate = (3 * bpp + 2) * 3;
> +
> +	if (bpg_offset < (uncompressed_bpg_rate - (3 * bpp)))
> +		return bpg_offset;
> +	else
> +		return (uncompressed_bpg_rate - (3 * bpp));
> +}
> +
> +int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver)

We just got rid of this /wrong/ downstream gunk in [1] in favour of the
upstreamed drm_dsc_compute_rc_parameters(), don't add it back.

[1]: https://lore.kernel.org/linux-arm-msm/20221026182824.876933-7-marijn.suijten@somainline.org/

> +{
> +	int bpp, bpc;
> +	int groups_per_line, groups_total;
> +	int min_rate_buffer_size;
> +	int hrd_delay;
> +	int pre_num_extra_mux_bits, num_extra_mux_bits;
> +	int slice_bits;
> +	int data;
> +	int final_value, final_scale;
> +	struct dpu_dsc_rc_init_params_lut *rc_param_lut;
> +	u32 slice_width_mod;
> +	int i, ratio_idx;
> +
> +	dsc->rc_model_size = 8192;
> +
> +	if ((dsc->dsc_version_major == 0x1) &&
> +			(dsc->dsc_version_minor == 0x1)) {
> +		if (scr_ver == 0x1)
> +			dsc->first_line_bpg_offset = 15;
> +		else
> +			dsc->first_line_bpg_offset = 12;
> +	} else if (dsc->dsc_version_minor == 0x2) {
> +		dsc->first_line_bpg_offset = _get_dsc_v1_2_bpg_offset(dsc);
> +	}
> +
> +	dsc->rc_edge_factor = 6;
> +	dsc->rc_tgt_offset_high = 3;
> +	dsc->rc_tgt_offset_low = 3;
> +	dsc->simple_422 = 0;
> +	dsc->convert_rgb = !(dsc->native_422 | dsc->native_420);
> +	dsc->vbr_enable = 0;
> +
> +	bpp = DSC_BPP(*dsc);
> +	bpc = dsc->bits_per_component;
> +
> +	ratio_idx = _get_rc_table_index(dsc, scr_ver);
> +	if ((ratio_idx < 0) || (ratio_idx >= DSC_RATIO_TYPE_MAX))
> +		return -EINVAL;
> +
> +
> +	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++)
> +		dsc->rc_buf_thresh[i] = dpu_dsc_rc_buf_thresh[i];
> +
> +	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
> +		dsc->rc_range_params[i].range_min_qp =
> +			dpu_dsc_rc_range_min_qp[ratio_idx][i];
> +		dsc->rc_range_params[i].range_max_qp =
> +			dpu_dsc_rc_range_max_qp[ratio_idx][i];
> +		dsc->rc_range_params[i].range_bpg_offset =
> +			dpu_dsc_rc_range_bpg[ratio_idx][i];
> +	}
> +
> +	rc_param_lut = &dpu_dsc_rc_init_param_lut[ratio_idx];
> +	dsc->rc_quant_incr_limit0 = rc_param_lut->rc_quant_incr_limit0;
> +	dsc->rc_quant_incr_limit1 = rc_param_lut->rc_quant_incr_limit1;
> +	dsc->initial_offset = rc_param_lut->initial_fullness_offset;
> +	dsc->initial_xmit_delay = rc_param_lut->initial_xmit_delay;
> +	dsc->second_line_bpg_offset = rc_param_lut->second_line_bpg_offset;
> +	dsc->second_line_offset_adj = rc_param_lut->second_line_offset_adj;
> +	dsc->flatness_min_qp = rc_param_lut->flatness_min_qp;
> +	dsc->flatness_max_qp = rc_param_lut->flatness_max_qp;
> +
> +	slice_width_mod = dsc->slice_width;
> +	if (dsc->native_422 || dsc->native_420) {
> +		slice_width_mod = dsc->slice_width / 2;
> +		bpp = bpp * 2;
> +	}
> +
> +	dsc->line_buf_depth = bpc + 1;
> +	dsc->mux_word_size = bpc > 10 ? DSC_MUX_WORD_SIZE_12_BPC : DSC_MUX_WORD_SIZE_8_10_BPC;
> +
> +	if ((dsc->dsc_version_minor == 0x2) && (dsc->native_420))
> +		dsc->nsl_bpg_offset = (2048 * (DIV_ROUND_UP(dsc->second_line_bpg_offset,
> +				(dsc->slice_height - 1))));
> +
> +	groups_per_line = DIV_ROUND_UP(slice_width_mod, 3);
> +
> +	dsc->slice_chunk_size = slice_width_mod * bpp / 8;
> +	if ((slice_width_mod * bpp) % 8)
> +		dsc->slice_chunk_size++;

Besides this code being completely superfluous, please familiarize
yourself with prior DSC contributions and review, and don't add (back)
patterns that were rejected or cleaned up.

- Marijn

> +
> +	/* rbs-min */
> +	min_rate_buffer_size =  dsc->rc_model_size - dsc->initial_offset +
> +			dsc->initial_xmit_delay * bpp +
> +			groups_per_line * dsc->first_line_bpg_offset;
> +
> +	hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp);
> +
> +	dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
> +
> +	dsc->initial_scale_value = 8 * dsc->rc_model_size /
> +			(dsc->rc_model_size - dsc->initial_offset);
> +
> +	slice_bits = 8 * dsc->slice_chunk_size * dsc->slice_height;
> +
> +	groups_total = groups_per_line * dsc->slice_height;
> +
> +	data = dsc->first_line_bpg_offset * 2048;
> +
> +	dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
> +
> +	if (dsc->native_422)
> +		pre_num_extra_mux_bits = 4 * dsc->mux_word_size + (4 * bpc + 4) + (3 * 4 * bpc) - 2;
> +	else if (dsc->native_420)
> +		pre_num_extra_mux_bits = 3 * dsc->mux_word_size + (4 * bpc + 4) + (2 * 4 * bpc) - 2;
> +	else
> +		pre_num_extra_mux_bits = 3 * (dsc->mux_word_size + (4 * bpc + 4) - 2);
> +
> +	num_extra_mux_bits = pre_num_extra_mux_bits - (dsc->mux_word_size -
> +		((slice_bits - pre_num_extra_mux_bits) % dsc->mux_word_size));
> +
> +	data = 2048 * (dsc->rc_model_size - dsc->initial_offset
> +		+ num_extra_mux_bits);
> +	dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
> +
> +	data = dsc->initial_xmit_delay * bpp;
> +	final_value =  dsc->rc_model_size - data + num_extra_mux_bits;
> +
> +	final_scale = 8 * dsc->rc_model_size /
> +		(dsc->rc_model_size - final_value);
> +
> +	dsc->final_offset = final_value;
> +
> +	data = (final_scale - 9) * (dsc->nfl_bpg_offset +
> +		dsc->slice_bpg_offset);
> +	dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
> +
> +	dsc->scale_decrement_interval = groups_per_line /
> +		(dsc->initial_scale_value - 8);
> +
> +	return 0;
> +}
> +
> +bool dpu_dsc_ich_reset_override_needed(bool pu_en,
> +		struct msm_display_dsc_info *dsc_info)
> +{
> +	/*
> +	 * As per the DSC spec, ICH_RESET can be either end of the slice line
> +	 * or at the end of the slice. HW internally generates ich_reset at
> +	 * end of the slice line if DSC_MERGE is used or encoder has two
> +	 * soft slices. However, if encoder has only 1 soft slice and DSC_MERGE
> +	 * is not used then it will generate ich_reset at the end of slice.
> +	 *
> +	 * Now as per the spec, during one PPS session, position where
> +	 * ich_reset is generated should not change. Now if full-screen frame
> +	 * has more than 1 soft slice then HW will automatically generate
> +	 * ich_reset at the end of slice_line. But for the same panel, if
> +	 * partial frame is enabled and only 1 encoder is used with 1 slice,
> +	 * then HW will generate ich_reset at end of the slice. This is a
> +	 * mismatch. Prevent this by overriding HW's decision.
> +	 */
> +	return pu_en && dsc_info && (dsc_info->drm_dsc.slice_count > 1) &&
> +		(dsc_info->drm_dsc.slice_width == dsc_info->drm_dsc.pic_width);
> +}
> +
> +int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc_info,
> +				int enc_ip_width, int dsc_cmn_mode)
> +{
> +	int max_ssm_delay, max_se_size, max_muxword_size;
> +	int compress_bpp_group, obuf_latency, input_ssm_out_latency;
> +	int base_hs_latency, chunk_bits, ob_data_width;
> +	int output_rate_extra_budget_bits, multi_hs_extra_budget_bits;
> +	int multi_hs_extra_latency,  mux_word_size;
> +	int ob_data_width_4comps, ob_data_width_3comps;
> +	int output_rate_ratio_complement, container_slice_width;
> +	int rtl_num_components, multi_hs_c, multi_hs_d;
> +
> +	int bpc = dsc_info->drm_dsc.bits_per_component;
> +	int bpp = DSC_BPP(dsc_info->drm_dsc);
> +	bool native_422 = dsc_info->drm_dsc.native_422;
> +	bool native_420 = dsc_info->drm_dsc.native_420;
> +
> +	/* Hardent core config */
> +	int multiplex_mode_enable = 0, split_panel_enable = 0;
> +	int rtl_max_bpc = 10, rtl_output_data_width = 64;
> +	int pipeline_latency = 28;
> +
> +	if (dsc_cmn_mode & DSC_MODE_MULTIPLEX)
> +		multiplex_mode_enable = 1;
> +	if (dsc_cmn_mode & DSC_MODE_SPLIT_PANEL)
> +		split_panel_enable = 1;
> +	container_slice_width = (native_422 ?
> +			dsc_info->drm_dsc.slice_width / 2 : dsc_info->drm_dsc.slice_width);
> +	max_muxword_size = (rtl_max_bpc >= 12) ? 64 : 48;
> +	max_se_size = 4 * (rtl_max_bpc + 1);
> +	max_ssm_delay = max_se_size + max_muxword_size - 1;
> +	mux_word_size = (bpc >= 12) ? 64 : 48;
> +	compress_bpp_group = native_422 ? (2 * bpp) : bpp;
> +	input_ssm_out_latency = pipeline_latency + 3 * (max_ssm_delay + 2)
> +			* dsc_info->num_active_ss_per_enc;
> +	rtl_num_components = (native_420 || native_422) ? 4 : 3;
> +	ob_data_width_4comps = (rtl_output_data_width >= (2 *
> +			max_muxword_size)) ?
> +			rtl_output_data_width :
> +			(2 * rtl_output_data_width);
> +	ob_data_width_3comps = (rtl_output_data_width >= max_muxword_size) ?
> +			rtl_output_data_width : 2 * rtl_output_data_width;
> +	ob_data_width = (rtl_num_components == 4) ?
> +			ob_data_width_4comps : ob_data_width_3comps;
> +	obuf_latency = DIV_ROUND_UP((9 * ob_data_width + mux_word_size),
> +			compress_bpp_group) + 1;
> +	base_hs_latency = dsc_info->drm_dsc.initial_xmit_delay +
> +		input_ssm_out_latency + obuf_latency;
> +	chunk_bits = 8 * dsc_info->drm_dsc.slice_chunk_size;
> +	output_rate_ratio_complement = ob_data_width - compress_bpp_group;
> +	output_rate_extra_budget_bits =
> +		(output_rate_ratio_complement * chunk_bits) >>
> +		((ob_data_width == 128) ? 7 : 6);
> +	multi_hs_c = split_panel_enable * multiplex_mode_enable;
> +	multi_hs_d = (dsc_info->num_active_ss_per_enc > 1) * (ob_data_width > compress_bpp_group);
> +	multi_hs_extra_budget_bits = multi_hs_c ?
> +				chunk_bits : (multi_hs_d ? chunk_bits :
> +					output_rate_extra_budget_bits);
> +	multi_hs_extra_latency = DIV_ROUND_UP(multi_hs_extra_budget_bits,
> +			compress_bpp_group);
> +	dsc_info->initial_lines = DIV_ROUND_UP((base_hs_latency +
> +				multi_hs_extra_latency),
> +			container_slice_width);
> +
> +	return 0;
> +}
> +
> +int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
> +					int intf_width)
> +{
> +	int  mod_offset;
> +	int slice_per_pkt, slice_per_intf;
> +	int bytes_in_slice, total_bytes_per_intf;
> +	u16 bpp;
> +	u32 bytes_in_dsc_pair;
> +	u32 total_bytes_in_dsc_pair;
> +
> +	if (!dsc_info || !dsc_info->drm_dsc.slice_width ||
> +			!dsc_info->drm_dsc.slice_height ||
> +			intf_width < dsc_info->drm_dsc.slice_width) {
> +		DPU_ERROR("invalid input, intf_width=%d slice_width=%d\n",
> +			intf_width, dsc_info ? dsc_info->drm_dsc.slice_width :
> +			-1);
> +		return -EINVAL;
> +	}
> +
> +	mod_offset = dsc_info->drm_dsc.slice_width % 3;
> +
> +
> +	switch (mod_offset) {
> +	case 0:
> +		dsc_info->slice_last_group_size = 2;
> +		break;
> +	case 1:
> +		dsc_info->slice_last_group_size = 0;
> +		break;
> +	case 2:
> +		dsc_info->slice_last_group_size = 1;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	dsc_info->det_thresh_flatness =
> +		2 << (dsc_info->drm_dsc.bits_per_component - 8);
> +
> +	slice_per_pkt = dsc_info->slice_per_pkt;
> +	slice_per_intf = DIV_ROUND_UP(intf_width,
> +			dsc_info->drm_dsc.slice_width);
> +
> +
> +	/*
> +	 * If slice_per_pkt is greater than slice_per_intf then default to 1.
> +	 * This can happen during partial update.
> +	 */
> +	if (slice_per_pkt > slice_per_intf)
> +		slice_per_pkt = 1;
> +
> +	bpp = DSC_BPP(dsc_info->drm_dsc);
> +	bytes_in_slice = DIV_ROUND_UP(dsc_info->drm_dsc.slice_width * bpp, 8);
> +	total_bytes_per_intf = bytes_in_slice * slice_per_intf;
> +
> +
> +	dsc_info->eol_byte_num = total_bytes_per_intf % 3;
> +	dsc_info->pclk_per_line =  DIV_ROUND_UP(total_bytes_per_intf, 3);
> +	dsc_info->bytes_in_slice = bytes_in_slice;
> +	dsc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
> +	dsc_info->pkt_per_line = slice_per_intf / slice_per_pkt;
> +
> +
> +	bytes_in_dsc_pair = DIV_ROUND_UP(bytes_in_slice * 2, 3);
> +	if (bytes_in_dsc_pair % 8) {
> +		dsc_info->dsc_4hsmerge_padding = 8 - (bytes_in_dsc_pair % 8);
> +		total_bytes_in_dsc_pair = bytes_in_dsc_pair +
> +				dsc_info->dsc_4hsmerge_padding;
> +		if (total_bytes_in_dsc_pair % 16)
> +			dsc_info->dsc_4hsmerge_alignment = 16 -
> +					(total_bytes_in_dsc_pair % 16);
> +	}
> +
> +	return 0;
> +}
> +
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
> new file mode 100644
> index 00000000..9f26455
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
> @@ -0,0 +1,25 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020 - 2023 The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#ifndef __DPU_DSC_HELPER_H__
> +#define __DPU_DSC_HELPER_H__
> +
> +#include "msm_drv.h"
> +
> +#define DSC_1_1_PPS_PARAMETER_SET_ELEMENTS   88
> +
> +int dpu_dsc_populate_dsc_config(struct drm_dsc_config *dsc, int scr_ver);
> +
> +int dpu_dsc_populate_dsc_private_params(struct msm_display_dsc_info *dsc_info,
> +					int intf_width);
> +
> +bool dpu_dsc_ich_reset_override_needed(bool pu_en, struct msm_display_dsc_info *dsc);
> +
> +int dpu_dsc_initial_line_calc(struct msm_display_dsc_info *dsc,
> +				int enc_ip_width, int dsc_cmn_mode);
> +
> +#endif /* __DPU_DSC_HELPER_H__ */
> +
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index f155803..cf4eb8d 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -57,6 +57,10 @@ struct msm_disp_state;
>  #define MAX_CRTCS      8
>  #define MAX_BRIDGES    8
>  
> +#define MSM_CHROMA_444 0x0
> +#define MSM_CHROMA_422 0x1
> +#define MSM_CHROMA_420 0x2
> +
>  #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
>  
>  enum msm_dp_controller {
> -- 
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
> 

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

* Re: [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability
  2023-01-23 18:24 ` [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability Kuogee Hsieh
@ 2023-01-23 22:17   ` Dmitry Baryshkov
  0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:17 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> FEC is pre-requirement of DSC. Therefore FEC has to be enabled
> before DSC enabled. This patch add functions to read sink's DSC
> and FEC related DPCD and decode them and set enable flags
> accordingly.

Please split this to FEC and DSC patches.

> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_panel.c | 91 ++++++++++++++++++++++++++++++++++++++-
>   drivers/gpu/drm/msm/dp/dp_panel.h | 20 ++++++++-
>   2 files changed, 109 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
> index 1800d89..5078247 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
> @@ -1,14 +1,18 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include "dp_panel.h"
>   
> +#include <drm/drm_fixed.h>
>   #include <drm/drm_connector.h>
>   #include <drm/drm_edid.h>
>   #include <drm/drm_print.h>
>   
> +#define DSC_TGT_BPP 8
> +
>   struct dp_panel_private {
>   	struct device *dev;
>   	struct drm_device *drm_dev;
> @@ -68,6 +72,9 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
>   		goto end;
>   	}
>   
> +	print_hex_dump_debug("[drm-dp] SINK DPCD: ",
> +		DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);

I think this can go away.

> +
>   	link_info->revision = dpcd[DP_DPCD_REV];
>   	major = (link_info->revision >> 4) & 0x0f;
>   	minor = link_info->revision & 0x0f;
> @@ -154,6 +161,83 @@ static int dp_panel_update_modes(struct drm_connector *connector,
>   	return rc;
>   }
>   
> +static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel)
> +{
> +	if (dp_panel->dsc_dpcd[0]) {
> +		dp_panel->sink_dsc_caps.dsc_capable = true;
> +		dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1];
> +		dp_panel->sink_dsc_caps.block_pred_en =
> +				dp_panel->dsc_dpcd[6] ? true : false;
> +		dp_panel->sink_dsc_caps.color_depth =
> +				dp_panel->dsc_dpcd[10];
> +
> +		if (dp_panel->sink_dsc_caps.version >= 0x11)
> +			dp_panel->dsc_en = true;
> +	} else {
> +		dp_panel->sink_dsc_caps.dsc_capable = false;
> +		dp_panel->dsc_en = false;
> +	}
> +}
> +
> +static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel)
> +{
> +	int rlen;
> +	struct dp_panel_private *panel;
> +	int dpcd_rev;
> +
> +	if (!dp_panel) {
> +		DRM_ERROR("invalid input\n");
> +		return;
> +	}
> +
> +	dpcd_rev = dp_panel->dpcd[DP_DPCD_REV];
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +	if (dpcd_rev >= 0x14) {
> +		rlen = drm_dp_dpcd_read(panel->aux, DP_DSC_SUPPORT,
> +			dp_panel->dsc_dpcd, (DP_DSC_RECEIVER_CAP_SIZE + 1));
> +		if (rlen < (DP_DSC_RECEIVER_CAP_SIZE + 1)) {
> +			drm_dbg_dp(panel->drm_dev, "dsc dpcd read failed, rlen=%d\n", rlen);
> +			return;
> +		}
> +
> +		print_hex_dump_debug("[drm-dp] SINK DSC DPCD: ",
> +			DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen, false);

Oh. An extra dump again. Can we get rid of them please? Or can we use 
the standard drm debug levels? So that it would be possible to turn them 
on and off with standard params.

> +
> +		dp_panel_decode_dsc_dpcd(dp_panel);
> +	}
> +}
> +
> +static void dp_panel_read_sink_fec_caps(struct dp_panel *dp_panel)
> +{
> +	int rlen;
> +	struct dp_panel_private *panel;
> +	s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1);
> +
> +	if (!dp_panel) {
> +		DRM_ERROR("invalid input\n");
> +		return;
> +	}
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +	rlen = drm_dp_dpcd_readb(panel->aux, DP_FEC_CAPABILITY,
> +			&dp_panel->fec_dpcd);
> +	if (rlen < 1) {
> +		DRM_ERROR("fec capability read failed, rlen=%d\n", rlen);
> +		return;
> +	}
> +
> +	print_hex_dump_debug("[drm-dp] SINK FEC DPCD: ",
> +		DUMP_PREFIX_NONE, 8, 1, &dp_panel->fec_dpcd, rlen, false);
> +
> +	dp_panel->fec_en = dp_panel->fec_dpcd & DP_FEC_CAPABLE;
> +
> +	if (dp_panel->fec_en)
> +		fec_overhead_fp = drm_fixp_from_fraction(100000, 97582);
> +
> +	dp_panel->fec_overhead_fp = fec_overhead_fp;
> +}
> +
>   int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
>   	struct drm_connector *connector)
>   {
> @@ -224,6 +308,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
>   		}
>   		panel->aux_cfg_update_done = false;
>   	}
> +
> +	dp_panel_read_sink_fec_caps(dp_panel);
> +
> +	if (dp_panel->fec_en)
> +		dp_panel_read_sink_dsc_caps(dp_panel);
>   end:
>   	return rc;
>   }
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index f04d021..fb30b92 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #ifndef _DP_PANEL_H_
> @@ -11,6 +12,7 @@
>   #include "dp_aux.h"
>   #include "dp_link.h"
>   #include "dp_hpd.h"
> +#include "msm_drv.h"
>   
>   struct edid;
>   
> @@ -34,12 +36,21 @@ struct dp_panel_in {
>   	struct dp_catalog *catalog;
>   };
>   
> +struct dp_dsc_caps {
> +	bool dsc_capable;
> +	u8 version;
> +	bool block_pred_en;
> +	u8 color_depth;
> +};
> +
>   struct dp_panel {
>   	/* dpcd raw data */
>   	u8 dpcd[DP_RECEIVER_CAP_SIZE + 1];
>   	u8 ds_cap_info[DP_DOWNSTREAM_PORTS * DP_DOWNSTREAM_CAP_SIZE];
>   	u32 ds_port_cnt;
>   	u32 dfp_present;
> +	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE + 1];
> +	u8 fec_dpcd;
>   
>   	struct dp_link_info link_info;
>   	struct drm_dp_desc desc;
> @@ -53,6 +64,13 @@ struct dp_panel {
>   	u32 max_dp_link_rate;
>   
>   	u32 max_bw_code;
> +
> +	struct dp_dsc_caps sink_dsc_caps;

Why do you need both decoded and raw DSC caps?

> +	bool dsc_feature_enable;
> +	bool fec_feature_enable;
> +	bool dsc_en;
> +	bool fec_en;
> +	s64 fec_overhead_fp;
>   };
>   
>   int dp_panel_init_panel_info(struct dp_panel *dp_panel);

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller
  2023-01-23 18:24 ` [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller Kuogee Hsieh
@ 2023-01-23 22:30   ` Dmitry Baryshkov
  0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:30 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> This patch provides DSC required functions at DP controller to
> complete DSC feature. those functions include enable fec, configure
> dsc, configure dto, transmit pps and finally flush hardware registers.

Too many items for a single patch in my opinion.

> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_catalog.c | 139 ++++++++-
>   drivers/gpu/drm/msm/dp/dp_catalog.h |  93 ++++++
>   drivers/gpu/drm/msm/dp/dp_ctrl.c    | 132 ++++++++-
>   drivers/gpu/drm/msm/dp/dp_display.c |  61 +++-
>   drivers/gpu/drm/msm/dp/dp_panel.c   | 570 +++++++++++++++++++++++++++++++++++-
>   drivers/gpu/drm/msm/dp/dp_panel.h   |   4 +
>   drivers/gpu/drm/msm/dp/dp_reg.h     |  40 ++-
>   drivers/gpu/drm/msm/msm_drv.h       |  16 +
>   8 files changed, 1033 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
> index 7ac37d8..20a86e7 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.c
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
> @@ -48,6 +48,11 @@
>   #define DP_INTERRUPT_STATUS2_MASK \
>   	(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
>   
> +enum dp_flush_bit {
> +	DP_PPS_FLUSH,
> +	DP_DHDR_FLUSH,
> +};
> +
>   struct dp_catalog_private {
>   	struct device *dev;
>   	struct drm_device *drm_dev;
> @@ -277,6 +282,30 @@ static void dump_regs(void __iomem *base, int len)
>   	}
>   }
>   
> +void dp_catalog_fec_config(struct dp_catalog *dp_catalog, bool enable)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +		struct dp_catalog_private, dp_catalog);
> +	u32 reg;
> +
> +	reg = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
> +
> +	/*
> +	 * fec_en = BIT(12)
> +	 * fec_seq_mode = BIT(22)
> +	 * sde_flush = BIT(23) | BIT(24)
> +	 * fb_boundary_sel = BIT(25)

This should go to #define's instead.

> +	 */
> +	if (enable)
> +		reg |= BIT(12) | BIT(22) | BIT(23) | BIT(24) | BIT(25);
> +	else
> +		reg &= ~BIT(12);
> +
> +	dp_write_link(catalog, REG_DP_MAINLINK_CTRL, reg);
> +	/* make sure mainlink configuration is updated with fec sequence */
> +	wmb();
> +}
> +
>   void dp_catalog_dump_regs(struct dp_catalog *dp_catalog)
>   {
>   	struct dp_catalog_private *catalog = container_of(dp_catalog,
> @@ -344,6 +373,54 @@ void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 cfg)
>   	dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
>   }
>   
> +void dp_catalog_config_dsc_dto(struct dp_catalog *dp_catalog)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +	struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data;
> +	u32 reg;
> +
> +	dp_write_p0(catalog, MMSS_DP_DSC_DTO_COUNT, dsc_data->dto_count);
> +
> +	reg = dp_read_p0(catalog, MMSS_DP_DSC_DTO);
> +
> +	if (dsc_data->dto_en) {
> +		reg |= BIT(0);
> +		reg |= BIT(3);
> +		reg |= (dsc_data->dto_n << 8);
> +		reg |= (dsc_data->dto_d << 16);
> +	}
> +
> +	dp_write_p0(catalog, MMSS_DP_DSC_DTO, reg);
> +
> +	reg = 0;
> +	if (dsc_data->dsc_en) {
> +		reg = BIT(0);
> +		reg |= (dsc_data->eol_byte_num << 3);
> +		reg |= (dsc_data->slice_per_pkt << 5);
> +		reg |= (dsc_data->bytes_per_pkt << 16);
> +		reg |= (dsc_data->be_in_lane << 10);
> +	}
> +	dp_write_link(catalog, DP_COMPRESSION_MODE_CTRL, reg);
> +
> +	drm_dbg_dp(catalog->drm_dev, "compression:0x%x\n", reg);
> +}
> +
> +void dp_catalog_override_ack_dto(struct dp_catalog *dp_catalog, bool not_ack)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +        u32 dsc_dto;
> +
> +	dsc_dto = dp_read_p0(catalog, MMSS_DP_DSC_DTO);
> +        if (not_ack)
> +                dsc_dto &= ~BIT(1);
> +        else
> +                dsc_dto = BIT(1);
> +
> +	dp_write_p0(catalog, MMSS_DP_DSC_DTO, dsc_dto);

The indentation looks weird. It might be my email client. Or may be not.

> +}
> +
>   void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog)
>   {
>   	struct dp_catalog_private *catalog = container_of(dp_catalog,
> @@ -429,6 +506,15 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
>   	}
>   }
>   
> +static void dp_catalog_sdp_update( struct dp_catalog *dp_catalog)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +
> +	dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
> +	dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
> +}
> +
>   void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog,
>   					u32 colorimetry_cfg,
>   					u32 test_bits_depth)
> @@ -504,7 +590,6 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
>   	drm_dbg_dp(catalog->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid);
>   	dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid);
>   	dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid);
> -	dp_write_p0(catalog, MMSS_DP_DSC_DTO, 0x0);
>   }
>   
>   int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog,
> @@ -918,6 +1003,58 @@ void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog)
>   	dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0);
>   }
>   
> +void dp_catalog_dsc_commit_pps(struct dp_catalog *dp_catalog)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +	struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data;
> +	int i;
> +
> +	dp_write_link(catalog, DP_PPS_HB_0_3, 0x7F1000);
> +	dp_write_link(catalog, DP_PPS_PB_0_3, 0xA22300);
> +
> +	for (i = 0; i < dsc_data->parity_word_len; i++)
> +		dp_write_link(catalog, DP_PPS_PB_4_7 + (i << 2),
> +				dsc_data->parity_word[i]);
> +
> +	for (i = 0; i < dsc_data->pps_word_len; i++)
> +		dp_write_link(catalog, DP_PPS_PPS_0_3 + (i << 2),
> +				dsc_data->pps_word[i]);
> +}
> +
> +static void dp_catalog_dp_flush(struct dp_catalog *dp_catalog,
> +		enum dp_flush_bit flush_bit)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +	u32 dp_flush;
> +	struct dp_dsc_cfg_data *dsc_data = &dp_catalog->dsc_data;
> +
> +	dp_flush = dp_read_link(catalog, MMSS_DP_FLUSH);
> +
> +	dsc_data->continuous_pps = true;

This doesn't look like a part of the flush. Especially since you check 
this boolean on the next line.

> +
> +	if ((flush_bit == DP_PPS_FLUSH) && dsc_data->continuous_pps)
> +		dp_flush &= ~BIT(2);
> +
> +	dp_flush |= BIT(flush_bit);

I'd prefer to see BIT(n) as a defines rather than doing a BIT(enum_value).

> +	dp_write_link(catalog, MMSS_DP_FLUSH, dp_flush);
> +
> +	/*
> +	 * TODO: no dp_config_sdp_update() required?
> +	 */

Is it going to be resolved?

> +	dp_catalog_sdp_update(dp_catalog);
> +}
> +
> +void dp_catalog_pps_flush(struct dp_catalog *dp_catalog)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +
> +	dp_catalog_dp_flush(dp_catalog, DP_PPS_FLUSH);
> +	drm_dbg_dp(catalog->drm_dev, "pps flush\n");
> +}
> +
>   struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
>   {
>   	struct dp_catalog_private *catalog;
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
> index 990c162..537fb8d 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.h
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
> @@ -62,6 +62,27 @@ enum dp_catalog_audio_header_type {
>   	DP_AUDIO_SDP_HEADER_MAX,
>   };
>   
> +struct dp_dsc_cfg_data {
> +	bool dsc_en;
> +	bool continuous_pps;
> +	char pps[128];
> +	u32 pps_len;
> +	u32 pps_word[32];
> +	u32 pps_word_len;
> +	u8 parity[32];
> +	u8 parity_len;
> +	u32 parity_word[8];
> +	u32 parity_word_len;
> +	u32 slice_per_pkt;
> +	u32 bytes_per_pkt;
> +	u32 eol_byte_num;
> +	u32 be_in_lane;
> +	u32 dto_en;
> +	u32 dto_n;
> +	u32 dto_d;
> +	u32 dto_count;
> +};
> +
>   struct dp_catalog {
>   	u32 aux_data;
>   	u32 total;
> @@ -72,8 +93,74 @@ struct dp_catalog {
>   	enum dp_catalog_audio_header_type sdp_header;
>   	u32 audio_data;
>   	bool wide_bus_en;
> +	struct dp_dsc_cfg_data dsc_data;
>   };
>   
> +static inline u8 dp_ecc_get_g0_value(u8 data)
> +{
> +	u8 c[4];
> +	u8 g[4];
> +	u8 ret_data = 0;
> +	u8 i;
> +
> +	for (i = 0; i < 4; i++)
> +		c[i] = (data >> i) & 0x01;
> +
> +	g[0] = c[3];
> +	g[1] = c[0] ^ c[3];
> +	g[2] = c[1];
> +	g[3] = c[2];
> +
> +	for (i = 0; i < 4; i++)
> +		ret_data = ((g[i] & 0x01) << i) | ret_data;
> +
> +	return ret_data;
> +}
> +
> +static inline u8 dp_ecc_get_g1_value(u8 data)
> +{
> +	u8 c[4];
> +	u8 g[4];
> +	u8 ret_data = 0;
> +	u8 i;
> +
> +	for (i = 0; i < 4; i++)
> +		c[i] = (data >> i) & 0x01;
> +
> +	g[0] = c[0] ^ c[3];
> +	g[1] = c[0] ^ c[1] ^ c[3];
> +	g[2] = c[1] ^ c[2];
> +	g[3] = c[2] ^ c[3];
> +
> +	for (i = 0; i < 4; i++)
> +		ret_data = ((g[i] & 0x01) << i) | ret_data;
> +
> +	return ret_data;
> +}
> +
> +static inline u8 dp_header_get_parity(u32 data)
> +{
> +	u8 x0 = 0;
> +	u8 x1 = 0;
> +	u8 ci = 0;
> +	u8 iData = 0;
> +	u8 i = 0;
> +	u8 parity_byte;
> +	u8 num_byte = (data > 0xFF) ? 8 : 2;
> +
> +	for (i = 0; i < num_byte; i++) {
> +		iData = (data >> i*4) & 0xF;
> +
> +		ci = iData ^ x1;
> +		x1 = x0 ^ dp_ecc_get_g1_value(ci);
> +		x0 = dp_ecc_get_g0_value(ci);
> +	}
> +
> +	parity_byte = x1 | (x0 << 4);
> +
> +	return parity_byte;
> +}
> +

Why do we have them in the header? Are they used by more than one module?

>   /* Debug module */
>   void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *disp_state);
>   
> @@ -137,4 +224,10 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *catalog);
>   void dp_catalog_audio_init(struct dp_catalog *catalog);
>   void dp_catalog_audio_sfe_level(struct dp_catalog *catalog);
>   
> +void dp_catalog_fec_config(struct dp_catalog *dp_catalog, bool enable);
> +void dp_catalog_dsc_commit_pps(struct dp_catalog *catalog);
> +void dp_catalog_config_dsc_dto(struct dp_catalog *catalog);
> +void dp_catalog_override_ack_dto(struct dp_catalog *dp_catalog, bool not_ack);
> +void dp_catalog_pps_flush(struct dp_catalog *catalog);
> +
>   #endif /* _DP_CATALOG_H_ */
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index ae9c2b8..b315bf3 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -134,9 +134,13 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
>   	tbd = dp_link_get_test_bits_depth(ctrl->link,
>   			ctrl->panel->dp_mode.bpp);
>   
> -	if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) {
> +	/*
> +	 * since dsc encoder output byte stream to dp controller,

outputs

> +	 * 8 bits bpc should be used as long as dsc eanabled
> +	 */
> +	if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN || ctrl->panel->dsc_en) {
>   		pr_debug("BIT_DEPTH not set. Configure default\n");
> -		tbd = DP_TEST_BIT_DEPTH_8;
> +		tbd = DP_TEST_BIT_DEPTH_8 >> DP_TEST_BIT_DEPTH_SHIFT;
>   	}
>   
>   	config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT;
> @@ -366,8 +370,8 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
>   	tu->lwidth_fp            = drm_fixp_from_fraction(in->hactive, 1);
>   	tu->orig_lwidth          = in->hactive;
>   	tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1);
> -	tu->orig_hbp             = in->hporch;
> -	tu->rb2                  = (in->hporch <= 80) ? 1 : 0;
> +        tu->orig_hbp             = in->hporch;

No unnecessary indentation changes, please.

> +	tu->rb2                  = (in->hporch < 160) ? 1 : 0;


>   
>   	if (tu->pixelEnc == 420) {
>   		temp1_fp = drm_fixp_from_fraction(2, 1);
> @@ -399,6 +403,8 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
>   	if (!in->dsc_en)
>   		goto fec_check;
>   
> +	tu->bpp = 24; /* hardcode to 24 if DSC is enabled */
> +
>   	temp1_fp = drm_fixp_from_fraction(in->compress_ratio, 100);
>   	temp2_fp = drm_fixp_from_fraction(in->bpp, 1);
>   	temp3_fp = drm_fixp_div(temp2_fp, temp1_fp);
> @@ -1076,6 +1082,11 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
>   {
>   	struct dp_tu_calc_input in;
>   	struct drm_display_mode *drm_mode;
> +	struct dp_panel_info *timing;
> +	struct msm_compression_info *comp_info;
> +
> +	timing = &ctrl->panel->dp_mode.timing;
> +	comp_info = &timing->comp_info;
>   
>   	drm_mode = &ctrl->panel->dp_mode.drm_mode;
>   
> @@ -1086,12 +1097,22 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
>   	in.nlanes = ctrl->link->link_params.num_lanes;
>   	in.bpp = ctrl->panel->dp_mode.bpp;
>   	in.pixel_enc = 444;
> -	in.dsc_en = 0;
> +	in.dsc_en = ctrl->panel->dsc_en;
>   	in.async_en = 0;
> -	in.fec_en = 0;
> +	in.fec_en = ctrl->panel->fec_en;
>   	in.num_of_dsc_slices = 0;
>   	in.compress_ratio = 100;
>   
> +
> +	/*
> +	 * TODO: only one dsc slice supported for now
> +	 */
> +	if (ctrl->panel->dsc_en) {
> +		in.num_of_dsc_slices = 1;
> +		in.compress_ratio = mult_frac(100, comp_info->src_bpp,
> +                                comp_info->tgt_bpp);
> +	}
> +
>   	_dp_ctrl_calc_tu(ctrl, &in, tu_table);
>   }
>   
> @@ -1424,6 +1445,74 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
>   	return ret;
>   }
>   
> +static void dp_ctrl_sink_fec_enable(struct dp_ctrl_private *ctrl)
> +{
> +	int rlen;
> +
> +	rlen = drm_dp_dpcd_writeb(ctrl->aux, DP_FEC_CONFIGURATION, 0x07);
> +	if (rlen < 1)
> +		DRM_ERROR("failed to enable sink fec\n");
> +
> +
> +}
> +
> +static void dp_ctrl_host_fec_start(struct dp_ctrl_private *ctrl)
> +{
> +	u8 fec_sts = 0;
> +	int i, max_retries = 3;
> +	bool fec_en_detected = false;
> +
> +	if (!ctrl->panel->fec_en)
> +		return;
> +
> +	/* Need to try to enable multiple times due to BS symbols collisions */
> +	for (i = 0; i < max_retries; i++) {
> +		dp_catalog_fec_config(ctrl->catalog, true);
> +
> +		/* wait for controller to start fec sequence */
> +		usleep_range(900, 1000);
> +
> +		/* read back FEC status and check if it is enabled */
> +		drm_dp_dpcd_readb(ctrl->aux, DP_FEC_STATUS, &fec_sts);
> +		if (fec_sts & DP_FEC_DECODE_EN_DETECTED) {
> +			fec_en_detected = true;
> +			break;
> +		}
> +	}
> +
> +	drm_dbg_dp(ctrl->drm_dev, "retries %d, fec_en_detected %d\n",
> +				i, fec_en_detected);
> +
> +	if (!fec_en_detected)
> +		DRM_ERROR("failed to enable sink fec\n");
> +}
> +
> +static void dp_ctrl_host_fec_stop(struct dp_ctrl_private *ctrl)
> +{
> +	dp_catalog_fec_config(ctrl->catalog, false);
> +}
> +
> +static void dp_ctrl_sink_dsc_enable(struct dp_ctrl_private *ctrl)
> +{
> +	int rlen;
> +	u32 dsc_enable;
> +	u8 xx = 0;
> +
> +
> +	if (!ctrl->panel->fec_en)
> +		return;
> +
> +	dsc_enable = ctrl->panel->dsc_en ? 1 : 0;
> +	rlen = drm_dp_dpcd_writeb(ctrl->aux, DP_DSC_ENABLE, dsc_enable);
> +	if (rlen < 1)
> +		DRM_ERROR("failed to enable sink dsc\n");
> +
> +
> +	dsc_enable = 0;

Why?

> +	drm_dp_dpcd_readb(ctrl->aux, DP_DSC_ENABLE, &xx);

Again, why do you need to read it back? And 'xx' doesn't sound like a 
good variable name.

> +
> +}
> +
>   static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
>   			int *training_step)
>   {
> @@ -1442,6 +1531,9 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
>   	 * a link training pattern, we have to first do soft reset.
>   	 */
>   
> +	if (ctrl->panel->fec_en)
> +		dp_ctrl_sink_fec_enable(ctrl);
> +
>   	ret = dp_ctrl_link_train(ctrl, training_step);
>   
>   	return ret;
> @@ -1986,14 +2078,25 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
>   	 */
>   	reinit_completion(&ctrl->video_comp);
>   
> +	if (ctrl->panel->dsc_en)
> +		dp_panel_config_dsc(ctrl->panel, true);
> +
>   	dp_ctrl_configure_source_params(ctrl);
>   
>   	dp_catalog_ctrl_config_msa(ctrl->catalog,
>   		ctrl->link->link_params.rate,
>   		pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
>   
> +	if (ctrl->panel->dsc_en) {
> +		dp_catalog_config_dsc_dto(ctrl->catalog);
> +		dp_catalog_dsc_commit_pps(ctrl->catalog);
> +		dp_catalog_pps_flush(ctrl->catalog);
> +	}
> +
>   	dp_ctrl_setup_tr_unit(ctrl);
>   
> +	dp_catalog_override_ack_dto(ctrl->catalog, true);
> +
>   	dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
>   
>   	ret = dp_ctrl_wait4video_ready(ctrl);
> @@ -2004,6 +2107,12 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
>   	drm_dbg_dp(ctrl->drm_dev,
>   		"mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
>   
> +	if (ctrl->panel->dsc_en) {
> +		/* wait for link training completion before fec config as per spec */
> +		dp_ctrl_host_fec_start(ctrl);
> +		dp_ctrl_sink_dsc_enable(ctrl);
> +	}
> +
>   end:
>   	return ret;
>   }
> @@ -2019,6 +2128,9 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
>   	dp_io = &ctrl->parser->io;
>   	phy = dp_io->phy;
>   
> +	if (ctrl->panel->dsc_en)
> +		dp_panel_config_dsc(ctrl->panel, false);
> +
>   	/* set dongle to D3 (power off) mode */
>   	dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
>   
> @@ -2093,6 +2205,14 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
>   	dp_io = &ctrl->parser->io;
>   	phy = dp_io->phy;
>   
> +	if (ctrl->panel->dsc_en) {
> +		dp_ctrl_host_fec_stop(ctrl);
> +		dp_panel_config_dsc(ctrl->panel, false);
> +		dp_catalog_config_dsc_dto(ctrl->catalog);
> +	}
> +
> +	dp_catalog_override_ack_dto(ctrl->catalog, false);
> +
>   	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
>   
>   	dp_catalog_ctrl_reset(ctrl->catalog);
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index bde1a7c..da59d13 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include <linux/module.h>
> @@ -99,7 +100,7 @@ struct dp_display_private {
>   	struct dp_debug   *debug;
>   
>   	struct dp_usbpd_cb usbpd_cb;
> -	struct dp_display_mode dp_mode;
> +	struct dp_display_mode *dp_mode;
>   	struct msm_dp dp_display;
>   
>   	/* wait for audio signaling */
> @@ -831,6 +832,9 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
>   		goto error_link;
>   	}
>   
> +	/* both dp_display and dp_panel shared same dp_mode */
> +	dp->dp_mode = &dp->panel->dp_mode;
> +
>   	dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,
>   			       dp->power, dp->catalog, dp->parser);
>   	if (IS_ERR(dp->ctrl)) {
> @@ -1662,7 +1666,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
>   	bool force_link_train = false;
>   
>   	dp_display = container_of(dp, struct dp_display_private, dp_display);
> -	if (!dp_display->dp_mode.drm_mode.clock) {
> +	if (!dp_display->dp_mode->drm_mode.clock) {
>   		DRM_ERROR("invalid params\n");
>   		return;
>   	}
> @@ -1678,7 +1682,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
>   		return;
>   	}
>   
> -	rc = dp_display_set_mode(dp, &dp_display->dp_mode);
> +	rc = dp_display_set_mode(dp, dp_display->dp_mode);
>   	if (rc) {
>   		DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
>   		mutex_unlock(&dp_display->event_mutex);
> @@ -1744,6 +1748,10 @@ void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
>   	if (state == ST_DISCONNECT_PENDING) {
>   		/* completed disconnection */
>   		dp_display->hpd_state = ST_DISCONNECTED;
> +		if (dp_display->panel->dsc_en) {
> +			dp_display->dp_mode->timing.comp_info.enabled = false;
> +			dp_display->panel->dsc_en = false;
> +		}
>   	} else {
>   		dp_display->hpd_state = ST_DISPLAY_OFF;
>   	}
> @@ -1762,23 +1770,50 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
>   
>   	dp_display = container_of(dp, struct dp_display_private, dp_display);
>   
> -	memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
> +	memset(dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
>   
>   	if (dp_display_check_video_test(dp))
> -		dp_display->dp_mode.bpp = dp_display_get_test_bpp(dp);
> +		dp_display->dp_mode->bpp = dp_display_get_test_bpp(dp);
>   	else /* Default num_components per pixel = 3 */
> -		dp_display->dp_mode.bpp = dp->connector->display_info.bpc * 3;
> +		dp_display->dp_mode->bpp = dp->connector->display_info.bpc * 3;
> +
> +	if (!dp_display->dp_mode->bpp)
> +		dp_display->dp_mode->bpp = 24; /* Default bpp */
> +
> +	drm_mode_copy(&dp_display->dp_mode->drm_mode, adjusted_mode);
> +
> +	dp_display->dp_mode->v_active_low =
> +		!!(dp_display->dp_mode->drm_mode.flags & DRM_MODE_FLAG_NVSYNC);
> +
> +	dp_display->dp_mode->h_active_low =
> +		!!(dp_display->dp_mode->drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
> +
> +
> +	if (dp_display->panel->dsc_en) {
> +		dp_display->dp_mode->capabilities |= DP_PANEL_CAPS_DSC;
> +		dp_panel_convert_to_dp_mode(dp_display->panel, dp_display->dp_mode);
> +	}
> +}
>   
> -	if (!dp_display->dp_mode.bpp)
> -		dp_display->dp_mode.bpp = 24; /* Default bpp */
> +void msm_dp_bridge_mode_set(struct drm_bridge *bridge,
> +				struct drm_display_mode *mode,
> +				struct drm_display_mode *adjusted_mode)
> +{
> +	dp_bridge_mode_set(bridge, mode, adjusted_mode);
> +}
>   
> -	drm_mode_copy(&dp_display->dp_mode.drm_mode, adjusted_mode);
> +struct msm_compression_info *msm_dp_bridge_get_compression(struct drm_bridge *drm_bridge)
> +{
> +	struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
> +	struct msm_dp *dp_display = dp_bridge->dp_display;
> +	struct dp_display_private *dp;
> +
> +	dp = container_of(dp_display, struct dp_display_private, dp_display);
>   
> -	dp_display->dp_mode.v_active_low =
> -		!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC);
> +	if (!dp->panel->dsc_en)
> +		return NULL;
>   
> -	dp_display->dp_mode.h_active_low =
> -		!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
> +	return &dp->dp_mode->timing.comp_info;
>   }
>   
>   void dp_bridge_hpd_enable(struct drm_bridge *bridge)
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
> index 55bb6b0..19e2f07 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
> @@ -5,11 +5,12 @@
>    */
>   
>   #include "dp_panel.h"
> -
> +#include "dpu_dsc_helper.h"

DP driver can not depend on DPU.

>   #include <drm/drm_fixed.h>
>   #include <drm/drm_connector.h>
>   #include <drm/drm_edid.h>
>   #include <drm/drm_print.h>
> +#include <drm/display/drm_dsc_helper.h>
>   
>   #define DSC_TGT_BPP 10
>   
> @@ -612,6 +613,573 @@ u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel)
>   	return colorimetry;
>   }
>   
> +static inline int fixp2int_ceil(s64 a)
> +{
> +	return (a ? drm_fixp2int_ceil(a) : 0);
> +}

??

> +
> +struct dp_dsc_slices_per_line {
> +	u32 min_ppr;
> +	u32 max_ppr;
> +	u8 num_slices;
> +};
> +
> +struct dp_dsc_peak_throughput {
> +	u32 index;
> +	u32 peak_throughput;
> +};
> +
> +struct dp_dsc_slice_caps_bit_map {
> +	u32 num_slices;
> +	u32 bit_index;
> +};
> +
> +const struct dp_dsc_slices_per_line slice_per_line_tbl[] = {
> +	{0,     340,    1   },
> +	{340,   680,    2   },
> +	{680,   1360,   4   },
> +	{1360,  3200,   8   },
> +	{3200,  4800,   12  },
> +	{4800,  6400,   16  },
> +	{6400,  8000,   20  },
> +	{8000,  9600,   24  }
> +};
> +
> +const struct dp_dsc_peak_throughput peak_throughput_mode_0_tbl[] = {
> +	{0, 0},
> +	{1, 340},
> +	{2, 400},
> +	{3, 450},
> +	{4, 500},
> +	{5, 550},
> +	{6, 600},
> +	{7, 650},
> +	{8, 700},
> +	{9, 750},
> +	{10, 800},
> +	{11, 850},
> +	{12, 900},
> +	{13, 950},
> +	{14, 1000},
> +};
> +
> +const struct dp_dsc_slice_caps_bit_map slice_caps_bit_map_tbl[] = {
> +	{1, 0},
> +	{2, 1},
> +	{4, 3},
> +	{6, 4},
> +	{8, 5},
> +	{10, 6},
> +	{12, 7},
> +	{16, 0},
> +	{20, 1},
> +	{24, 2},
> +};
> +
> +static bool dp_panel_check_slice_support(u32 num_slices, u32 raw_data_1,
> +		u32 raw_data_2)
> +{
> +	const struct dp_dsc_slice_caps_bit_map *bcap;
> +	u32 raw_data;
> +	int i;
> +
> +	if (num_slices <= 12)
> +		raw_data = raw_data_1;
> +	else
> +		raw_data = raw_data_2;
> +
> +	for (i = 0; i < ARRAY_SIZE(slice_caps_bit_map_tbl); i++) {
> +		bcap = &slice_caps_bit_map_tbl[i];
> +
> +		if (bcap->num_slices == num_slices) {
> +			raw_data &= (1 << bcap->bit_index);
> +
> +			if (raw_data)
> +				return true;
> +			else
> +				return false;
> +		}
> +	}
> +
> +	return false;
> +}
> +
> +static int dp_panel_dsc_prepare_basic_params(
> +		struct msm_compression_info *comp_info,
> +		const struct dp_display_mode *dp_mode,
> +		struct dp_panel *dp_panel)
> +{
> +	struct dp_panel_private *panel;
> +	struct drm_dsc_config *dsc;
> +	int i;
> +	const struct dp_dsc_slices_per_line *rec;
> +	const struct dp_dsc_peak_throughput *tput;
> +	u32 slice_width;
> +	u32 ppr = dp_mode->timing.pixel_clk_khz/1000;
> +	u32 max_slice_width;
> +	u32 ppr_max_index;
> +	u32 peak_throughput;
> +	u32 ppr_per_slice;
> +	u32 slice_caps_1;
> +	u32 slice_caps_2;
> +	u32 dsc_version_major, dsc_version_minor;
> +	bool dsc_version_supported = false;
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +
> +	dsc_version_major = dp_panel->sink_dsc_caps.version & 0xF;
> +	dsc_version_minor = (dp_panel->sink_dsc_caps.version >> 4) & 0xF;
> +	dsc_version_supported = (dsc_version_major == 0x1 &&
> +			(dsc_version_minor == 0x1 || dsc_version_minor == 0x2))
> +			? true : false;
> +
> +	drm_dbg_dp(panel->drm_dev, "DSC version: %d.%d, dpcd value: %x\n",
> +			dsc_version_major, dsc_version_minor,
> +			dp_panel->sink_dsc_caps.version);
> +
> +	if (!dsc_version_supported) {
> +		dsc_version_major = 1;
> +		dsc_version_minor = 1;
> +		DRM_ERROR("invalid sink DSC version, fallback to %d.%d\n",
> +				dsc_version_major, dsc_version_minor);
> +	}
> +
> +	dsc = &comp_info->msm_dsc_info.drm_dsc;
> +	dsc->dsc_version_major = dsc_version_major;
> +	dsc->dsc_version_minor = dsc_version_minor;
> +	comp_info->msm_dsc_info.scr_rev = 0x0;
> +
> +
> +	comp_info->msm_dsc_info.slice_per_pkt = 0;
> +	for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) {
> +		rec = &slice_per_line_tbl[i];
> +		if ((ppr > rec->min_ppr) && (ppr <= rec->max_ppr)) {
> +			comp_info->msm_dsc_info.slice_per_pkt = rec->num_slices;
> +			i++;
> +			break;
> +		}
> +	}
> +
> +	if (comp_info->msm_dsc_info.slice_per_pkt == 0)
> +		return -EINVAL;
> +
> +	ppr_max_index = dp_panel->dsc_dpcd[11] &= 0xf;
> +	if (!ppr_max_index || ppr_max_index >= 15) {
> +		drm_dbg_dp(panel->drm_dev,
> +				"Throughput mode 0 not supported");
> +		return -EINVAL;
> +	}
> +
> +	tput = &peak_throughput_mode_0_tbl[ppr_max_index];
> +	peak_throughput = tput->peak_throughput;
> +
> +	max_slice_width = dp_panel->dsc_dpcd[12] * 320;
> +	slice_width = (dp_mode->timing.h_active /
> +				comp_info->msm_dsc_info.slice_per_pkt);
> +
> +	ppr_per_slice = ppr/comp_info->msm_dsc_info.slice_per_pkt;
> +
> +	slice_caps_1 = dp_panel->dsc_dpcd[4];
> +	slice_caps_2 = dp_panel->dsc_dpcd[13] & 0x7;
> +
> +	/*
> +	 * There are 3 conditions to check for sink support:
> +	 * 1. The slice width cannot exceed the maximum.
> +	 * 2. The ppr per slice cannot exceed the maximum.
> +	 * 3. The number of slices must be explicitly supported.
> +	 */
> +	while (slice_width >= max_slice_width ||
> +			ppr_per_slice > peak_throughput ||
> +			!dp_panel_check_slice_support(
> +			comp_info->msm_dsc_info.slice_per_pkt, slice_caps_1,
> +			slice_caps_2)) {
> +		if (i == ARRAY_SIZE(slice_per_line_tbl))
> +			return -EINVAL;
> +
> +		rec = &slice_per_line_tbl[i];
> +		comp_info->msm_dsc_info.slice_per_pkt = rec->num_slices;
> +		slice_width = (dp_mode->timing.h_active /
> +				comp_info->msm_dsc_info.slice_per_pkt);
> +		ppr_per_slice = ppr/comp_info->msm_dsc_info.slice_per_pkt;
> +		i++;
> +	}
> +
> +	dsc->block_pred_enable = dp_panel->sink_dsc_caps.block_pred_en;
> +
> +	dsc->pic_width = dp_mode->timing.h_active;
> +	dsc->pic_height = dp_mode->timing.v_active;
> +	dsc->slice_width = slice_width;
> +
> +	if (dsc->pic_height % 108 == 0)
> +		dsc->slice_height = 108;
> +	else if (dsc->pic_height % 16 == 0)
> +		dsc->slice_height = 16;
> +	else if (dsc->pic_height % 12 == 0)
> +		dsc->slice_height = 12;
> +	else
> +		dsc->slice_height = 15;
> +
> +	dsc->bits_per_component = (dp_mode->timing.bpp / 3);
> +	dsc->bits_per_pixel = DSC_TGT_BPP << 4;
> +	dsc->slice_count = DIV_ROUND_UP(dp_mode->timing.h_active, slice_width);
> +
> +	comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC;
> +	comp_info->tgt_bpp = DSC_TGT_BPP;
> +	comp_info->src_bpp = dp_mode->timing.bpp;
> +	comp_info->comp_ratio = dp_mode->timing.bpp / DSC_TGT_BPP;
> +	comp_info->enabled = true;
> +
> +	return 0;
> +}
> +
> +static void dp_panel_get_dto_params(u32 src_bpp, u32 tgt_bpp, u32 *num, u32 *denom)
> +{
> +	if ((tgt_bpp == 12) && (src_bpp == 24)) {
> +		*num = 1;
> +		*denom = 2;
> +	} else if ((tgt_bpp == 15) && (src_bpp == 30)) {
> +		*num = 5;
> +		*denom = 8;
> +	} else if ((tgt_bpp == 8) && ((src_bpp == 24) || (src_bpp == 30))) {
> +		*num = 1;
> +		*denom = 3;
> +	} else if ((tgt_bpp == 10) && (src_bpp == 30)) {
> +		*num = 5;
> +		*denom = 12;
> +	} else {
> +		DRM_ERROR("dto params not found\n");
> +		*num = 0;
> +		*denom = 1;
> +	}
> +}
> +
> +static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel)
> +{
> +	struct dp_panel_private *panel;
> +	struct dp_dsc_cfg_data *dsc_data;
> +	u8 *pps, *parity;
> +	u32 *pps_word, *parity_word;
> +	int i, index_4;
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +
> +	dsc_data = &panel->catalog->dsc_data;
> +	pps = dsc_data->pps;
> +	pps_word = dsc_data->pps_word;
> +	parity = dsc_data->parity;
> +	parity_word = dsc_data->parity_word;
> +
> +	memset(parity, 0, sizeof(dsc_data->parity));
> +
> +	dsc_data->pps_word_len = dsc_data->pps_len >> 2;
> +	dsc_data->parity_len = dsc_data->pps_word_len;
> +	dsc_data->parity_word_len = (dsc_data->parity_len >> 2) + 1;
> +
> +	for (i = 0; i < dsc_data->pps_word_len; i++) {
> +		index_4 = i << 2;
> +		pps_word[i] = pps[index_4 + 0] << 0 |
> +				pps[index_4 + 1] << 8 |
> +				pps[index_4 + 2] << 16 |
> +				pps[index_4 + 3] << 24;
> +
> +		parity[i] = dp_header_get_parity(pps_word[i]);
> +	}
> +
> +	for (i = 0; i < dsc_data->parity_word_len; i++) {
> +		index_4 = i << 2;
> +		parity_word[i] = parity[index_4 + 0] << 0 |
> +				   parity[index_4 + 1] << 8 |
> +				   parity[index_4 + 2] << 16 |
> +				   parity[index_4 + 3] << 24;
> +	}
> +}
> +
> +void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable)
> +{
> +	struct dp_panel_private *panel;
> +	struct dp_panel_info *timing;
> +	struct msm_compression_info *comp_info;
> +	struct dp_dsc_cfg_data *dsc_data;
> +	struct drm_dsc_picture_parameter_set *pps_payload;
> +	struct drm_dsc_config *dsc;
> +
> +	if (!dp_panel->dsc_en)
> +		return;
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +
> +	dsc_data = &panel->catalog->dsc_data;
> +	timing = &dp_panel->dp_mode.timing;
> +	comp_info = &timing->comp_info;
> +	dsc = &comp_info->msm_dsc_info.drm_dsc;
> +
> +	if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) {
> +		memset(dsc_data->pps, 0, sizeof(dsc_data->pps));
> +		pps_payload = (struct drm_dsc_picture_parameter_set *)dsc_data->pps;
> +		drm_dsc_pps_payload_pack(pps_payload, dsc);
> +
> +		dsc_data->pps_len = DSC_1_1_PPS_PARAMETER_SET_ELEMENTS;
> +		dp_panel_dsc_prepare_pps_packet(dp_panel);
> +
> +		dsc_data->slice_per_pkt = comp_info->msm_dsc_info.slice_per_pkt - 1;
> +		dsc_data->bytes_per_pkt = comp_info->msm_dsc_info.bytes_per_pkt;
> +		dsc_data->bytes_per_pkt /= comp_info->msm_dsc_info.slice_per_pkt;
> +		dsc_data->eol_byte_num = comp_info->msm_dsc_info.eol_byte_num;
> +		dsc_data->dto_count = comp_info->msm_dsc_info.pclk_per_line;
> +		dsc_data->be_in_lane = 10;
> +		dsc_data->dsc_en = true;
> +		dsc_data->dto_en = true;
> +		dp_panel_get_dto_params(comp_info->src_bpp, comp_info->tgt_bpp, &dsc_data->dto_n,
> +				&dsc_data->dto_d);
> +	} else {
> +		dsc_data->dsc_en = false;
> +		dsc_data->dto_en = false;
> +		dsc_data->dto_n = 0;
> +		dsc_data->dto_d = 0;
> +		dsc_data->continuous_pps = false;
> +	}
> +}
> +
> +static void _dp_panel_dsc_get_num_extra_pclk(struct msm_compression_info *comp_info)
> +{
> +	unsigned int dto_n = 0, dto_d = 0, remainder;
> +	int ack_required, last_few_ack_required, accum_ack;
> +	int last_few_pclk, last_few_pclk_required;
> +	struct msm_display_dsc_info *dsc_info = &comp_info->msm_dsc_info;
> +	int start, temp, line_width = dsc_info->drm_dsc.pic_width/2;
> +	s64 temp1_fp, temp2_fp;
> +
> +	dp_panel_get_dto_params(comp_info->src_bpp, comp_info->tgt_bpp, &dto_n, &dto_d);
> +
> +	ack_required = dsc_info->pclk_per_line;
> +
> +	/* number of pclk cycles left outside of the complete DTO set */
> +	last_few_pclk = line_width % dto_d;
> +
> +	/* number of pclk cycles outside of the complete dto */
> +	temp1_fp = drm_fixp_from_fraction(line_width, dto_d);
> +	temp2_fp = drm_fixp_from_fraction(dto_n, 1);
> +	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +	temp = drm_fixp2int(temp1_fp);
> +	last_few_ack_required = ack_required - temp;
> +
> +	/*
> +	 * check how many more pclk is needed to
> +	 * accommodate the last few ack required
> +	 */
> +	remainder = dto_n;
> +	accum_ack = 0;
> +	last_few_pclk_required = 0;
> +	while (accum_ack < last_few_ack_required) {
> +		last_few_pclk_required++;
> +
> +		if (remainder >= dto_n)
> +			start = remainder;
> +		else
> +			start = remainder + dto_d;
> +
> +		remainder = start - dto_n;
> +		if (remainder < dto_n)
> +			accum_ack++;
> +	}
> +
> +	/* if fewer pclk than required */
> +	if (last_few_pclk < last_few_pclk_required)
> +		dsc_info->extra_width = last_few_pclk_required - last_few_pclk;
> +	else
> +		dsc_info->extra_width = 0;
> +}
> +
> +static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel,
> +		struct msm_display_dsc_info *dsc_info,
> +		struct dp_display_mode *dp_mode, u32 dsc_byte_cnt)
> +{
> +	int num_slices, tot_num_eoc_symbols;
> +	int tot_num_hor_bytes, tot_num_dummy_bytes;
> +	int dwidth_dsc_bytes, eoc_bytes;
> +	u32 num_lanes;
> +	struct dp_panel_private *panel;
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +
> +	num_lanes = panel->link->link_params.num_lanes;
> +	num_slices = dsc_info->slice_per_pkt;
> +
> +	eoc_bytes = dsc_byte_cnt % num_lanes;
> +	tot_num_eoc_symbols = num_lanes * num_slices;
> +	tot_num_hor_bytes = dsc_byte_cnt * num_slices;
> +	tot_num_dummy_bytes = (num_lanes - eoc_bytes) * num_slices;
> +
> +	if (!eoc_bytes)
> +		tot_num_dummy_bytes = 0;
> +
> +	dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols +
> +				tot_num_dummy_bytes;
> +
> +	drm_dbg_dp(panel->drm_dev, "dwidth_dsc_bytes:%d, tot_num_hor_bytes:%d\n",
> +			dwidth_dsc_bytes, tot_num_hor_bytes);
> +
> +	dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes,
> +			tot_num_hor_bytes);
> +
> +	dp_mode->timing.dsc_overhead_fp = dp_mode->dsc_overhead_fp;
> +}
> +
> +static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel,
> +		struct msm_compression_info *comp_info,
> +		struct dp_display_mode *dp_mode)
> +{
> +	int comp_ratio = 100, intf_width;
> +	int slice_per_pkt, slice_per_intf;
> +	s64 temp1_fp, temp2_fp;
> +	s64 numerator_fp, denominator_fp;
> +	s64 dsc_byte_count_fp;
> +	u32 dsc_byte_count, temp1, temp2;
> +	struct msm_display_dsc_info *dsc_info = &comp_info->msm_dsc_info;
> +
> +	intf_width = dp_mode->timing.h_active;
> +	if (!dsc_info || !dsc_info->drm_dsc.slice_width || !dsc_info->slice_per_pkt ||
> +			 (intf_width < dsc_info->drm_dsc.slice_width))
> +		return;
> +
> +	slice_per_pkt = dsc_info->slice_per_pkt;
> +	slice_per_intf = DIV_ROUND_UP(intf_width,
> +			dsc_info->drm_dsc.slice_width);
> +
> +	comp_ratio = mult_frac(100, comp_info->src_bpp, comp_info->tgt_bpp);
> +
> +	temp1_fp = drm_fixp_from_fraction(comp_ratio, 100);
> +	temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1);
> +	denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +	numerator_fp = drm_fixp_from_fraction(
> +			intf_width * dsc_info->drm_dsc.bits_per_component * 3, 1);
> +	dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp);
> +	dsc_byte_count = fixp2int_ceil(dsc_byte_count_fp);
> +
> +	temp1 = dsc_byte_count * slice_per_intf;
> +	temp2 = temp1;
> +	if (temp1 % 3 != 0)
> +		temp1 += 3 - (temp1 % 3);
> +
> +	dsc_info->eol_byte_num = temp1 - temp2;
> +
> +	temp1_fp = drm_fixp_from_fraction(slice_per_intf, 6);
> +	temp2_fp = drm_fixp_mul(dsc_byte_count_fp, temp1_fp);
> +	dsc_info->pclk_per_line = fixp2int_ceil(temp2_fp);
> +
> +	_dp_panel_dsc_get_num_extra_pclk(comp_info);
> +	dsc_info->pclk_per_line--;
> +
> +	_dp_panel_dsc_bw_overhead_calc(dp_panel, dsc_info, dp_mode, dsc_byte_count);
> +}
> +
> +void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
> +		struct dp_display_mode *dp_mode)
> +{
> +	struct dp_panel_private *panel;
> +	const u32 num_components = 3, default_bpp = 24;
> +	struct drm_display_mode *drm_mode;
> +	struct dp_panel_info *timing;
> +	struct msm_compression_info *comp_info;
> +	bool dsc_cap = (dp_mode->capabilities & DP_PANEL_CAPS_DSC) ?
> +				true : false;
> +	int rc;
> +
> +	if (!dp_panel->dsc_en)
> +		return;
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +
> +	drm_mode = &dp_mode->drm_mode;
> +	timing = &dp_mode->timing;
> +
> +	timing->h_active = drm_mode->hdisplay;
> +	timing->h_back_porch = drm_mode->htotal - drm_mode->hsync_end;
> +	timing->h_sync_width = drm_mode->htotal -
> +                        (drm_mode->hsync_start + dp_mode->timing.h_back_porch);
> +
> +	timing->h_front_porch = drm_mode->hsync_start -
> +					 drm_mode->hdisplay;
> +	timing->h_skew = drm_mode->hskew;
> +
> +	timing->v_active = drm_mode->vdisplay;
> +	timing->v_back_porch = drm_mode->vtotal - drm_mode->vsync_end;
> +	timing->v_sync_width = drm_mode->vtotal -
> +                (drm_mode->vsync_start + dp_mode->timing.v_back_porch);
> +
> +	timing->v_front_porch = drm_mode->vsync_start - drm_mode->vdisplay;
> +
> +	timing->refresh_rate = drm_mode_vrefresh(drm_mode);
> +	timing->pixel_clk_khz = drm_mode->clock;
> +
> +	timing->v_active_low =
> +		!!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC);
> +
> +	timing->h_active_low =
> +		!!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC);
> +
> +	timing->bpp =
> +		dp_panel->connector->display_info.bpc * num_components;
> +	if (!timing->bpp)
> +		timing->bpp = default_bpp;
> +
> +	timing->widebus_en = dp_panel->widebus_en;
> +	timing->dsc_overhead_fp = 0;
> +
> +	comp_info = &timing->comp_info;
> +	comp_info->src_bpp = default_bpp;
> +	comp_info->tgt_bpp = default_bpp;
> +	comp_info->comp_type = MSM_DISPLAY_COMPRESSION_NONE;
> +	comp_info->comp_ratio = 1;
> +	comp_info->enabled = false;
> +
> +	/* As YUV was not supported now, so set the default format to RGB */
> +	dp_mode->output_format = DP_OUTPUT_FORMAT_RGB;
> +	/*
> +	 * If a given videomode can be only supported in YCBCR420, set
> +	 * the output format to YUV420. While now our driver did not
> +	 * support YUV display over DP, so just place this flag here.
> +	 * When we want to support YUV, we can use this flag to do
> +	 * a lot of settings, like CDM, CSC and pixel_clock.
> +	 */
> +	if (drm_mode_is_420_only(&dp_panel->connector->display_info,
> +			drm_mode)) {
> +		dp_mode->output_format = DP_OUTPUT_FORMAT_YCBCR420;
> +		drm_dbg_dp(panel->drm_dev, "YCBCR420 was not supported");
> +	}
> +
> +	timing->bpp = dp_panel_get_mode_bpp(dp_panel,
> +			timing->bpp, timing->pixel_clk_khz);
> +
> +
> +	if (dp_panel->dsc_en && dsc_cap) {
> +		if (dp_panel_dsc_prepare_basic_params(comp_info,
> +					dp_mode, dp_panel)) {
> +			drm_dbg_dp(panel->drm_dev,
> +					"prepare DSC basic params failed\n");
> +			return;
> +		}
> +
> +		rc = dpu_dsc_populate_dsc_config(&comp_info->msm_dsc_info.drm_dsc, 0);
> +		if (rc) {
> +			drm_dbg_dp(panel->drm_dev,
> +					"failed populating dsc params \n");
> +			return;
> +		}
> +
> +		rc = dpu_dsc_populate_dsc_private_params(&comp_info->msm_dsc_info,
> +				dp_mode->timing.h_active);
> +		if (rc) {
> +			drm_dbg_dp(panel->drm_dev,
> +					"failed populating other dsc params\n");
> +			return;
> +		}
> +
> +		dp_panel_dsc_pclk_param_calc(dp_panel, comp_info, dp_mode);
> +	}
> +	dp_mode->fec_overhead_fp = dp_panel->fec_overhead_fp;
> +}
> +
>   struct dp_panel *dp_panel_get(struct dp_panel_in *in)
>   {
>   	struct dp_panel_private *panel;
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index 4c45d51..576056c 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -112,6 +112,7 @@ struct dp_panel {
>   	bool fec_feature_enable;
>   	bool dsc_en;
>   	bool fec_en;
> +	bool widebus_en;
>   	s64 fec_overhead_fp;
>   };
>   
> @@ -128,6 +129,9 @@ int dp_panel_get_modes(struct dp_panel *dp_panel,
>   void dp_panel_handle_sink_request(struct dp_panel *dp_panel);
>   void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable);
>   u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel);
> +void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable);
> +void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
> +		struct dp_display_mode *dp_mode);
>   
>   /**
>    * is_link_rate_valid() - validates the link rate
> diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
> index 2686028..96d48d0c 100644
> --- a/drivers/gpu/drm/msm/dp/dp_reg.h
> +++ b/drivers/gpu/drm/msm/dp/dp_reg.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
>    * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #ifndef _DP_REG_H_
> @@ -167,7 +168,38 @@
>   #define MMSS_DP_PSR_CRC_RG			(0x00000154)
>   #define MMSS_DP_PSR_CRC_B			(0x00000158)
>   
> -#define REG_DP_COMPRESSION_MODE_CTRL		(0x00000180)
> +#define DP_COMPRESSION_MODE_CTRL		(0x00000180)
> +#define DP_PPS_HB_0_3				(0x00000184)
> +#define DP_PPS_PB_0_3				(0x00000188)
> +#define DP_PPS_PB_4_7				(0x0000018C)
> +#define DP_PPS_PB_8_11				(0x00000190)
> +#define DP_PPS_PB_12_15				(0x00000194)
> +#define DP_PPS_PB_16_19				(0x00000198)
> +#define DP_PPS_PB_20_23				(0x0000019C)
> +#define DP_PPS_PB_24_27				(0x000001A0)
> +#define DP_PPS_PB_28_31				(0x000001A4)
> +#define DP_PPS_PPS_0_3				(0x000001A8)
> +#define DP_PPS_PPS_4_7				(0x000001AC)
> +#define DP_PPS_PPS_8_11				(0x000001B0)
> +#define DP_PPS_PPS_12_15			(0x000001B4)
> +#define DP_PPS_PPS_16_19			(0x000001B8)
> +#define DP_PPS_PPS_20_23			(0x000001BC)
> +#define DP_PPS_PPS_24_27			(0x000001C0)
> +#define DP_PPS_PPS_28_31			(0x000001C4)
> +#define DP_PPS_PPS_32_35			(0x000001C8)
> +#define DP_PPS_PPS_36_39			(0x000001CC)
> +#define DP_PPS_PPS_40_43			(0x000001D0)
> +#define DP_PPS_PPS_44_47			(0x000001D4)
> +#define DP_PPS_PPS_48_51			(0x000001D8)
> +#define DP_PPS_PPS_52_55			(0x000001DC)
> +#define DP_PPS_PPS_56_59			(0x000001E0)
> +#define DP_PPS_PPS_60_63			(0x000001E4)
> +#define DP_PPS_PPS_64_67			(0x000001E8)
> +#define DP_PPS_PPS_68_71			(0x000001EC)
> +#define DP_PPS_PPS_72_75			(0x000001F0)
> +#define DP_PPS_PPS_76_79			(0x000001F4)
> +#define DP_PPS_PPS_80_83			(0x000001F8)
> +#define DP_PPS_PPS_84_87			(0x000001FC)
>   
>   #define MMSS_DP_AUDIO_CFG			(0x00000200)
>   #define MMSS_DP_AUDIO_STATUS			(0x00000204)
> @@ -178,6 +210,8 @@
>   
>   #define MMSS_DP_SDP_CFG				(0x00000228)
>   #define MMSS_DP_SDP_CFG2			(0x0000022C)
> +#define MMSS_DP_SDP_CFG3			(0x0000024C)
> +#define MMSS_DP_SDP_CFG4			(0x000004EC)
>   #define MMSS_DP_AUDIO_TIMESTAMP_0		(0x00000230)
>   #define MMSS_DP_AUDIO_TIMESTAMP_1		(0x00000234)
>   
> @@ -210,6 +244,9 @@
>   #define MMSS_DP_AUDIO_INFOFRAME_1		(0x000002AC)
>   #define MMSS_DP_AUDIO_INFOFRAME_2		(0x000002B0)
>   
> +#define MMSS_DP_FLUSH				(0x000002F8)
> +#define MMSS_DP1_FLUSH				(0x000002FC)
> +
>   #define MMSS_DP_GENERIC0_0			(0x00000300)
>   #define MMSS_DP_GENERIC0_1			(0x00000304)
>   #define MMSS_DP_GENERIC0_2			(0x00000308)
> @@ -268,6 +305,7 @@
>   
>   #define MMSS_DP_TPG_MAIN_CONTROL		(0x00000060)
>   #define MMSS_DP_DSC_DTO				(0x0000007C)
> +#define MMSS_DP_DSC_DTO_COUNT			(0x00000084)
>   #define DP_TPG_CHECKERED_RECT_PATTERN		(0x00000100)
>   
>   #define MMSS_DP_TPG_VIDEO_CONFIG		(0x00000064)
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index cf4eb8d..6a46ed7 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -476,6 +476,11 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_displa
>   
>   void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor);
>   bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);
> +struct msm_compression_info *msm_dp_bridge_get_compression(struct drm_bridge *drm_bridge);
> +
> +void msm_dp_bridge_mode_set(struct drm_bridge *bridge,
> +				struct drm_display_mode *mode,
> +				struct drm_display_mode *adjusted_mode);

Why do you need to export this function?

>   
>   #else
>   static inline int __init msm_dp_register(void)
> @@ -510,6 +515,17 @@ static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
>   	return false;
>   }
>   
> +static inline struct msm_compression_info *msm_dp_bridge_get_compression(
> +				struct drm_bridge *drm_bridge)
> +{
> +	return NULL;
> +}
> +static inline void msm_dp_bridge_mode_set(struct drm_bridge *bridge,
> +				struct drm_display_mode *mode,
> +				struct drm_display_mode *adjusted_mode)
> +{
> +
> +}
>   #endif
>   
>   #ifdef CONFIG_DRM_MSM_MDP4

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number
  2023-01-23 18:24 ` [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number Kuogee Hsieh
@ 2023-01-23 22:34   ` Dmitry Baryshkov
  0 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:34 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> Mainlink_levels determined when two actions to take place by hardware,
> a new BS sequence due to start of video and a static HW MVID is sent
> to panel. This patch add function to configure mainlink level properly
> base on lane number.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_catalog.c | 37 ++++++++++++++++++++++++++++++++++++-
>   drivers/gpu/drm/msm/dp/dp_catalog.h |  4 +++-
>   drivers/gpu/drm/msm/dp/dp_ctrl.c    |  4 ++++
>   3 files changed, 43 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
> index 676279d..7ac37d8 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.c
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2017-2023, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2021. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
> @@ -359,6 +360,40 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog)
>   			ln_mapping);
>   }
>   
> +void dp_catalog_ctrl_mainlink_levels(struct dp_catalog *dp_catalog,
> +					u8 lane_cnt)
> +{
> +	struct dp_catalog_private *catalog = container_of(dp_catalog,
> +				struct dp_catalog_private, dp_catalog);
> +
> +	u32 mainlink_levels, safe_to_exit_level = 14;
> +
> +	switch (lane_cnt) {
> +	case 1:
> +		safe_to_exit_level = 14;
> +		break;
> +	case 2:
> +		safe_to_exit_level = 8;
> +		break;
> +	case 4:
> +		safe_to_exit_level = 5;
> +		break;
> +	default:
> +		drm_dbg_dp(catalog->drm_dev, "setting the default safe_to_exit_level=%u\n",
> +				safe_to_exit_level);

So, set it here rather than somewhere at the top of the function.

> +		break;
> +	}
> +
> +	mainlink_levels = dp_read_link(catalog, REG_DP_MAINLINK_LEVELS);
> +	mainlink_levels &= 0xFE0;
> +	mainlink_levels |= safe_to_exit_level;
> +
> +	drm_dbg_dp(catalog->drm_dev, "mainlink_level=0x%x, safe_to_exit_level=0x%x\n",
> +		mainlink_levels, safe_to_exit_level);
> +
> +	dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, mainlink_levels);
> +}
> +
>   void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
>   						bool enable)
>   {
> diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
> index 1f717f4..990c162 100644
> --- a/drivers/gpu/drm/msm/dp/dp_catalog.h
> +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2017-2023, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2021. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #ifndef _DP_CATALOG_H_
> @@ -92,6 +93,7 @@ u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
>   void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state);
>   void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config);
>   void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog);
> +void dp_catalog_ctrl_mainlink_levels(struct dp_catalog *dp_catalog, u8 lane_cnt);
>   void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable);
>   void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
>   void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index dd26ca6..959a78c 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -161,6 +161,8 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
>   	u32 cc, tb;
>   
>   	dp_catalog_ctrl_lane_mapping(ctrl->catalog);
> +	dp_catalog_ctrl_mainlink_levels(ctrl->catalog,
> +				ctrl->link->link_params.num_lanes);
>   	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
>   
>   	dp_ctrl_config_ctrl(ctrl);
> @@ -1296,6 +1298,8 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
>   {
>   	int ret = 0;
>   
> +	dp_catalog_ctrl_mainlink_levels(ctrl->catalog,
> +				ctrl->link->link_params.num_lanes);
>   	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
>   
>   	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
  2023-01-23 18:24 ` [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0 Kuogee Hsieh
@ 2023-01-23 22:41   ` Dmitry Baryshkov
  2023-01-24  0:49   ` kernel test robot
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:41 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> MSA MISC0 bit 1 to 7 contains Colorimetry Indicator Field. At current
> implementation, Colorimetry Indicator Field of MISC0 is not configured
> correctly. This patch add support of RGB formats Colorimetry.

Any Fixes tag? Not to mention that fixes should come first.

> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_ctrl.c  |  5 +++--
>   drivers/gpu/drm/msm/dp/dp_link.c  | 29 +++++++++++++++++++------
>   drivers/gpu/drm/msm/dp/dp_panel.c | 45 +++++++++++++++++++++++++++++++++++++++
>   drivers/gpu/drm/msm/dp/dp_panel.h |  1 +
>   4 files changed, 71 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index 959a78c..d0d1848 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
> @@ -169,7 +170,7 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
>   
>   	tb = dp_link_get_test_bits_depth(ctrl->link,
>   		ctrl->panel->dp_mode.bpp);
> -	cc = dp_link_get_colorimetry_config(ctrl->link);
> +	cc = dp_panel_get_misc_colorimetry_val(ctrl->panel);
>   	dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb);
>   	dp_panel_timing_cfg(ctrl->panel);
>   }
> diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
> index f1f1d64..e957948 100644
> --- a/drivers/gpu/drm/msm/dp/dp_link.c
> +++ b/drivers/gpu/drm/msm/dp/dp_link.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
> - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2012-2023, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
> @@ -12,6 +13,12 @@
>   
>   #define DP_TEST_REQUEST_MASK		0x7F
>   
> +enum dynamic_range {
> +	DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
> +	DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
> +	DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF,

No need to assign values here, unless they serve some purpose. Do they?

> +};
> +
>   enum audio_sample_rate {
>   	AUDIO_SAMPLE_RATE_32_KHZ	= 0x00,
>   	AUDIO_SAMPLE_RATE_44_1_KHZ	= 0x01,
> @@ -1079,6 +1086,7 @@ int dp_link_process_request(struct dp_link *dp_link)
>   int dp_link_get_colorimetry_config(struct dp_link *dp_link)
>   {
>   	u32 cc;
> +	enum dynamic_range dr;
>   	struct dp_link_private *link;
>   
>   	if (!dp_link) {
> @@ -1088,14 +1096,21 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link)
>   
>   	link = container_of(dp_link, struct dp_link_private, dp_link);
>   
> -	/*
> -	 * Unless a video pattern CTS test is ongoing, use RGB_VESA
> -	 * Only RGB_VESA and RGB_CEA supported for now
> -	 */
> +	/* unless a video pattern CTS test is ongoing, use CEA_VESA */
>   	if (dp_link_is_video_pattern_requested(link))
> -		cc = link->dp_link.test_video.test_dyn_range;
> +		dr = link->dp_link.test_video.test_dyn_range;
>   	else
> -		cc = DP_TEST_DYNAMIC_RANGE_VESA;
> +		dr = DP_DYNAMIC_RANGE_RGB_VESA;
> +
> +	/* Only RGB_VESA nd RGB_CEA supported for now */
> +	switch (dr) {
> +	case DP_DYNAMIC_RANGE_RGB_CEA:
> +		cc = BIT(2);
> +		break;
> +	case DP_DYNAMIC_RANGE_RGB_VESA:
> +	default:
> +		cc = 0;
> +	}
>   
>   	return cc;
>   }
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
> index 36dad05..55bb6b0 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.c
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.c
> @@ -567,6 +567,51 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel)
>   	return 0;
>   }
>   
> +/**

This marks the start of kerneldoc. But the rest of the comment isn't a 
kerneldoc.

> + * Mapper function which outputs colorimetry to be used for a
> + * given colorspace value when misc field of MSA is used to
> + * change the colorimetry. Currently only RGB formats have been
> + * added. This API will be extended to YUV once its supported on DP.

its != it's

> + */
> +u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel)
> +{
> +	u8 colorimetry;
> +	u32 colorspace;
> +	u32 cc;
> +	struct dp_panel_private *panel;
> +
> +	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
> +
> +	cc = dp_link_get_colorimetry_config(panel->link);
> +	/*
> +	 * If there is a non-zero value then compliance test-case
> +	 * is going on, otherwise we can honor the colorspace setting
> +	 */
> +	if (cc)
> +		return cc;
> +
> +	colorspace = dp_panel->connector->state->colorspace;
> +	switch (colorspace) {
> +	case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
> +	case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
> +		colorimetry = 0x7;
> +		break;
> +	case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED:
> +		colorimetry = 0x3;
> +		break;
> +	case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT:
> +		colorimetry = 0xb;
> +		break;
> +	case DRM_MODE_COLORIMETRY_OPRGB:
> +		colorimetry = 0xc;
> +		break;
> +	default:
> +		colorimetry = 0;
> +	}
> +
> +	return colorimetry;
> +}
> +
>   struct dp_panel *dp_panel_get(struct dp_panel_in *in)
>   {
>   	struct dp_panel_private *panel;
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index fb30b92..1153e88 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -85,6 +85,7 @@ int dp_panel_get_modes(struct dp_panel *dp_panel,
>   		struct drm_connector *connector);
>   void dp_panel_handle_sink_request(struct dp_panel *dp_panel);
>   void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable);
> +u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel);
>   
>   /**
>    * is_link_rate_valid() - validates the link rate

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 06/14] drm/msm/dp: add display compression related struct
  2023-01-23 18:24 ` [PATCH v1 06/14] drm/msm/dp: add display compression related struct Kuogee Hsieh
@ 2023-01-23 22:46   ` Dmitry Baryshkov
  2023-01-24 15:15   ` Neil Armstrong
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 22:46 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> Add display compression related struct to support variant compression
> mechanism. However, DSC is the only one supported at this moment.
> VDC may be added later.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_panel.h | 42 ++++++++++++++++++
>   drivers/gpu/drm/msm/msm_drv.h     | 89 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 131 insertions(+)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index 1153e88..4c45d51 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -21,12 +21,54 @@ struct edid;
>   #define DP_DOWNSTREAM_PORTS		4
>   #define DP_DOWNSTREAM_CAP_SIZE		4
>   
> +
> +#define DP_PANEL_CAPS_DSC	BIT(0)
> +
> +enum dp_output_format {
> +	DP_OUTPUT_FORMAT_RGB,
> +	DP_OUTPUT_FORMAT_YCBCR420,
> +	DP_OUTPUT_FORMAT_YCBCR422,
> +	DP_OUTPUT_FORMAT_YCBCR444,
> +	DP_OUTPUT_FORMAT_INVALID,
> +};
> +
> +
> +struct dp_panel_info {
> +	u32 h_active;
> +	u32 v_active;
> +	u32 h_back_porch;
> +	u32 h_front_porch;
> +	u32 h_sync_width;
> +	u32 h_active_low;
> +	u32 v_back_porch;
> +	u32 v_front_porch;
> +	u32 v_sync_width;
> +	u32 v_active_low;
> +	u32 h_skew;
> +	u32 refresh_rate;
> +	u32 pixel_clk_khz;
> +	u32 bpp;
> +	bool widebus_en;
> +	struct msm_compression_info comp_info;
> +	s64 dsc_overhead_fp;
> +};
> +
>   struct dp_display_mode {
>   	struct drm_display_mode drm_mode;
> +	struct dp_panel_info timing;
>   	u32 capabilities;
> +	s64 fec_overhead_fp;
> +	s64 dsc_overhead_fp;
>   	u32 bpp;
>   	u32 h_active_low;
>   	u32 v_active_low;
> +	/**
> +	 * @output_format:
> +	 *
> +	 * This is used to indicate DP output format.
> +	 * The output format can be read from drm_mode.
> +	 */
> +	enum dp_output_format output_format;
>   };
>   
>   struct dp_panel_in {
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index 9f0c184..f155803 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
>    * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    * Copyright (C) 2013 Red Hat
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
> @@ -70,6 +71,16 @@ enum msm_dp_controller {
>   #define MAX_H_TILES_PER_DISPLAY 2
>   
>   /**
> + * enum msm_display_compression_type - compression method used for pixel stream
> + * @MSM_DISPLAY_COMPRESSION_NONE:     Pixel data is not compressed
> + * @MSM_DISPLAY_COMPRESSION_DSC:      DSC compresison is used
> + */
> +enum msm_display_compression_type {
> +	MSM_DISPLAY_COMPRESSION_NONE,
> +	MSM_DISPLAY_COMPRESSION_DSC,
> +};
> +
> +/**
>    * enum msm_event_wait - type of HW events to wait for
>    * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
>    * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
> @@ -82,6 +93,84 @@ enum msm_event_wait {
>   };
>   
>   /**
> + * struct msm_display_dsc_info - defines dsc configuration

This structure was removed. Please keep it this way. We are not going to 
reintroduce it unless it is really required for some reason. And up to 
now I don't see a good reason for adding it back.

> + * @config                   DSC encoder configuration
> + * @scr_rev:                 DSC revision.
> + * @initial_lines:           Number of initial lines stored in encoder.
> + * @pkt_per_line:            Number of packets per line.
> + * @bytes_in_slice:          Number of bytes in slice.
> + * @eol_byte_num:            Valid bytes at the end of line.
> + * @bytes_per_pkt            Number of bytes in DSI packet
> + * @pclk_per_line:           Compressed width.
> + * @slice_last_group_size:   Size of last group in pixels.
> + * @slice_per_pkt:           Number of slices per packet.
> + * @num_active_ss_per_enc:   Number of active soft slices per encoder.
> + * @source_color_space:      Source color space of DSC encoder
> + * @chroma_format:           Chroma_format of DSC encoder.
> + * @det_thresh_flatness:     Flatness threshold.
> + * @extra_width:             Extra width required in timing calculations.
> + * @pps_delay_ms:            Post PPS command delay in milliseconds.
> + * @dsc_4hsmerge_en:         Using DSC 4HS merge topology
> + * @dsc_4hsmerge_padding     4HS merge DSC pair padding value in bytes
> + * @dsc_4hsmerge_alignment   4HS merge DSC alignment value in bytes
> + * @half_panel_pu            True for single and dual dsc encoders if partial
> + *                           update sets the roi width to half of mode width
> + *                           False in all other cases
> + */
> +struct msm_display_dsc_info {
> +	struct drm_dsc_config drm_dsc;
> +	u8 scr_rev;
> +
> +	int initial_lines;
> +	int pkt_per_line;
> +	int bytes_in_slice;
> +	int bytes_per_pkt;
> +	int eol_byte_num;
> +	int pclk_per_line;
> +	int slice_last_group_size;
> +	int slice_per_pkt;
> +	int num_active_ss_per_enc;
> +	int source_color_space;
> +	int chroma_format;
> +	int det_thresh_flatness;
> +	u32 extra_width;
> +	u32 pps_delay_ms;
> +	bool dsc_4hsmerge_en;
> +	u32 dsc_4hsmerge_padding;
> +	u32 dsc_4hsmerge_alignment;
> +	bool half_panel_pu;
> +};
> +
> +/*
> + * conver from struct drm_dsc_config to struct msm_display_dsc_info
> + */
> +#define to_msm_dsc_info(dsc) container_of((dsc), struct msm_display_dsc_info, drm_dsc)
> +
> +/**
> + * Bits/pixel target >> 4  (removing the fractional bits)
> + * returns the integer bpp value from the drm_dsc_config struct
> + */
> +#define DSC_BPP(config) ((config).bits_per_pixel >> 4)
> +
> +/**
> + * struct msm_compression_info - defined panel compression
> + * @enabled:          enabled/disabled
> + * @comp_type:        type of compression supported
> + * @comp_ratio:       compression ratio
> + * @src_bpp:          bits per pixel before compression
> + * @tgt_bpp:          bits per pixel after compression
> + * @msm_dsc_info:     msm dsc info if the compression supported is DSC
> + */
> +struct msm_compression_info {
> +	bool enabled;
> +	enum msm_display_compression_type comp_type;
> +	u32 comp_ratio;
> +	u32 src_bpp;
> +	u32 tgt_bpp;
> +	struct msm_display_dsc_info msm_dsc_info;
> +};
> +
> +/**
>    * struct msm_display_topology - defines a display topology pipeline
>    * @num_lm:       number of layer mixers used
>    * @num_intf:     number of interfaces the panel is mounted on

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp
  2023-01-23 18:24 ` [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp Kuogee Hsieh
@ 2023-01-23 23:38   ` kernel test robot
  0 siblings, 0 replies; 50+ messages in thread
From: kernel test robot @ 2023-01-23 23:38 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, Kuogee Hsieh,
	oe-kbuild-all, freedreno, linux-kernel

Hi Kuogee,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on next-20230123]
[also build test WARNING on linus/master v6.2-rc5]
[cannot apply to drm-misc/drm-misc-next drm/drm-next drm-exynos/exynos-drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-tip/drm-tip v6.2-rc5 v6.2-rc4 v6.2-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kuogee-Hsieh/drm-msm-dp-add-dpcd-read-of-both-dsc-and-fec-capability/20230124-022759
patch link:    https://lore.kernel.org/r/1674498274-6010-3-git-send-email-quic_khsieh%40quicinc.com
patch subject: [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20230124/202301240748.RCxiAZH1-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/745d7acf9ef8affe996fce2f0658a6d95ac151fd
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Kuogee-Hsieh/drm-msm-dp-add-dpcd-read-of-both-dsc-and-fec-capability/20230124-022759
        git checkout 745d7acf9ef8affe996fce2f0658a6d95ac151fd
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc SHELL=/bin/bash drivers/gpu/drm/msm/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/msm/dp/dp_panel.c: In function 'dp_panel_get_supported_bpp':
>> drivers/gpu/drm/msm/dp/dp_panel.c:125:34: warning: variable 'panel' set but not used [-Wunused-but-set-variable]
     125 |         struct dp_panel_private *panel;
         |                                  ^~~~~


vim +/panel +125 drivers/gpu/drm/msm/dp/dp_panel.c

   120	
   121	static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel,
   122			u32 mode_edid_bpp, u32 mode_pclk_khz)
   123	{
   124		struct dp_link_info *link_info;
 > 125		struct dp_panel_private *panel;
   126		const u32 max_supported_bpp = 30;
   127		u32 min_supported_bpp = 18;
   128		u32 bpp = 0, link_bitrate = 0, mode_bitrate;
   129		s64 rate_fp = 0;
   130	
   131		panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
   132	
   133		if (dp_panel->dsc_en)
   134			min_supported_bpp = 24;
   135	
   136		bpp = min_t(u32, mode_edid_bpp, max_supported_bpp);
   137	
   138		link_info = &dp_panel->link_info;
   139	
   140		rate_fp = drm_int2fixp(link_info->num_lanes * link_info->rate * 8);
   141	
   142		if (dp_panel->fec_en)
   143			rate_fp = drm_fixp_div(rate_fp, dp_panel->fec_overhead_fp);
   144	
   145		link_bitrate = drm_fixp2int(rate_fp);
   146	
   147		for (; bpp > min_supported_bpp; bpp -= 6) {
   148			if (dp_panel->dsc_en) {
   149				if (bpp == 30 && !(dp_panel->sink_dsc_caps.color_depth & DP_DSC_10_BPC))
   150					continue;
   151				else if (bpp == 24 && !(dp_panel->sink_dsc_caps.color_depth & DP_DSC_8_BPC))
   152					continue;
   153	
   154				mode_bitrate = mode_pclk_khz * DSC_TGT_BPP;
   155			} else {
   156				mode_bitrate = mode_pclk_khz * bpp;
   157			}
   158	
   159			if (mode_bitrate <= link_bitrate)
   160				break;
   161		}
   162	
   163		if (bpp < min_supported_bpp)
   164			DRM_ERROR("bpp %d is below minimum supported bpp %d\n", bpp,
   165					min_supported_bpp);
   166	
   167		if (dp_panel->dsc_en && bpp != 24 && bpp != 30 && bpp != 36)
   168			DRM_ERROR("bpp %d is not supported when dsc is enabled\n", bpp);
   169	
   170		return bpp;
   171	}
   172	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

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

* Re: [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm
  2023-01-23 18:24 ` [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm Kuogee Hsieh
@ 2023-01-23 23:56   ` Dmitry Baryshkov
  2023-01-24  0:08   ` kernel test robot
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-23 23:56 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> At display port, the pixel data is packed into TU (transfer units)
> which is used to carry main video stream data during its horizontal active
> period. TUs are mapping into the main-Link to facilitate the support of
> various lane counts regardless of the pixel bit depth and colorimetry
> format. Stuffing symbols are required if packed data rate less than link
> symbol rate. TU size is calculated base on factors such as, pixel rate,
> BPP, main link rate, main link lane and etc, and shall be 32 to 64
> link symbols per lane. Each vendor has its own algorithm to calculate
> TU size. This patch upgrade TU size calculation base on newest algorithm.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_ctrl.c | 702 +++++++++++++++++++++++----------------
>   1 file changed, 416 insertions(+), 286 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index d0d1848..ae9c2b8 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -182,18 +182,24 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
>    */
>   struct tu_algo_data {
>   	s64 lclk_fp;
> +	s64 orig_lclk_fp;
>   	s64 pclk_fp;
> +	s64 orig_pclk_fp;
>   	s64 lwidth;
>   	s64 lwidth_fp;
> +	int orig_lwidth;
>   	s64 hbp_relative_to_pclk;
>   	s64 hbp_relative_to_pclk_fp;
>   	int nlanes;
> +	int orig_hbp;
>   	int bpp;
>   	int pixelEnc;
>   	int dsc_en;
>   	int async_en;
> +	int fec_en;
>   	int bpc;
>   
> +	int rb2;
>   	uint delay_start_link_extra_pixclk;
>   	int extra_buffer_margin;
>   	s64 ratio_fp;
> @@ -250,19 +256,30 @@ struct tu_algo_data {
>   	int even_distribution_BF;
>   	int even_distribution_legacy;
>   	int even_distribution;
> +
> +	int hbp_delayStartCheck;
> +	int pre_tu_hw_pipe_delay;
> +	int post_tu_hw_pipe_delay;
> +	int link_config_hactive_time;
> +	int delay_start_link_lclk;
> +	int tu_active_cycles;
> +	s64 parity_symbols;
> +	int resolution_line_time;
> +	int last_partial_lclk;
> +
>   	int min_hblank_violated;
>   	s64 delay_start_time_fp;
>   	s64 hbp_time_fp;
>   	s64 hactive_time_fp;
>   	s64 diff_abs_fp;
> -
> +	int second_loop_set;
>   	s64 ratio;
>   };
>   
>   static int _tu_param_compare(s64 a, s64 b)
>   {
> -	u32 a_sign;
> -	u32 b_sign;
> +	u32 a_int, a_frac, a_sign;
> +	u32 b_int, b_frac, b_sign;
>   	s64 a_temp, b_temp, minus_1;
>   
>   	if (a == b)
> @@ -270,8 +287,12 @@ static int _tu_param_compare(s64 a, s64 b)
>   
>   	minus_1 = drm_fixp_from_fraction(-1, 1);
>   
> +	a_int = (a >> 32) & 0x7FFFFFFF;
> +	a_frac = a & 0xFFFFFFFF;
>   	a_sign = (a >> 32) & 0x80000000 ? 1 : 0;
>   
> +	b_int = (b >> 32) & 0x7FFFFFFF;
> +	b_frac = b & 0xFFFFFFFF;
>   	b_sign = (b >> 32) & 0x80000000 ? 1 : 0;
>   
>   	if (a_sign > b_sign)
> @@ -295,6 +316,21 @@ static int _tu_param_compare(s64 a, s64 b)
>   	}
>   }
>   
> +static s64 fixp_subtract(s64 a, s64 b)
> +{
> +	s64 minus_1 = drm_fixp_from_fraction(-1, 1);
> +
> +	if (a >= b)
> +		return a - b;
> +
> +	return drm_fixp_mul(b - a, minus_1);
> +}
> +
> +static inline int fixp2int_ceil(s64 a)
> +{
> +	return a ? drm_fixp2int_ceil(a) : 0;
> +}
> +
>   static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
>   					struct tu_algo_data *tu)
>   {
> @@ -305,6 +341,7 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
>   	s64 pclk_dsc_fp;
>   	s64 dwidth_dsc_fp;
>   	s64 hbp_dsc_fp;
> +	s64 overhead_dsc;
>   
>   	int tot_num_eoc_symbols = 0;
>   	int tot_num_hor_bytes   = 0;
> @@ -315,16 +352,22 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
>   	s64 temp1_fp, temp2_fp, temp3_fp;
>   
>   	tu->lclk_fp              = drm_fixp_from_fraction(in->lclk, 1);
> +	tu->orig_lclk_fp         = tu->lclk_fp;
>   	tu->pclk_fp              = drm_fixp_from_fraction(in->pclk_khz, 1000);
> +	tu->orig_pclk_fp         = tu->pclk_fp;
>   	tu->lwidth               = in->hactive;
>   	tu->hbp_relative_to_pclk = in->hporch;
>   	tu->nlanes               = in->nlanes;
>   	tu->bpp                  = in->bpp;
>   	tu->pixelEnc             = in->pixel_enc;
>   	tu->dsc_en               = in->dsc_en;
> +	tu->fec_en               = in->fec_en;
>   	tu->async_en             = in->async_en;
>   	tu->lwidth_fp            = drm_fixp_from_fraction(in->hactive, 1);
> +	tu->orig_lwidth          = in->hactive;
>   	tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1);
> +	tu->orig_hbp             = in->hporch;
> +	tu->rb2                  = (in->hporch <= 80) ? 1 : 0;
>   
>   	if (tu->pixelEnc == 420) {
>   		temp1_fp = drm_fixp_from_fraction(2, 1);
> @@ -378,6 +421,7 @@ static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in,
>   	dwidth_dsc_bytes = (tot_num_hor_bytes +
>   				tot_num_eoc_symbols +
>   				(eoc_bytes == 0 ? 0 : tot_num_dummy_bytes));
> +	overhead_dsc     = dwidth_dsc_bytes / tot_num_hor_bytes;
>   
>   	dwidth_dsc_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, 3);
>   
> @@ -409,12 +453,12 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
>   	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
>   
> -	tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
> +	tu->new_valid_boundary_link = fixp2int_ceil(temp2_fp);
>   
>   	temp = (tu->i_upper_boundary_count *
>   				tu->new_valid_boundary_link +
>   				tu->i_lower_boundary_count *
> -				(tu->new_valid_boundary_link-1));
> +				(tu->new_valid_boundary_link - 1));
>   	tu->average_valid2_fp = drm_fixp_from_fraction(temp,
>   					(tu->i_upper_boundary_count +
>   					tu->i_lower_boundary_count));
> @@ -489,11 +533,11 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   
>   	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
>   	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
> -	tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp;
> +	tu->n_n_err_fp = fixp_subtract(tu->effective_valid_fp, temp2_fp);
>   
>   	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
>   	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
> -	tu->n_err_fp = tu->average_valid2_fp - temp2_fp;
> +	tu->n_err_fp = fixp_subtract(tu->average_valid2_fp, temp2_fp);
>   
>   	tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
>   
> @@ -501,11 +545,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	temp2_fp = tu->lwidth_fp;
>   	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
>   	temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp);
> -
> -	if (temp2_fp)
> -		tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp);
> -	else
> -		tu->n_tus_incl_last_incomplete_tu = 0;
> +	tu->n_tus_incl_last_incomplete_tu = fixp2int_ceil(temp2_fp);
>   
>   	temp1 = 0;
>   	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
> @@ -513,9 +553,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	temp1_fp = tu->average_valid2_fp - temp2_fp;
>   	temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1);
>   	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
> -
> -	if (temp1_fp)
> -		temp1 = drm_fixp2int_ceil(temp1_fp);
> +	temp1 = fixp2int_ceil(temp1_fp);
>   
>   	temp = tu->i_upper_boundary_count * tu->nlanes;
>   	temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
> @@ -524,32 +562,20 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	temp2_fp = temp1_fp - temp2_fp;
>   	temp1_fp = drm_fixp_from_fraction(temp, 1);
>   	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +	temp2 = fixp2int_ceil(temp2_fp);
>   
> -	if (temp2_fp)
> -		temp2 = drm_fixp2int_ceil(temp2_fp);
> -	else
> -		temp2 = 0;
>   	tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2);
>   
>   	temp1_fp = drm_fixp_from_fraction(8, tu->bpp);
>   	temp2_fp = drm_fixp_from_fraction(
>   	tu->extra_required_bytes_new_tmp, 1);
>   	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
> -
> -	if (temp1_fp)
> -		tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp);
> -	else
> -		tu->extra_pclk_cycles_tmp = 0;
> +	tu->extra_pclk_cycles_tmp = fixp2int_ceil(temp1_fp);
>   
>   	temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1);
>   	temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
>   	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> -
> -	if (temp1_fp)
> -		tu->extra_pclk_cycles_in_link_clk_tmp =
> -						drm_fixp2int_ceil(temp1_fp);
> -	else
> -		tu->extra_pclk_cycles_in_link_clk_tmp = 0;
> +	tu->extra_pclk_cycles_in_link_clk_tmp = fixp2int_ceil(temp1_fp);
>   
>   	tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link;
>   
> @@ -562,6 +588,57 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1);
>   	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
>   
> +	if (tu->rb2) {
> +		temp1_fp = drm_fixp_mul(tu->delay_start_time_fp, tu->lclk_fp);
> +		tu->delay_start_link_lclk = fixp2int_ceil(temp1_fp);
> +
> +		if (tu->remainder_tus > tu->i_upper_boundary_count) {
> +			temp = (tu->remainder_tus - tu->i_upper_boundary_count) *
> +							(tu->new_valid_boundary_link - 1);
> +			temp += (tu->i_upper_boundary_count * tu->new_valid_boundary_link);
> +			temp *= tu->nlanes;
> +		} else {
> +			temp = tu->nlanes * tu->remainder_tus * tu->new_valid_boundary_link;
> +		}
> +
> +		temp1 = tu->i_lower_boundary_count * (tu->new_valid_boundary_link - 1);
> +		temp1 += tu->i_upper_boundary_count * tu->new_valid_boundary_link;
> +		temp1 *= tu->paired_tus * tu->nlanes;
> +		temp1_fp = drm_fixp_from_fraction(tu->n_symbols - temp1 - temp, tu->nlanes);
> +		tu->last_partial_lclk = fixp2int_ceil(temp1_fp);
> +
> +		tu->tu_active_cycles = (int)((tu->n_tus_per_lane * tu->tu_size) +
> +								tu->last_partial_lclk);
> +		tu->post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/;
> +		temp = tu->pre_tu_hw_pipe_delay + tu->delay_start_link_lclk +
> +					tu->tu_active_cycles + tu->post_tu_hw_pipe_delay;
> +
> +		if (tu->fec_en == 1) {
> +			if (tu->nlanes == 1) {
> +				temp1_fp = drm_fixp_from_fraction(temp, 500);
> +				tu->parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1;
> +			} else {
> +				temp1_fp = drm_fixp_from_fraction(temp, 250);
> +				tu->parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1;
> +			}
> +		} else { //no fec BW impact
> +			tu->parity_symbols = 0;
> +		}
> +
> +		tu->link_config_hactive_time = temp + tu->parity_symbols;
> +
> +		if (tu->resolution_line_time >= tu->link_config_hactive_time + 1 /*margin*/)
> +			tu->hbp_delayStartCheck = 1;
> +		else
> +			tu->hbp_delayStartCheck = 0;
> +	} else {
> +		compare_result_3 = _tu_param_compare(tu->hbp_time_fp, tu->delay_start_time_fp);
> +		if (compare_result_3 < 2)
> +			tu->hbp_delayStartCheck = 1;
> +		else
> +			tu->hbp_delayStartCheck = 0;
> +	}
> +
>   	compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp);
>   	if (compare_result_1 == 2)
>   		compare_result_1 = 1;
> @@ -574,13 +651,6 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	else
>   		compare_result_2 = 0;
>   
> -	compare_result_3 = _tu_param_compare(tu->hbp_time_fp,
> -					tu->delay_start_time_fp);
> -	if (compare_result_3 == 2)
> -		compare_result_3 = 0;
> -	else
> -		compare_result_3 = 1;
> -
>   	if (((tu->even_distribution == 1) ||
>   			((tu->even_distribution_BF == 0) &&
>   			(tu->even_distribution_legacy == 0))) &&
> @@ -588,7 +658,7 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   			compare_result_2 &&
>   			(compare_result_1 || (tu->min_hblank_violated == 1)) &&
>   			(tu->new_valid_boundary_link - 1) > 0 &&
> -			compare_result_3 &&
> +			(tu->hbp_delayStartCheck == 1) &&
>   			(tu->delay_start_link_tmp <= 1023)) {
>   		tu->upper_boundary_count = tu->i_upper_boundary_count;
>   		tu->lower_boundary_count = tu->i_lower_boundary_count;
> @@ -607,342 +677,402 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
>   	}
>   }
>   
> +static void _dp_calc_boundary(struct tu_algo_data *tu)
> +{
> +	s64 temp1_fp = 0, temp2_fp = 0;
> +
> +	do {
> +		tu->err_fp = drm_fixp_from_fraction(1000, 1);
> +
> +		temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
> +		temp2_fp = drm_fixp_from_fraction(
> +				tu->delay_start_link_extra_pixclk, 1);
> +		temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
> +		tu->extra_buffer_margin = fixp2int_ceil(temp1_fp);
> +
> +		temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
> +		temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
> +		tu->n_symbols = fixp2int_ceil(temp1_fp);
> +
> +		for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
> +			for (tu->i_upper_boundary_count = 1;
> +				tu->i_upper_boundary_count <= 15;
> +				tu->i_upper_boundary_count++) {
> +				for (tu->i_lower_boundary_count = 1;
> +					tu->i_lower_boundary_count <= 15;
> +					tu->i_lower_boundary_count++) {
> +					_tu_valid_boundary_calc(tu);
> +				}
> +			}
> +		}
> +		tu->delay_start_link_extra_pixclk--;
> +	} while (!tu->boundary_moderation_en &&
> +		tu->boundary_mod_lower_err == 1 &&
> +		tu->delay_start_link_extra_pixclk != 0 &&
> +		((tu->second_loop_set == 0 && tu->rb2 == 1) || tu->rb2 == 0));
> +}
> +
> +static void _dp_calc_extra_bytes(struct tu_algo_data *tu)
> +{
> +	u64 temp = 0;
> +	s64 temp1_fp = 0, temp2_fp = 0;
> +
> +	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
> +	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
> +	temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
> +	temp2_fp = temp1_fp - temp2_fp;
> +	temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1);
> +	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +
> +	temp = drm_fixp2int(temp2_fp);
> +	if (temp)
> +		tu->extra_bytes = fixp2int_ceil(temp2_fp);
> +	else
> +		tu->extra_bytes = 0;
> +
> +	temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1);
> +	temp2_fp = drm_fixp_from_fraction(8, tu->bpp);
> +	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +	tu->extra_pclk_cycles = fixp2int_ceil(temp1_fp);
> +
> +	temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
> +	temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1);
> +	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
> +	tu->extra_pclk_cycles_in_link_clk = fixp2int_ceil(temp1_fp);
> +}
> +
> +
>   static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl,
>   				struct dp_tu_calc_input *in,
>   				struct dp_vc_tu_mapping_table *tu_table)
>   {
> -	struct tu_algo_data *tu;
> +	struct tu_algo_data tu;
>   	int compare_result_1, compare_result_2;
> -	u64 temp = 0;
> +	u64 temp = 0, temp1;
>   	s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
>   
>   	s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */
> -	s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */
> -	s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */
>   	s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000);
>   
>   	u8 DP_BRUTE_FORCE = 1;
>   	s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */
>   	uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
> -	uint HBLANK_MARGIN = 4;
> +	s64 HBLANK_MARGIN = drm_fixp_from_fraction(4, 1);
> +	s64 HBLANK_MARGIN_EXTRA = 0;
>   
> -	tu = kzalloc(sizeof(*tu), GFP_KERNEL);
> -	if (!tu)
> -		return;
>   
> -	dp_panel_update_tu_timings(in, tu);
> +	memset(&tu, 0, sizeof(tu));
>   
> -	tu->err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
> +	dp_panel_update_tu_timings(in, &tu);
> +
> +	tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
>   
>   	temp1_fp = drm_fixp_from_fraction(4, 1);
> -	temp2_fp = drm_fixp_mul(temp1_fp, tu->lclk_fp);
> -	temp_fp = drm_fixp_div(temp2_fp, tu->pclk_fp);
> -	tu->extra_buffer_margin = drm_fixp2int_ceil(temp_fp);
> +	temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
> +	temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
> +	tu.extra_buffer_margin = fixp2int_ceil(temp_fp);
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
> -	temp2_fp = drm_fixp_mul(tu->pclk_fp, temp1_fp);
> -	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
> +	if (in->compress_ratio == 375 && tu.bpp == 30)
> +		temp1_fp = drm_fixp_from_fraction(24, 8);
> +	else
> +		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
> +
> +	temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
> +	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
>   	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
> -	tu->ratio_fp = drm_fixp_div(temp2_fp, tu->lclk_fp);
> -
> -	tu->original_ratio_fp = tu->ratio_fp;
> -	tu->boundary_moderation_en = false;
> -	tu->upper_boundary_count = 0;
> -	tu->lower_boundary_count = 0;
> -	tu->i_upper_boundary_count = 0;
> -	tu->i_lower_boundary_count = 0;
> -	tu->valid_lower_boundary_link = 0;
> -	tu->even_distribution_BF = 0;
> -	tu->even_distribution_legacy = 0;
> -	tu->even_distribution = 0;
> -	tu->delay_start_time_fp = 0;
> -
> -	tu->err_fp = drm_fixp_from_fraction(1000, 1);
> -	tu->n_err_fp = 0;
> -	tu->n_n_err_fp = 0;
> -
> -	tu->ratio = drm_fixp2int(tu->ratio_fp);
> -	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
> -	div64_u64_rem(tu->lwidth_fp, temp1_fp, &temp2_fp);
> -	if (temp2_fp != 0 &&
> -			!tu->ratio && tu->dsc_en == 0) {
> -		tu->ratio_fp = drm_fixp_mul(tu->ratio_fp, RATIO_SCALE_fp);
> -		tu->ratio = drm_fixp2int(tu->ratio_fp);
> -		if (tu->ratio)
> -			tu->ratio_fp = drm_fixp_from_fraction(1, 1);
> +	tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
> +
> +	tu.original_ratio_fp = tu.ratio_fp;
> +	tu.boundary_moderation_en = false;
> +	tu.upper_boundary_count = 0;
> +	tu.lower_boundary_count = 0;
> +	tu.i_upper_boundary_count = 0;
> +	tu.i_lower_boundary_count = 0;
> +	tu.valid_lower_boundary_link = 0;
> +	tu.even_distribution_BF = 0;
> +	tu.even_distribution_legacy = 0;
> +	tu.even_distribution = 0;
> +	tu.hbp_delayStartCheck = 0;
> +	tu.pre_tu_hw_pipe_delay = 0;
> +	tu.post_tu_hw_pipe_delay = 0;
> +	tu.link_config_hactive_time = 0;
> +	tu.delay_start_link_lclk = 0;
> +	tu.tu_active_cycles = 0;
> +	tu.resolution_line_time = 0;
> +	tu.last_partial_lclk = 0;
> +	tu.delay_start_time_fp = 0;
> +	tu.second_loop_set = 0;
> +
> +	tu.err_fp = drm_fixp_from_fraction(1000, 1);
> +	tu.n_err_fp = 0;
> +	tu.n_n_err_fp = 0;
> +
> +	temp = drm_fixp2int(tu.lwidth_fp);
> +	if ((((u32)temp % tu.nlanes) != 0) && (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 2)
> +			&& (tu.dsc_en == 0)) {
> +		tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
> +		if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1)
> +			tu.ratio_fp = DRM_FIXED_ONE;
>   	}
>   
> -	if (tu->ratio > 1)
> -		tu->ratio = 1;
> +	if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1)
> +		tu.ratio_fp = DRM_FIXED_ONE;
>   
> -	if (tu->ratio == 1)
> -		goto tu_size_calc;
> -
> -	compare_result_1 = _tu_param_compare(tu->ratio_fp, const_p49_fp);
> -	if (!compare_result_1 || compare_result_1 == 1)
> -		compare_result_1 = 1;
> -	else
> -		compare_result_1 = 0;
> -
> -	compare_result_2 = _tu_param_compare(tu->ratio_fp, const_p56_fp);
> -	if (!compare_result_2 || compare_result_2 == 2)
> -		compare_result_2 = 1;
> -	else
> -		compare_result_2 = 0;
> -
> -	if (tu->dsc_en && compare_result_1 && compare_result_2) {
> -		HBLANK_MARGIN += 4;
> -		drm_dbg_dp(ctrl->drm_dev,
> -			"increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN);
> +	if (HBLANK_MARGIN_EXTRA != 0) {
> +		HBLANK_MARGIN += HBLANK_MARGIN_EXTRA;
> +		DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
> +			HBLANK_MARGIN_EXTRA);

This code results in format string warnings.

>   	}
>   
> -tu_size_calc:
> -	for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
> -		temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1);
> -		temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
> -		temp = drm_fixp2int_ceil(temp2_fp);
> +	for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
> +		temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
> +		temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
> +		temp = fixp2int_ceil(temp2_fp);
>   		temp1_fp = drm_fixp_from_fraction(temp, 1);
> -		tu->n_err_fp = temp1_fp - temp2_fp;
> +		tu.n_err_fp = temp1_fp - temp2_fp;
>   
> -		if (tu->n_err_fp < tu->err_fp) {
> -			tu->err_fp = tu->n_err_fp;
> -			tu->tu_size_desired = tu->tu_size;
> +		if (tu.n_err_fp < tu.err_fp) {
> +			tu.err_fp = tu.n_err_fp;
> +			tu.tu_size_desired = tu.tu_size;
>   		}
>   	}
>   
> -	tu->tu_size_minus1 = tu->tu_size_desired - 1;
> +	tu.tu_size_minus1 = tu.tu_size_desired - 1;
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
> -	temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
> -	tu->valid_boundary_link = drm_fixp2int_ceil(temp2_fp);
> +	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
> +	temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
> +	tu.valid_boundary_link = fixp2int_ceil(temp2_fp);
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
> -	temp2_fp = tu->lwidth_fp;
> +	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
> +	temp2_fp = tu.lwidth_fp;
>   	temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
> +	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
>   	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
> -	tu->n_tus = drm_fixp2int(temp2_fp);
> +	tu.n_tus = drm_fixp2int(temp2_fp);
>   	if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000)
> -		tu->n_tus += 1;
> -
> -	tu->even_distribution_legacy = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
> -
> -	drm_dbg_dp(ctrl->drm_dev,
> -			"n_sym = %d, num_of_tus = %d\n",
> -			tu->valid_boundary_link, tu->n_tus);
> -
> -	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
> -	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
> -	temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1);
> -	temp2_fp = temp1_fp - temp2_fp;
> -	temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1);
> -	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> -
> -	temp = drm_fixp2int(temp2_fp);
> -	if (temp && temp2_fp)
> -		tu->extra_bytes = drm_fixp2int_ceil(temp2_fp);
> -	else
> -		tu->extra_bytes = 0;
> -
> -	temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1);
> -	temp2_fp = drm_fixp_from_fraction(8, tu->bpp);
> -	temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +		tu.n_tus += 1;
>   
> -	if (temp && temp1_fp)
> -		tu->extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp);
> -	else
> -		tu->extra_pclk_cycles = drm_fixp2int(temp1_fp);
> +	tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
> +	DRM_DEBUG("Info: n_sym = %d, num_of_tus = %d\n",
> +		tu.valid_boundary_link, tu.n_tus);
>   
> -	temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
> -	temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1);
> -	temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
> +	_dp_calc_extra_bytes(&tu);
>   
> -	if (temp1_fp)
> -		tu->extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp);
> -	else
> -		tu->extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp);
> +	tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
>   
> -	tu->filler_size = tu->tu_size_desired - tu->valid_boundary_link;
> +	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
> +	tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
> -	tu->ratio_by_tu_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp);
> -
> -	tu->delay_start_link = tu->extra_pclk_cycles_in_link_clk +
> -				tu->filler_size + tu->extra_buffer_margin;
> +	tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
> +				tu.filler_size + tu.extra_buffer_margin;
>   
> -	tu->resulting_valid_fp =
> -			drm_fixp_from_fraction(tu->valid_boundary_link, 1);
> +	tu.resulting_valid_fp =
> +			drm_fixp_from_fraction(tu.valid_boundary_link, 1);
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
> -	temp2_fp = drm_fixp_div(tu->resulting_valid_fp, temp1_fp);
> -	tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp;
> +	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
> +	temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
> +	tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
>   
> -	temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1);
> -	temp1_fp = tu->hbp_relative_to_pclk_fp - temp1_fp;
> -	tu->hbp_time_fp = drm_fixp_div(temp1_fp, tu->pclk_fp);
> +	temp1_fp = drm_fixp_from_fraction((tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1);
> +	tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1);
> -	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
> +	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
> +	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
>   
> -	compare_result_1 = _tu_param_compare(tu->hbp_time_fp,
> -					tu->delay_start_time_fp);
> -	if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */
> -		tu->min_hblank_violated = 1;
> +	compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
> +					tu.delay_start_time_fp);
> +	if (compare_result_1 == 2) /* hbp_time_fp < delay_start_time_fp */
> +		tu.min_hblank_violated = 1;
>   
> -	tu->hactive_time_fp = drm_fixp_div(tu->lwidth_fp, tu->pclk_fp);
> +	tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp);
>   
> -	compare_result_2 = _tu_param_compare(tu->hactive_time_fp,
> -						tu->delay_start_time_fp);
> +	compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
> +						tu.delay_start_time_fp);
>   	if (compare_result_2 == 2)
> -		tu->min_hblank_violated = 1;
> -
> -	tu->delay_start_time_fp = 0;
> +		tu.min_hblank_violated = 1;
>   
>   	/* brute force */
>   
> -	tu->delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
> -	tu->diff_abs_fp = tu->resulting_valid_fp - tu->ratio_by_tu_fp;
> +	tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
> +	tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
>   
> -	temp = drm_fixp2int(tu->diff_abs_fp);
> -	if (!temp && tu->diff_abs_fp <= 0xffff)
> -		tu->diff_abs_fp = 0;
> +	temp = drm_fixp2int(tu.diff_abs_fp);
> +	if (!temp && tu.diff_abs_fp <= 0xffff)
> +		tu.diff_abs_fp = 0;
>   
>   	/* if(diff_abs < 0) diff_abs *= -1 */
> -	if (tu->diff_abs_fp < 0)
> -		tu->diff_abs_fp = drm_fixp_mul(tu->diff_abs_fp, -1);
> +	if (tu.diff_abs_fp < 0)
> +		tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
> +
> +	tu.boundary_mod_lower_err = 0;
> +
> +	temp1_fp = drm_fixp_div(tu.orig_lclk_fp, tu.orig_pclk_fp);
> +
> +	temp2_fp = drm_fixp_from_fraction(tu.orig_lwidth + tu.orig_hbp, 2);
> +	temp_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +	tu.resolution_line_time = drm_fixp2int(temp_fp);
> +	tu.pre_tu_hw_pipe_delay = fixp2int_ceil(temp1_fp) + 2 /*cdc fifo write jitter+2*/
> +				+ 3 /*pre-delay start cycles*/
> +				+ 3 /*post-delay start cycles*/ + 1 /*BE on the link*/;
> +	tu.post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/;
> +
> +	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
> +	temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
> +	tu.n_symbols = fixp2int_ceil(temp1_fp);
> +
> +	if (tu.rb2) {
> +		temp1_fp = drm_fixp_mul(tu.delay_start_time_fp, tu.lclk_fp);
> +		tu.delay_start_link_lclk = fixp2int_ceil(temp1_fp);
> +
> +		tu.new_valid_boundary_link = tu.valid_boundary_link;
> +		tu.i_upper_boundary_count = 1;
> +		tu.i_lower_boundary_count = 0;
> +
> +		temp1 = tu.i_upper_boundary_count * tu.new_valid_boundary_link;
> +		temp1 += tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1);
> +		tu.average_valid2_fp = drm_fixp_from_fraction(temp1,
> +				(tu.i_upper_boundary_count + tu.i_lower_boundary_count));
> +
> +		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
> +		temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
> +		temp2_fp = drm_fixp_div(temp1_fp, tu.average_valid2_fp);
> +		tu.n_tus = drm_fixp2int(temp2_fp);
> +
> +		tu.n_tus_per_lane = tu.n_tus / tu.nlanes;
> +		tu.paired_tus = (int)((tu.n_tus_per_lane) /
> +				(tu.i_upper_boundary_count + tu.i_lower_boundary_count));
> +
> +		tu.remainder_tus = tu.n_tus_per_lane - tu.paired_tus *
> +				(tu.i_upper_boundary_count + tu.i_lower_boundary_count);
> +
> +		if (tu.remainder_tus > tu.i_upper_boundary_count) {
> +			temp = (tu.remainder_tus - tu.i_upper_boundary_count) *
> +							(tu.new_valid_boundary_link - 1);
> +			temp += (tu.i_upper_boundary_count * tu.new_valid_boundary_link);
> +			temp *= tu.nlanes;
> +		} else {
> +			temp = tu.nlanes * tu.remainder_tus * tu.new_valid_boundary_link;
> +		}
>   
> -	tu->boundary_mod_lower_err = 0;
> -	if ((tu->diff_abs_fp != 0 &&
> -			((tu->diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
> -			 (tu->even_distribution_legacy == 0) ||
> -			 (DP_BRUTE_FORCE == 1))) ||
> -			(tu->min_hblank_violated == 1)) {
> -		do {
> -			tu->err_fp = drm_fixp_from_fraction(1000, 1);
> +		temp1 = tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1);
> +		temp1 += tu.i_upper_boundary_count * tu.new_valid_boundary_link;
> +		temp1 *= tu.paired_tus * tu.nlanes;
> +		temp1_fp = drm_fixp_from_fraction(tu.n_symbols - temp1 - temp, tu.nlanes);
> +		tu.last_partial_lclk = fixp2int_ceil(temp1_fp);
> +
> +		tu.tu_active_cycles = (int)((tu.n_tus_per_lane * tu.tu_size) +
> +								tu.last_partial_lclk);
> +
> +		temp = tu.pre_tu_hw_pipe_delay + tu.delay_start_link_lclk +
> +						tu.tu_active_cycles + tu.post_tu_hw_pipe_delay;
> +
> +		if (tu.fec_en == 1) {
> +			if (tu.nlanes == 1) {
> +				temp1_fp = drm_fixp_from_fraction(temp, 500);
> +				tu.parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1;
> +			} else {
> +				temp1_fp = drm_fixp_from_fraction(temp, 250);
> +				tu.parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1;
> +			}
> +		} else { //no fec BW impact
> +			tu.parity_symbols = 0;
> +		}
>   
> -			temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp);
> -			temp2_fp = drm_fixp_from_fraction(
> -					tu->delay_start_link_extra_pixclk, 1);
> -			temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp);
> +		tu.link_config_hactive_time = temp + tu.parity_symbols;
>   
> -			if (temp1_fp)
> -				tu->extra_buffer_margin =
> -					drm_fixp2int_ceil(temp1_fp);
> -			else
> -				tu->extra_buffer_margin = 0;
> +		if (tu.link_config_hactive_time + 1 /*margin*/ >= tu.resolution_line_time)
> +			tu.min_hblank_violated = 1;
> +	}
>   
> -			temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
> -			temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
> +	tu.delay_start_time_fp = 0;
>   
> -			if (temp1_fp)
> -				tu->n_symbols = drm_fixp2int_ceil(temp1_fp);
> -			else
> -				tu->n_symbols = 0;
> -
> -			for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
> -				for (tu->i_upper_boundary_count = 1;
> -					tu->i_upper_boundary_count <= 15;
> -					tu->i_upper_boundary_count++) {
> -					for (tu->i_lower_boundary_count = 1;
> -						tu->i_lower_boundary_count <= 15;
> -						tu->i_lower_boundary_count++) {
> -						_tu_valid_boundary_calc(tu);
> -					}
> -				}
> -			}
> -			tu->delay_start_link_extra_pixclk--;
> -		} while (tu->boundary_moderation_en != true &&
> -			tu->boundary_mod_lower_err == 1 &&
> -			tu->delay_start_link_extra_pixclk != 0);
> +	if ((tu.diff_abs_fp != 0 &&
> +			((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
> +			 (tu.even_distribution_legacy == 0) ||
> +			 (DP_BRUTE_FORCE == 1))) ||
> +			(tu.min_hblank_violated == 1)) {
> +		_dp_calc_boundary(&tu);
>   
> -		if (tu->boundary_moderation_en == true) {
> +		if (tu.boundary_moderation_en) {
>   			temp1_fp = drm_fixp_from_fraction(
> -					(tu->upper_boundary_count *
> -					tu->valid_boundary_link +
> -					tu->lower_boundary_count *
> -					(tu->valid_boundary_link - 1)), 1);
> +					(tu.upper_boundary_count *
> +					tu.valid_boundary_link +
> +					tu.lower_boundary_count *
> +					(tu.valid_boundary_link - 1)), 1);
>   			temp2_fp = drm_fixp_from_fraction(
> -					(tu->upper_boundary_count +
> -					tu->lower_boundary_count), 1);
> -			tu->resulting_valid_fp =
> +					(tu.upper_boundary_count +
> +					tu.lower_boundary_count), 1);
> +			tu.resulting_valid_fp =
>   					drm_fixp_div(temp1_fp, temp2_fp);
>   
>   			temp1_fp = drm_fixp_from_fraction(
> -					tu->tu_size_desired, 1);
> -			tu->ratio_by_tu_fp =
> -				drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
> +					tu.tu_size_desired, 1);
> +			tu.ratio_by_tu_fp =
> +				drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
>   
> -			tu->valid_lower_boundary_link =
> -				tu->valid_boundary_link - 1;
> +			tu.valid_lower_boundary_link =
> +				tu.valid_boundary_link - 1;
>   
> -			temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
> -			temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp);
> +			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
> +			temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
>   			temp2_fp = drm_fixp_div(temp1_fp,
> -						tu->resulting_valid_fp);
> -			tu->n_tus = drm_fixp2int(temp2_fp);
> +						tu.resulting_valid_fp);
> +			tu.n_tus = drm_fixp2int(temp2_fp);
>   
> -			tu->tu_size_minus1 = tu->tu_size_desired - 1;
> -			tu->even_distribution_BF = 1;
> +			tu.tu_size_minus1 = tu.tu_size_desired - 1;
> +			tu.even_distribution_BF = 1;
>   
>   			temp1_fp =
> -				drm_fixp_from_fraction(tu->tu_size_desired, 1);
> +				drm_fixp_from_fraction(tu.tu_size_desired, 1);
>   			temp2_fp =
> -				drm_fixp_div(tu->resulting_valid_fp, temp1_fp);
> -			tu->TU_ratio_err_fp = temp2_fp - tu->original_ratio_fp;
> +				drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
> +			tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
>   		}
>   	}
>   
> -	temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu->lwidth_fp);
> +	if (tu.async_en) {
> +		temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp);
> +		temp = fixp2int_ceil(temp2_fp);
>   
> -	if (temp2_fp)
> -		temp = drm_fixp2int_ceil(temp2_fp);
> -	else
> -		temp = 0;
> -
> -	temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1);
> -	temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
> -	temp1_fp = drm_fixp_from_fraction(tu->bpp, 8);
> -	temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
> -	temp1_fp = drm_fixp_from_fraction(temp, 1);
> -	temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> -	temp = drm_fixp2int(temp2_fp);
> +		temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
> +		temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
> +		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
> +		temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
> +		temp1_fp = drm_fixp_from_fraction(temp, 1);
> +		temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
> +		temp = drm_fixp2int(temp2_fp);
>   
> -	if (tu->async_en)
> -		tu->delay_start_link += (int)temp;
> +		tu.delay_start_link += (int)temp;
> +	}
>   
> -	temp1_fp = drm_fixp_from_fraction(tu->delay_start_link, 1);
> -	tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp);
> +	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
> +	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
>   
>   	/* OUTPUTS */
> -	tu_table->valid_boundary_link       = tu->valid_boundary_link;
> -	tu_table->delay_start_link          = tu->delay_start_link;
> -	tu_table->boundary_moderation_en    = tu->boundary_moderation_en;
> -	tu_table->valid_lower_boundary_link = tu->valid_lower_boundary_link;
> -	tu_table->upper_boundary_count      = tu->upper_boundary_count;
> -	tu_table->lower_boundary_count      = tu->lower_boundary_count;
> -	tu_table->tu_size_minus1            = tu->tu_size_minus1;
> -
> -	drm_dbg_dp(ctrl->drm_dev, "TU: valid_boundary_link: %d\n",
> -				tu_table->valid_boundary_link);
> -	drm_dbg_dp(ctrl->drm_dev, "TU: delay_start_link: %d\n",
> -				tu_table->delay_start_link);
> -	drm_dbg_dp(ctrl->drm_dev, "TU: boundary_moderation_en: %d\n",
> +	tu_table->valid_boundary_link       = tu.valid_boundary_link;
> +	tu_table->delay_start_link          = tu.delay_start_link;
> +	tu_table->boundary_moderation_en    = tu.boundary_moderation_en;
> +	tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
> +	tu_table->upper_boundary_count      = tu.upper_boundary_count;
> +	tu_table->lower_boundary_count      = tu.lower_boundary_count;
> +	tu_table->tu_size_minus1            = tu.tu_size_minus1;
> +
> +	DRM_DEBUG("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link);
> +	DRM_DEBUG("TU: delay_start_link: %d\n", tu_table->delay_start_link);
> +	DRM_DEBUG("TU: boundary_moderation_en: %d\n",
>   			tu_table->boundary_moderation_en);
> -	drm_dbg_dp(ctrl->drm_dev, "TU: valid_lower_boundary_link: %d\n",
> +	DRM_DEBUG("TU: valid_lower_boundary_link: %d\n",
>   			tu_table->valid_lower_boundary_link);
> -	drm_dbg_dp(ctrl->drm_dev, "TU: upper_boundary_count: %d\n",
> +	DRM_DEBUG("TU: upper_boundary_count: %d\n",
>   			tu_table->upper_boundary_count);
> -	drm_dbg_dp(ctrl->drm_dev, "TU: lower_boundary_count: %d\n",
> +	DRM_DEBUG("TU: lower_boundary_count: %d\n",
>   			tu_table->lower_boundary_count);
> -	drm_dbg_dp(ctrl->drm_dev, "TU: tu_size_minus1: %d\n",
> -			tu_table->tu_size_minus1);
> -
> -	kfree(tu);
> +	DRM_DEBUG("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
>   }
>   
>   static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
> -		struct dp_vc_tu_mapping_table *tu_table)
> +				struct dp_vc_tu_mapping_table *tu_table)
>   {
>   	struct dp_tu_calc_input in;
>   	struct drm_display_mode *drm_mode;

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm
  2023-01-23 18:24 ` [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm Kuogee Hsieh
  2023-01-23 23:56   ` Dmitry Baryshkov
@ 2023-01-24  0:08   ` kernel test robot
  1 sibling, 0 replies; 50+ messages in thread
From: kernel test robot @ 2023-01-24  0:08 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, Kuogee Hsieh,
	oe-kbuild-all, freedreno, linux-kernel

Hi Kuogee,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on next-20230123]
[also build test WARNING on linus/master v6.2-rc5]
[cannot apply to drm-misc/drm-misc-next drm/drm-next drm-exynos/exynos-drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-tip/drm-tip v6.2-rc5 v6.2-rc4 v6.2-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kuogee-Hsieh/drm-msm-dp-add-dpcd-read-of-both-dsc-and-fec-capability/20230124-022759
patch link:    https://lore.kernel.org/r/1674498274-6010-6-git-send-email-quic_khsieh%40quicinc.com
patch subject: [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20230124/202301240854.5yJVG3RR-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/286a3dd6028ada56b471b5cb977f5ed461b094e4
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Kuogee-Hsieh/drm-msm-dp-add-dpcd-read-of-both-dsc-and-fec-capability/20230124-022759
        git checkout 286a3dd6028ada56b471b5cb977f5ed461b094e4
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/gpu/drm/msm/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/msm/dp/dp_ctrl.c: In function '_tu_param_compare':
   drivers/gpu/drm/msm/dp/dp_ctrl.c:282:20: warning: variable 'b_frac' set but not used [-Wunused-but-set-variable]
     282 |         u32 b_int, b_frac, b_sign;
         |                    ^~~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:282:13: warning: variable 'b_int' set but not used [-Wunused-but-set-variable]
     282 |         u32 b_int, b_frac, b_sign;
         |             ^~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:281:20: warning: variable 'a_frac' set but not used [-Wunused-but-set-variable]
     281 |         u32 a_int, a_frac, a_sign;
         |                    ^~~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:281:13: warning: variable 'a_int' set but not used [-Wunused-but-set-variable]
     281 |         u32 a_int, a_frac, a_sign;
         |             ^~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c: In function 'dp_panel_update_tu_timings':
   drivers/gpu/drm/msm/dp/dp_ctrl.c:344:13: warning: variable 'overhead_dsc' set but not used [-Wunused-but-set-variable]
     344 |         s64 overhead_dsc;
         |             ^~~~~~~~~~~~
   In file included from drivers/gpu/drm/msm/dp/dp_ctrl.c:18:
   drivers/gpu/drm/msm/dp/dp_ctrl.c: In function '_dp_ctrl_calc_tu':
   drivers/gpu/drm/msm/dp/dp_ctrl.c:823:27: warning: format '%d' expects argument of type 'int', but argument 4 has type 's64' {aka 'long long int'} [-Wformat=]
     823 |                 DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~
         |                                                                             |
         |                                                                             s64 {aka long long int}
   include/drm/drm_print.h:524:65: note: in definition of macro '__drm_dbg'
     524 | #define __drm_dbg(fmt, ...)             ___drm_dbg(NULL, fmt, ##__VA_ARGS__)
         |                                                                 ^~~~~~~~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:823:17: note: in expansion of macro 'DRM_DEBUG'
     823 |                 DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
         |                 ^~~~~~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:823:61: note: format string is defined here
     823 |                 DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
         |                                                            ~^
         |                                                             |
         |                                                             int
         |                                                            %lld
   drivers/gpu/drm/msm/dp/dp_ctrl.c:823:27: warning: format '%d' expects argument of type 'int', but argument 5 has type 's64' {aka 'long long int'} [-Wformat=]
     823 |                 DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     824 |                         HBLANK_MARGIN_EXTRA);
         |                         ~~~~~~~~~~~~~~~~~~~
         |                         |
         |                         s64 {aka long long int}
   include/drm/drm_print.h:524:65: note: in definition of macro '__drm_dbg'
     524 | #define __drm_dbg(fmt, ...)             ___drm_dbg(NULL, fmt, ##__VA_ARGS__)
         |                                                                 ^~~~~~~~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:823:17: note: in expansion of macro 'DRM_DEBUG'
     823 |                 DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
         |                 ^~~~~~~~~
   drivers/gpu/drm/msm/dp/dp_ctrl.c:823:70: note: format string is defined here
     823 |                 DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
         |                                                                     ~^
         |                                                                      |
         |                                                                      int
         |                                                                     %lld
   drivers/gpu/drm/msm/dp/dp_ctrl.c: In function '_dp_ctrl_calc_tu.constprop':
>> drivers/gpu/drm/msm/dp/dp_ctrl.c:1072:1: warning: the frame size of 1084 bytes is larger than 1024 bytes [-Wframe-larger-than=]
    1072 | }
         | ^


vim +1072 drivers/gpu/drm/msm/dp/dp_ctrl.c

286a3dd6028ada Kuogee Hsieh     2023-01-23   743  
286a3dd6028ada Kuogee Hsieh     2023-01-23   744  
202aceac8bb3ae Kuogee Hsieh     2022-02-17   745  static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl,
202aceac8bb3ae Kuogee Hsieh     2022-02-17   746  				struct dp_tu_calc_input *in,
c943b4948b5848 Chandan Uddaraju 2020-08-27   747  				struct dp_vc_tu_mapping_table *tu_table)
c943b4948b5848 Chandan Uddaraju 2020-08-27   748  {
286a3dd6028ada Kuogee Hsieh     2023-01-23   749  	struct tu_algo_data tu;
c943b4948b5848 Chandan Uddaraju 2020-08-27   750  	int compare_result_1, compare_result_2;
286a3dd6028ada Kuogee Hsieh     2023-01-23   751  	u64 temp = 0, temp1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   752  	s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0;
c943b4948b5848 Chandan Uddaraju 2020-08-27   753  
c943b4948b5848 Chandan Uddaraju 2020-08-27   754  	s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */
c943b4948b5848 Chandan Uddaraju 2020-08-27   755  	s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000);
c943b4948b5848 Chandan Uddaraju 2020-08-27   756  
c943b4948b5848 Chandan Uddaraju 2020-08-27   757  	u8 DP_BRUTE_FORCE = 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   758  	s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */
c943b4948b5848 Chandan Uddaraju 2020-08-27   759  	uint EXTRA_PIXCLK_CYCLE_DELAY = 4;
286a3dd6028ada Kuogee Hsieh     2023-01-23   760  	s64 HBLANK_MARGIN = drm_fixp_from_fraction(4, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   761  	s64 HBLANK_MARGIN_EXTRA = 0;
c943b4948b5848 Chandan Uddaraju 2020-08-27   762  
c943b4948b5848 Chandan Uddaraju 2020-08-27   763  
286a3dd6028ada Kuogee Hsieh     2023-01-23   764  	memset(&tu, 0, sizeof(tu));
c943b4948b5848 Chandan Uddaraju 2020-08-27   765  
286a3dd6028ada Kuogee Hsieh     2023-01-23   766  	dp_panel_update_tu_timings(in, &tu);
c943b4948b5848 Chandan Uddaraju 2020-08-27   767  
286a3dd6028ada Kuogee Hsieh     2023-01-23   768  	tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */
c943b4948b5848 Chandan Uddaraju 2020-08-27   769  
286a3dd6028ada Kuogee Hsieh     2023-01-23   770  	temp1_fp = drm_fixp_from_fraction(4, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   771  	temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   772  	temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   773  	tu.extra_buffer_margin = fixp2int_ceil(temp_fp);
cc9014bf63a4d8 Lee Jones        2020-11-24   774  
286a3dd6028ada Kuogee Hsieh     2023-01-23   775  	if (in->compress_ratio == 375 && tu.bpp == 30)
286a3dd6028ada Kuogee Hsieh     2023-01-23   776  		temp1_fp = drm_fixp_from_fraction(24, 8);
286a3dd6028ada Kuogee Hsieh     2023-01-23   777  	else
286a3dd6028ada Kuogee Hsieh     2023-01-23   778  		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
cc9014bf63a4d8 Lee Jones        2020-11-24   779  
286a3dd6028ada Kuogee Hsieh     2023-01-23   780  	temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   781  	temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   782  	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   783  	tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   784  
286a3dd6028ada Kuogee Hsieh     2023-01-23   785  	tu.original_ratio_fp = tu.ratio_fp;
286a3dd6028ada Kuogee Hsieh     2023-01-23   786  	tu.boundary_moderation_en = false;
286a3dd6028ada Kuogee Hsieh     2023-01-23   787  	tu.upper_boundary_count = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   788  	tu.lower_boundary_count = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   789  	tu.i_upper_boundary_count = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   790  	tu.i_lower_boundary_count = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   791  	tu.valid_lower_boundary_link = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   792  	tu.even_distribution_BF = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   793  	tu.even_distribution_legacy = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   794  	tu.even_distribution = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   795  	tu.hbp_delayStartCheck = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   796  	tu.pre_tu_hw_pipe_delay = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   797  	tu.post_tu_hw_pipe_delay = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   798  	tu.link_config_hactive_time = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   799  	tu.delay_start_link_lclk = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   800  	tu.tu_active_cycles = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   801  	tu.resolution_line_time = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   802  	tu.last_partial_lclk = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   803  	tu.delay_start_time_fp = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   804  	tu.second_loop_set = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   805  
286a3dd6028ada Kuogee Hsieh     2023-01-23   806  	tu.err_fp = drm_fixp_from_fraction(1000, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   807  	tu.n_err_fp = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   808  	tu.n_n_err_fp = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   809  
286a3dd6028ada Kuogee Hsieh     2023-01-23   810  	temp = drm_fixp2int(tu.lwidth_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   811  	if ((((u32)temp % tu.nlanes) != 0) && (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 2)
286a3dd6028ada Kuogee Hsieh     2023-01-23   812  			&& (tu.dsc_en == 0)) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   813  		tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   814  		if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1)
286a3dd6028ada Kuogee Hsieh     2023-01-23   815  			tu.ratio_fp = DRM_FIXED_ONE;
c943b4948b5848 Chandan Uddaraju 2020-08-27   816  	}
c943b4948b5848 Chandan Uddaraju 2020-08-27   817  
286a3dd6028ada Kuogee Hsieh     2023-01-23   818  	if (_tu_param_compare(tu.ratio_fp, DRM_FIXED_ONE) == 1)
286a3dd6028ada Kuogee Hsieh     2023-01-23   819  		tu.ratio_fp = DRM_FIXED_ONE;
c943b4948b5848 Chandan Uddaraju 2020-08-27   820  
286a3dd6028ada Kuogee Hsieh     2023-01-23   821  	if (HBLANK_MARGIN_EXTRA != 0) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   822  		HBLANK_MARGIN += HBLANK_MARGIN_EXTRA;
286a3dd6028ada Kuogee Hsieh     2023-01-23   823  		DRM_DEBUG("Info: increase HBLANK_MARGIN to %d. (PLUS%d)\n", HBLANK_MARGIN,
286a3dd6028ada Kuogee Hsieh     2023-01-23   824  			HBLANK_MARGIN_EXTRA);
c943b4948b5848 Chandan Uddaraju 2020-08-27   825  	}
c943b4948b5848 Chandan Uddaraju 2020-08-27   826  
286a3dd6028ada Kuogee Hsieh     2023-01-23   827  	for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   828  		temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   829  		temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   830  		temp = fixp2int_ceil(temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   831  		temp1_fp = drm_fixp_from_fraction(temp, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   832  		tu.n_err_fp = temp1_fp - temp2_fp;
c943b4948b5848 Chandan Uddaraju 2020-08-27   833  
286a3dd6028ada Kuogee Hsieh     2023-01-23   834  		if (tu.n_err_fp < tu.err_fp) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   835  			tu.err_fp = tu.n_err_fp;
286a3dd6028ada Kuogee Hsieh     2023-01-23   836  			tu.tu_size_desired = tu.tu_size;
c943b4948b5848 Chandan Uddaraju 2020-08-27   837  		}
c943b4948b5848 Chandan Uddaraju 2020-08-27   838  	}
c943b4948b5848 Chandan Uddaraju 2020-08-27   839  
286a3dd6028ada Kuogee Hsieh     2023-01-23   840  	tu.tu_size_minus1 = tu.tu_size_desired - 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   841  
286a3dd6028ada Kuogee Hsieh     2023-01-23   842  	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   843  	temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   844  	tu.valid_boundary_link = fixp2int_ceil(temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   845  
286a3dd6028ada Kuogee Hsieh     2023-01-23   846  	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
286a3dd6028ada Kuogee Hsieh     2023-01-23   847  	temp2_fp = tu.lwidth_fp;
c943b4948b5848 Chandan Uddaraju 2020-08-27   848  	temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   849  
286a3dd6028ada Kuogee Hsieh     2023-01-23   850  	temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1);
c943b4948b5848 Chandan Uddaraju 2020-08-27   851  	temp2_fp = drm_fixp_div(temp2_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   852  	tu.n_tus = drm_fixp2int(temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   853  	if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000)
286a3dd6028ada Kuogee Hsieh     2023-01-23   854  		tu.n_tus += 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   855  
286a3dd6028ada Kuogee Hsieh     2023-01-23   856  	tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   857  	DRM_DEBUG("Info: n_sym = %d, num_of_tus = %d\n",
286a3dd6028ada Kuogee Hsieh     2023-01-23   858  		tu.valid_boundary_link, tu.n_tus);
202aceac8bb3ae Kuogee Hsieh     2022-02-17   859  
286a3dd6028ada Kuogee Hsieh     2023-01-23   860  	_dp_calc_extra_bytes(&tu);
c943b4948b5848 Chandan Uddaraju 2020-08-27   861  
286a3dd6028ada Kuogee Hsieh     2023-01-23   862  	tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link;
c943b4948b5848 Chandan Uddaraju 2020-08-27   863  
286a3dd6028ada Kuogee Hsieh     2023-01-23   864  	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   865  	tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   866  
286a3dd6028ada Kuogee Hsieh     2023-01-23   867  	tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk +
286a3dd6028ada Kuogee Hsieh     2023-01-23   868  				tu.filler_size + tu.extra_buffer_margin;
c943b4948b5848 Chandan Uddaraju 2020-08-27   869  
286a3dd6028ada Kuogee Hsieh     2023-01-23   870  	tu.resulting_valid_fp =
286a3dd6028ada Kuogee Hsieh     2023-01-23   871  			drm_fixp_from_fraction(tu.valid_boundary_link, 1);
c943b4948b5848 Chandan Uddaraju 2020-08-27   872  
286a3dd6028ada Kuogee Hsieh     2023-01-23   873  	temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   874  	temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   875  	tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
c943b4948b5848 Chandan Uddaraju 2020-08-27   876  
286a3dd6028ada Kuogee Hsieh     2023-01-23   877  	temp1_fp = drm_fixp_from_fraction((tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   878  	tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   879  
286a3dd6028ada Kuogee Hsieh     2023-01-23   880  	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   881  	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   882  
286a3dd6028ada Kuogee Hsieh     2023-01-23   883  	compare_result_1 = _tu_param_compare(tu.hbp_time_fp,
286a3dd6028ada Kuogee Hsieh     2023-01-23   884  					tu.delay_start_time_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   885  	if (compare_result_1 == 2) /* hbp_time_fp < delay_start_time_fp */
286a3dd6028ada Kuogee Hsieh     2023-01-23   886  		tu.min_hblank_violated = 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   887  
286a3dd6028ada Kuogee Hsieh     2023-01-23   888  	tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   889  
286a3dd6028ada Kuogee Hsieh     2023-01-23   890  	compare_result_2 = _tu_param_compare(tu.hactive_time_fp,
286a3dd6028ada Kuogee Hsieh     2023-01-23   891  						tu.delay_start_time_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   892  	if (compare_result_2 == 2)
286a3dd6028ada Kuogee Hsieh     2023-01-23   893  		tu.min_hblank_violated = 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   894  
c943b4948b5848 Chandan Uddaraju 2020-08-27   895  	/* brute force */
c943b4948b5848 Chandan Uddaraju 2020-08-27   896  
286a3dd6028ada Kuogee Hsieh     2023-01-23   897  	tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY;
286a3dd6028ada Kuogee Hsieh     2023-01-23   898  	tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp;
c943b4948b5848 Chandan Uddaraju 2020-08-27   899  
286a3dd6028ada Kuogee Hsieh     2023-01-23   900  	temp = drm_fixp2int(tu.diff_abs_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   901  	if (!temp && tu.diff_abs_fp <= 0xffff)
286a3dd6028ada Kuogee Hsieh     2023-01-23   902  		tu.diff_abs_fp = 0;
c943b4948b5848 Chandan Uddaraju 2020-08-27   903  
c943b4948b5848 Chandan Uddaraju 2020-08-27   904  	/* if(diff_abs < 0) diff_abs *= -1 */
286a3dd6028ada Kuogee Hsieh     2023-01-23   905  	if (tu.diff_abs_fp < 0)
286a3dd6028ada Kuogee Hsieh     2023-01-23   906  		tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   907  
286a3dd6028ada Kuogee Hsieh     2023-01-23   908  	tu.boundary_mod_lower_err = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   909  
286a3dd6028ada Kuogee Hsieh     2023-01-23   910  	temp1_fp = drm_fixp_div(tu.orig_lclk_fp, tu.orig_pclk_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   911  
286a3dd6028ada Kuogee Hsieh     2023-01-23   912  	temp2_fp = drm_fixp_from_fraction(tu.orig_lwidth + tu.orig_hbp, 2);
286a3dd6028ada Kuogee Hsieh     2023-01-23   913  	temp_fp = drm_fixp_mul(temp1_fp, temp2_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   914  	tu.resolution_line_time = drm_fixp2int(temp_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   915  	tu.pre_tu_hw_pipe_delay = fixp2int_ceil(temp1_fp) + 2 /*cdc fifo write jitter+2*/
286a3dd6028ada Kuogee Hsieh     2023-01-23   916  				+ 3 /*pre-delay start cycles*/
286a3dd6028ada Kuogee Hsieh     2023-01-23   917  				+ 3 /*post-delay start cycles*/ + 1 /*BE on the link*/;
286a3dd6028ada Kuogee Hsieh     2023-01-23   918  	tu.post_tu_hw_pipe_delay = 4 /*BS_on_the_link*/ + 1 /*BE_next_ren*/;
286a3dd6028ada Kuogee Hsieh     2023-01-23   919  
286a3dd6028ada Kuogee Hsieh     2023-01-23   920  	temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
286a3dd6028ada Kuogee Hsieh     2023-01-23   921  	temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   922  	tu.n_symbols = fixp2int_ceil(temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   923  
286a3dd6028ada Kuogee Hsieh     2023-01-23   924  	if (tu.rb2) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   925  		temp1_fp = drm_fixp_mul(tu.delay_start_time_fp, tu.lclk_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   926  		tu.delay_start_link_lclk = fixp2int_ceil(temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   927  
286a3dd6028ada Kuogee Hsieh     2023-01-23   928  		tu.new_valid_boundary_link = tu.valid_boundary_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23   929  		tu.i_upper_boundary_count = 1;
286a3dd6028ada Kuogee Hsieh     2023-01-23   930  		tu.i_lower_boundary_count = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   931  
286a3dd6028ada Kuogee Hsieh     2023-01-23   932  		temp1 = tu.i_upper_boundary_count * tu.new_valid_boundary_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23   933  		temp1 += tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   934  		tu.average_valid2_fp = drm_fixp_from_fraction(temp1,
286a3dd6028ada Kuogee Hsieh     2023-01-23   935  				(tu.i_upper_boundary_count + tu.i_lower_boundary_count));
286a3dd6028ada Kuogee Hsieh     2023-01-23   936  
286a3dd6028ada Kuogee Hsieh     2023-01-23   937  		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
286a3dd6028ada Kuogee Hsieh     2023-01-23   938  		temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   939  		temp2_fp = drm_fixp_div(temp1_fp, tu.average_valid2_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   940  		tu.n_tus = drm_fixp2int(temp2_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23   941  
286a3dd6028ada Kuogee Hsieh     2023-01-23   942  		tu.n_tus_per_lane = tu.n_tus / tu.nlanes;
286a3dd6028ada Kuogee Hsieh     2023-01-23   943  		tu.paired_tus = (int)((tu.n_tus_per_lane) /
286a3dd6028ada Kuogee Hsieh     2023-01-23   944  				(tu.i_upper_boundary_count + tu.i_lower_boundary_count));
286a3dd6028ada Kuogee Hsieh     2023-01-23   945  
286a3dd6028ada Kuogee Hsieh     2023-01-23   946  		tu.remainder_tus = tu.n_tus_per_lane - tu.paired_tus *
286a3dd6028ada Kuogee Hsieh     2023-01-23   947  				(tu.i_upper_boundary_count + tu.i_lower_boundary_count);
286a3dd6028ada Kuogee Hsieh     2023-01-23   948  
286a3dd6028ada Kuogee Hsieh     2023-01-23   949  		if (tu.remainder_tus > tu.i_upper_boundary_count) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   950  			temp = (tu.remainder_tus - tu.i_upper_boundary_count) *
286a3dd6028ada Kuogee Hsieh     2023-01-23   951  							(tu.new_valid_boundary_link - 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   952  			temp += (tu.i_upper_boundary_count * tu.new_valid_boundary_link);
286a3dd6028ada Kuogee Hsieh     2023-01-23   953  			temp *= tu.nlanes;
286a3dd6028ada Kuogee Hsieh     2023-01-23   954  		} else {
286a3dd6028ada Kuogee Hsieh     2023-01-23   955  			temp = tu.nlanes * tu.remainder_tus * tu.new_valid_boundary_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23   956  		}
c943b4948b5848 Chandan Uddaraju 2020-08-27   957  
286a3dd6028ada Kuogee Hsieh     2023-01-23   958  		temp1 = tu.i_lower_boundary_count * (tu.new_valid_boundary_link - 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23   959  		temp1 += tu.i_upper_boundary_count * tu.new_valid_boundary_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23   960  		temp1 *= tu.paired_tus * tu.nlanes;
286a3dd6028ada Kuogee Hsieh     2023-01-23   961  		temp1_fp = drm_fixp_from_fraction(tu.n_symbols - temp1 - temp, tu.nlanes);
286a3dd6028ada Kuogee Hsieh     2023-01-23   962  		tu.last_partial_lclk = fixp2int_ceil(temp1_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27   963  
286a3dd6028ada Kuogee Hsieh     2023-01-23   964  		tu.tu_active_cycles = (int)((tu.n_tus_per_lane * tu.tu_size) +
286a3dd6028ada Kuogee Hsieh     2023-01-23   965  								tu.last_partial_lclk);
c943b4948b5848 Chandan Uddaraju 2020-08-27   966  
286a3dd6028ada Kuogee Hsieh     2023-01-23   967  		temp = tu.pre_tu_hw_pipe_delay + tu.delay_start_link_lclk +
286a3dd6028ada Kuogee Hsieh     2023-01-23   968  						tu.tu_active_cycles + tu.post_tu_hw_pipe_delay;
cc9014bf63a4d8 Lee Jones        2020-11-24   969  
286a3dd6028ada Kuogee Hsieh     2023-01-23   970  		if (tu.fec_en == 1) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   971  			if (tu.nlanes == 1) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   972  				temp1_fp = drm_fixp_from_fraction(temp, 500);
286a3dd6028ada Kuogee Hsieh     2023-01-23   973  				tu.parity_symbols = fixp2int_ceil(temp1_fp) * 12 + 1;
286a3dd6028ada Kuogee Hsieh     2023-01-23   974  			} else {
286a3dd6028ada Kuogee Hsieh     2023-01-23   975  				temp1_fp = drm_fixp_from_fraction(temp, 250);
286a3dd6028ada Kuogee Hsieh     2023-01-23   976  				tu.parity_symbols = fixp2int_ceil(temp1_fp) * 6 + 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   977  			}
286a3dd6028ada Kuogee Hsieh     2023-01-23   978  		} else { //no fec BW impact
286a3dd6028ada Kuogee Hsieh     2023-01-23   979  			tu.parity_symbols = 0;
c943b4948b5848 Chandan Uddaraju 2020-08-27   980  		}
286a3dd6028ada Kuogee Hsieh     2023-01-23   981  
286a3dd6028ada Kuogee Hsieh     2023-01-23   982  		tu.link_config_hactive_time = temp + tu.parity_symbols;
286a3dd6028ada Kuogee Hsieh     2023-01-23   983  
286a3dd6028ada Kuogee Hsieh     2023-01-23   984  		if (tu.link_config_hactive_time + 1 /*margin*/ >= tu.resolution_line_time)
286a3dd6028ada Kuogee Hsieh     2023-01-23   985  			tu.min_hblank_violated = 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27   986  	}
c943b4948b5848 Chandan Uddaraju 2020-08-27   987  
286a3dd6028ada Kuogee Hsieh     2023-01-23   988  	tu.delay_start_time_fp = 0;
286a3dd6028ada Kuogee Hsieh     2023-01-23   989  
286a3dd6028ada Kuogee Hsieh     2023-01-23   990  	if ((tu.diff_abs_fp != 0 &&
286a3dd6028ada Kuogee Hsieh     2023-01-23   991  			((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
286a3dd6028ada Kuogee Hsieh     2023-01-23   992  			 (tu.even_distribution_legacy == 0) ||
286a3dd6028ada Kuogee Hsieh     2023-01-23   993  			 (DP_BRUTE_FORCE == 1))) ||
286a3dd6028ada Kuogee Hsieh     2023-01-23   994  			(tu.min_hblank_violated == 1)) {
286a3dd6028ada Kuogee Hsieh     2023-01-23   995  		_dp_calc_boundary(&tu);
286a3dd6028ada Kuogee Hsieh     2023-01-23   996  
286a3dd6028ada Kuogee Hsieh     2023-01-23   997  		if (tu.boundary_moderation_en) {
c943b4948b5848 Chandan Uddaraju 2020-08-27   998  			temp1_fp = drm_fixp_from_fraction(
286a3dd6028ada Kuogee Hsieh     2023-01-23   999  					(tu.upper_boundary_count *
286a3dd6028ada Kuogee Hsieh     2023-01-23  1000  					tu.valid_boundary_link +
286a3dd6028ada Kuogee Hsieh     2023-01-23  1001  					tu.lower_boundary_count *
286a3dd6028ada Kuogee Hsieh     2023-01-23  1002  					(tu.valid_boundary_link - 1)), 1);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1003  			temp2_fp = drm_fixp_from_fraction(
286a3dd6028ada Kuogee Hsieh     2023-01-23  1004  					(tu.upper_boundary_count +
286a3dd6028ada Kuogee Hsieh     2023-01-23  1005  					tu.lower_boundary_count), 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1006  			tu.resulting_valid_fp =
c943b4948b5848 Chandan Uddaraju 2020-08-27  1007  					drm_fixp_div(temp1_fp, temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1008  
c943b4948b5848 Chandan Uddaraju 2020-08-27  1009  			temp1_fp = drm_fixp_from_fraction(
286a3dd6028ada Kuogee Hsieh     2023-01-23  1010  					tu.tu_size_desired, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1011  			tu.ratio_by_tu_fp =
286a3dd6028ada Kuogee Hsieh     2023-01-23  1012  				drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1013  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1014  			tu.valid_lower_boundary_link =
286a3dd6028ada Kuogee Hsieh     2023-01-23  1015  				tu.valid_boundary_link - 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27  1016  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1017  			temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1018  			temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1019  			temp2_fp = drm_fixp_div(temp1_fp,
286a3dd6028ada Kuogee Hsieh     2023-01-23  1020  						tu.resulting_valid_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1021  			tu.n_tus = drm_fixp2int(temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1022  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1023  			tu.tu_size_minus1 = tu.tu_size_desired - 1;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1024  			tu.even_distribution_BF = 1;
c943b4948b5848 Chandan Uddaraju 2020-08-27  1025  
c943b4948b5848 Chandan Uddaraju 2020-08-27  1026  			temp1_fp =
286a3dd6028ada Kuogee Hsieh     2023-01-23  1027  				drm_fixp_from_fraction(tu.tu_size_desired, 1);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1028  			temp2_fp =
286a3dd6028ada Kuogee Hsieh     2023-01-23  1029  				drm_fixp_div(tu.resulting_valid_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1030  			tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp;
c943b4948b5848 Chandan Uddaraju 2020-08-27  1031  		}
c943b4948b5848 Chandan Uddaraju 2020-08-27  1032  	}
c943b4948b5848 Chandan Uddaraju 2020-08-27  1033  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1034  	if (tu.async_en) {
286a3dd6028ada Kuogee Hsieh     2023-01-23  1035  		temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1036  		temp = fixp2int_ceil(temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1037  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1038  		temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1039  		temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1040  		temp1_fp = drm_fixp_from_fraction(tu.bpp, 8);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1041  		temp2_fp = drm_fixp_div(temp1_fp, temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1042  		temp1_fp = drm_fixp_from_fraction(temp, 1);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1043  		temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1044  		temp = drm_fixp2int(temp2_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1045  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1046  		tu.delay_start_link += (int)temp;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1047  	}
c943b4948b5848 Chandan Uddaraju 2020-08-27  1048  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1049  	temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1050  	tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp);
c943b4948b5848 Chandan Uddaraju 2020-08-27  1051  
c943b4948b5848 Chandan Uddaraju 2020-08-27  1052  	/* OUTPUTS */
286a3dd6028ada Kuogee Hsieh     2023-01-23  1053  	tu_table->valid_boundary_link       = tu.valid_boundary_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1054  	tu_table->delay_start_link          = tu.delay_start_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1055  	tu_table->boundary_moderation_en    = tu.boundary_moderation_en;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1056  	tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1057  	tu_table->upper_boundary_count      = tu.upper_boundary_count;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1058  	tu_table->lower_boundary_count      = tu.lower_boundary_count;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1059  	tu_table->tu_size_minus1            = tu.tu_size_minus1;
286a3dd6028ada Kuogee Hsieh     2023-01-23  1060  
286a3dd6028ada Kuogee Hsieh     2023-01-23  1061  	DRM_DEBUG("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1062  	DRM_DEBUG("TU: delay_start_link: %d\n", tu_table->delay_start_link);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1063  	DRM_DEBUG("TU: boundary_moderation_en: %d\n",
c943b4948b5848 Chandan Uddaraju 2020-08-27  1064  			tu_table->boundary_moderation_en);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1065  	DRM_DEBUG("TU: valid_lower_boundary_link: %d\n",
c943b4948b5848 Chandan Uddaraju 2020-08-27  1066  			tu_table->valid_lower_boundary_link);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1067  	DRM_DEBUG("TU: upper_boundary_count: %d\n",
c943b4948b5848 Chandan Uddaraju 2020-08-27  1068  			tu_table->upper_boundary_count);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1069  	DRM_DEBUG("TU: lower_boundary_count: %d\n",
c943b4948b5848 Chandan Uddaraju 2020-08-27  1070  			tu_table->lower_boundary_count);
286a3dd6028ada Kuogee Hsieh     2023-01-23  1071  	DRM_DEBUG("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
c943b4948b5848 Chandan Uddaraju 2020-08-27 @1072  }
c943b4948b5848 Chandan Uddaraju 2020-08-27  1073  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

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

* Re: [PATCH v1 00/14] add display port DSC feature
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (14 preceding siblings ...)
  2023-01-23 18:34 ` [PATCH v1 00/14] add display port DSC feature Marijn Suijten
@ 2023-01-24  0:10 ` Dmitry Baryshkov
  2023-01-25  0:28 ` Abhinav Kumar
  16 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-24  0:10 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> This patch add DSC related supporting functions into to both dp controller and dpu enccoder
> 
> Kuogee Hsieh (14):
>    drm/msm/dp: add dpcd read of both dsc and fec capability
>    drm/msm/dp: add dsc factor into calculation of supported bpp
>    drm/msm/dp: add configure mainlink_levels base on lane number
>    drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
>    drm/msm/dp: upgrade tu calculation base on newest algorithm
>    drm/msm/dp: add display compression related struct
>    drm/msm/dp: add dsc helper functions
>    drm/msm/dp: add dsc supporting functions to DP controller
>    drm/msm/dsi: export struct msm_compression_info to dpu encoder
>    drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
>    drm/msm/disp/dpu1: add supports of new flush mechanism
>    drm/msm/disp/dpu1: revise timing engine programming to work for DSC
>    drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder
>    drm/msm/disp/dpu1: add sc7280 dsc block and sub block

Some generic notes regarding the series. I understand that the the 
series is complex, but following points might ease both your work and 
the review proces.

First, atomicity. If your commit message says 'do this and that', it is 
highly likely that the patch should be split into smaller parts.

Second, please pay attention to the history. If some part of the code or 
  the data structure was removed, you have to justify bringing it back. 
This is extremely important in your case, as significant parts of the 
code come from the vendor code, thut it is easy to step on the same rake 
again. And if the previous removal was incorrect, please describe why.

If we went through 10 revisions of a patch a year ago, it's not worth 
sending again a patch that closely remedies one of early iterations. It 
doesn't stand a chance of getting through.

Next. Obvious item. ./scripts/checkpatch.pl should be your friend. It is 
not.

Last, but not least. Please follow the mailing list. Less than a week 
ago one of reviews pointed out that commit messages like 'this patch 
does this and that' are not really welcomed. By sending the same kind of 
commit messages, you stand a high chance of receiveing the same 
response. Please go through the recommendations in 
Documentation/process/submitting-patches.rst.

> 
>   drivers/gpu/drm/msm/Makefile                       |   2 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c     | 537 +++++++++++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h     |  25 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 341 +++++++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   4 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   7 +-
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  43 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c     |  50 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  74 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         |  43 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         |  21 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c     | 371 +++++++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 ++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            |  10 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
>   drivers/gpu/drm/msm/dp/dp_catalog.c                | 176 ++++-
>   drivers/gpu/drm/msm/dp/dp_catalog.h                |  97 ++-
>   drivers/gpu/drm/msm/dp/dp_ctrl.c                   | 839 ++++++++++++++-------
>   drivers/gpu/drm/msm/dp/dp_display.c                |  61 +-
>   drivers/gpu/drm/msm/dp/dp_link.c                   |  29 +-
>   drivers/gpu/drm/msm/dp/dp_panel.c                  | 749 +++++++++++++++++-
>   drivers/gpu/drm/msm/dp/dp_panel.h                  |  67 +-
>   drivers/gpu/drm/msm/dp/dp_reg.h                    |  40 +-
>   drivers/gpu/drm/msm/dsi/dsi.c                      |   3 +-
>   drivers/gpu/drm/msm/dsi/dsi.h                      |   3 +-
>   drivers/gpu/drm/msm/dsi/dsi_host.c                 |  14 +-
>   drivers/gpu/drm/msm/msm_drv.h                      | 113 ++-
>   32 files changed, 3429 insertions(+), 497 deletions(-)
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> 

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
  2023-01-23 18:24 ` [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0 Kuogee Hsieh
  2023-01-23 22:41   ` Dmitry Baryshkov
@ 2023-01-24  0:49   ` kernel test robot
  1 sibling, 0 replies; 50+ messages in thread
From: kernel test robot @ 2023-01-24  0:49 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: quic_sbillaka, linux-arm-msm, quic_abhinavk, Kuogee Hsieh,
	oe-kbuild-all, freedreno, linux-kernel

Hi Kuogee,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on next-20230123]
[also build test WARNING on linus/master v6.2-rc5]
[cannot apply to drm-misc/drm-misc-next drm/drm-next drm-exynos/exynos-drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-tip/drm-tip v6.2-rc5 v6.2-rc4 v6.2-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kuogee-Hsieh/drm-msm-dp-add-dpcd-read-of-both-dsc-and-fec-capability/20230124-022759
patch link:    https://lore.kernel.org/r/1674498274-6010-5-git-send-email-quic_khsieh%40quicinc.com
patch subject: [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20230124/202301240836.ik3aytbc-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/834f569a141af42cb93424c24e7d146f3b88405b
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Kuogee-Hsieh/drm-msm-dp-add-dpcd-read-of-both-dsc-and-fec-capability/20230124-022759
        git checkout 834f569a141af42cb93424c24e7d146f3b88405b
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc SHELL=/bin/bash drivers/gpu/drm/msm/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/msm/dp/dp_panel.c:571: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
    * Mapper function which outputs colorimetry to be used for a


vim +571 drivers/gpu/drm/msm/dp/dp_panel.c

   569	
   570	/**
 > 571	 * Mapper function which outputs colorimetry to be used for a
   572	 * given colorspace value when misc field of MSA is used to
   573	 * change the colorimetry. Currently only RGB formats have been
   574	 * added. This API will be extended to YUV once its supported on DP.
   575	 */
   576	u8 dp_panel_get_misc_colorimetry_val(struct dp_panel *dp_panel)
   577	{
   578		u8 colorimetry;
   579		u32 colorspace;
   580		u32 cc;
   581		struct dp_panel_private *panel;
   582	
   583		panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
   584	
   585		cc = dp_link_get_colorimetry_config(panel->link);
   586		/*
   587		 * If there is a non-zero value then compliance test-case
   588		 * is going on, otherwise we can honor the colorspace setting
   589		 */
   590		if (cc)
   591			return cc;
   592	
   593		colorspace = dp_panel->connector->state->colorspace;
   594		switch (colorspace) {
   595		case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
   596		case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
   597			colorimetry = 0x7;
   598			break;
   599		case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED:
   600			colorimetry = 0x3;
   601			break;
   602		case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT:
   603			colorimetry = 0xb;
   604			break;
   605		case DRM_MODE_COLORIMETRY_OPRGB:
   606			colorimetry = 0xc;
   607			break;
   608		default:
   609			colorimetry = 0;
   610		}
   611	
   612		return colorimetry;
   613	}
   614	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-23 18:24 ` [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Kuogee Hsieh
  2023-01-23 20:11   ` Marijn Suijten
@ 2023-01-24  7:44   ` Dmitry Baryshkov
  2023-01-24 15:18   ` Neil Armstrong
  2 siblings, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-24  7:44 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> DSC V1.2 encoder engine is newly added hardware module. This patch
> add support functions to configure and enable DSC V1.2 encoder engine.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/Makefile                   |   1 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    |   2 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  60 +++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c     |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h     |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 371 +++++++++++++++++++++++++
>   6 files changed, 463 insertions(+), 17 deletions(-)
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 28cf52b..271c29a15 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>   	disp/dpu1/dpu_hw_catalog.o \
>   	disp/dpu1/dpu_hw_ctl.o \
>   	disp/dpu1/dpu_hw_dsc.o \
> +	disp/dpu1/dpu_hw_dsc_1_2.o \
>   	disp/dpu1/dpu_dsc_helper.o \
>   	disp/dpu1/dpu_hw_interrupts.o \
>   	disp/dpu1/dpu_hw_intf.o \
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 7f4a439..901e317 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -1821,7 +1821,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
>   				     u32 initial_lines)
>   {
>   	if (hw_dsc->ops.dsc_config)
> -		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines);
> +		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);
>   
>   	if (hw_dsc->ops.dsc_config_thresh)
>   		hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> index 978e3bd..7b0b092 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
>    */
>   
> @@ -11,6 +11,7 @@
>   #include <linux/bug.h>
>   #include <linux/bitmap.h>
>   #include <linux/err.h>
> +#include "dpu_hw_mdss.h"
>   
>   /**
>    * Max hardware block count: For ex: max 12 SSPP pipes or
> @@ -182,6 +183,7 @@ enum {
>    * @DPU_PINGPONG_TE2        Additional tear check block for split pipes
>    * @DPU_PINGPONG_SPLIT      PP block supports split fifo
>    * @DPU_PINGPONG_SLAVE      PP block is a suitable slave for split fifo
> + * @DPU_PINGPONG_DSC,       Display stream compression blocks
>    * @DPU_PINGPONG_DITHER,    Dither blocks
>    * @DPU_PINGPONG_MAX
>    */
> @@ -190,10 +192,32 @@ enum {
>   	DPU_PINGPONG_TE2,
>   	DPU_PINGPONG_SPLIT,
>   	DPU_PINGPONG_SLAVE,
> +	DPU_PINGPONG_DSC,
>   	DPU_PINGPONG_DITHER,
>   	DPU_PINGPONG_MAX
>   };
>   
> +
> +/** DSC sub-blocks/features
> + * @DPU_DSC_OUTPUT_CTRL         Supports the control of the pp id which gets
> + *                              the pixel output from this DSC.
> + * @DPU_DSC_HW_REV_1_1          dsc block supports dsc 1.1 only
> + * @DPU_DSC_HW_REV_1_2          dsc block supports dsc 1.1 and 1.2
> + * @DPU_DSC_NATIVE_422_EN,      Supports native422 and native420 encoding
> + * @DPU_DSC_ENC,                DSC encoder sub block
> + * @DPU_DSC_CTL,                DSC ctl sub block
> + * @DPU_DSC_MAX
> + */
> +enum {
> +	DPU_DSC_OUTPUT_CTRL = 0x1,
> +	DPU_DSC_HW_REV_1_1,
> +	DPU_DSC_HW_REV_1_2,
> +	DPU_DSC_NATIVE_422_EN,
> +	DPU_DSC_ENC,
> +	DPU_DSC_CTL,
> +	DPU_DSC_MAX
> +};
> +
>   /**
>    * CTL sub-blocks
>    * @DPU_CTL_SPLIT_DISPLAY:	CTL supports video mode split display
> @@ -276,15 +300,6 @@ enum {
>   };
>   
>   /**
> - * DSC features
> - * @DPU_DSC_OUTPUT_CTRL       Configure which PINGPONG block gets
> - *                            the pixel output from this DSC.
> - */
> -enum {
> -	DPU_DSC_OUTPUT_CTRL = 0x1,
> -};
> -

Any reason for this move?

> -/**
>    * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
>    * @name:              string name for debug purposes
>    * @id:                enum identifying this block
> @@ -346,6 +361,14 @@ struct dpu_pp_blk {
>   };
>   
>   /**
> + * struct dpu_dsc_blk : DSC Encoder sub-blk information
> + * @info:   HW register and features supported by this sub-blk
> + */
> +struct dpu_dsc_blk {
> +	DPU_HW_SUBBLK_INFO;
> +};
> +
> +/**
>    * enum dpu_qos_lut_usage - define QoS LUT use cases
>    */
>   enum dpu_qos_lut_usage {
> @@ -403,6 +426,7 @@ struct dpu_rotation_cfg {
>    * @pixel_ram_size     size of latency hiding and de-tiling buffer in bytes
>    * @max_hdeci_exp      max horizontal decimation supported (max is 2^value)
>    * @max_vdeci_exp      max vertical decimation supported (max is 2^value)
> + * @max_dsc_width      max dsc line width support.
>    */
>   struct dpu_caps {
>   	u32 max_mixer_width;
> @@ -419,6 +443,7 @@ struct dpu_caps {
>   	u32 pixel_ram_size;
>   	u32 max_hdeci_exp;
>   	u32 max_vdeci_exp;
> +	u32 max_dsc_width;
>   };
>   
>   /**
> @@ -494,9 +519,20 @@ struct dpu_dspp_sub_blks {
>   struct dpu_pingpong_sub_blks {
>   	struct dpu_pp_blk te;
>   	struct dpu_pp_blk te2;
> +	struct dpu_pp_blk dsc;
>   	struct dpu_pp_blk dither;
>   };
>   
> +
> +/**
> + * struct dpu_dsc_sub_blks : DSC sub-blks
> + *
> + */
> +struct dpu_dsc_sub_blks {
> +	struct dpu_dsc_blk enc;
> +	struct dpu_dsc_blk ctl;
> +};
> +
>   /**
>    * dpu_clk_ctrl_type - Defines top level clock control signals
>    */
> @@ -641,10 +677,14 @@ struct dpu_merge_3d_cfg  {
>    * struct dpu_dsc_cfg - information of DSC blocks
>    * @id                 enum identifying this block
>    * @base               register offset of this block
> + * @len:               length of hardware block
>    * @features           bit mask identifying sub-blocks/features
> + * @dsc_pair_mask:     Bitmask of DSCs that can be controlled by same CTL
>    */
>   struct dpu_dsc_cfg {
>   	DPU_HW_BLK_INFO;
> +	DECLARE_BITMAP(dsc_pair_mask, DSC_MAX);

Please change this from the bitmap to enum dpu_dsc instance

> +	const struct dpu_dsc_sub_blks *sblk;
>   };
>   
>   /**
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> index 619926d..51e8890 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2020-2022, Linaro Limited
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include "dpu_kms.h"
> @@ -41,10 +42,11 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
>   static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>   			      struct drm_dsc_config *dsc,
>   			      u32 mode,
> -			      u32 initial_lines)
> +			      u32 initial_lines,
> +			      bool ich_reset_override)
>   {
>   	struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
> -	u32 data;
> +	u32 data, lsb, bpp;
>   	u32 slice_last_group_size;
>   	u32 det_thresh_flatness;
>   	bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
> @@ -58,7 +60,14 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>   	data = (initial_lines << 20);
>   	data |= ((slice_last_group_size - 1) << 18);
>   	/* bpp is 6.4 format, 4 LSBs bits are for fractional part */
> -	data |= (dsc->bits_per_pixel << 8);
> +	data |= dsc->bits_per_pixel << 12;
> +	lsb = dsc->bits_per_pixel % 4;
> +	bpp = dsc->bits_per_pixel / 4;
> +	bpp *= 4;
> +	bpp <<= 4;
> +	bpp |= lsb;
> +

NAK. This was changed by the commit d3c1a8663d0d ("drm/msm/dpu1: Account 
for DSC's bits_per_pixel having 4 fractional bits"). It removed the code 
that you are trying to bring back.

> +	data |= bpp << 8;
>   	data |= (dsc->block_pred_enable << 7);
>   	data |= (dsc->line_buf_depth << 3);
>   	data |= (dsc->simple_422 << 2);
> @@ -221,7 +230,13 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>   
>   	c->idx = idx;
>   	c->caps = cfg;
> -	_setup_dsc_ops(&c->ops, c->caps->features);
> +
> +	if (test_bit(DPU_DSC_HW_REV_1_1, &c->caps->features))
> +		_setup_dsc_ops(&c->ops, c->caps->features);
> +	else if (test_bit(DPU_DSC_HW_REV_1_2, &c->caps->features))
> +		dpu_dsc_1_2_setup_ops(&c->ops, c->caps->features);
> +	else
> +		_setup_dsc_ops(&c->ops, c->caps->features);

Can we handle this in a more sensible way, please. E.g. let RM check the 
flags and then call either dpu_hw_dsc_1_1_init() or dpu_hw_dsc_1_2_init()?

Granted that to generations of DSC blocks are _that_ different it might 
even make sense to handle them separately in the HW catalog too, but I 
wouldn't insist on that.

>   
>   	return c;
>   }
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> index ae9b5db..a48f572 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> @@ -1,5 +1,8 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (c) 2020-2022, Linaro Limited */
> +/*
> + * Copyright (c) 2020-2022, Linaro Limited
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
> + */
>   
>   #ifndef _DPU_HW_DSC_H
>   #define _DPU_HW_DSC_H
> @@ -33,7 +36,8 @@ struct dpu_hw_dsc_ops {
>   	void (*dsc_config)(struct dpu_hw_dsc *hw_dsc,
>   			   struct drm_dsc_config *dsc,
>   			   u32 mode,
> -			   u32 initial_lines);
> +			   u32 initial_lines,
> +			   bool ich_reset_override);

Documentation?

>   
>   	/**
>   	 * dsc_config_thresh - programs panel thresholds
> @@ -43,6 +47,12 @@ struct dpu_hw_dsc_ops {
>   	void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
>   				  struct drm_dsc_config *dsc);
>   
> +	/**
> +	 * bind_pingpong_blk - enable/disable the connection with pp
> +	 * @hw_dsc: Pointer to dsc context
> +	 * @enable: enable/disable connection
> +	 * @pp: pingpong blk id
> +	 */
>   	void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc,
>   				  bool enable,
>   				  enum dpu_pingpong pp);
> @@ -51,6 +61,7 @@ struct dpu_hw_dsc_ops {
>   struct dpu_hw_dsc {
>   	struct dpu_hw_blk base;
>   	struct dpu_hw_blk_reg_map hw;
> +	struct dpu_hw_ctl *hw_ctl;

Why? This is not used by the rest of the patch.

>   
>   	/* dsc */
>   	enum dpu_dsc idx;
> @@ -76,9 +87,17 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>    */
>   void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc);
>   
> +/**
> + * dpu_hw_dsc - convert base object dpu_hw_base to container
> + * @hw: Pointer to base hardware block
> + * return: Pointer to hardware block container
> + */

You are adding docs for the obvious items (which is unnecessary and just 
clobbers the code), but leaving out important items (for which docs 
might be necessary).

>   static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw)
>   {
>   	return container_of(hw, struct dpu_hw_dsc, base);
>   }
>   
> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
> +		const unsigned long features);
> +
>   #endif /* _DPU_HW_DSC_H */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> new file mode 100644
> index 00000000..2be74ae
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#include "dpu_kms.h"
> +#include "dpu_hw_catalog.h"
> +#include "dpu_hwio.h"
> +#include "dpu_hw_mdss.h"
> +#include "dpu_hw_dsc.h"
> +
> +
> +#define DSC_CMN_MAIN_CNF           0x00
> +
> +/* DPU_DSC_ENC register offsets */
> +#define ENC_DF_CTRL                0x00
> +#define ENC_GENERAL_STATUS         0x04
> +#define ENC_HSLICE_STATUS          0x08
> +#define ENC_OUT_STATUS             0x0C
> +#define ENC_INT_STAT               0x10
> +#define ENC_INT_CLR                0x14
> +#define ENC_INT_MASK               0x18
> +#define DSC_MAIN_CONF              0x30
> +#define DSC_PICTURE_SIZE           0x34
> +#define DSC_SLICE_SIZE             0x38
> +#define DSC_MISC_SIZE              0x3C
> +#define DSC_HRD_DELAYS             0x40
> +#define DSC_RC_SCALE               0x44
> +#define DSC_RC_SCALE_INC_DEC       0x48
> +#define DSC_RC_OFFSETS_1           0x4C
> +#define DSC_RC_OFFSETS_2           0x50
> +#define DSC_RC_OFFSETS_3           0x54
> +#define DSC_RC_OFFSETS_4           0x58
> +#define DSC_FLATNESS_QP            0x5C
> +#define DSC_RC_MODEL_SIZE          0x60
> +#define DSC_RC_CONFIG              0x64
> +#define DSC_RC_BUF_THRESH_0        0x68
> +#define DSC_RC_BUF_THRESH_1        0x6C
> +#define DSC_RC_BUF_THRESH_2        0x70
> +#define DSC_RC_BUF_THRESH_3        0x74
> +#define DSC_RC_MIN_QP_0            0x78
> +#define DSC_RC_MIN_QP_1            0x7C
> +#define DSC_RC_MIN_QP_2            0x80
> +#define DSC_RC_MAX_QP_0            0x84
> +#define DSC_RC_MAX_QP_1            0x88
> +#define DSC_RC_MAX_QP_2             0x8C
> +#define DSC_RC_RANGE_BPG_OFFSETS_0  0x90
> +#define DSC_RC_RANGE_BPG_OFFSETS_1  0x94
> +#define DSC_RC_RANGE_BPG_OFFSETS_2  0x98
> +
> +/* DPU_DSC_CTL register offsets */
> +#define DSC_CTL                    0x00
> +#define DSC_CFG                    0x04
> +#define DSC_DATA_IN_SWAP           0x08
> +#define DSC_CLK_CTRL               0x0C
> +
> +
> +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss)
> +{
> +	enum dpu_dsc idx;
> +
> +	idx = hw_dsc->idx;
> +
> +	if (!(hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))) {
> +		if (num_ss == 1)
> +			return 2399;
> +		else if (num_ss == 2)
> +			return 1199;
> +	} else {
> +		if (num_ss == 1)
> +			return 1199;
> +		else if (num_ss == 2)
> +			return 599;
> +	}
> +	return 0;

int max_addr = 2400 / num_ss;
if (hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))
     max_addr /= 2;

return max_addr -1;

Isn't this nicer?

> +}
> +
> +static inline int _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id,
> +		u32 *idx)
> +{
> +	const struct dpu_dsc_sub_blks *sblk;
> +
> +	if (!hw_dsc)
> +		return -EINVAL;
> +
> +	*idx = 0;
> +
> +	sblk = hw_dsc->caps->sblk;
> +
> +	switch (s_id) {
> +
> +	case DPU_DSC_ENC:
> +		*idx = sblk->enc.base;
> +		break;
> +	case DPU_DSC_CTL:
> +		*idx = sblk->ctl.base;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	u32 idx;
> +
> +	if (!hw_dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +	DPU_REG_WRITE(hw, DSC_CFG + idx, 0);
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, 0);
> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, 0);
> +}
> +
> +static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc,
> +		struct drm_dsc_config *dsc, u32 mode,
> +		u32 initial_lines, bool ich_reset_override)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	struct msm_display_dsc_info *dsc_info;
> +	u32 idx;
> +	u32 data = 0;
> +	u32 bpp;
> +	void __iomem *off;
> +
> +	if (!hw_dsc || !dsc)
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +
> +	dsc_info = to_msm_dsc_info(dsc);
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	if (mode & DSC_MODE_SPLIT_PANEL)
> +		data |= BIT(0);
> +
> +	if (mode & DSC_MODE_MULTIPLEX)
> +		data |= BIT(1);
> +
> +	data |= (dsc_info->num_active_ss_per_enc & 0x3) << 7;
> +
> +	DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data);
> +
> +	data = (dsc_info->initial_lines & 0xff);
> +	data |= ((mode & DSC_MODE_VIDEO) ? 1 : 0) << 9;
> +	if (ich_reset_override)
> +		data |= 0xC00; // set bit 10 and 11

Comment style is wrong. The comment is useless: from 0xc00 we see which 
bits are being set. We'd better know why. Please add corresponding 
defines to the bits and bitfields in these function.

> +	data |= (_dsc_calc_ob_max_addr(hw_dsc, dsc_info->num_active_ss_per_enc) << 18);
> +
> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, data);
> +
> +	data = (dsc->dsc_version_minor & 0xf) << 28;
> +	if (dsc->dsc_version_minor == 0x2) {
> +		if (dsc->native_422)
> +			data |= BIT(22);
> +		if (dsc->native_420)
> +			data |= BIT(21);
> +	}
> +
> +	bpp = dsc->bits_per_pixel;
> +	/* as per hw requirement bpp should be programmed
> +	 * twice the actual value in case of 420 or 422 encoding
> +	 */
> +	if (dsc->native_422 || dsc->native_420)
> +		bpp = 2 * bpp;
> +	data |= (dsc->block_pred_enable ? 1 : 0) << 20;
> +	data |= (bpp << 10);
> +	data |= (dsc->line_buf_depth & 0xf) << 6;
> +	data |= dsc->convert_rgb << 4;
> +	data |= dsc->bits_per_component & 0xf;
> +
> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, data);
> +
> +	data = (dsc->pic_width & 0xffff) |
> +		((dsc->pic_height & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_PICTURE_SIZE + idx, data);
> +
> +	data = (dsc->slice_width & 0xffff) |
> +		((dsc->slice_height & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_SLICE_SIZE + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_MISC_SIZE + idx,
> +			(dsc->slice_chunk_size) & 0xffff);
> +
> +	data = (dsc->initial_xmit_delay & 0xffff) |
> +		((dsc->initial_dec_delay & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_HRD_DELAYS + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_SCALE + idx,
> +			dsc->initial_scale_value & 0x3f);
> +
> +	data = (dsc->scale_increment_interval & 0xffff) |
> +		((dsc->scale_decrement_interval & 0x7ff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_SCALE_INC_DEC + idx, data);
> +
> +	data = (dsc->first_line_bpg_offset & 0x1f) |
> +		((dsc->second_line_bpg_offset & 0x1f) << 5);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_1 + idx, data);
> +
> +	data = (dsc->nfl_bpg_offset & 0xffff) |
> +		((dsc->slice_bpg_offset & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_2 + idx, data);
> +
> +	data = (dsc->initial_offset & 0xffff) |
> +		((dsc->final_offset & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_3 + idx, data);
> +
> +	data = (dsc->nsl_bpg_offset & 0xffff) |
> +		((dsc->second_line_offset_adj & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_4 + idx, data);
> +
> +	data = (dsc->flatness_min_qp & 0x1f);
> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
> +
> +	DPU_REG_WRITE(hw, DSC_FLATNESS_QP + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_MODEL_SIZE + idx,
> +			(dsc->rc_model_size) & 0xffff);
> +
> +	data = dsc->rc_edge_factor & 0xf;
> +	data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8;
> +	data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13;
> +	data |= (dsc->rc_tgt_offset_high & 0xf) << 20;
> +	data |= (dsc->rc_tgt_offset_low & 0xf) << 24;
> +
> +	DPU_REG_WRITE(hw, DSC_RC_CONFIG + idx, data);
> +
> +	/* program the dsc wrapper */
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	off = hw->blk_addr + idx;
> +
> +	data = BIT(0); /* encoder enable */
> +	if (dsc->native_422)
> +		data |= BIT(8);
> +	else if (dsc->native_420)
> +		data |= BIT(9);
> +	if (!dsc->convert_rgb)
> +		data |= BIT(10);
> +	if (dsc->bits_per_component == 8)
> +		data |= BIT(11);
> +	if (mode & DSC_MODE_SPLIT_PANEL)
> +		data |= BIT(12);
> +	if (mode & DSC_MODE_MULTIPLEX)
> +		data |= BIT(13);
> +	if (!(mode & DSC_MODE_VIDEO))
> +		data |= BIT(17);
> +
> +	if (dsc_info->dsc_4hsmerge_en) {
> +		data |= dsc_info->dsc_4hsmerge_padding << 18;
> +		data |= dsc_info->dsc_4hsmerge_alignment << 22;
> +		data |= BIT(16);
> +	}
> +
> +	DPU_REG_WRITE(hw, DSC_CFG + idx, data);
> +
> +//	DPU_REG_WRITE(hw, DSC_DATA_IN_SWAP + idx, 0x14e5);

Is this necessary or not? If not, please drop it.

> +}
> +
> +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc,
> +		struct drm_dsc_config *dsc)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	struct msm_display_dsc_info *dsc_info;
> +	u32 idx, off;
> +	int i, j = 0;
> +	struct drm_dsc_rc_range_parameters *rc;
> +	u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0;
> +
> +	if (!hw_dsc || !dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +
> +	dsc_info = to_msm_dsc_info(dsc);
> +
> +	rc = dsc->rc_range_params;
> +
> +	off = 0;
> +	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
> +		data |= dsc->rc_buf_thresh[i] << (8*j);
> +		j++;
> +		if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) {
> +			DPU_REG_WRITE(hw, DSC_RC_BUF_THRESH_0 + idx + off,
> +					data);
> +			off += 4;
> +			j = 0;
> +			data = 0;
> +		}
> +	}
> +
> +	off = 0;
> +	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
> +		min_qp |= (rc[i].range_min_qp & 0x1f) << 5*j;
> +		max_qp |= (rc[i].range_max_qp & 0x1f) << 5*j;
> +		bpg_off |= (rc[i].range_bpg_offset & 0x3f) << 6*j;
> +		j++;
> +		if (j == 5) {
> +			DPU_REG_WRITE(hw, DSC_RC_MIN_QP_0 + idx + off,
> +					min_qp);
> +			DPU_REG_WRITE(hw, DSC_RC_MAX_QP_0 + idx + off,
> +					max_qp);
> +			DPU_REG_WRITE(hw,
> +					DSC_RC_RANGE_BPG_OFFSETS_0 + idx + off,
> +					bpg_off);
> +			off += 4;
> +			j = 0;
> +			min_qp = 0;
> +			max_qp = 0;
> +			bpg_off = 0;
> +		}
> +	}
> +}
> +
> +static void dpu_hw_dsc_bind_pingpong_blk_1_2(
> +		struct dpu_hw_dsc *hw_dsc,
> +		bool enable,
> +		const enum dpu_pingpong pp)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	int idx;
> +	int mux_cfg = 0xF; /* Disabled */
> +
> +	if (!hw_dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +	if (enable)
> +		mux_cfg = (pp - PINGPONG_0) & 0x7;
> +
> +	DPU_REG_WRITE(hw, DSC_CTL + idx, mux_cfg);
> +}
> +
> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
> +		const unsigned long features)
> +{
> +	ops->dsc_disable = dpu_hw_dsc_disable_1_2;
> +	ops->dsc_config = dpu_hw_dsc_config_1_2;
> +	ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2;
> +	ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2;
> +}

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-23 18:24 ` [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC Kuogee Hsieh
  2023-01-23 21:39   ` Dmitry Baryshkov
@ 2023-01-24  9:11   ` Dmitry Baryshkov
  2023-01-24 17:55     ` Kuogee Hsieh
  1 sibling, 1 reply; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-24  9:11 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 20:24, Kuogee Hsieh wrote:
> Current implementation timing engine programming does not consider
> compression factors. This patch add consideration of DSC factors
> while programming timing engine.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |   2 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  14 ++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 +++++++++++++--------
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>   5 files changed, 110 insertions(+), 54 deletions(-)
> 

[skipped]

> @@ -113,82 +124,96 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>   	/* read interface_cfg */
>   	intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
>   
> -	if (ctx->cap->type == INTF_DP)
> +	if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)
>   		dp_intf = true;
>   
>   	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
> -	p->h_front_porch;
> +			p->h_front_porch;
>   	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
> -	p->v_front_porch;
> +			p->v_front_porch;

Actually I went on through the history and found the previous 
submission, https://patchwork.freedesktop.org/patch/471505/.
Exactly the same piece of code. Did you expect that the comments will be 
different this time?

I really hoped that at that time we already went through this. But it 
seems I was wrong. That series went through v10 or v12 before being 
accepted. And it was just adding wide_bus_en. Back at that time we 
lightly discussed that the code will receive compression support. But I 
never expected to see the original submission again.

It might sound bad, but could you please find somebody who can do 
internal review for you? Good internal review.

That said, I really do not expect to see v2 before the whole series is 
reworked, restructured and prepared for the review on your side.

>   
>   	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
> -	hsync_period) + p->hsync_skew;
> +			hsync_period) + p->hsync_skew;
>   	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
> -	p->hsync_skew - 1;
> +			p->hsync_skew - 1;
> +
> +	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
>   
>   	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
>   	hsync_end_x = hsync_period - p->h_front_porch - 1;
>   
> -	if (p->width != p->xres) { /* border fill added */
> -		active_h_start = hsync_start_x;
> -		active_h_end = active_h_start + p->xres - 1;
> -	} else {
> -		active_h_start = 0;
> -		active_h_end = 0;
> -	}
> -
> -	if (p->height != p->yres) { /* border fill added */
> -		active_v_start = display_v_start;
> -		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
> -	} else {
> -		active_v_start = 0;
> -		active_v_end = 0;
> -	}
> -
> -	if (active_h_end) {
> -		active_hctl = (active_h_end << 16) | active_h_start;
> -		intf_cfg |= INTF_CFG_ACTIVE_H_EN;
> -	} else {
> -		active_hctl = 0;
> -	}
> -
> -	if (active_v_end)
> -		intf_cfg |= INTF_CFG_ACTIVE_V_EN;
> -
> -	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
> -	display_hctl = (hsync_end_x << 16) | hsync_start_x;
> -
>   	/*
>   	 * DATA_HCTL_EN controls data timing which can be different from
>   	 * video timing. It is recommended to enable it for all cases, except
>   	 * if compression is enabled in 1 pixel per clock mode
>   	 */
> +	if (!p->compression_en || p->wide_bus_en)
> +		intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
> +
>   	if (p->wide_bus_en)
> -		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
> +		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
>   
> +	/*
> +	 * If widebus is disabled:
> +	 * For uncompressed stream, the data is valid for the entire active
> +	 * window period.
> +	 * For compressed stream, data is valid for a shorter time period
> +	 * inside the active window depending on the compression ratio.
> +	 *
> +	 * If widebus is enabled:
> +	 * For uncompressed stream, data is valid for only half the active
> +	 * window, since the data rate is doubled in this mode.
> +	 * p->width holds the adjusted width for DP but unadjusted width for DSI
> +	 * For compressed stream, data validity window needs to be adjusted for
> +	 * compression ratio and then further halved.
> +	 */
>   	data_width = p->width;
>   
> +	if (p->compression_en) {
> +		if (p->wide_bus_en)
> +			data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6);
> +		else
> +			data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
> +	} else if (!dp_intf && p->wide_bus_en) {
> +		data_width = p->width >> 1;
> +	} else {
> +		data_width = p->width;
> +	}
> +
>   	hsync_data_start_x = hsync_start_x;
>   	hsync_data_end_x =  hsync_start_x + data_width - 1;
>   
> +	display_hctl = (hsync_end_x << 16) | hsync_start_x;
>   	display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
>   
>   	if (dp_intf) {
>   		/* DP timing adjustment */
>   		display_v_start += p->hsync_pulse_width + p->h_back_porch;
>   		display_v_end   -= p->h_front_porch;
> +	}
> +
> +	intf_cfg |= INTF_CFG_ACTIVE_H_EN;
> +	intf_cfg |= INTF_CFG_ACTIVE_V_EN;
> +	active_h_start = hsync_start_x;
> +	active_h_end = active_h_start + p->xres - 1;
> +	active_v_start = display_v_start;
> +	active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>   
> -		active_h_start = hsync_start_x;
> -		active_h_end = active_h_start + p->xres - 1;
> -		active_v_start = display_v_start;
> -		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
> +	active_hctl = (active_h_end << 16) | active_h_start;
>   
> -		active_hctl = (active_h_end << 16) | active_h_start;
> +	if (dp_intf) {
>   		display_hctl = active_hctl;
>   
> -		intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
> +		if (p->compression_en) {
> +			active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16;
> +			active_data_hctl += hsync_start_x;
> +
> +			display_data_hctl = active_data_hctl;
> +		}
>   	}
>   
> +	_check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en, &intf_cfg2);
> +
>   	den_polarity = 0;
>   	if (ctx->cap->type == INTF_HDMI) {
>   		hsync_polarity = p->yres >= 720 ? 0 : 1;
> @@ -202,7 +227,7 @@ static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder
  2023-01-23 18:24 ` [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Kuogee Hsieh
  2023-01-23 22:06   ` Dmitry Baryshkov
@ 2023-01-24 15:06   ` Neil Armstrong
  2023-01-30 20:27   ` Marijn Suijten
  2 siblings, 0 replies; 50+ messages in thread
From: Neil Armstrong @ 2023-01-24 15:06 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 19:24, Kuogee Hsieh wrote:
> struct msm_compression_info is used to support several different
> compression mechanisms. It also contains customized info required
> to configure DSC encoder engine. This patch also make changes DSI
> module to have DSI exports struct msm_compreion_info to dpu encoder
> instead of struct drm_dsc_config.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  7 +++++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 ++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 10 ++++++++--
>   drivers/gpu/drm/msm/dsi/dsi.c               |  3 ++-
>   drivers/gpu/drm/msm/dsi/dsi.h               |  3 ++-
>   drivers/gpu/drm/msm/dsi/dsi_host.c          | 14 ++++++++++++--
>   drivers/gpu/drm/msm/msm_drv.h               |  4 ++--
>   7 files changed, 33 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 758261e..7f4a439 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -2,7 +2,7 @@
>   /*
>    * Copyright (C) 2013 Red Hat
>    * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved.
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    *
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
> @@ -210,6 +210,7 @@ struct dpu_encoder_virt {
>   
>   	/* DSC configuration */
>   	struct drm_dsc_config *dsc;
> +	struct msm_compression_info *comp_info;
>   };
>   
>   #define to_dpu_encoder_virt(x) container_of(x, struct dpu_encoder_virt, base)
> @@ -2275,7 +2276,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>   		dpu_enc->idle_pc_supported =
>   				dpu_kms->catalog->caps->has_idle_pc;
>   
> -	dpu_enc->dsc = disp_info->dsc;
> +	dpu_enc->comp_info = disp_info->comp_info;
> +	if (dpu_enc->comp_info)
> +		dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc;
>   
>   	mutex_lock(&dpu_enc->enc_lock);
>   	for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) {
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> index 9e7236e..bd2da5e 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
>    * Copyright (C) 2013 Red Hat
>    * Author: Rob Clark <robdclark@gmail.com>
> @@ -36,7 +36,7 @@ struct msm_display_info {
>   	uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
>   	bool is_cmd_mode;
>   	bool is_te_using_watchdog_timer;
> -	struct drm_dsc_config *dsc;
> +	struct msm_compression_info *comp_info;
>   };
>   
>   /**
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index d612419..70a74ed 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -2,7 +2,7 @@
>   /*
>    * Copyright (C) 2013 Red Hat
>    * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    *
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
> @@ -570,7 +570,7 @@ static int _dpu_kms_initialize_dsi(struct drm_device *dev,
>   		info.h_tile_instance[info.num_of_h_tiles++] = i;
>   		info.is_cmd_mode = msm_dsi_is_cmd_mode(priv->dsi[i]);
>   
> -		info.dsc = msm_dsi_get_dsc_config(priv->dsi[i]);
> +		info.comp_info = msm_dsi_get_dsc_config(priv->dsi[i]);

This breaks DSC on DSI since before we had a pointer of the DSC struct that would be filled
by the DSI driver later in pre_enable(), and now we have a copy of it before it is filled.

Instead we should keep a pointer of the DSC struct in the comp_info, store the DP dsc struct in the
dp panel private and pass the dsc pointer back in dp_panel_dsc_prepare_basic_params().

>   
>   		if (msm_dsi_is_bonded_dsi(priv->dsi[i]) && priv->dsi[other]) {
>   			rc = msm_dsi_modeset_init(priv->dsi[other], dev, encoder);
> @@ -622,6 +622,8 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
>   		info.num_of_h_tiles = 1;
>   		info.h_tile_instance[0] = i;
>   		info.intf_type = encoder->encoder_type;
> +		info.is_cmd_mode = 0; /* dp always video mode */
> +		info.comp_info = NULL;
>   		rc = dpu_encoder_setup(dev, encoder, &info);
>   		if (rc) {
>   			DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
> @@ -892,6 +894,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
>   
>   	pm_runtime_get_sync(&dpu_kms->pdev->dev);
>   
> +	for (i = 0; i < cat->dsc_count; i++)
> +		msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len,
> +				dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i);
> +
>   	/* dump CTL sub-blocks HW regs info */
>   	for (i = 0; i < cat->ctl_count; i++)
>   		msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len,
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
> index 31fdee2..52b7e33 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include "dsi.h"
> @@ -13,7 +14,7 @@ bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
>   	return !(host_flags & MIPI_DSI_MODE_VIDEO);
>   }
>   
> -struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
> +struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
>   {
>   	return msm_dsi_host_get_dsc_config(msm_dsi->host);
>   }
> diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h
> index bd3763a..79ada54 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi.h
> +++ b/drivers/gpu/drm/msm/dsi/dsi.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
>    * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #ifndef __DSI_CONNECTOR_H__
> @@ -133,7 +134,7 @@ int dsi_calc_clk_rate_v2(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
>   int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi);
>   void msm_dsi_host_snapshot(struct msm_disp_state *disp_state, struct mipi_dsi_host *host);
>   void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host);
> -struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
> +struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host);
>   
>   /* dsi phy */
>   struct msm_dsi_phy;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
> index 18fa30e..6188f4b 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_host.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2015, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include <linux/clk.h>
> @@ -163,6 +164,7 @@ struct msm_dsi_host {
>   
>   	struct drm_display_mode *mode;
>   	struct drm_dsc_config *dsc;
> +	struct msm_compression_info comp_info;
>   
>   	/* connected device info */
>   	unsigned int channel;
> @@ -2600,9 +2602,17 @@ void msm_dsi_host_test_pattern_en(struct mipi_dsi_host *host)
>   				DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER_SW_TRIGGER);
>   }
>   
> -struct drm_dsc_config *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
> +struct msm_compression_info *msm_dsi_host_get_dsc_config(struct mipi_dsi_host *host)
>   {
>   	struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
> +	struct msm_compression_info *comp_info = NULL;
>   
> -	return msm_host->dsc;
> +	if (msm_host->dsc) {
> +		comp_info = &msm_host->comp_info;
> +		comp_info->msm_dsc_info.drm_dsc = *msm_host->dsc;
> +		comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC;
> +		comp_info->enabled = true;
> +	}
> +
> +	return comp_info;
>   }
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index 6a46ed7..eab0901 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -430,7 +430,7 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi
>   bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi);
>   bool msm_dsi_is_bonded_dsi(struct msm_dsi *msm_dsi);
>   bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi);
> -struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
> +struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi);
>   #else
>   static inline void __init msm_dsi_register(void)
>   {
> @@ -460,7 +460,7 @@ static inline bool msm_dsi_is_master_dsi(struct msm_dsi *msm_dsi)
>   	return false;
>   }
>   
> -static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
> +static inline struct msm_compression_info *msm_dsi_get_dsc_config(struct msm_dsi *msm_dsi)
>   {
>   	return NULL;
>   }


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

* Re: [PATCH v1 06/14] drm/msm/dp: add display compression related struct
  2023-01-23 18:24 ` [PATCH v1 06/14] drm/msm/dp: add display compression related struct Kuogee Hsieh
  2023-01-23 22:46   ` Dmitry Baryshkov
@ 2023-01-24 15:15   ` Neil Armstrong
  1 sibling, 0 replies; 50+ messages in thread
From: Neil Armstrong @ 2023-01-24 15:15 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 19:24, Kuogee Hsieh wrote:
> Add display compression related struct to support variant compression
> mechanism. However, DSC is the only one supported at this moment.
> VDC may be added later.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/dp/dp_panel.h | 42 ++++++++++++++++++
>   drivers/gpu/drm/msm/msm_drv.h     | 89 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 131 insertions(+)
> 
> diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
> index 1153e88..4c45d51 100644
> --- a/drivers/gpu/drm/msm/dp/dp_panel.h
> +++ b/drivers/gpu/drm/msm/dp/dp_panel.h
> @@ -21,12 +21,54 @@ struct edid;
>   #define DP_DOWNSTREAM_PORTS		4
>   #define DP_DOWNSTREAM_CAP_SIZE		4
>   
> +
> +#define DP_PANEL_CAPS_DSC	BIT(0)
> +
> +enum dp_output_format {
> +	DP_OUTPUT_FORMAT_RGB,
> +	DP_OUTPUT_FORMAT_YCBCR420,
> +	DP_OUTPUT_FORMAT_YCBCR422,
> +	DP_OUTPUT_FORMAT_YCBCR444,
> +	DP_OUTPUT_FORMAT_INVALID,
> +};
> +
> +
> +struct dp_panel_info {
> +	u32 h_active;
> +	u32 v_active;
> +	u32 h_back_porch;
> +	u32 h_front_porch;
> +	u32 h_sync_width;
> +	u32 h_active_low;
> +	u32 v_back_porch;
> +	u32 v_front_porch;
> +	u32 v_sync_width;
> +	u32 v_active_low;
> +	u32 h_skew;
> +	u32 refresh_rate;
> +	u32 pixel_clk_khz;
> +	u32 bpp;
> +	bool widebus_en;
> +	struct msm_compression_info comp_info;
> +	s64 dsc_overhead_fp;
> +};
> +
>   struct dp_display_mode {
>   	struct drm_display_mode drm_mode;
> +	struct dp_panel_info timing;
>   	u32 capabilities;
> +	s64 fec_overhead_fp;
> +	s64 dsc_overhead_fp;
>   	u32 bpp;
>   	u32 h_active_low;
>   	u32 v_active_low;
> +	/**
> +	 * @output_format:
> +	 *
> +	 * This is used to indicate DP output format.
> +	 * The output format can be read from drm_mode.
> +	 */
> +	enum dp_output_format output_format;
>   };
>   
>   struct dp_panel_in {
> diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
> index 9f0c184..f155803 100644
> --- a/drivers/gpu/drm/msm/msm_drv.h
> +++ b/drivers/gpu/drm/msm/msm_drv.h
> @@ -1,6 +1,7 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
>    * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023. Qualcomm Innovation Center, Inc. All rights reserved
>    * Copyright (C) 2013 Red Hat
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
> @@ -70,6 +71,16 @@ enum msm_dp_controller {
>   #define MAX_H_TILES_PER_DISPLAY 2
>   
>   /**
> + * enum msm_display_compression_type - compression method used for pixel stream
> + * @MSM_DISPLAY_COMPRESSION_NONE:     Pixel data is not compressed
> + * @MSM_DISPLAY_COMPRESSION_DSC:      DSC compresison is used
> + */
> +enum msm_display_compression_type {
> +	MSM_DISPLAY_COMPRESSION_NONE,
> +	MSM_DISPLAY_COMPRESSION_DSC,
> +};
> +
> +/**
>    * enum msm_event_wait - type of HW events to wait for
>    * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
>    * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
> @@ -82,6 +93,84 @@ enum msm_event_wait {
>   };
>   
>   /**
> + * struct msm_display_dsc_info - defines dsc configuration
> + * @config                   DSC encoder configuration
> + * @scr_rev:                 DSC revision.
> + * @initial_lines:           Number of initial lines stored in encoder.
> + * @pkt_per_line:            Number of packets per line.
> + * @bytes_in_slice:          Number of bytes in slice.
> + * @eol_byte_num:            Valid bytes at the end of line.
> + * @bytes_per_pkt            Number of bytes in DSI packet
> + * @pclk_per_line:           Compressed width.
> + * @slice_last_group_size:   Size of last group in pixels.
> + * @slice_per_pkt:           Number of slices per packet.
> + * @num_active_ss_per_enc:   Number of active soft slices per encoder.
> + * @source_color_space:      Source color space of DSC encoder
> + * @chroma_format:           Chroma_format of DSC encoder.
> + * @det_thresh_flatness:     Flatness threshold.
> + * @extra_width:             Extra width required in timing calculations.
> + * @pps_delay_ms:            Post PPS command delay in milliseconds.
> + * @dsc_4hsmerge_en:         Using DSC 4HS merge topology
> + * @dsc_4hsmerge_padding     4HS merge DSC pair padding value in bytes
> + * @dsc_4hsmerge_alignment   4HS merge DSC alignment value in bytes
> + * @half_panel_pu            True for single and dual dsc encoders if partial
> + *                           update sets the roi width to half of mode width
> + *                           False in all other cases
> + */
> +struct msm_display_dsc_info {
> +	struct drm_dsc_config drm_dsc;
> +	u8 scr_rev;
> +
> +	int initial_lines;
> +	int pkt_per_line;
> +	int bytes_in_slice;
> +	int bytes_per_pkt;
> +	int eol_byte_num;
> +	int pclk_per_line;
> +	int slice_last_group_size;
> +	int slice_per_pkt;
> +	int num_active_ss_per_enc;
> +	int source_color_space;
> +	int chroma_format;
> +	int det_thresh_flatness;
> +	u32 extra_width;
> +	u32 pps_delay_ms;
> +	bool dsc_4hsmerge_en;
> +	u32 dsc_4hsmerge_padding;
> +	u32 dsc_4hsmerge_alignment;
> +	bool half_panel_pu;
> +};
> +
> +/*
> + * conver from struct drm_dsc_config to struct msm_display_dsc_info
> + */
> +#define to_msm_dsc_info(dsc) container_of((dsc), struct msm_display_dsc_info, drm_dsc)

This is weird, you consider dsc struct is in control of dpu, but no with DSC it's part
of the DSI panel struct.

msm_display_dsc_info->drm_dsc should be a pointer.

If some values caculated in msm_display_dsc_info are *really* needed, then a new structure
should be added, but as a companion of the dsm dsc pointer, not containing it.

> +
> +/**
> + * Bits/pixel target >> 4  (removing the fractional bits)
> + * returns the integer bpp value from the drm_dsc_config struct
> + */
> +#define DSC_BPP(config) ((config).bits_per_pixel >> 4)
> +
> +/**
> + * struct msm_compression_info - defined panel compression
> + * @enabled:          enabled/disabled
> + * @comp_type:        type of compression supported
> + * @comp_ratio:       compression ratio
> + * @src_bpp:          bits per pixel before compression
> + * @tgt_bpp:          bits per pixel after compression
> + * @msm_dsc_info:     msm dsc info if the compression supported is DSC
> + */
> +struct msm_compression_info {
> +	bool enabled;

I would rather use comp_type = MSM_DISPLAY_COMPRESSION_NONE instead of having a supplementary bool....

> +	enum msm_display_compression_type comp_type;
> +	u32 comp_ratio;
> +	u32 src_bpp;
> +	u32 tgt_bpp;

Those are never used outside of dp, so get them out.

> +	struct msm_display_dsc_info msm_dsc_info;
> +};
> +
> +/**
>    * struct msm_display_topology - defines a display topology pipeline
>    * @num_lm:       number of layer mixers used
>    * @num_intf:     number of interfaces the panel is mounted on


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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-23 18:24 ` [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Kuogee Hsieh
  2023-01-23 20:11   ` Marijn Suijten
  2023-01-24  7:44   ` Dmitry Baryshkov
@ 2023-01-24 15:18   ` Neil Armstrong
  2 siblings, 0 replies; 50+ messages in thread
From: Neil Armstrong @ 2023-01-24 15:18 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 19:24, Kuogee Hsieh wrote:
> DSC V1.2 encoder engine is newly added hardware module. This patch
> add support functions to configure and enable DSC V1.2 encoder engine.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/Makefile                   |   1 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    |   2 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  60 +++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c     |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h     |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 371 +++++++++++++++++++++++++
>   6 files changed, 463 insertions(+), 17 deletions(-)
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 28cf52b..271c29a15 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>   	disp/dpu1/dpu_hw_catalog.o \
>   	disp/dpu1/dpu_hw_ctl.o \
>   	disp/dpu1/dpu_hw_dsc.o \
> +	disp/dpu1/dpu_hw_dsc_1_2.o \
>   	disp/dpu1/dpu_dsc_helper.o \
>   	disp/dpu1/dpu_hw_interrupts.o \
>   	disp/dpu1/dpu_hw_intf.o \
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 7f4a439..901e317 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -1821,7 +1821,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
>   				     u32 initial_lines)
>   {
>   	if (hw_dsc->ops.dsc_config)
> -		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines);
> +		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);
>   
>   	if (hw_dsc->ops.dsc_config_thresh)
>   		hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> index 978e3bd..7b0b092 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
>    */
>   
> @@ -11,6 +11,7 @@
>   #include <linux/bug.h>
>   #include <linux/bitmap.h>
>   #include <linux/err.h>
> +#include "dpu_hw_mdss.h"
>   
>   /**
>    * Max hardware block count: For ex: max 12 SSPP pipes or
> @@ -182,6 +183,7 @@ enum {
>    * @DPU_PINGPONG_TE2        Additional tear check block for split pipes
>    * @DPU_PINGPONG_SPLIT      PP block supports split fifo
>    * @DPU_PINGPONG_SLAVE      PP block is a suitable slave for split fifo
> + * @DPU_PINGPONG_DSC,       Display stream compression blocks
>    * @DPU_PINGPONG_DITHER,    Dither blocks
>    * @DPU_PINGPONG_MAX
>    */
> @@ -190,10 +192,32 @@ enum {
>   	DPU_PINGPONG_TE2,
>   	DPU_PINGPONG_SPLIT,
>   	DPU_PINGPONG_SLAVE,
> +	DPU_PINGPONG_DSC,
>   	DPU_PINGPONG_DITHER,
>   	DPU_PINGPONG_MAX
>   };
>   
> +
> +/** DSC sub-blocks/features
> + * @DPU_DSC_OUTPUT_CTRL         Supports the control of the pp id which gets
> + *                              the pixel output from this DSC.
> + * @DPU_DSC_HW_REV_1_1          dsc block supports dsc 1.1 only
> + * @DPU_DSC_HW_REV_1_2          dsc block supports dsc 1.1 and 1.2
> + * @DPU_DSC_NATIVE_422_EN,      Supports native422 and native420 encoding
> + * @DPU_DSC_ENC,                DSC encoder sub block
> + * @DPU_DSC_CTL,                DSC ctl sub block
> + * @DPU_DSC_MAX
> + */
> +enum {
> +	DPU_DSC_OUTPUT_CTRL = 0x1,
> +	DPU_DSC_HW_REV_1_1,
> +	DPU_DSC_HW_REV_1_2,
> +	DPU_DSC_NATIVE_422_EN,
> +	DPU_DSC_ENC,
> +	DPU_DSC_CTL,
> +	DPU_DSC_MAX
> +};
> +
>   /**
>    * CTL sub-blocks
>    * @DPU_CTL_SPLIT_DISPLAY:	CTL supports video mode split display
> @@ -276,15 +300,6 @@ enum {
>   };
>   
>   /**
> - * DSC features
> - * @DPU_DSC_OUTPUT_CTRL       Configure which PINGPONG block gets
> - *                            the pixel output from this DSC.
> - */
> -enum {
> -	DPU_DSC_OUTPUT_CTRL = 0x1,
> -};
> -
> -/**
>    * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
>    * @name:              string name for debug purposes
>    * @id:                enum identifying this block
> @@ -346,6 +361,14 @@ struct dpu_pp_blk {
>   };
>   
>   /**
> + * struct dpu_dsc_blk : DSC Encoder sub-blk information
> + * @info:   HW register and features supported by this sub-blk
> + */
> +struct dpu_dsc_blk {
> +	DPU_HW_SUBBLK_INFO;
> +};
> +
> +/**
>    * enum dpu_qos_lut_usage - define QoS LUT use cases
>    */
>   enum dpu_qos_lut_usage {
> @@ -403,6 +426,7 @@ struct dpu_rotation_cfg {
>    * @pixel_ram_size     size of latency hiding and de-tiling buffer in bytes
>    * @max_hdeci_exp      max horizontal decimation supported (max is 2^value)
>    * @max_vdeci_exp      max vertical decimation supported (max is 2^value)
> + * @max_dsc_width      max dsc line width support.
>    */
>   struct dpu_caps {
>   	u32 max_mixer_width;
> @@ -419,6 +443,7 @@ struct dpu_caps {
>   	u32 pixel_ram_size;
>   	u32 max_hdeci_exp;
>   	u32 max_vdeci_exp;
> +	u32 max_dsc_width;
>   };
>   
>   /**
> @@ -494,9 +519,20 @@ struct dpu_dspp_sub_blks {
>   struct dpu_pingpong_sub_blks {
>   	struct dpu_pp_blk te;
>   	struct dpu_pp_blk te2;
> +	struct dpu_pp_blk dsc;
>   	struct dpu_pp_blk dither;
>   };
>   
> +
> +/**
> + * struct dpu_dsc_sub_blks : DSC sub-blks
> + *
> + */
> +struct dpu_dsc_sub_blks {
> +	struct dpu_dsc_blk enc;
> +	struct dpu_dsc_blk ctl;
> +};
> +
>   /**
>    * dpu_clk_ctrl_type - Defines top level clock control signals
>    */
> @@ -641,10 +677,14 @@ struct dpu_merge_3d_cfg  {
>    * struct dpu_dsc_cfg - information of DSC blocks
>    * @id                 enum identifying this block
>    * @base               register offset of this block
> + * @len:               length of hardware block
>    * @features           bit mask identifying sub-blocks/features
> + * @dsc_pair_mask:     Bitmask of DSCs that can be controlled by same CTL
>    */
>   struct dpu_dsc_cfg {
>   	DPU_HW_BLK_INFO;
> +	DECLARE_BITMAP(dsc_pair_mask, DSC_MAX);
> +	const struct dpu_dsc_sub_blks *sblk;
>   };
>   
>   /**
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> index 619926d..51e8890 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2020-2022, Linaro Limited
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>    */
>   
>   #include "dpu_kms.h"
> @@ -41,10 +42,11 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
>   static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>   			      struct drm_dsc_config *dsc,
>   			      u32 mode,
> -			      u32 initial_lines)
> +			      u32 initial_lines,
> +			      bool ich_reset_override)
>   {
>   	struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
> -	u32 data;
> +	u32 data, lsb, bpp;
>   	u32 slice_last_group_size;
>   	u32 det_thresh_flatness;
>   	bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
> @@ -58,7 +60,14 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>   	data = (initial_lines << 20);
>   	data |= ((slice_last_group_size - 1) << 18);
>   	/* bpp is 6.4 format, 4 LSBs bits are for fractional part */
> -	data |= (dsc->bits_per_pixel << 8);
> +	data |= dsc->bits_per_pixel << 12;
> +	lsb = dsc->bits_per_pixel % 4;
> +	bpp = dsc->bits_per_pixel / 4;
> +	bpp *= 4;
> +	bpp <<= 4;
> +	bpp |= lsb;
> +
> +	data |= bpp << 8;
>   	data |= (dsc->block_pred_enable << 7);
>   	data |= (dsc->line_buf_depth << 3);
>   	data |= (dsc->simple_422 << 2);
> @@ -221,7 +230,13 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>   
>   	c->idx = idx;
>   	c->caps = cfg;
> -	_setup_dsc_ops(&c->ops, c->caps->features);
> +
> +	if (test_bit(DPU_DSC_HW_REV_1_1, &c->caps->features))
> +		_setup_dsc_ops(&c->ops, c->caps->features);
> +	else if (test_bit(DPU_DSC_HW_REV_1_2, &c->caps->features))
> +		dpu_dsc_1_2_setup_ops(&c->ops, c->caps->features);
> +	else
> +		_setup_dsc_ops(&c->ops, c->caps->features);
>   
>   	return c;
>   }
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> index ae9b5db..a48f572 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
> @@ -1,5 +1,8 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
> -/* Copyright (c) 2020-2022, Linaro Limited */
> +/*
> + * Copyright (c) 2020-2022, Linaro Limited
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
> + */
>   
>   #ifndef _DPU_HW_DSC_H
>   #define _DPU_HW_DSC_H
> @@ -33,7 +36,8 @@ struct dpu_hw_dsc_ops {
>   	void (*dsc_config)(struct dpu_hw_dsc *hw_dsc,
>   			   struct drm_dsc_config *dsc,
>   			   u32 mode,
> -			   u32 initial_lines);
> +			   u32 initial_lines,
> +			   bool ich_reset_override);
>   
>   	/**
>   	 * dsc_config_thresh - programs panel thresholds
> @@ -43,6 +47,12 @@ struct dpu_hw_dsc_ops {
>   	void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
>   				  struct drm_dsc_config *dsc);
>   
> +	/**
> +	 * bind_pingpong_blk - enable/disable the connection with pp
> +	 * @hw_dsc: Pointer to dsc context
> +	 * @enable: enable/disable connection
> +	 * @pp: pingpong blk id
> +	 */
>   	void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc,
>   				  bool enable,
>   				  enum dpu_pingpong pp);
> @@ -51,6 +61,7 @@ struct dpu_hw_dsc_ops {
>   struct dpu_hw_dsc {
>   	struct dpu_hw_blk base;
>   	struct dpu_hw_blk_reg_map hw;
> +	struct dpu_hw_ctl *hw_ctl;
>   
>   	/* dsc */
>   	enum dpu_dsc idx;
> @@ -76,9 +87,17 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>    */
>   void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc);
>   
> +/**
> + * dpu_hw_dsc - convert base object dpu_hw_base to container
> + * @hw: Pointer to base hardware block
> + * return: Pointer to hardware block container
> + */
>   static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw)
>   {
>   	return container_of(hw, struct dpu_hw_dsc, base);
>   }
>   
> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
> +		const unsigned long features);
> +
>   #endif /* _DPU_HW_DSC_H */
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> new file mode 100644
> index 00000000..2be74ae
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
> + */
> +
> +#include "dpu_kms.h"
> +#include "dpu_hw_catalog.h"
> +#include "dpu_hwio.h"
> +#include "dpu_hw_mdss.h"
> +#include "dpu_hw_dsc.h"
> +
> +
> +#define DSC_CMN_MAIN_CNF           0x00
> +
> +/* DPU_DSC_ENC register offsets */
> +#define ENC_DF_CTRL                0x00
> +#define ENC_GENERAL_STATUS         0x04
> +#define ENC_HSLICE_STATUS          0x08
> +#define ENC_OUT_STATUS             0x0C
> +#define ENC_INT_STAT               0x10
> +#define ENC_INT_CLR                0x14
> +#define ENC_INT_MASK               0x18
> +#define DSC_MAIN_CONF              0x30
> +#define DSC_PICTURE_SIZE           0x34
> +#define DSC_SLICE_SIZE             0x38
> +#define DSC_MISC_SIZE              0x3C
> +#define DSC_HRD_DELAYS             0x40
> +#define DSC_RC_SCALE               0x44
> +#define DSC_RC_SCALE_INC_DEC       0x48
> +#define DSC_RC_OFFSETS_1           0x4C
> +#define DSC_RC_OFFSETS_2           0x50
> +#define DSC_RC_OFFSETS_3           0x54
> +#define DSC_RC_OFFSETS_4           0x58
> +#define DSC_FLATNESS_QP            0x5C
> +#define DSC_RC_MODEL_SIZE          0x60
> +#define DSC_RC_CONFIG              0x64
> +#define DSC_RC_BUF_THRESH_0        0x68
> +#define DSC_RC_BUF_THRESH_1        0x6C
> +#define DSC_RC_BUF_THRESH_2        0x70
> +#define DSC_RC_BUF_THRESH_3        0x74
> +#define DSC_RC_MIN_QP_0            0x78
> +#define DSC_RC_MIN_QP_1            0x7C
> +#define DSC_RC_MIN_QP_2            0x80
> +#define DSC_RC_MAX_QP_0            0x84
> +#define DSC_RC_MAX_QP_1            0x88
> +#define DSC_RC_MAX_QP_2             0x8C
> +#define DSC_RC_RANGE_BPG_OFFSETS_0  0x90
> +#define DSC_RC_RANGE_BPG_OFFSETS_1  0x94
> +#define DSC_RC_RANGE_BPG_OFFSETS_2  0x98
> +
> +/* DPU_DSC_CTL register offsets */
> +#define DSC_CTL                    0x00
> +#define DSC_CFG                    0x04
> +#define DSC_DATA_IN_SWAP           0x08
> +#define DSC_CLK_CTRL               0x0C
> +
> +
> +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss)
> +{
> +	enum dpu_dsc idx;
> +
> +	idx = hw_dsc->idx;
> +
> +	if (!(hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))) {
> +		if (num_ss == 1)
> +			return 2399;
> +		else if (num_ss == 2)
> +			return 1199;
> +	} else {
> +		if (num_ss == 1)
> +			return 1199;
> +		else if (num_ss == 2)
> +			return 599;
> +	}
> +	return 0;
> +}
> +
> +static inline int _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id,
> +		u32 *idx)
> +{
> +	const struct dpu_dsc_sub_blks *sblk;
> +
> +	if (!hw_dsc)
> +		return -EINVAL;
> +
> +	*idx = 0;
> +
> +	sblk = hw_dsc->caps->sblk;
> +
> +	switch (s_id) {
> +
> +	case DPU_DSC_ENC:
> +		*idx = sblk->enc.base;
> +		break;
> +	case DPU_DSC_CTL:
> +		*idx = sblk->ctl.base;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	u32 idx;
> +
> +	if (!hw_dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +	DPU_REG_WRITE(hw, DSC_CFG + idx, 0);
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, 0);
> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, 0);
> +}
> +
> +static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc,
> +		struct drm_dsc_config *dsc, u32 mode,
> +		u32 initial_lines, bool ich_reset_override)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	struct msm_display_dsc_info *dsc_info;
> +	u32 idx;
> +	u32 data = 0;
> +	u32 bpp;
> +	void __iomem *off;
> +
> +	if (!hw_dsc || !dsc)
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +
> +	dsc_info = to_msm_dsc_info(dsc);


Please don't do that, the architecture of dsc_info is crap, if you *really* need some
values that are not part of drm_dsc, then pass this *new" struct as parameter of dsc_config()
and change the dsc_config() declaration, it's not a problem.

> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	if (mode & DSC_MODE_SPLIT_PANEL)
> +		data |= BIT(0);
> +
> +	if (mode & DSC_MODE_MULTIPLEX)
> +		data |= BIT(1);
> +
> +	data |= (dsc_info->num_active_ss_per_enc & 0x3) << 7;
> +
> +	DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data);
> +
> +	data = (dsc_info->initial_lines & 0xff);
> +	data |= ((mode & DSC_MODE_VIDEO) ? 1 : 0) << 9;
> +	if (ich_reset_override)
> +		data |= 0xC00; // set bit 10 and 11
> +	data |= (_dsc_calc_ob_max_addr(hw_dsc, dsc_info->num_active_ss_per_enc) << 18);
> +
> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, data);
> +
> +	data = (dsc->dsc_version_minor & 0xf) << 28;
> +	if (dsc->dsc_version_minor == 0x2) {
> +		if (dsc->native_422)
> +			data |= BIT(22);
> +		if (dsc->native_420)
> +			data |= BIT(21);
> +	}
> +
> +	bpp = dsc->bits_per_pixel;
> +	/* as per hw requirement bpp should be programmed
> +	 * twice the actual value in case of 420 or 422 encoding
> +	 */
> +	if (dsc->native_422 || dsc->native_420)
> +		bpp = 2 * bpp;
> +	data |= (dsc->block_pred_enable ? 1 : 0) << 20;
> +	data |= (bpp << 10);
> +	data |= (dsc->line_buf_depth & 0xf) << 6;
> +	data |= dsc->convert_rgb << 4;
> +	data |= dsc->bits_per_component & 0xf;
> +
> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, data);
> +
> +	data = (dsc->pic_width & 0xffff) |
> +		((dsc->pic_height & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_PICTURE_SIZE + idx, data);
> +
> +	data = (dsc->slice_width & 0xffff) |
> +		((dsc->slice_height & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_SLICE_SIZE + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_MISC_SIZE + idx,
> +			(dsc->slice_chunk_size) & 0xffff);
> +
> +	data = (dsc->initial_xmit_delay & 0xffff) |
> +		((dsc->initial_dec_delay & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_HRD_DELAYS + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_SCALE + idx,
> +			dsc->initial_scale_value & 0x3f);
> +
> +	data = (dsc->scale_increment_interval & 0xffff) |
> +		((dsc->scale_decrement_interval & 0x7ff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_SCALE_INC_DEC + idx, data);
> +
> +	data = (dsc->first_line_bpg_offset & 0x1f) |
> +		((dsc->second_line_bpg_offset & 0x1f) << 5);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_1 + idx, data);
> +
> +	data = (dsc->nfl_bpg_offset & 0xffff) |
> +		((dsc->slice_bpg_offset & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_2 + idx, data);
> +
> +	data = (dsc->initial_offset & 0xffff) |
> +		((dsc->final_offset & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_3 + idx, data);
> +
> +	data = (dsc->nsl_bpg_offset & 0xffff) |
> +		((dsc->second_line_offset_adj & 0xffff) << 16);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_4 + idx, data);
> +
> +	data = (dsc->flatness_min_qp & 0x1f);
> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
> +
> +	DPU_REG_WRITE(hw, DSC_FLATNESS_QP + idx, data);
> +
> +	DPU_REG_WRITE(hw, DSC_RC_MODEL_SIZE + idx,
> +			(dsc->rc_model_size) & 0xffff);
> +
> +	data = dsc->rc_edge_factor & 0xf;
> +	data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8;
> +	data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13;
> +	data |= (dsc->rc_tgt_offset_high & 0xf) << 20;
> +	data |= (dsc->rc_tgt_offset_low & 0xf) << 24;
> +
> +	DPU_REG_WRITE(hw, DSC_RC_CONFIG + idx, data);
> +
> +	/* program the dsc wrapper */
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	off = hw->blk_addr + idx;
> +
> +	data = BIT(0); /* encoder enable */
> +	if (dsc->native_422)
> +		data |= BIT(8);
> +	else if (dsc->native_420)
> +		data |= BIT(9);
> +	if (!dsc->convert_rgb)
> +		data |= BIT(10);
> +	if (dsc->bits_per_component == 8)
> +		data |= BIT(11);
> +	if (mode & DSC_MODE_SPLIT_PANEL)
> +		data |= BIT(12);
> +	if (mode & DSC_MODE_MULTIPLEX)
> +		data |= BIT(13);
> +	if (!(mode & DSC_MODE_VIDEO))
> +		data |= BIT(17);
> +
> +	if (dsc_info->dsc_4hsmerge_en) {
> +		data |= dsc_info->dsc_4hsmerge_padding << 18;
> +		data |= dsc_info->dsc_4hsmerge_alignment << 22;
> +		data |= BIT(16);
> +	}
> +
> +	DPU_REG_WRITE(hw, DSC_CFG + idx, data);
> +
> +//	DPU_REG_WRITE(hw, DSC_DATA_IN_SWAP + idx, 0x14e5);
> +}
> +
> +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc,
> +		struct drm_dsc_config *dsc)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	struct msm_display_dsc_info *dsc_info;
> +	u32 idx, off;
> +	int i, j = 0;
> +	struct drm_dsc_rc_range_parameters *rc;
> +	u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0;
> +
> +	if (!hw_dsc || !dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +
> +	dsc_info = to_msm_dsc_info(dsc);
> +
> +	rc = dsc->rc_range_params;
> +
> +	off = 0;
> +	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
> +		data |= dsc->rc_buf_thresh[i] << (8*j);
> +		j++;
> +		if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) {
> +			DPU_REG_WRITE(hw, DSC_RC_BUF_THRESH_0 + idx + off,
> +					data);
> +			off += 4;
> +			j = 0;
> +			data = 0;
> +		}
> +	}
> +
> +	off = 0;
> +	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
> +		min_qp |= (rc[i].range_min_qp & 0x1f) << 5*j;
> +		max_qp |= (rc[i].range_max_qp & 0x1f) << 5*j;
> +		bpg_off |= (rc[i].range_bpg_offset & 0x3f) << 6*j;
> +		j++;
> +		if (j == 5) {
> +			DPU_REG_WRITE(hw, DSC_RC_MIN_QP_0 + idx + off,
> +					min_qp);
> +			DPU_REG_WRITE(hw, DSC_RC_MAX_QP_0 + idx + off,
> +					max_qp);
> +			DPU_REG_WRITE(hw,
> +					DSC_RC_RANGE_BPG_OFFSETS_0 + idx + off,
> +					bpg_off);
> +			off += 4;
> +			j = 0;
> +			min_qp = 0;
> +			max_qp = 0;
> +			bpg_off = 0;
> +		}
> +	}
> +}
> +
> +static void dpu_hw_dsc_bind_pingpong_blk_1_2(
> +		struct dpu_hw_dsc *hw_dsc,
> +		bool enable,
> +		const enum dpu_pingpong pp)
> +{
> +	struct dpu_hw_blk_reg_map *hw;
> +	int idx;
> +	int mux_cfg = 0xF; /* Disabled */
> +
> +	if (!hw_dsc)
> +		return;
> +
> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
> +		return;
> +
> +	hw = &hw_dsc->hw;
> +	if (enable)
> +		mux_cfg = (pp - PINGPONG_0) & 0x7;
> +
> +	DPU_REG_WRITE(hw, DSC_CTL + idx, mux_cfg);
> +}
> +
> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
> +		const unsigned long features)
> +{
> +	ops->dsc_disable = dpu_hw_dsc_disable_1_2;
> +	ops->dsc_config = dpu_hw_dsc_config_1_2;
> +	ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2;
> +	ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2;
> +}


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

* Re: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-24  9:11   ` Dmitry Baryshkov
@ 2023-01-24 17:55     ` Kuogee Hsieh
  2023-01-24 21:37       ` Dmitry Baryshkov
  2023-01-24 23:36       ` Marijn Suijten
  0 siblings, 2 replies; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-24 17:55 UTC (permalink / raw)
  To: Dmitry Baryshkov, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel


On 1/24/2023 1:11 AM, Dmitry Baryshkov wrote:
> On 23/01/2023 20:24, Kuogee Hsieh wrote:
>> Current implementation timing engine programming does not consider
>> compression factors. This patch add consideration of DSC factors
>> while programming timing engine.
>>
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
>>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |   2 +
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  14 ++-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 
>> +++++++++++++--------
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>>   5 files changed, 110 insertions(+), 54 deletions(-)
>>
>
> [skipped]
>
>> @@ -113,82 +124,96 @@ static void 
>> dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>>       /* read interface_cfg */
>>       intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
>>   -    if (ctx->cap->type == INTF_DP)
>> +    if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)
>>           dp_intf = true;
>>         hsync_period = p->hsync_pulse_width + p->h_back_porch + 
>> p->width +
>> -    p->h_front_porch;
>> +            p->h_front_porch;
>>       vsync_period = p->vsync_pulse_width + p->v_back_porch + 
>> p->height +
>> -    p->v_front_porch;
>> +            p->v_front_porch;
>
> Actually I went on through the history and found the previous 
> submission, https://patchwork.freedesktop.org/patch/471505/.
> Exactly the same piece of code. Did you expect that the comments will 
> be different this time?
>
> I really hoped that at that time we already went through this. But it 
> seems I was wrong. That series went through v10 or v12 before being 
> accepted. And it was just adding wide_bus_en. Back at that time we 
> lightly discussed that the code will receive compression support. But 
> I never expected to see the original submission again.
>
> It might sound bad, but could you please find somebody who can do 
> internal review for you? Good internal review.
>
> That said, I really do not expect to see v2 before the whole series is 
> reworked, restructured and prepared for the review on your side.

This timing engine code is derived from our downstream code directly and 
it has been used at many mobile devices by many vendors for many years 
already.

On the other words, it had been tested very thorough and works on 
dsi/dp/hdmi/dsc/widebus applications.

When i brought dsc v1.2 over, I just merged it over and did not consider 
too much.

Can we adapt this code so that both upstream and down stream shared same 
timing engine programming so that easier to maintain?





>
>>         display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
>> -    hsync_period) + p->hsync_skew;
>> +            hsync_period) + p->hsync_skew;
>>       display_v_end = ((vsync_period - p->v_front_porch) * 
>> hsync_period) +
>> -    p->hsync_skew - 1;
>> +            p->hsync_skew - 1;
>> +
>> +    hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
>>         hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
>>       hsync_end_x = hsync_period - p->h_front_porch - 1;
>>   -    if (p->width != p->xres) { /* border fill added */
>> -        active_h_start = hsync_start_x;
>> -        active_h_end = active_h_start + p->xres - 1;
>> -    } else {
>> -        active_h_start = 0;
>> -        active_h_end = 0;
>> -    }
>> -
>> -    if (p->height != p->yres) { /* border fill added */
>> -        active_v_start = display_v_start;
>> -        active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>> -    } else {
>> -        active_v_start = 0;
>> -        active_v_end = 0;
>> -    }
>> -
>> -    if (active_h_end) {
>> -        active_hctl = (active_h_end << 16) | active_h_start;
>> -        intf_cfg |= INTF_CFG_ACTIVE_H_EN;
>> -    } else {
>> -        active_hctl = 0;
>> -    }
>> -
>> -    if (active_v_end)
>> -        intf_cfg |= INTF_CFG_ACTIVE_V_EN;
>> -
>> -    hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
>> -    display_hctl = (hsync_end_x << 16) | hsync_start_x;
>> -
>>       /*
>>        * DATA_HCTL_EN controls data timing which can be different from
>>        * video timing. It is recommended to enable it for all cases, 
>> except
>>        * if compression is enabled in 1 pixel per clock mode
>>        */
>> +    if (!p->compression_en || p->wide_bus_en)
>> +        intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
>> +
>>       if (p->wide_bus_en)
>> -        intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
>> +        intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
>>   +    /*
>> +     * If widebus is disabled:
>> +     * For uncompressed stream, the data is valid for the entire active
>> +     * window period.
>> +     * For compressed stream, data is valid for a shorter time period
>> +     * inside the active window depending on the compression ratio.
>> +     *
>> +     * If widebus is enabled:
>> +     * For uncompressed stream, data is valid for only half the active
>> +     * window, since the data rate is doubled in this mode.
>> +     * p->width holds the adjusted width for DP but unadjusted width 
>> for DSI
>> +     * For compressed stream, data validity window needs to be 
>> adjusted for
>> +     * compression ratio and then further halved.
>> +     */
>>       data_width = p->width;
>>   +    if (p->compression_en) {
>> +        if (p->wide_bus_en)
>> +            data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6);
>> +        else
>> +            data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
>> +    } else if (!dp_intf && p->wide_bus_en) {
>> +        data_width = p->width >> 1;
>> +    } else {
>> +        data_width = p->width;
>> +    }
>> +
>>       hsync_data_start_x = hsync_start_x;
>>       hsync_data_end_x =  hsync_start_x + data_width - 1;
>>   +    display_hctl = (hsync_end_x << 16) | hsync_start_x;
>>       display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
>>         if (dp_intf) {
>>           /* DP timing adjustment */
>>           display_v_start += p->hsync_pulse_width + p->h_back_porch;
>>           display_v_end   -= p->h_front_porch;
>> +    }
>> +
>> +    intf_cfg |= INTF_CFG_ACTIVE_H_EN;
>> +    intf_cfg |= INTF_CFG_ACTIVE_V_EN;
>> +    active_h_start = hsync_start_x;
>> +    active_h_end = active_h_start + p->xres - 1;
>> +    active_v_start = display_v_start;
>> +    active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>>   -        active_h_start = hsync_start_x;
>> -        active_h_end = active_h_start + p->xres - 1;
>> -        active_v_start = display_v_start;
>> -        active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>> +    active_hctl = (active_h_end << 16) | active_h_start;
>>   -        active_hctl = (active_h_end << 16) | active_h_start;
>> +    if (dp_intf) {
>>           display_hctl = active_hctl;
>>   -        intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
>> +        if (p->compression_en) {
>> +            active_data_hctl = (hsync_start_x + p->extra_dto_cycles) 
>> << 16;
>> +            active_data_hctl += hsync_start_x;
>> +
>> +            display_data_hctl = active_data_hctl;
>> +        }
>>       }
>>   +    _check_and_set_comp_bit(ctx, p->dsc_4hs_merge, 
>> p->compression_en, &intf_cfg2);
>> +
>>       den_polarity = 0;
>>       if (ctx->cap->type == INTF_HDMI) {
>>           hsync_polarity = p->yres >= 720 ? 0 : 1;
>> @@ -202,7 +227,7 @@ static void 
>> dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>

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

* Re: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-24 17:55     ` Kuogee Hsieh
@ 2023-01-24 21:37       ` Dmitry Baryshkov
  2023-01-24 23:36       ` Marijn Suijten
  1 sibling, 0 replies; 50+ messages in thread
From: Dmitry Baryshkov @ 2023-01-24 21:37 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 24/01/2023 19:55, Kuogee Hsieh wrote:
> 
> On 1/24/2023 1:11 AM, Dmitry Baryshkov wrote:
>> On 23/01/2023 20:24, Kuogee Hsieh wrote:
>>> Current implementation timing engine programming does not consider
>>> compression factors. This patch add consideration of DSC factors
>>> while programming timing engine.
>>>
>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>>> ---
>>>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |   2 +
>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  14 ++-
>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 
>>> +++++++++++++--------
>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>>>   5 files changed, 110 insertions(+), 54 deletions(-)
>>>
>>
>> [skipped]
>>
>>> @@ -113,82 +124,96 @@ static void 
>>> dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>>>       /* read interface_cfg */
>>>       intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
>>>   -    if (ctx->cap->type == INTF_DP)
>>> +    if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP)
>>>           dp_intf = true;
>>>         hsync_period = p->hsync_pulse_width + p->h_back_porch + 
>>> p->width +
>>> -    p->h_front_porch;
>>> +            p->h_front_porch;
>>>       vsync_period = p->vsync_pulse_width + p->v_back_porch + 
>>> p->height +
>>> -    p->v_front_porch;
>>> +            p->v_front_porch;
>>
>> Actually I went on through the history and found the previous 
>> submission, https://patchwork.freedesktop.org/patch/471505/.
>> Exactly the same piece of code. Did you expect that the comments will 
>> be different this time?
>>
>> I really hoped that at that time we already went through this. But it 
>> seems I was wrong. That series went through v10 or v12 before being 
>> accepted. And it was just adding wide_bus_en. Back at that time we 
>> lightly discussed that the code will receive compression support. But 
>> I never expected to see the original submission again.
>>
>> It might sound bad, but could you please find somebody who can do 
>> internal review for you? Good internal review.
>>
>> That said, I really do not expect to see v2 before the whole series is 
>> reworked, restructured and prepared for the review on your side.
> 
> This timing engine code is derived from our downstream code directly and 
> it has been used at many mobile devices by many vendors for many years 
> already.
> 
> On the other words, it had been tested very thorough and works on 
> dsi/dp/hdmi/dsc/widebus applications.

As far as I understand, it has been tested on the recent generations of 
the hardware. I doubt that anybody retests new techpack drops on 
previous hardware generations. Correct?

When was the last time this particular code drop was tested on 
INTF_HDMI? I think it was back in the 4.4 era. Newer vendor kernels do 
not have hdmi-staging, so at least the claim of testing this codepiece 
on HDMI is not correct.

What is the earliest chip that has been driven by this particular code 
instance?

> When i brought dsc v1.2 over, I just merged it over and did not consider 
> too much.
> 
> Can we adapt this code so that both upstream and down stream shared same 
> timing engine programming so that easier to maintain?

We have been discussing exactly the same piece of code a year ago. Could 
you please recheck the comments that were provided to your patches. And 
I actually mean that. There were 12 iterations of wide bus patchset. 
Timing engine programming patch had 8. I do not want to start again from 
the very beginning.

The basic idea is that you have to evolve the code rather than flushing 
us with the 'latest and greatest code dump'. Split this into individual 
atomic changes that we can review. Provide justification (= motivation) 
for each change. Previously we haven't seen them.

We know that current function works. We must be able to assume that new 
instance doesn't break things. Or, if something breaks, understand which 
particular change broke it. Consider the case that your patch breaks 
msm8998. Or sdm845. How can we cope? Would you be able to spot the place 
which did that? I know I wouldn't. The only way would be to revert the 
patch completely. And inherently the whole series.

>>
>>>         display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
>>> -    hsync_period) + p->hsync_skew;
>>> +            hsync_period) + p->hsync_skew;
>>>       display_v_end = ((vsync_period - p->v_front_porch) * 
>>> hsync_period) +
>>> -    p->hsync_skew - 1;
>>> +            p->hsync_skew - 1;
>>> +
>>> +    hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
>>>         hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
>>>       hsync_end_x = hsync_period - p->h_front_porch - 1;
>>>   -    if (p->width != p->xres) { /* border fill added */
>>> -        active_h_start = hsync_start_x;
>>> -        active_h_end = active_h_start + p->xres - 1;
>>> -    } else {
>>> -        active_h_start = 0;
>>> -        active_h_end = 0;
>>> -    }
>>> -
>>> -    if (p->height != p->yres) { /* border fill added */
>>> -        active_v_start = display_v_start;
>>> -        active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>>> -    } else {
>>> -        active_v_start = 0;
>>> -        active_v_end = 0;
>>> -    }
>>> -
>>> -    if (active_h_end) {
>>> -        active_hctl = (active_h_end << 16) | active_h_start;
>>> -        intf_cfg |= INTF_CFG_ACTIVE_H_EN;
>>> -    } else {
>>> -        active_hctl = 0;
>>> -    }
>>> -
>>> -    if (active_v_end)
>>> -        intf_cfg |= INTF_CFG_ACTIVE_V_EN;
>>> -
>>> -    hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
>>> -    display_hctl = (hsync_end_x << 16) | hsync_start_x;
>>> -
>>>       /*
>>>        * DATA_HCTL_EN controls data timing which can be different from
>>>        * video timing. It is recommended to enable it for all cases, 
>>> except
>>>        * if compression is enabled in 1 pixel per clock mode
>>>        */
>>> +    if (!p->compression_en || p->wide_bus_en)
>>> +        intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
>>> +
>>>       if (p->wide_bus_en)
>>> -        intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
>>> +        intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
>>>   +    /*
>>> +     * If widebus is disabled:
>>> +     * For uncompressed stream, the data is valid for the entire active
>>> +     * window period.
>>> +     * For compressed stream, data is valid for a shorter time period
>>> +     * inside the active window depending on the compression ratio.
>>> +     *
>>> +     * If widebus is enabled:
>>> +     * For uncompressed stream, data is valid for only half the active
>>> +     * window, since the data rate is doubled in this mode.
>>> +     * p->width holds the adjusted width for DP but unadjusted width 
>>> for DSI
>>> +     * For compressed stream, data validity window needs to be 
>>> adjusted for
>>> +     * compression ratio and then further halved.
>>> +     */
>>>       data_width = p->width;
>>>   +    if (p->compression_en) {
>>> +        if (p->wide_bus_en)
>>> +            data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6);
>>> +        else
>>> +            data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3);
>>> +    } else if (!dp_intf && p->wide_bus_en) {
>>> +        data_width = p->width >> 1;
>>> +    } else {
>>> +        data_width = p->width;
>>> +    }
>>> +
>>>       hsync_data_start_x = hsync_start_x;
>>>       hsync_data_end_x =  hsync_start_x + data_width - 1;
>>>   +    display_hctl = (hsync_end_x << 16) | hsync_start_x;
>>>       display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
>>>         if (dp_intf) {
>>>           /* DP timing adjustment */
>>>           display_v_start += p->hsync_pulse_width + p->h_back_porch;
>>>           display_v_end   -= p->h_front_porch;
>>> +    }
>>> +
>>> +    intf_cfg |= INTF_CFG_ACTIVE_H_EN;
>>> +    intf_cfg |= INTF_CFG_ACTIVE_V_EN;
>>> +    active_h_start = hsync_start_x;
>>> +    active_h_end = active_h_start + p->xres - 1;
>>> +    active_v_start = display_v_start;
>>> +    active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>>>   -        active_h_start = hsync_start_x;
>>> -        active_h_end = active_h_start + p->xres - 1;
>>> -        active_v_start = display_v_start;
>>> -        active_v_end = active_v_start + (p->yres * hsync_period) - 1;
>>> +    active_hctl = (active_h_end << 16) | active_h_start;
>>>   -        active_hctl = (active_h_end << 16) | active_h_start;
>>> +    if (dp_intf) {
>>>           display_hctl = active_hctl;
>>>   -        intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
>>> +        if (p->compression_en) {
>>> +            active_data_hctl = (hsync_start_x + p->extra_dto_cycles) 
>>> << 16;
>>> +            active_data_hctl += hsync_start_x;
>>> +
>>> +            display_data_hctl = active_data_hctl;
>>> +        }
>>>       }
>>>   +    _check_and_set_comp_bit(ctx, p->dsc_4hs_merge, 
>>> p->compression_en, &intf_cfg2);
>>> +
>>>       den_polarity = 0;
>>>       if (ctx->cap->type == INTF_HDMI) {
>>>           hsync_polarity = p->yres >= 720 ? 0 : 1;
>>> @@ -202,7 +227,7 @@ static void 
>>> dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
>>

-- 
With best wishes
Dmitry


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

* Re: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-24 17:55     ` Kuogee Hsieh
  2023-01-24 21:37       ` Dmitry Baryshkov
@ 2023-01-24 23:36       ` Marijn Suijten
  2023-01-25  9:08         ` Neil Armstrong
  1 sibling, 1 reply; 50+ messages in thread
From: Marijn Suijten @ 2023-01-24 23:36 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: vkoul, quic_sbillaka, quic_abhinavk, andersson, dianders,
	dri-devel, swboyd, agross, linux-arm-msm, Dmitry Baryshkov,
	freedreno, sean, linux-kernel

On 2023-01-24 09:55:24, Kuogee Hsieh wrote:

<snip>

> This timing engine code is derived from our downstream code directly and 
> it has been used at many mobile devices by many vendors for many years 
> already.
> 
> On the other words, it had been tested very thorough and works on 
> dsi/dp/hdmi/dsc/widebus applications.

And the code already in mainline has seen 12 rounds of review, with a
focus on inter-SoC compatibility.  Regardless of that, we have processes
to make changes on mainline: formatting changes (when actually making an
improvement) go separate from semantic changes.  Bugfixes are clearly
described in individual patches with Fixes: tags.  If you really think
the code has to be as proposed in this patch, follow Dmitry's advice and
split this accordingly.

> When i brought dsc v1.2 over, I just merged it over and did not consider 
> too much.

And that is exactly what is wrong with this *entire* series: copying
over downstream code without "considering too much", stomping over
previous review and even reverting bugfixes [1] [2] without giving it
ANY ATTENTION in your patch description.  That's unacceptable and
insulting to contributors and reviewers.  Full stop.  Or did you expect
us to turn a blind eye?  This is mainline, not some techpack playground.

[1]: https://lore.kernel.org/linux-arm-msm/20230123201133.zzt2zbyaw3pfkzi6@SoMainline.org/
[2]: https://lore.kernel.org/linux-arm-msm/20221026182824.876933-10-marijn.suijten@somainline.org/

> Can we adapt this code so that both upstream and down stream shared same 
> timing engine programming so that easier to maintain?

Easy, I've said this before in IRC and will state it again: stop this
techpack nonsense and focus on upstream-first.  When something passes
mainline review (and please don't bother maintainers and reviewers with
series like this) it is inevitably good enough to be copied to
techpack... at which point techpack becomes worthless as you can just
backport a mainline patch or use a recent-enough kernel.


tl;dr: it seems like you nor anyone involved in pre-reviewing/vetting
this series is familiar with upstream guidelines.  Follow the global
advice from Dmitry [3] to reach a more efficient v2, and please don't
let this run to v10 (or beyond) again.

One suggestion to improve efficiency: split off the DPU v1.2 hardware
block addition (and related changes) into a separate series.  A smaller
series (and properly split patches!) will give everyone less moving
parts to worry about, and paves the way for DSI support without blocking
on DP.

[3]: https://lore.kernel.org/linux-arm-msm/47c83e8c-09f1-d1dd-ca79-574122638256@linaro.org/

- Marijn

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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-23 20:11   ` Marijn Suijten
@ 2023-01-24 23:52     ` Kuogee Hsieh
  2023-01-30 20:16       ` Marijn Suijten
  0 siblings, 1 reply; 50+ messages in thread
From: Kuogee Hsieh @ 2023-01-24 23:52 UTC (permalink / raw)
  To: Marijn Suijten
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel


On 1/23/2023 12:11 PM, Marijn Suijten wrote:
> add support for*
>
> drm/msm/dpu*
>
> On 2023-01-23 10:24:30, Kuogee Hsieh wrote:
>> DSC V1.2 encoder engine is newly added hardware module. This patch
>> add support functions to configure and enable DSC V1.2 encoder engine.
>>
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
>>   drivers/gpu/drm/msm/Makefile                   |   1 +
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c    |   2 +-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  60 +++-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c     |  23 +-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h     |  23 +-
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c | 371 +++++++++++++++++++++++++
>>   6 files changed, 463 insertions(+), 17 deletions(-)
>>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
>>
>> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
>> index 28cf52b..271c29a15 100644
>> --- a/drivers/gpu/drm/msm/Makefile
>> +++ b/drivers/gpu/drm/msm/Makefile
>> @@ -65,6 +65,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>>   	disp/dpu1/dpu_hw_catalog.o \
>>   	disp/dpu1/dpu_hw_ctl.o \
>>   	disp/dpu1/dpu_hw_dsc.o \
>> +	disp/dpu1/dpu_hw_dsc_1_2.o \
>>   	disp/dpu1/dpu_dsc_helper.o \
>>   	disp/dpu1/dpu_hw_interrupts.o \
>>   	disp/dpu1/dpu_hw_intf.o \
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> index 7f4a439..901e317 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> @@ -1821,7 +1821,7 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_hw_dsc *hw_dsc,
>>   				     u32 initial_lines)
>>   {
>>   	if (hw_dsc->ops.dsc_config)
>> -		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines);
>> +		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, initial_lines, false);
> As usual, an enum is better: readers have no idea what a free-floating
> bool means.
>
>>   
>>   	if (hw_dsc->ops.dsc_config_thresh)
>>   		hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc);
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
>> index 978e3bd..7b0b092 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
>> @@ -1,6 +1,6 @@
>>   /* SPDX-License-Identifier: GPL-2.0-only */
>>   /*
>> - * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
>> + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
>>    * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
>>    */
>>   
>> @@ -11,6 +11,7 @@
>>   #include <linux/bug.h>
>>   #include <linux/bitmap.h>
>>   #include <linux/err.h>
>> +#include "dpu_hw_mdss.h"
> Unused if you remove the unused DECLARE_BITMAP(dsc_pair_mask, DSC_MAX).
>
>>   
>>   /**
>>    * Max hardware block count: For ex: max 12 SSPP pipes or
>> @@ -182,6 +183,7 @@ enum {
>>    * @DPU_PINGPONG_TE2        Additional tear check block for split pipes
>>    * @DPU_PINGPONG_SPLIT      PP block supports split fifo
>>    * @DPU_PINGPONG_SLAVE      PP block is a suitable slave for split fifo
>> + * @DPU_PINGPONG_DSC,       Display stream compression blocks
>>    * @DPU_PINGPONG_DITHER,    Dither blocks
>>    * @DPU_PINGPONG_MAX
>>    */
>> @@ -190,10 +192,32 @@ enum {
>>   	DPU_PINGPONG_TE2,
>>   	DPU_PINGPONG_SPLIT,
>>   	DPU_PINGPONG_SLAVE,
>> +	DPU_PINGPONG_DSC,
> This is not used.
>
>>   	DPU_PINGPONG_DITHER,
>>   	DPU_PINGPONG_MAX
>>   };
>>   
>> +
>> +/** DSC sub-blocks/features
> Newline between /** and the text.
>
>> + * @DPU_DSC_OUTPUT_CTRL         Supports the control of the pp id which gets
>> + *                              the pixel output from this DSC.
> The original comment is much more concise, can we keep it?
>
>> + * @DPU_DSC_HW_REV_1_1          dsc block supports dsc 1.1 only
>> + * @DPU_DSC_HW_REV_1_2          dsc block supports dsc 1.1 and 1.2
> Capitalize DSC just like elsewhere.
>
>> + * @DPU_DSC_NATIVE_422_EN,      Supports native422 and native420 encoding
>> + * @DPU_DSC_ENC,                DSC encoder sub block
>> + * @DPU_DSC_CTL,                DSC ctl sub block
> No need for trailing commas in doc comments; if anything replace them
> with colons?
>
>> + * @DPU_DSC_MAX
>> + */
>> +enum {
>> +	DPU_DSC_OUTPUT_CTRL = 0x1,
>> +	DPU_DSC_HW_REV_1_1,
>> +	DPU_DSC_HW_REV_1_2,
>> +	DPU_DSC_NATIVE_422_EN,
>> +	DPU_DSC_ENC,
>> +	DPU_DSC_CTL,
> These two enum values only have a meaning within the dpu_hw_dsc_1_2.c
> file, and have nothing to do with the other feature flags/block
> description.  Please move them there (and give _dsc_subblk_offset a
> proper enum type).
>
>> +	DPU_DSC_MAX
>> +};
>> +
>>   /**
>>    * CTL sub-blocks
>>    * @DPU_CTL_SPLIT_DISPLAY:	CTL supports video mode split display
>> @@ -276,15 +300,6 @@ enum {
>>   };
>>   
>>   /**
>> - * DSC features
>> - * @DPU_DSC_OUTPUT_CTRL       Configure which PINGPONG block gets
>> - *                            the pixel output from this DSC.
>> - */
>> -enum {
>> -	DPU_DSC_OUTPUT_CTRL = 0x1,
> Did this have to move?
>
>> -};
>> -
>> -/**
>>    * MACRO DPU_HW_BLK_INFO - information of HW blocks inside DPU
>>    * @name:              string name for debug purposes
>>    * @id:                enum identifying this block
>> @@ -346,6 +361,14 @@ struct dpu_pp_blk {
>>   };
>>   
>>   /**
>> + * struct dpu_dsc_blk : DSC Encoder sub-blk information
> Use a hyphen here and everywhere else:
> https://docs.kernel.org/doc-guide/kernel-doc.html
>
>> + * @info:   HW register and features supported by this sub-blk
>> + */
>> +struct dpu_dsc_blk {
>> +	DPU_HW_SUBBLK_INFO;
>> +};
>> +
>> +/**
>>    * enum dpu_qos_lut_usage - define QoS LUT use cases
>>    */
>>   enum dpu_qos_lut_usage {
>> @@ -403,6 +426,7 @@ struct dpu_rotation_cfg {
>>    * @pixel_ram_size     size of latency hiding and de-tiling buffer in bytes
>>    * @max_hdeci_exp      max horizontal decimation supported (max is 2^value)
>>    * @max_vdeci_exp      max vertical decimation supported (max is 2^value)
>> + * @max_dsc_width      max dsc line width support.
> DSC*
>
>>    */
>>   struct dpu_caps {
>>   	u32 max_mixer_width;
>> @@ -419,6 +443,7 @@ struct dpu_caps {
>>   	u32 pixel_ram_size;
>>   	u32 max_hdeci_exp;
>>   	u32 max_vdeci_exp;
>> +	u32 max_dsc_width;
> This is never read.
>
>>   };
>>   
>>   /**
>> @@ -494,9 +519,20 @@ struct dpu_dspp_sub_blks {
>>   struct dpu_pingpong_sub_blks {
>>   	struct dpu_pp_blk te;
>>   	struct dpu_pp_blk te2;
>> +	struct dpu_pp_blk dsc;
> Unused.
>
>>   	struct dpu_pp_blk dither;
>>   };
>>   
>> +
>> +/**
>> + * struct dpu_dsc_sub_blks : DSC sub-blks
>> + *
> A sub-block of sub-blocks?  Use the documentation to explain what this
> is for, describe @enc and @ctl.
>
>> + */
>> +struct dpu_dsc_sub_blks {
>> +	struct dpu_dsc_blk enc;
>> +	struct dpu_dsc_blk ctl;
>> +};
>> +
>>   /**
>>    * dpu_clk_ctrl_type - Defines top level clock control signals
>>    */
>> @@ -641,10 +677,14 @@ struct dpu_merge_3d_cfg  {
>>    * struct dpu_dsc_cfg - information of DSC blocks
>>    * @id                 enum identifying this block
>>    * @base               register offset of this block
>> + * @len:               length of hardware block
>>    * @features           bit mask identifying sub-blocks/features
>> + * @dsc_pair_mask:     Bitmask of DSCs that can be controlled by same CTL
>>    */
>>   struct dpu_dsc_cfg {
>>   	DPU_HW_BLK_INFO;
>> +	DECLARE_BITMAP(dsc_pair_mask, DSC_MAX);
> This bitmask is unused.
>
>> +	const struct dpu_dsc_sub_blks *sblk;
>>   };
>>   
>>   /**
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
>> index 619926d..51e8890 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c
>> @@ -1,6 +1,7 @@
>>   // SPDX-License-Identifier: GPL-2.0-only
>>   /*
>>    * Copyright (c) 2020-2022, Linaro Limited
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>>    */
>>   
>>   #include "dpu_kms.h"
>> @@ -41,10 +42,11 @@ static void dpu_hw_dsc_disable(struct dpu_hw_dsc *dsc)
>>   static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>>   			      struct drm_dsc_config *dsc,
>>   			      u32 mode,
>> -			      u32 initial_lines)
>> +			      u32 initial_lines,
>> +			      bool ich_reset_override)
>>   {
>>   	struct dpu_hw_blk_reg_map *c = &hw_dsc->hw;
>> -	u32 data;
>> +	u32 data, lsb, bpp;
>>   	u32 slice_last_group_size;
>>   	u32 det_thresh_flatness;
>>   	bool is_cmd_mode = !(mode & DSC_MODE_VIDEO);
>> @@ -58,7 +60,14 @@ static void dpu_hw_dsc_config(struct dpu_hw_dsc *hw_dsc,
>>   	data = (initial_lines << 20);
>>   	data |= ((slice_last_group_size - 1) << 18);
>>   	/* bpp is 6.4 format, 4 LSBs bits are for fractional part */
>> -	data |= (dsc->bits_per_pixel << 8);
>> +	data |= dsc->bits_per_pixel << 12;
>> +	lsb = dsc->bits_per_pixel % 4;
>> +	bpp = dsc->bits_per_pixel / 4;
>> +	bpp *= 4;
>> +	bpp <<= 4;
>> +	bpp |= lsb;
>> +
>> +	data |= bpp << 8;
> Why are you re-adding this nonsense?  It was removed in [1] _and_ does
> not account for bits_per_pixel _already being in x.4 format_. This will
> regress existing hardware.
>
> [1]: https://lore.kernel.org/linux-arm-msm/20221026182824.876933-10-marijn.suijten@somainline.org/
>
>>   	data |= (dsc->block_pred_enable << 7);
>>   	data |= (dsc->line_buf_depth << 3);
>>   	data |= (dsc->simple_422 << 2);
>> @@ -221,7 +230,13 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>>   
>>   	c->idx = idx;
>>   	c->caps = cfg;
>> -	_setup_dsc_ops(&c->ops, c->caps->features);
>> +
>> +	if (test_bit(DPU_DSC_HW_REV_1_1, &c->caps->features))
>> +		_setup_dsc_ops(&c->ops, c->caps->features);
>> +	else if (test_bit(DPU_DSC_HW_REV_1_2, &c->caps->features))
>> +		dpu_dsc_1_2_setup_ops(&c->ops, c->caps->features);
>> +	else
>> +		_setup_dsc_ops(&c->ops, c->caps->features);
>>   
>>   	return c;
>>   }
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
>> index ae9b5db..a48f572 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h
>> @@ -1,5 +1,8 @@
>>   /* SPDX-License-Identifier: GPL-2.0-only */
>> -/* Copyright (c) 2020-2022, Linaro Limited */
>> +/*
>> + * Copyright (c) 2020-2022, Linaro Limited
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>> + */
>>   
>>   #ifndef _DPU_HW_DSC_H
>>   #define _DPU_HW_DSC_H
>> @@ -33,7 +36,8 @@ struct dpu_hw_dsc_ops {
>>   	void (*dsc_config)(struct dpu_hw_dsc *hw_dsc,
>>   			   struct drm_dsc_config *dsc,
>>   			   u32 mode,
>> -			   u32 initial_lines);
>> +			   u32 initial_lines,
>> +			   bool ich_reset_override);
>>   
>>   	/**
>>   	 * dsc_config_thresh - programs panel thresholds
>> @@ -43,6 +47,12 @@ struct dpu_hw_dsc_ops {
>>   	void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc,
>>   				  struct drm_dsc_config *dsc);
>>   
>> +	/**
>> +	 * bind_pingpong_blk - enable/disable the connection with pp
> Inherit docs from the enum.
>
>> +	 * @hw_dsc: Pointer to dsc context
> DSC*
>
>> +	 * @enable: enable/disable connection
>> +	 * @pp: pingpong blk id
> It's documentation, write out block fully.
>
>> +	 */
>>   	void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc,
>>   				  bool enable,
>>   				  enum dpu_pingpong pp);
>> @@ -51,6 +61,7 @@ struct dpu_hw_dsc_ops {
>>   struct dpu_hw_dsc {
>>   	struct dpu_hw_blk base;
>>   	struct dpu_hw_blk_reg_map hw;
>> +	struct dpu_hw_ctl *hw_ctl;
> Unused.
>
>>   
>>   	/* dsc */
>>   	enum dpu_dsc idx;
>> @@ -76,9 +87,17 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(enum dpu_dsc idx, void __iomem *addr,
>>    */
>>   void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc);
>>   
>> +/**
>> + * dpu_hw_dsc - convert base object dpu_hw_base to container
>> + * @hw: Pointer to base hardware block
>> + * return: Pointer to hardware block container
>> + */
>>   static inline struct dpu_hw_dsc *to_dpu_hw_dsc(struct dpu_hw_blk *hw)
>>   {
>>   	return container_of(hw, struct dpu_hw_dsc, base);
>>   }
>>   
>> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
>> +		const unsigned long features);
>> +
>>   #endif /* _DPU_HW_DSC_H */
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
>> new file mode 100644
>> index 00000000..2be74ae
>> --- /dev/null
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
>> @@ -0,0 +1,371 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved
>> + */
>> +
>> +#include "dpu_kms.h"
>> +#include "dpu_hw_catalog.h"
>> +#include "dpu_hwio.h"
>> +#include "dpu_hw_mdss.h"
>> +#include "dpu_hw_dsc.h"
>> +
>> +
>> +#define DSC_CMN_MAIN_CNF           0x00
>> +
>> +/* DPU_DSC_ENC register offsets */
>> +#define ENC_DF_CTRL                0x00
>> +#define ENC_GENERAL_STATUS         0x04
>> +#define ENC_HSLICE_STATUS          0x08
>> +#define ENC_OUT_STATUS             0x0C
>> +#define ENC_INT_STAT               0x10
>> +#define ENC_INT_CLR                0x14
>> +#define ENC_INT_MASK               0x18
>> +#define DSC_MAIN_CONF              0x30
>> +#define DSC_PICTURE_SIZE           0x34
>> +#define DSC_SLICE_SIZE             0x38
>> +#define DSC_MISC_SIZE              0x3C
>> +#define DSC_HRD_DELAYS             0x40
>> +#define DSC_RC_SCALE               0x44
>> +#define DSC_RC_SCALE_INC_DEC       0x48
>> +#define DSC_RC_OFFSETS_1           0x4C
>> +#define DSC_RC_OFFSETS_2           0x50
>> +#define DSC_RC_OFFSETS_3           0x54
>> +#define DSC_RC_OFFSETS_4           0x58
>> +#define DSC_FLATNESS_QP            0x5C
>> +#define DSC_RC_MODEL_SIZE          0x60
>> +#define DSC_RC_CONFIG              0x64
>> +#define DSC_RC_BUF_THRESH_0        0x68
>> +#define DSC_RC_BUF_THRESH_1        0x6C
>> +#define DSC_RC_BUF_THRESH_2        0x70
>> +#define DSC_RC_BUF_THRESH_3        0x74
>> +#define DSC_RC_MIN_QP_0            0x78
>> +#define DSC_RC_MIN_QP_1            0x7C
>> +#define DSC_RC_MIN_QP_2            0x80
>> +#define DSC_RC_MAX_QP_0            0x84
>> +#define DSC_RC_MAX_QP_1            0x88
>> +#define DSC_RC_MAX_QP_2             0x8C
>> +#define DSC_RC_RANGE_BPG_OFFSETS_0  0x90
>> +#define DSC_RC_RANGE_BPG_OFFSETS_1  0x94
>> +#define DSC_RC_RANGE_BPG_OFFSETS_2  0x98
> Reindent to line this back up.
>
>> +
>> +/* DPU_DSC_CTL register offsets */
>> +#define DSC_CTL                    0x00
>> +#define DSC_CFG                    0x04
>> +#define DSC_DATA_IN_SWAP           0x08
>> +#define DSC_CLK_CTRL               0x0C
>> +
>> +
>> +static int _dsc_calc_ob_max_addr(struct dpu_hw_dsc *hw_dsc, int num_ss)
>> +{
>> +	enum dpu_dsc idx;
>> +
>> +	idx = hw_dsc->idx;
>> +
>> +	if (!(hw_dsc->caps->features & BIT(DPU_DSC_NATIVE_422_EN))) {
> Why not swap the bodies instead of inverting this.
>
>> +		if (num_ss == 1)
>> +			return 2399;
>> +		else if (num_ss == 2)
>> +			return 1199;
>> +	} else {
>> +		if (num_ss == 1)
>> +			return 1199;
>> +		else if (num_ss == 2)
>> +			return 599;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static inline int _dsc_subblk_offset(struct dpu_hw_dsc *hw_dsc, int s_id,
>> +		u32 *idx)
>> +{
>> +	const struct dpu_dsc_sub_blks *sblk;
>> +
>> +	if (!hw_dsc)
>> +		return -EINVAL;
>> +
>> +	*idx = 0;
>> +
>> +	sblk = hw_dsc->caps->sblk;
>> +
>> +	switch (s_id) {
>> +
>> +	case DPU_DSC_ENC:
>> +		*idx = sblk->enc.base;
>> +		break;
>> +	case DPU_DSC_CTL:
>> +		*idx = sblk->ctl.base;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void dpu_hw_dsc_disable_1_2(struct dpu_hw_dsc *hw_dsc)
>> +{
>> +	struct dpu_hw_blk_reg_map *hw;
>> +	u32 idx;
> Can we rename these to offset or subblk_offset or something more clear?
>
>> +
>> +	if (!hw_dsc)
>> +		return;
>> +
>> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
>> +		return;
> These error checks are excessive: you pass in a non-null hw_dsc and
> known enum constant - _dsc_subblk_offset should perhaps not return
> errors at all.
>
>> +
>> +	hw = &hw_dsc->hw;
>> +	DPU_REG_WRITE(hw, DSC_CFG + idx, 0);
> Swap the arguments to + so that it's clear that DSC_CFG is a register on
> the subblock offset denoted by "idx", not the other way around.
>
>> +
>> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
>> +		return;
>> +
>> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, 0);
>> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, 0);
>> +}
>> +
>> +static void dpu_hw_dsc_config_1_2(struct dpu_hw_dsc *hw_dsc,
>> +		struct drm_dsc_config *dsc, u32 mode,
>> +		u32 initial_lines, bool ich_reset_override)
>> +{
>> +	struct dpu_hw_blk_reg_map *hw;
>> +	struct msm_display_dsc_info *dsc_info;
>> +	u32 idx;
>> +	u32 data = 0;
>> +	u32 bpp;
>> +	void __iomem *off;
>> +
>> +	if (!hw_dsc || !dsc)
>> +		return;
>> +
>> +	hw = &hw_dsc->hw;
>> +
>> +	dsc_info = to_msm_dsc_info(dsc);
>> +
>> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
>> +		return;
>> +
>> +	if (mode & DSC_MODE_SPLIT_PANEL)
>> +		data |= BIT(0);
>> +
>> +	if (mode & DSC_MODE_MULTIPLEX)
>> +		data |= BIT(1);
> These are well known bitwise definitions for a reason, data |= mode will
> do (or out DSC_MODE_VIDEO since you have to shift that one at BIT(9).
>
>> +
>> +	data |= (dsc_info->num_active_ss_per_enc & 0x3) << 7;
>> +
>> +	DPU_REG_WRITE(hw, DSC_CMN_MAIN_CNF, data);
>> +
>> +	data = (dsc_info->initial_lines & 0xff);
> You already get initial_lines passed as function argument, but ignore
> it?
>
>> +	data |= ((mode & DSC_MODE_VIDEO) ? 1 : 0) << 9;
> Yuck. if (mode & DSC_MODE_VIDEO) data |= BIT(9);.
>
>> +	if (ich_reset_override)
>> +		data |= 0xC00; // set bit 10 and 11
> Instead of a comment, make this self-describing BIT(10) | BIT(11) code.
>
>> +	data |= (_dsc_calc_ob_max_addr(hw_dsc, dsc_info->num_active_ss_per_enc) << 18);
>> +
>> +	DPU_REG_WRITE(hw, ENC_DF_CTRL + idx, data);
>> +
>> +	data = (dsc->dsc_version_minor & 0xf) << 28;
>> +	if (dsc->dsc_version_minor == 0x2) {
>> +		if (dsc->native_422)
>> +			data |= BIT(22);
>> +		if (dsc->native_420)
>> +			data |= BIT(21);
>> +	}
>> +
>> +	bpp = dsc->bits_per_pixel;
> As above, don't forget to read the documentation on this field:
>
>      Target bits per pixel with 4 fractional bits, bits_per_pixel << 4
>
>> +	/* as per hw requirement bpp should be programmed
>> +	 * twice the actual value in case of 420 or 422 encoding
>> +	 */
>> +	if (dsc->native_422 || dsc->native_420)
>> +		bpp = 2 * bpp;
>> +	data |= (dsc->block_pred_enable ? 1 : 0) << 20;
>> +	data |= (bpp << 10);
> Either wrap everything or nothing in ().
>
>> +	data |= (dsc->line_buf_depth & 0xf) << 6;
>> +	data |= dsc->convert_rgb << 4;
>> +	data |= dsc->bits_per_component & 0xf;
>> +
>> +	DPU_REG_WRITE(hw, DSC_MAIN_CONF + idx, data);
>> +
>> +	data = (dsc->pic_width & 0xffff) |
>> +		((dsc->pic_height & 0xffff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_PICTURE_SIZE + idx, data);
>> +
>> +	data = (dsc->slice_width & 0xffff) |
>> +		((dsc->slice_height & 0xffff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_SLICE_SIZE + idx, data);
>> +
>> +	DPU_REG_WRITE(hw, DSC_MISC_SIZE + idx,
>> +			(dsc->slice_chunk_size) & 0xffff);
>> +
>> +	data = (dsc->initial_xmit_delay & 0xffff) |
>> +		((dsc->initial_dec_delay & 0xffff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_HRD_DELAYS + idx, data);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_SCALE + idx,
>> +			dsc->initial_scale_value & 0x3f);
>> +
>> +	data = (dsc->scale_increment_interval & 0xffff) |
>> +		((dsc->scale_decrement_interval & 0x7ff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_SCALE_INC_DEC + idx, data);
>> +
>> +	data = (dsc->first_line_bpg_offset & 0x1f) |
>> +		((dsc->second_line_bpg_offset & 0x1f) << 5);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_1 + idx, data);
>> +
>> +	data = (dsc->nfl_bpg_offset & 0xffff) |
>> +		((dsc->slice_bpg_offset & 0xffff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_2 + idx, data);
>> +
>> +	data = (dsc->initial_offset & 0xffff) |
>> +		((dsc->final_offset & 0xffff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_3 + idx, data);
>> +
>> +	data = (dsc->nsl_bpg_offset & 0xffff) |
>> +		((dsc->second_line_offset_adj & 0xffff) << 16);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_OFFSETS_4 + idx, data);
>> +
>> +	data = (dsc->flatness_min_qp & 0x1f);
>> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
>> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
> dpu_hw_dsc.c computes this on the fly.  After removing that, and
> using initial_lines from the function parameters, only
> dsc_info->num_active_ss_per_enc remains.  Do you really need that
> msm_display_dsc_info struct here, do you need it at all?

I ported these code from our down stream code base.

I make it work first, then clean it up will follow.

I submit it for review since it looks like you guy like to have code sooner.

yes, eliminate msm_display_dsc_info is my next target and hope it can be 
done.





>
>> +
>> +	DPU_REG_WRITE(hw, DSC_FLATNESS_QP + idx, data);
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_MODEL_SIZE + idx,
>> +			(dsc->rc_model_size) & 0xffff);
>> +
>> +	data = dsc->rc_edge_factor & 0xf;
>> +	data |= (dsc->rc_quant_incr_limit0 & 0x1f) << 8;
>> +	data |= (dsc->rc_quant_incr_limit1 & 0x1f) << 13;
>> +	data |= (dsc->rc_tgt_offset_high & 0xf) << 20;
>> +	data |= (dsc->rc_tgt_offset_low & 0xf) << 24;
>> +
>> +	DPU_REG_WRITE(hw, DSC_RC_CONFIG + idx, data);
>> +
>> +	/* program the dsc wrapper */
>> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
>> +		return;
>> +
>> +	off = hw->blk_addr + idx;
>> +
>> +	data = BIT(0); /* encoder enable */
>> +	if (dsc->native_422)
>> +		data |= BIT(8);
>> +	else if (dsc->native_420)
>> +		data |= BIT(9);
>> +	if (!dsc->convert_rgb)
>> +		data |= BIT(10);
>> +	if (dsc->bits_per_component == 8)
>> +		data |= BIT(11);
>> +	if (mode & DSC_MODE_SPLIT_PANEL)
>> +		data |= BIT(12);
>> +	if (mode & DSC_MODE_MULTIPLEX)
>> +		data |= BIT(13);
>> +	if (!(mode & DSC_MODE_VIDEO))
>> +		data |= BIT(17);
>> +
>> +	if (dsc_info->dsc_4hsmerge_en) {
>> +		data |= dsc_info->dsc_4hsmerge_padding << 18;
>> +		data |= dsc_info->dsc_4hsmerge_alignment << 22;
>> +		data |= BIT(16);
>> +	}
>> +
>> +	DPU_REG_WRITE(hw, DSC_CFG + idx, data);
>> +
>> +//	DPU_REG_WRITE(hw, DSC_DATA_IN_SWAP + idx, 0x14e5);
> No commented-out code please, especially not with //
>
>> +}
>> +
>> +static void dpu_hw_dsc_config_thresh_1_2(struct dpu_hw_dsc *hw_dsc,
>> +		struct drm_dsc_config *dsc)
>> +{
>> +	struct dpu_hw_blk_reg_map *hw;
>> +	struct msm_display_dsc_info *dsc_info;
>> +	u32 idx, off;
>> +	int i, j = 0;
>> +	struct drm_dsc_rc_range_parameters *rc;
>> +	u32 data = 0, min_qp = 0, max_qp = 0, bpg_off = 0;
>> +
>> +	if (!hw_dsc || !dsc)
>> +		return;
>> +
>> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_ENC, &idx))
>> +		return;
>> +
>> +	hw = &hw_dsc->hw;
>> +
>> +	dsc_info = to_msm_dsc_info(dsc);
>> +
>> +	rc = dsc->rc_range_params;
>> +
>> +	off = 0;
>> +	for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) {
>> +		data |= dsc->rc_buf_thresh[i] << (8*j);
> Lack of spaces does not make this multiplication any prettier to read.
>
> * has precedence over << but it's better to replicate the () below as
> well.
>
>> +		j++;
>> +		if ((j == 4) || (i == DSC_NUM_BUF_RANGES - 2)) {
>> +			DPU_REG_WRITE(hw, DSC_RC_BUF_THRESH_0 + idx + off,
>> +					data);
>> +			off += 4;
>> +			j = 0;
>> +			data = 0;
>> +		}
>> +	}
>> +
>> +	off = 0;
>> +	for (i = 0; i < DSC_NUM_BUF_RANGES; i++) {
>> +		min_qp |= (rc[i].range_min_qp & 0x1f) << 5*j;
>> +		max_qp |= (rc[i].range_max_qp & 0x1f) << 5*j;
>> +		bpg_off |= (rc[i].range_bpg_offset & 0x3f) << 6*j;
> These values _must_ already be masked to be useful in
> drm_dsc_compute_rc_parameters(), no need to mask them again just like
> the v1.1 block implementation.
>
>> +		j++;
>> +		if (j == 5) {
>> +			DPU_REG_WRITE(hw, DSC_RC_MIN_QP_0 + idx + off,
>> +					min_qp);
>> +			DPU_REG_WRITE(hw, DSC_RC_MAX_QP_0 + idx + off,
>> +					max_qp);
>> +			DPU_REG_WRITE(hw,
>> +					DSC_RC_RANGE_BPG_OFFSETS_0 + idx + off,
>> +					bpg_off);
>> +			off += 4;
>> +			j = 0;
>> +			min_qp = 0;
>> +			max_qp = 0;
>> +			bpg_off = 0;
>> +		}
>> +	}
>> +}
>> +
>> +static void dpu_hw_dsc_bind_pingpong_blk_1_2(
>> +		struct dpu_hw_dsc *hw_dsc,
>> +		bool enable,
>> +		const enum dpu_pingpong pp)
>> +{
>> +	struct dpu_hw_blk_reg_map *hw;
>> +	int idx;
>> +	int mux_cfg = 0xF; /* Disabled */
> Lowercase hex (and anywhere else if I skipped any).
>
>> +
>> +	if (!hw_dsc)
>> +		return;
> As with the v1.1 implementation, we don't check this, and your function
> below also checks it (but it does not need to).
>
>> +	if (_dsc_subblk_offset(hw_dsc, DPU_DSC_CTL, &idx))
>> +		return;
>> +
>> +	hw = &hw_dsc->hw;
>> +	if (enable)
>> +		mux_cfg = (pp - PINGPONG_0) & 0x7;
>> +
>> +	DPU_REG_WRITE(hw, DSC_CTL + idx, mux_cfg);
>> +}
>> +
>> +void dpu_dsc_1_2_setup_ops(struct dpu_hw_dsc_ops *ops,
>> +		const unsigned long features)
>> +{
>> +	ops->dsc_disable = dpu_hw_dsc_disable_1_2;
>> +	ops->dsc_config = dpu_hw_dsc_config_1_2;
>> +	ops->dsc_config_thresh = dpu_hw_dsc_config_thresh_1_2;
>> +	ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2;
>> +}
>> -- 
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>> a Linux Foundation Collaborative Project
>>
> All in all you really need to revise and clean your patches before
> sending them to the lists; these are already far too many comments and
> nits, and massively take away from reviewing code behaviour which I have
> not even started with after looking at 1 out of 14 patches :(
>
> - Marijn

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

* Re: [PATCH v1 00/14] add display port DSC feature
  2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
                   ` (15 preceding siblings ...)
  2023-01-24  0:10 ` Dmitry Baryshkov
@ 2023-01-25  0:28 ` Abhinav Kumar
  16 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2023-01-25  0:28 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, linux-kernel, Marijn Suijten

Hi Dmitry / Marijn

I have seen your review comments and agree there is much work to be done 
to get this in a better shape.

We will post a better V2 to address the concerns.

Would appreciate some patience till then.

Thanks for your support in reviews as always

Abhinav

On 1/23/2023 10:24 AM, Kuogee Hsieh wrote:
> This patch add DSC related supporting functions into to both dp controller and dpu enccoder
> 
> Kuogee Hsieh (14):
>    drm/msm/dp: add dpcd read of both dsc and fec capability
>    drm/msm/dp: add dsc factor into calculation of supported bpp
>    drm/msm/dp: add configure mainlink_levels base on lane number
>    drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0
>    drm/msm/dp: upgrade tu calculation base on newest algorithm
>    drm/msm/dp: add display compression related struct
>    drm/msm/dp: add dsc helper functions
>    drm/msm/dp: add dsc supporting functions to DP controller
>    drm/msm/dsi: export struct msm_compression_info to dpu encoder
>    drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
>    drm/msm/disp/dpu1: add supports of new flush mechanism
>    drm/msm/disp/dpu1: revise timing engine programming to work for DSC
>    drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder
>    drm/msm/disp/dpu1: add sc7280 dsc block and sub block
> 
>   drivers/gpu/drm/msm/Makefile                       |   2 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c     | 537 +++++++++++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h     |  25 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 341 +++++++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |   4 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   7 +-
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  43 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c     |  50 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  74 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         |  43 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         |  21 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c         |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h         |  23 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c     | 371 +++++++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c        | 132 ++--
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h        |  10 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h         |   6 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            |  10 +-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
>   drivers/gpu/drm/msm/dp/dp_catalog.c                | 176 ++++-
>   drivers/gpu/drm/msm/dp/dp_catalog.h                |  97 ++-
>   drivers/gpu/drm/msm/dp/dp_ctrl.c                   | 839 ++++++++++++++-------
>   drivers/gpu/drm/msm/dp/dp_display.c                |  61 +-
>   drivers/gpu/drm/msm/dp/dp_link.c                   |  29 +-
>   drivers/gpu/drm/msm/dp/dp_panel.c                  | 749 +++++++++++++++++-
>   drivers/gpu/drm/msm/dp/dp_panel.h                  |  67 +-
>   drivers/gpu/drm/msm/dp/dp_reg.h                    |  40 +-
>   drivers/gpu/drm/msm/dsi/dsi.c                      |   3 +-
>   drivers/gpu/drm/msm/dsi/dsi.h                      |   3 +-
>   drivers/gpu/drm/msm/dsi/dsi_host.c                 |  14 +-
>   drivers/gpu/drm/msm/msm_drv.h                      | 113 ++-
>   32 files changed, 3429 insertions(+), 497 deletions(-)
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.c
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_dsc_helper.h
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c
> 

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

* Re: [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder
  2023-01-23 18:24 ` [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder Kuogee Hsieh
@ 2023-01-25  9:01   ` Neil Armstrong
  0 siblings, 0 replies; 50+ messages in thread
From: Neil Armstrong @ 2023-01-25  9:01 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, dmitry.baryshkov, andersson
  Cc: linux-arm-msm, quic_sbillaka, freedreno, quic_abhinavk, linux-kernel

On 23/01/2023 19:24, Kuogee Hsieh wrote:
> Since display Port is an external peripheral, runtime compression
> detection is added to handle plug in and unplugged events. Currently
> only DSC compression supported. Once DSC compression detected, topology
> is static added and used to allocate system resources to accommodate
> DSC requirement. DSC related parameters are calculated and committed to
> DSC encoder. Also compression information are propagated to phy and
> committed to timing engine at video mode. This patch completes DSC
> implementation.
> 
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 314 ++++++++++++++++-----
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |   5 +-
>   .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  34 ++-
>   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h    |   3 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  10 +-
>   5 files changed, 292 insertions(+), 74 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index d2625b3..d7f5f93 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -15,6 +15,7 @@
>   #include <drm/drm_crtc.h>
>   #include <drm/drm_file.h>
>   #include <drm/drm_probe_helper.h>
> +#include <drm/drm_bridge.h>
>   
>   #include "msm_drv.h"
>   #include "dpu_kms.h"
> @@ -30,6 +31,7 @@
>   #include "dpu_crtc.h"
>   #include "dpu_trace.h"
>   #include "dpu_core_irq.h"
> +#include "dpu_dsc_helper.h"
>   #include "disp/msm_disp_snapshot.h"
>   
>   #define DPU_DEBUG_ENC(e, fmt, ...) DRM_DEBUG_ATOMIC("enc%d " fmt,\
> @@ -542,12 +544,12 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc)
>   	return (num_dsc > 0) && (num_dsc > intf_count);
>   }
>   
> -static struct msm_display_topology dpu_encoder_get_topology(
> +static void dpu_encoder_get_topology(
>   			struct dpu_encoder_virt *dpu_enc,
>   			struct dpu_kms *dpu_kms,
> -			struct drm_display_mode *mode)
> +			struct drm_display_mode *mode,
> +			struct msm_display_topology *topology)
>   {
> -	struct msm_display_topology topology = {0};
>   	int i, intf_count = 0;
>   
>   	for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++)
> @@ -567,19 +569,19 @@ static struct msm_display_topology dpu_encoder_get_topology(
>   	 * sufficient number
>   	 */
>   	if (intf_count == 2)
> -		topology.num_lm = 2;
> +		topology->num_lm = 2;
>   	else if (!dpu_kms->catalog->caps->has_3d_merge)
> -		topology.num_lm = 1;
> +		topology->num_lm = 1;
>   	else
> -		topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
> +		topology->num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
>   
>   	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) {
>   		if (dpu_kms->catalog->dspp &&
> -			(dpu_kms->catalog->dspp_count >= topology.num_lm))
> -			topology.num_dspp = topology.num_lm;
> +			(dpu_kms->catalog->dspp_count >= topology->num_lm))
> +			topology->num_dspp = topology->num_lm;
>   	}
>   
> -	topology.num_intf = intf_count;
> +	topology->num_intf = intf_count;
>   
>   	if (dpu_enc->dsc) {
>   		/*
> @@ -588,12 +590,31 @@ static struct msm_display_topology dpu_encoder_get_topology(
>   		 * this is power optimal and can drive up to (including) 4k
>   		 * screens
>   		 */
> -		topology.num_dsc = 2;
> -		topology.num_lm = 2;
> -		topology.num_intf = 1;
> +		topology->num_dsc = 2;
> +		topology->num_intf = 1;
> +		topology->num_lm = 2;
>   	}
>   
> -	return topology;
> +	/*
> +	 * default topology for display port DSC implementation.
> +	 * TODO:
> +	 *	change to runtime resource calculation
> +	 */
> +	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
> +		topology->num_dsc = 0;
> +		topology->num_intf = intf_count;
> +
> +		if (dpu_enc->comp_info) {
> +			/* In case of Display Stream Compression (DSC), we would use
> +			 * 2 encoders, 2 layer mixers and 1 interface
> +			 * this is power optimal and can drive up to (including) 4k
> +			 * screens
> +			 */
> +			topology->num_dsc = 1;
> +			topology->num_intf = 1;
> +			topology->num_lm = 1;
> +		}
> +	}
>   }
>   
>   static int dpu_encoder_virt_atomic_check(
> @@ -605,7 +626,7 @@ static int dpu_encoder_virt_atomic_check(
>   	struct msm_drm_private *priv;
>   	struct dpu_kms *dpu_kms;
>   	struct drm_display_mode *adj_mode;
> -	struct msm_display_topology topology;
> +	struct msm_display_topology *topology;
>   	struct dpu_global_state *global_state;
>   	int i = 0;
>   	int ret = 0;
> @@ -642,7 +663,27 @@ static int dpu_encoder_virt_atomic_check(
>   		}
>   	}
>   
> -	topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
> +	/*
> +	 * For display port, at this moment we know panel had been plugged in
> +	 * and dsc supported is detected.
> +	 * however we do not know the details of resolution will be used
> +	 * until mode_set had been done.
> +	 *
> +	 * use default topology to reserve system resource for dsc
> +	 *
> +	 * TODO: run time calculation of topology instead of hardcode it now
> +	 */
> +	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
> +		struct drm_bridge *bridge;
> +
> +		if (!dpu_enc->comp_info) {
> +			bridge = drm_bridge_chain_get_first_bridge(drm_enc);
> +			dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge);
> +		}
> +	}
> +
> +	topology = &dpu_enc->topology;
> +	dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, topology);
>   
>   	/* Reserve dynamic resources now. */
>   	if (!ret) {
> @@ -655,7 +696,7 @@ static int dpu_encoder_virt_atomic_check(
>   
>   			if (!crtc_state->active_changed || crtc_state->active)
>   				ret = dpu_rm_reserve(&dpu_kms->rm, global_state,
> -						drm_enc, crtc_state, topology);
> +						drm_enc, crtc_state, *topology);
>   		}
>   	}
>   
> @@ -1009,7 +1050,37 @@ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
>   
>   		if (phys->ops.cleanup_wb_job)
>   			phys->ops.cleanup_wb_job(phys, job);
> +	}
> +}
> +
> +static void dpu_encoder_populate_encoder_phys(struct drm_encoder *drm_enc,
> +					struct dpu_encoder_virt *dpu_enc)
> +{
> +	struct msm_compression_info *comp_info;
> +	struct msm_display_dsc_info *dsc_info;
> +	int i;
> +
> +	if (!dpu_enc->comp_info)
> +		return;
> +
> +	comp_info = dpu_enc->comp_info;
> +	dsc_info = &comp_info->msm_dsc_info;
> +
> +	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> +		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
> +
> +		if (!phys)
> +			continue;
> +
> +		phys->comp_type = comp_info->comp_type;
> +		phys->comp_ratio = comp_info->comp_ratio;
>   
> +		if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) {
> +			phys->dsc_extra_pclk_cycle_cnt = dsc_info->pclk_per_line;
> +			phys->dsc_extra_disp_width = dsc_info->extra_width;
> +			phys->dce_bytes_per_line =
> +				dsc_info->bytes_per_pkt * dsc_info->pkt_per_line;
> +		}
>   	}
>   }
>   
> @@ -1050,6 +1121,24 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   
>   	trace_dpu_enc_mode_set(DRMID(drm_enc));
>   
> +	/*
> +	 * For display port, msm_dp_bridge_mode_set() will conver panel info
> +	 * into dp_mode. This including detail dsc information if it is enabled.
> +	 * after that, msm_dp_bridge_get_compression() will return detail
> +	 * dsc compression info
> +	 */
> +	if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS) {
> +		struct drm_display_mode *mode, *adjusted_mode;
> +		struct drm_bridge *bridge;
> +
> +		mode = &crtc_state->mode;
> +		adjusted_mode = &crtc_state->adjusted_mode;
> +		bridge = drm_bridge_chain_get_first_bridge(drm_enc);
> +		msm_dp_bridge_mode_set(bridge, mode, adjusted_mode);
> +
> +		dpu_enc->comp_info = msm_dp_bridge_get_compression(bridge);
> +	}
> +
>   	/* Query resource that have been reserved in atomic check step. */
>   	num_pp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
>   		drm_enc->base.id, DPU_HW_BLK_PINGPONG, hw_pp,
> @@ -1061,19 +1150,18 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   	dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
>   		drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp,
>   		ARRAY_SIZE(hw_dspp));
> +	num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
> +		drm_enc->base.id, DPU_HW_BLK_DSC,
> +		hw_dsc, ARRAY_SIZE(hw_dsc));
>   
>   	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
>   		dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i])
>   						: NULL;
>   
> -	if (dpu_enc->dsc) {
> -		num_dsc = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
> -							drm_enc->base.id, DPU_HW_BLK_DSC,
> -							hw_dsc, ARRAY_SIZE(hw_dsc));
> -		for (i = 0; i < num_dsc; i++) {
> -			dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]);
> -			dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0);
> -		}
> +	for (i = 0; i < num_dsc; i++) {
> +		dpu_enc->hw_dsc[i] = to_dpu_hw_dsc(hw_dsc[i]);
> +		dpu_enc->hw_pp[i]->dsc = dpu_enc->hw_dsc[i]; /* bind dsc to pp */
> +		dsc_mask |= BIT(dpu_enc->hw_dsc[i]->idx - DSC_0);
>   	}
>   
>   	dpu_enc->dsc_mask = dsc_mask;
> @@ -1110,10 +1198,22 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   		phys->hw_pp = dpu_enc->hw_pp[i];
>   		phys->hw_ctl = to_dpu_hw_ctl(hw_ctl[i]);
>   
> +		if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
> +			phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
> +
> +		/* phys->hw_intf populated at dpu_encoder_setup_display() */
> +		if (!phys->hw_intf) {
> +			DPU_ERROR_ENC(dpu_enc,
> +				"no intf block assigned at idx: %d\n", i);
> +			return;
> +		}
> +
>   		phys->cached_mode = crtc_state->adjusted_mode;
>   		if (phys->ops.atomic_mode_set)
>   			phys->ops.atomic_mode_set(phys, crtc_state, conn_state);
>   	}
> +
> +	dpu_encoder_populate_encoder_phys(drm_enc, dpu_enc);
>   }
>   
>   static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
> @@ -1208,6 +1308,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
>   	mutex_unlock(&dpu_enc->enc_lock);
>   }
>   
> +static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc);
> +
>   static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
>   {
>   	struct dpu_encoder_virt *dpu_enc = NULL;
> @@ -1233,6 +1335,10 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
>   			phys->ops.disable(phys);
>   	}
>   
> +	if (dpu_enc->comp_info && (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_TMDS)) {
> +		dpu_encoder_unprep_dsc(dpu_enc);
> +		dpu_enc->comp_info = NULL;
> +	}
>   
>   	/* after phys waits for frame-done, should be no more frames pending */
>   	if (atomic_xchg(&dpu_enc->frame_done_timeout_ms, 0)) {
> @@ -1795,40 +1901,16 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work)
>   			nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
>   }
>   
> -static u32
> -dpu_encoder_dsc_initial_line_calc(struct drm_dsc_config *dsc,
> -				  u32 enc_ip_width)
> -{
> -	int ssm_delay, total_pixels, soft_slice_per_enc;
> -
> -	soft_slice_per_enc = enc_ip_width / dsc->slice_width;
> -
> -	/*
> -	 * minimum number of initial line pixels is a sum of:
> -	 * 1. sub-stream multiplexer delay (83 groups for 8bpc,
> -	 *    91 for 10 bpc) * 3
> -	 * 2. for two soft slice cases, add extra sub-stream multiplexer * 3
> -	 * 3. the initial xmit delay
> -	 * 4. total pipeline delay through the "lock step" of encoder (47)
> -	 * 5. 6 additional pixels as the output of the rate buffer is
> -	 *    48 bits wide
> -	 */
> -	ssm_delay = ((dsc->bits_per_component < 10) ? 84 : 92);
> -	total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47;
> -	if (soft_slice_per_enc > 1)
> -		total_pixels += (ssm_delay * 3);
> -	return DIV_ROUND_UP(total_pixels, dsc->slice_width);
> -}
> -
>   static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
>   				     struct dpu_hw_dsc *hw_dsc,
>   				     struct dpu_hw_pingpong *hw_pp,
> -				     struct drm_dsc_config *dsc,
> +				     struct msm_display_dsc_info *dsc_info,
>   				     u32 common_mode,
>   				     u32 initial_lines)
>   {
>   	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
>   	struct dpu_hw_ctl *ctl;
> +	struct drm_dsc_config *dsc = &dsc_info->drm_dsc;
>   
>   	ctl = cur_master->hw_ctl;
>   
> @@ -1852,51 +1934,137 @@ static void dpu_encoder_dsc_pipe_cfg(struct dpu_encoder_virt *dpu_enc,
>   
>   }
>   
> +static void dpu_encoder_dsc_disable(struct dpu_encoder_virt *dpu_enc,
> +				     struct dpu_hw_dsc *hw_dsc,
> +				     struct dpu_hw_pingpong *hw_pp)
> +{
> +	struct dpu_encoder_phys *cur_master = dpu_enc->cur_master;
> +	struct dpu_hw_ctl *ctl;
> +
> +	ctl = cur_master->hw_ctl;
> +
> +	if (hw_dsc->ops.dsc_disable)
> +		hw_dsc->ops.dsc_disable(hw_dsc);
> +
> +	if (hw_pp->ops.disable_dsc)
> +		hw_pp->ops.disable_dsc(hw_pp);
> +
> +}
> +
>   static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc,
> -				 struct drm_dsc_config *dsc)
> +				 struct msm_display_dsc_info *dsc_info)
>   {
>   	/* coding only for 2LM, 2enc, 1 dsc config */
>   	struct dpu_encoder_phys *enc_master = dpu_enc->cur_master;
>   	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
>   	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
> +	struct msm_display_topology *topology = &dpu_enc->topology;
> +	enum dpu_3d_blend_mode mode_3d;
>   	int this_frame_slices;
>   	int intf_ip_w, enc_ip_w;
> -	int dsc_common_mode;
> -	int pic_width;
> -	u32 initial_lines;
> +	int dsc_common_mode = 0;
> +	int dsc_pic_width;
> +	int num_lm, num_dsc, num_intf;
> +	bool dsc_merge, merge_3d, dsc_4hsmerge;
> +	bool disable_merge_3d = false;
> +	int ich_res;
>   	int i;
>   
>   	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
>   		hw_pp[i] = dpu_enc->hw_pp[i];
>   		hw_dsc[i] = dpu_enc->hw_dsc[i];
> +	}
>   
> -		if (!hw_pp[i] || !hw_dsc[i]) {
> -			DPU_ERROR_ENC(dpu_enc, "invalid params for DSC\n");
> -			return;
> -		}
> +	num_lm = topology->num_lm;
> +	num_dsc = topology->num_dsc;
> +	num_intf = topology->num_intf;
> +
> +
> +	mode_3d = (num_lm > num_dsc) ? BLEND_3D_H_ROW_INT : BLEND_3D_NONE;
> +	merge_3d = ((mode_3d != BLEND_3D_NONE) && !(enc_master->hw_intf->cfg.split_link_en)) ?
> +			true : false;
> +
> +	dsc_merge = ((num_dsc > num_intf) && !dsc_info->half_panel_pu &&
> +			!(enc_master->hw_intf->cfg.split_link_en)) ? true : false;
> +	disable_merge_3d = (merge_3d && dsc_info->half_panel_pu) ?  false : true;
> +	dsc_4hsmerge = (dsc_merge && num_dsc == 4 && num_intf == 1) ?  true : false;
> +
> +	/*
> +	 * If this encoder is driving more than one DSC encoder, they
> +	 * operate in tandem, same pic dimension needs to be used by
> +	 * each of them.(pp-split is assumed to be not supported)
> +	 *
> +	 * If encoder is driving more than 2 DSCs, each DSC pair will operate
> +	 * on half of the picture in tandem.
> +	 */
> +	dsc_pic_width = dsc_info->drm_dsc.pic_width;
> +
> +	if (num_dsc > 2) {
> +		dsc_pic_width /= 2;
> +		dsc_info->dsc_4hsmerge_en = dsc_4hsmerge;
>   	}
>   
> -	dsc_common_mode = 0;
> -	pic_width = dsc->pic_width;
> +	this_frame_slices = dsc_pic_width / dsc_info->drm_dsc.slice_width;
> +	intf_ip_w = this_frame_slices * dsc_info->drm_dsc.slice_width;
> +	enc_ip_w = intf_ip_w;
> +
> +	if (!dsc_info->half_panel_pu)
> +		intf_ip_w /= num_intf;
> +	if (!dsc_info->half_panel_pu && (num_dsc > 1))
> +		dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
> +	if (dsc_merge) {
> +		dsc_common_mode |= DSC_MODE_MULTIPLEX;
> +		/*
> +		 * in dsc merge case: when using 2 encoders for the same
> +		 * stream, no. of slices need to be same on both the
> +		 * encoders.
> +		 */
> +		enc_ip_w = intf_ip_w / 2;
> +	}
>   
> -	dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL;
>   	if (enc_master->intf_mode == INTF_MODE_VIDEO)
>   		dsc_common_mode |= DSC_MODE_VIDEO;
>   
> -	this_frame_slices = pic_width / dsc->slice_width;
> -	intf_ip_w = this_frame_slices * dsc->slice_width;
> +	dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count;
> +
> +	if (dsc_info->dsc_4hsmerge_en)
> +		dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 2;
> +	else if ((dsc_common_mode & DSC_MODE_MULTIPLEX) || (dsc_info->half_panel_pu))
> +		dsc_info->num_active_ss_per_enc = dsc_info->drm_dsc.slice_count >> 1;
> +
> +	dpu_dsc_populate_dsc_private_params(dsc_info, intf_ip_w);
> +
> +	dpu_dsc_initial_line_calc(dsc_info, enc_ip_w, dsc_common_mode);
>   
>   	/*
>   	 * dsc merge case: when using 2 encoders for the same stream,
>   	 * no. of slices need to be same on both the encoders.
>   	 */
> -	enc_ip_w = intf_ip_w / 2;
> -	initial_lines = dpu_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
> +	ich_res = dpu_dsc_ich_reset_override_needed(dsc_info->half_panel_pu, dsc_info);
> +
> +	for (i = 0; i < num_dsc; i++) {
> +		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc_info,
> +					dsc_common_mode, 0);
> +	}
> +}
> +
> +static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc)
> +{
> +	/* coding only for 2LM, 2enc, 1 dsc config */
> +	struct dpu_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
> +	struct dpu_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
> +	struct msm_display_topology *topology = &dpu_enc->topology;
> +	int i, num_dsc;
>   
>   	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
> -		dpu_encoder_dsc_pipe_cfg(dpu_enc, hw_dsc[i], hw_pp[i], dsc,
> -					dsc_common_mode, initial_lines);
> +		hw_pp[i] = dpu_enc->hw_pp[i];
> +		hw_dsc[i] = dpu_enc->hw_dsc[i];
>   	}
> +
> +	num_dsc = topology->num_dsc;
> +
> +	for (i = 0; i < num_dsc; i++)
> +		dpu_encoder_dsc_disable(dpu_enc, hw_dsc[i], hw_pp[i]);
>   }
>   
>   void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
> @@ -1904,6 +2072,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
>   	struct dpu_encoder_virt *dpu_enc;
>   	struct dpu_encoder_phys *phys;
>   	bool needs_hw_reset = false;
> +	bool needs_phy_enable = false;
>   	unsigned int i;
>   
>   	dpu_enc = to_dpu_encoder_virt(drm_enc);
> @@ -1918,6 +2087,9 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
>   			phys->ops.prepare_for_kickoff(phys);
>   		if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET)
>   			needs_hw_reset = true;
> +
> +		if (phys->enable_state == DPU_ENC_ENABLING)
> +			needs_phy_enable = true;
>   	}
>   	DPU_ATRACE_END("enc_prepare_for_kickoff");
>   
> @@ -1931,8 +2103,10 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
>   		}
>   	}
>   
> -	if (dpu_enc->dsc)
> -		dpu_encoder_prep_dsc(dpu_enc, dpu_enc->dsc);
> +	if (needs_phy_enable && dpu_enc->comp_info)
> +		dpu_encoder_prep_dsc(dpu_enc, &dpu_enc->comp_info->msm_dsc_info);
> +
> +
>   }
>   
>   bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc)
> @@ -2295,7 +2469,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>   				dpu_kms->catalog->caps->has_idle_pc;
>   
>   	dpu_enc->comp_info = disp_info->comp_info;
> -	if (dpu_enc->comp_info)
> +	if (dpu_enc->comp_info && dpu_enc->comp_info->enabled)
>   		dpu_enc->dsc = &dpu_enc->comp_info->msm_dsc_info.drm_dsc;
>   
>   	mutex_lock(&dpu_enc->enc_lock);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> index 0569b36..ae4f6a8 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /*
> - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
>    */
>   
> @@ -202,6 +202,9 @@ struct dpu_encoder_phys {
>   	int irq[INTR_IDX_MAX];
>   	enum msm_display_compression_type comp_type;
>   	u32 comp_ratio;
> +	u32 dsc_extra_pclk_cycle_cnt;
> +	u32 dsc_extra_disp_width;
> +	u32 dce_bytes_per_line;
>   };
>   
>   static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> index 3330e185..6c7d791 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
> @@ -86,6 +86,11 @@ static void drm_mode_to_intf_timing_params(
>   	timing->underflow_clr = 0xff;
>   	timing->hsync_skew = mode->hskew;
>   
> +	if (phys_enc->comp_type != MSM_DISPLAY_COMPRESSION_NONE) {
> +		timing->compression_en = true;
> +		timing->dce_bytes_per_line = phys_enc->dce_bytes_per_line;
> +	}
> +
>   	/* DSI controller cannot handle active-low sync signals. */
>   	if (phys_enc->hw_intf->cap->type == INTF_DSI) {
>   		timing->hsync_polarity = 0;
> @@ -104,14 +109,36 @@ static void drm_mode_to_intf_timing_params(
>   
>   	/*
>   	 * for DP, divide the horizonal parameters by 2 when
> -	 * widebus is enabled
> +	 * widebus or compression is enabled, irrespective of
> +	 * compression ratio
>   	 */
> -	if (phys_enc->hw_intf->cap->type == INTF_DP && timing->wide_bus_en) {
> +	if (phys_enc->hw_intf->cap->type == INTF_DP &&
> +		(timing->wide_bus_en || (phys_enc->comp_ratio > 1))) {
>   		timing->width = timing->width >> 1;
>   		timing->xres = timing->xres >> 1;
>   		timing->h_back_porch = timing->h_back_porch >> 1;
>   		timing->h_front_porch = timing->h_front_porch >> 1;
>   		timing->hsync_pulse_width = timing->hsync_pulse_width >> 1;
> +
> +		if (phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC &&
> +				(phys_enc->comp_ratio > 1)) {
> +			timing->extra_dto_cycles =
> +					phys_enc->dsc_extra_pclk_cycle_cnt;
> +			timing->width += phys_enc->dsc_extra_disp_width;
> +			timing->h_back_porch +=
> +					phys_enc->dsc_extra_disp_width;
> +		}
> +	}
> +
> +	/*
> +	 * for DSI, if compression is enabled, then divide the horizonal active
> +	 * timing parameters by compression ratio.
> +	 */
> +	if ((phys_enc->hw_intf->cap->type != INTF_DP) &&
> +			((phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC))) {
> +		// adjust active dimensions
> +		timing->width = DIV_ROUND_UP(timing->width, phys_enc->comp_ratio);
> +		timing->xres = DIV_ROUND_UP(timing->xres, phys_enc->comp_ratio);
>   	}
>   }
>   
> @@ -281,6 +308,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
>   
>   	phys_enc->hw_intf->hw_rev = phys_enc->dpu_kms->core_rev;
>   
> +	if (phys_enc->hw_pp->dsc)
> +		intf_cfg.dsc_num = phys_enc->hw_pp->dsc->idx;

Why ??? it breaks when in multiplex mode and we have multiple DSCs !

> +
>   	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
>   	phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
>   			&timing_params, fmt);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
> index c002234..ee71cee 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h
> @@ -1,5 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0-only */
>   /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #ifndef _DPU_HW_PINGPONG_H
> @@ -8,6 +9,7 @@
>   #include "dpu_hw_catalog.h"
>   #include "dpu_hw_mdss.h"
>   #include "dpu_hw_util.h"
> +#include "dpu_hw_dsc.h"
>   
>   #define DITHER_MATRIX_SZ 16
>   
> @@ -149,6 +151,7 @@ struct dpu_hw_pingpong {
>   	enum dpu_pingpong idx;
>   	const struct dpu_pingpong_cfg *caps;
>   	struct dpu_hw_merge_3d *merge_3d;
> +	struct dpu_hw_dsc *dsc;
>   
>   	/* ops */
>   	struct dpu_hw_pingpong_ops ops;
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> index 396429e..bb22ec8 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> @@ -1,6 +1,7 @@
>   // SPDX-License-Identifier: GPL-2.0-only
>   /*
>    * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
>    */
>   
>   #define pr_fmt(fmt)	"[drm:%s] " fmt, __func__
> @@ -246,6 +247,11 @@ int dpu_rm_init(struct dpu_rm *rm,
>   		struct dpu_hw_dsc *hw;
>   		const struct dpu_dsc_cfg *dsc = &cat->dsc[i];
>   
> +		if (dsc->id < DSC_0 || dsc->id >= DSC_MAX) {
> +			DPU_ERROR("skip dsc %d with invalid id\n", dsc->id);
> +			continue;
> +		}
> +
>   		hw = dpu_hw_dsc_init(dsc->id, mmio, cat);
>   		if (IS_ERR_OR_NULL(hw)) {
>   			rc = PTR_ERR(hw);
> @@ -535,8 +541,10 @@ static int _dpu_rm_make_reservation(
>   	}
>   
>   	ret  = _dpu_rm_reserve_dsc(rm, global_state, enc, &reqs->topology);
> -	if (ret)
> +	if (ret) {
> +		DPU_ERROR("unable to find appropriate DSC\n");
>   		return ret;
> +	}
>   
>   	return ret;
>   }


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

* Re: [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC
  2023-01-24 23:36       ` Marijn Suijten
@ 2023-01-25  9:08         ` Neil Armstrong
  0 siblings, 0 replies; 50+ messages in thread
From: Neil Armstrong @ 2023-01-25  9:08 UTC (permalink / raw)
  To: Marijn Suijten, Kuogee Hsieh
  Cc: vkoul, quic_sbillaka, quic_abhinavk, andersson, dianders,
	dri-devel, swboyd, agross, linux-arm-msm, Dmitry Baryshkov,
	freedreno, sean, linux-kernel

On 25/01/2023 00:36, Marijn Suijten wrote:
> On 2023-01-24 09:55:24, Kuogee Hsieh wrote:
> 
> <snip>
> 
>> This timing engine code is derived from our downstream code directly and
>> it has been used at many mobile devices by many vendors for many years
>> already.
>>
>> On the other words, it had been tested very thorough and works on
>> dsi/dp/hdmi/dsc/widebus applications.
> 
> And the code already in mainline has seen 12 rounds of review, with a
> focus on inter-SoC compatibility.  Regardless of that, we have processes
> to make changes on mainline: formatting changes (when actually making an
> improvement) go separate from semantic changes.  Bugfixes are clearly
> described in individual patches with Fixes: tags.  If you really think
> the code has to be as proposed in this patch, follow Dmitry's advice and
> split this accordingly.
> 
>> When i brought dsc v1.2 over, I just merged it over and did not consider
>> too much.
> 
> And that is exactly what is wrong with this *entire* series: copying
> over downstream code without "considering too much", stomping over
> previous review and even reverting bugfixes [1] [2] without giving it
> ANY ATTENTION in your patch description.  That's unacceptable and
> insulting to contributors and reviewers.  Full stop.  Or did you expect
> us to turn a blind eye?  This is mainline, not some techpack playground.
> 
> [1]: https://lore.kernel.org/linux-arm-msm/20230123201133.zzt2zbyaw3pfkzi6@SoMainline.org/
> [2]: https://lore.kernel.org/linux-arm-msm/20221026182824.876933-10-marijn.suijten@somainline.org/
> 
>> Can we adapt this code so that both upstream and down stream shared same
>> timing engine programming so that easier to maintain?
> 
> Easy, I've said this before in IRC and will state it again: stop this
> techpack nonsense and focus on upstream-first.  When something passes
> mainline review (and please don't bother maintainers and reviewers with
> series like this) it is inevitably good enough to be copied to
> techpack... at which point techpack becomes worthless as you can just
> backport a mainline patch or use a recent-enough kernel.
> 
> 
> tl;dr: it seems like you nor anyone involved in pre-reviewing/vetting
> this series is familiar with upstream guidelines.  Follow the global
> advice from Dmitry [3] to reach a more efficient v2, and please don't
> let this run to v10 (or beyond) again.
> 
> One suggestion to improve efficiency: split off the DPU v1.2 hardware
> block addition (and related changes) into a separate series.  A smaller
> series (and properly split patches!) will give everyone less moving
> parts to worry about, and paves the way for DSI support without blocking
> on DP.

Yes to split DSC 1.2 integration and DP+DSC in 2 patchsets, with the various
fixes not necessary to make DP+DSC work in separate patches.

Be aware the rule is to make sure each single change doesn't break boot and builds
without warning, the rule is to make sure each single kernel change can be built
and doesn't break booting. And build the code with "W=1" to the make parameter to
trigger advanced GCC warnings.

This rule exists to permit running a git bisect to determine which commit introduces
a regression.

And the second most important rule is: a single change per patch, and a clear description
of the change in the commit message.
If your message needs a "change this and also change this" then it's wrong and it must be reworked.

Do incremental changes, like introduce a new struct, then use it afterwards.

Neil

> 
> [3]: https://lore.kernel.org/linux-arm-msm/47c83e8c-09f1-d1dd-ca79-574122638256@linaro.org/
> 
> - Marijn


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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-24 23:52     ` Kuogee Hsieh
@ 2023-01-30 20:16       ` Marijn Suijten
  2023-01-30 21:22         ` Abhinav Kumar
  0 siblings, 1 reply; 50+ messages in thread
From: Marijn Suijten @ 2023-01-30 20:16 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel

On 2023-01-24 15:52:46, Kuogee Hsieh wrote:

<snip>

If only replying to a small chunk somewhere in the middle of a diff
and/or large review, please cut out unnecessary bits to make your reply
easier to find :)

> >> +	data = (dsc->flatness_min_qp & 0x1f);
> >> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
> >> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
> > dpu_hw_dsc.c computes this on the fly.  After removing that, and
> > using initial_lines from the function parameters, only
> > dsc_info->num_active_ss_per_enc remains.  Do you really need that
> > msm_display_dsc_info struct here, do you need it at all?
> 
> I ported these code from our down stream code base.
> 
> I make it work first, then clean it up will follow.
> 
> I submit it for review since it looks like you guy like to have code sooner.

Correct, I was looking forward to these patches albeit complete with the
promised DSI support from Jessica, which still seems to be pending.

When sending patches to that extent, with the intent of getting quick
turnaround but knowing that they are not ready for prime time yet (or
were they, based on your "submit it for review" mention? Don't you mean
testing?), please annotate the series with an RFC tag accompanied with a
description what still needs to be done and why.  That would have saved
a great deal of comments and review.

> yes, eliminate msm_display_dsc_info is my next target and hope it can be 
> done.

Thank you.  Again, if that was the intent from the get-go, that's
perfect material to put in an RFC series' cover letter.

- Marijn

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

* Re: [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder
  2023-01-23 18:24 ` [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Kuogee Hsieh
  2023-01-23 22:06   ` Dmitry Baryshkov
  2023-01-24 15:06   ` Neil Armstrong
@ 2023-01-30 20:27   ` Marijn Suijten
  2 siblings, 0 replies; 50+ messages in thread
From: Marijn Suijten @ 2023-01-30 20:27 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, quic_abhinavk, andersson, dri-devel,
	dianders, vkoul, agross, linux-arm-msm, dmitry.baryshkov, swboyd,
	sean, linux-kernel

On 2023-01-23 10:24:29, Kuogee Hsieh wrote:
<snip>
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index d612419..70a74ed 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
<snip>
> @@ -892,6 +894,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
>  
>  	pm_runtime_get_sync(&dpu_kms->pdev->dev);
>  
> +	for (i = 0; i < cat->dsc_count; i++)
> +		msm_disp_snapshot_add_block(disp_state, cat->dsc[i].len,
> +				dpu_kms->mmio + cat->dsc[i].base, "dsc_%d", i);
> +

Note that we've landed snapshotting of the DSC block in [1] because we
need it now, and - as discussed elsewhere - is perfect material to be
submitted in a standalone, appropriately described/titled patch (fine to
be part of a series, as long as that patch comprises this single diff).

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=a7efe60e36b9c0e966d7f82ac90a89b591d984e9

Keep in mind that it was added at the bottom of dpu_kms_mdp_snapshot()
instead of the top, so git might not clean it up or mark it as conflict
during a rebase; don't forget to drop it from v2 :)

>  	/* dump CTL sub-blocks HW regs info */
>  	for (i = 0; i < cat->ctl_count; i++)
>  		msm_disp_snapshot_add_block(disp_state, cat->ctl[i].len,

<snip>

- Marijn

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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-30 20:16       ` Marijn Suijten
@ 2023-01-30 21:22         ` Abhinav Kumar
  2023-01-30 22:31           ` Marijn Suijten
  0 siblings, 1 reply; 50+ messages in thread
From: Abhinav Kumar @ 2023-01-30 21:22 UTC (permalink / raw)
  To: Marijn Suijten, Kuogee Hsieh
  Cc: freedreno, quic_sbillaka, andersson, dri-devel, dianders, vkoul,
	agross, linux-arm-msm, dmitry.baryshkov, swboyd, sean,
	linux-kernel

Hi Marijn

On 1/30/2023 12:16 PM, Marijn Suijten wrote:
> On 2023-01-24 15:52:46, Kuogee Hsieh wrote:
> 
> <snip>
> 
> If only replying to a small chunk somewhere in the middle of a diff
> and/or large review, please cut out unnecessary bits to make your reply
> easier to find :)
> 
>>>> +	data = (dsc->flatness_min_qp & 0x1f);
>>>> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
>>>> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
>>> dpu_hw_dsc.c computes this on the fly.  After removing that, and
>>> using initial_lines from the function parameters, only
>>> dsc_info->num_active_ss_per_enc remains.  Do you really need that
>>> msm_display_dsc_info struct here, do you need it at all?
>>
>> I ported these code from our down stream code base.
>>
>> I make it work first, then clean it up will follow.
>>
>> I submit it for review since it looks like you guy like to have code sooner.
> 
> Correct, I was looking forward to these patches albeit complete with the
> promised DSI support from Jessica, which still seems to be pending.
> 

DSI support is still being worked upon.

I dont think we promised DSC 1.2 will come with DSI together in the same 
series. It was always going to be DSC 1.2 + DP followed by another 
series from Jessica for DSI.

Lets set the expectations right.

Thanks

Abhinav
> When sending patches to that extent, with the intent of getting quick
> turnaround but knowing that they are not ready for prime time yet (or
> were they, based on your "submit it for review" mention? Don't you mean
> testing?), please annotate the series with an RFC tag accompanied with a
> description what still needs to be done and why.  That would have saved
> a great deal of comments and review.
> 
>> yes, eliminate msm_display_dsc_info is my next target and hope it can be
>> done.
> 
> Thank you.  Again, if that was the intent from the get-go, that's
> perfect material to put in an RFC series' cover letter.
> 
> - Marijn

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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-30 21:22         ` Abhinav Kumar
@ 2023-01-30 22:31           ` Marijn Suijten
  2023-01-30 22:39             ` Abhinav Kumar
  0 siblings, 1 reply; 50+ messages in thread
From: Marijn Suijten @ 2023-01-30 22:31 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: vkoul, quic_sbillaka, andersson, freedreno, dianders, dri-devel,
	swboyd, agross, linux-arm-msm, dmitry.baryshkov, Kuogee Hsieh,
	sean, linux-kernel

Abhinav,

On 2023-01-30 13:22:03, Abhinav Kumar wrote:
> Hi Marijn
> 
> On 1/30/2023 12:16 PM, Marijn Suijten wrote:
> > On 2023-01-24 15:52:46, Kuogee Hsieh wrote:
> > 
> > <snip>
> > 
> > If only replying to a small chunk somewhere in the middle of a diff
> > and/or large review, please cut out unnecessary bits to make your reply
> > easier to find :)
> > 
> >>>> +	data = (dsc->flatness_min_qp & 0x1f);
> >>>> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
> >>>> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
> >>> dpu_hw_dsc.c computes this on the fly.  After removing that, and
> >>> using initial_lines from the function parameters, only
> >>> dsc_info->num_active_ss_per_enc remains.  Do you really need that
> >>> msm_display_dsc_info struct here, do you need it at all?
> >>
> >> I ported these code from our down stream code base.
> >>
> >> I make it work first, then clean it up will follow.
> >>
> >> I submit it for review since it looks like you guy like to have code sooner.
> > 
> > Correct, I was looking forward to these patches albeit complete with the
> > promised DSI support from Jessica, which still seems to be pending.
> > 
> 
> DSI support is still being worked upon.
> 
> I dont think we promised DSC 1.2 will come with DSI together in the same 
> series. It was always going to be DSC 1.2 + DP followed by another 
> series from Jessica for DSI.
> 
> Lets set the expectations right.

Not saying that these patches were promised as part of this series (as
said, "which still seem to be pending"), just making clear that this
series if of no use to me (no hurry to get the code in my hands sooner)
until the DSI patches are also shared which I would have started working
on myself if I didn't know QUIC was picking it up to distract from the
current v1.1 broken-ness on SM8150 and SM8250.

To set my (and at least Neil's) expectations straight as well: DSC 1.2
HW support should come in a separate series without DP support.  Smaller
series (not to mention appropriately split-up patches) lead to a
decrease in scope, less dependencies and hopefully more efficient v2 -
for all involved.

- Marijn

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

* Re: [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine
  2023-01-30 22:31           ` Marijn Suijten
@ 2023-01-30 22:39             ` Abhinav Kumar
  0 siblings, 0 replies; 50+ messages in thread
From: Abhinav Kumar @ 2023-01-30 22:39 UTC (permalink / raw)
  To: Marijn Suijten
  Cc: vkoul, quic_sbillaka, andersson, freedreno, dianders, dri-devel,
	swboyd, agross, linux-arm-msm, dmitry.baryshkov, Kuogee Hsieh,
	sean, linux-kernel



On 1/30/2023 2:31 PM, Marijn Suijten wrote:
> Abhinav,
> 
> On 2023-01-30 13:22:03, Abhinav Kumar wrote:
>> Hi Marijn
>>
>> On 1/30/2023 12:16 PM, Marijn Suijten wrote:
>>> On 2023-01-24 15:52:46, Kuogee Hsieh wrote:
>>>
>>> <snip>
>>>
>>> If only replying to a small chunk somewhere in the middle of a diff
>>> and/or large review, please cut out unnecessary bits to make your reply
>>> easier to find :)
>>>
>>>>>> +	data = (dsc->flatness_min_qp & 0x1f);
>>>>>> +	data |= (dsc->flatness_max_qp & 0x1f) << 5;
>>>>>> +	data |= (dsc_info->det_thresh_flatness & 0xff) << 10;
>>>>> dpu_hw_dsc.c computes this on the fly.  After removing that, and
>>>>> using initial_lines from the function parameters, only
>>>>> dsc_info->num_active_ss_per_enc remains.  Do you really need that
>>>>> msm_display_dsc_info struct here, do you need it at all?
>>>>
>>>> I ported these code from our down stream code base.
>>>>
>>>> I make it work first, then clean it up will follow.
>>>>
>>>> I submit it for review since it looks like you guy like to have code sooner.
>>>
>>> Correct, I was looking forward to these patches albeit complete with the
>>> promised DSI support from Jessica, which still seems to be pending.
>>>
>>
>> DSI support is still being worked upon.
>>
>> I dont think we promised DSC 1.2 will come with DSI together in the same
>> series. It was always going to be DSC 1.2 + DP followed by another
>> series from Jessica for DSI.
>>
>> Lets set the expectations right.
> 
> Not saying that these patches were promised as part of this series (as
> said, "which still seem to be pending"), just making clear that this
> series if of no use to me (no hurry to get the code in my hands sooner)
> until the DSI patches are also shared which I would have started working
> on myself if I didn't know QUIC was picking it up to distract from the
> current v1.1 broken-ness on SM8150 and SM8250.
> 

This is being by Quic for everyone's benefit. So that we can land a 
working DSC 1.2 solution for DSI as a working example for all future 
panels. We only took it up to help others like you and linaro team to 
give a working example of a DSC 1.2 panel with command mode in upstream.


> To set my (and at least Neil's) expectations straight as well: DSC 1.2
> HW support should come in a separate series without DP support.  Smaller
> series (not to mention appropriately split-up patches) lead to a
> decrease in scope, less dependencies and hopefully more efficient v2 -
> for all involved.
> 

As I already wrote earlier, we will fix the mistakes of v1, make v2 
better and it will be split up better. But DSC 1.2 HW support had to be 
pushed along with DP or DSI to show its working. We chose DP to go with 
it as it aligns better with our upstream plans.


> - Marijn

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

end of thread, other threads:[~2023-01-30 22:42 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-23 18:24 [PATCH v1 00/14] add display port DSC feature Kuogee Hsieh
2023-01-23 18:24 ` [PATCH v1 01/14] drm/msm/dp: add dpcd read of both dsc and fec capability Kuogee Hsieh
2023-01-23 22:17   ` Dmitry Baryshkov
2023-01-23 18:24 ` [PATCH v1 02/14] drm/msm/dp: add dsc factor into calculation of supported bpp Kuogee Hsieh
2023-01-23 23:38   ` kernel test robot
2023-01-23 18:24 ` [PATCH v1 03/14] drm/msm/dp: add configure mainlink_levels base on lane number Kuogee Hsieh
2023-01-23 22:34   ` Dmitry Baryshkov
2023-01-23 18:24 ` [PATCH v1 04/14] drm/msm/dp: correct configure Colorimetry Indicator Field at MISC0 Kuogee Hsieh
2023-01-23 22:41   ` Dmitry Baryshkov
2023-01-24  0:49   ` kernel test robot
2023-01-23 18:24 ` [PATCH v1 05/14] drm/msm/dp: upgrade tu calculation base on newest algorithm Kuogee Hsieh
2023-01-23 23:56   ` Dmitry Baryshkov
2023-01-24  0:08   ` kernel test robot
2023-01-23 18:24 ` [PATCH v1 06/14] drm/msm/dp: add display compression related struct Kuogee Hsieh
2023-01-23 22:46   ` Dmitry Baryshkov
2023-01-24 15:15   ` Neil Armstrong
2023-01-23 18:24 ` [PATCH v1 07/14] drm/msm/dp: add dsc helper functions Kuogee Hsieh
2023-01-23 22:02   ` Dmitry Baryshkov
2023-01-23 22:08   ` Marijn Suijten
2023-01-23 18:24 ` [PATCH v1 08/14] drm/msm/dp: add dsc supporting functions to DP controller Kuogee Hsieh
2023-01-23 22:30   ` Dmitry Baryshkov
2023-01-23 18:24 ` [PATCH v1 09/14] drm/msm/dsi: export struct msm_compression_info to dpu encoder Kuogee Hsieh
2023-01-23 22:06   ` Dmitry Baryshkov
2023-01-24 15:06   ` Neil Armstrong
2023-01-30 20:27   ` Marijn Suijten
2023-01-23 18:24 ` [PATCH v1 10/14] drm/msm/disp/dpu: add supports of DSC encoder v1.2 engine Kuogee Hsieh
2023-01-23 20:11   ` Marijn Suijten
2023-01-24 23:52     ` Kuogee Hsieh
2023-01-30 20:16       ` Marijn Suijten
2023-01-30 21:22         ` Abhinav Kumar
2023-01-30 22:31           ` Marijn Suijten
2023-01-30 22:39             ` Abhinav Kumar
2023-01-24  7:44   ` Dmitry Baryshkov
2023-01-24 15:18   ` Neil Armstrong
2023-01-23 18:24 ` [PATCH v1 11/14] drm/msm/disp/dpu1: add supports of new flush mechanism Kuogee Hsieh
2023-01-23 21:43   ` Dmitry Baryshkov
2023-01-23 18:24 ` [PATCH v1 12/14] drm/msm/disp/dpu1: revise timing engine programming to work for DSC Kuogee Hsieh
2023-01-23 21:39   ` Dmitry Baryshkov
2023-01-24  9:11   ` Dmitry Baryshkov
2023-01-24 17:55     ` Kuogee Hsieh
2023-01-24 21:37       ` Dmitry Baryshkov
2023-01-24 23:36       ` Marijn Suijten
2023-01-25  9:08         ` Neil Armstrong
2023-01-23 18:24 ` [PATCH v1 13/14] drm/msm/disp/dpu1: add dsc supporting functions to dpu encoder Kuogee Hsieh
2023-01-25  9:01   ` Neil Armstrong
2023-01-23 18:24 ` [PATCH v1 14/14] drm/msm/disp/dpu1: add sc7280 dsc block and sub block Kuogee Hsieh
2023-01-23 20:19   ` Marijn Suijten
2023-01-23 18:34 ` [PATCH v1 00/14] add display port DSC feature Marijn Suijten
2023-01-24  0:10 ` Dmitry Baryshkov
2023-01-25  0:28 ` Abhinav Kumar

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).