Re: [PATCH] Revert "drm/msm/dp: use drm_bridge_hpd_notify() to report HPD status changes"

2024-02-27 Thread Paloma Arellano



On 2/27/2024 2:11 PM, Abhinav Kumar wrote:



On 2/27/2024 2:08 PM, Dmitry Baryshkov wrote:

This reverts commit e467e0bde881 ("drm/msm/dp: use
drm_bridge_hpd_notify() to report HPD status changes").

The commit changed the way how the MSM DP driver communicates
HPD-related events to the userspace. The mentioned commit made some of
the HPD events being reported earlier. This way userspace starts poking
around. It interacts in a bad way with the dp_bridge_detect and the
driver's state machine, ending up either with the very long delays
during hotplug detection or even inability of the DP driver to report
the display as connected.

A proper fix will involve redesigning of the HPD handling in the MSM DP
driver. It is underway, but it will be intrusive and can not be thought
about as a simple fix for the issue. Thus, revert the offending commit.



Yes, for fixing this on 6.9 I am fine with this.

I hope there were not other changes which were built on top of this. 
So it will be better if we retest internal HPD case as well with this.


We will do that in a day or two and give Tested-by.

Fixes: e467e0bde881 ("drm/msm/dp: use drm_bridge_hpd_notify() to 
report HPD status changes")

Link: https://gitlab.freedesktop.org/drm/msm/-/issues/50
Reported-by: Johan Hovold 
Link: https://lore.kernel.org/r/zd3ypgmrprxv-...@hovoldconsulting.com/
Signed-off-by: Dmitry Baryshkov 
---
  drivers/gpu/drm/msm/dp/dp_display.c | 20 ++--
  1 file changed, 18 insertions(+), 2 deletions(-)



For the change itself,


Reviewed-by: Abhinav Kumar 



Tested-by: Paloma Arellano 



Re: [PATCH v5 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-22 Thread Paloma Arellano



On 2/22/2024 1:56 PM, Dmitry Baryshkov wrote:

On Thu, 22 Feb 2024 at 23:28, Paloma Arellano  wrote:


On 2/22/2024 1:18 PM, Dmitry Baryshkov wrote:

On Thu, 22 Feb 2024 at 21:40, Paloma Arellano  wrote:

Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v5:
  - Slightly modify use of drm_dp_vsc_sdp_pack()
  - Remove dp_catalog NULL checks
  - Modify dp_utils_pack_sdp_header() to more clearly pack the
header buffer
  - Move dp_utils_pack_sdp_header() inside of
dp_catalog_panel_send_vsc_sdp to clearly show the relationship
between the header buffer and the vsc_sdp struct
  - Due to the last point, remove the dp_utils_pack_vsc_sdp()
function and only call drm_dp_vsc_sdp_pack() in
dp_panel_setup_vsc_sdp_yuv_420()

Changes in v4:
  - Remove struct msm_dp_sdp_with_parity
  - Use dp_utils_pack_sdp_header() to pack the SDP header and
parity bytes into a buffer
  - Use this buffer when writing the VSC SDP data in
dp_catalog_panel_send_vsc_sdp()
  - Write to all of the MMSS_DP_GENERIC0 registers instead of just
the ones with non-zero values

Changes in v3:
  - Create a new struct, msm_dp_sdp_with_parity, which holds the
packing information for VSC SDP
  - Use drm_dp_vsc_sdp_pack() to pack the data into the new
msm_dp_sdp_with_parity struct instead of specifically packing
for YUV420 format
  - Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP
data using the new msm_dp_sdp_with_parity struct

Changes in v2:
  - Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
  - Remove dp_sdp from the dp_catalog struct since this data is
being allocated at the point used
  - Create a new function in dp_utils to pack the VSC SDP data
into a buffer
  - Create a new function that packs the SDP header bytes into a
buffer. This function is made generic so that it can be
utilized by dp_audio
header bytes into a buffer
  - Create a new function in dp_utils that takes the packed buffer
and writes to the DP_GENERIC0_* registers
  - Split the dp_catalog_panel_config_vsc_sdp() function into two
to disable/enable sending VSC SDP packets
  - Check the DP HW version using the original useage of
dp_catalog_hw_revision() and correct the version checking
logic
  - Rename dp_panel_setup_vsc_sdp() to
dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
   drivers/gpu/drm/msm/dp/dp_catalog.c | 93 +
   drivers/gpu/drm/msm/dp/dp_catalog.h |  6 ++
   drivers/gpu/drm/msm/dp/dp_ctrl.c|  4 ++
   drivers/gpu/drm/msm/dp/dp_panel.c   | 52 
   drivers/gpu/drm/msm/dp/dp_reg.h |  3 +
   drivers/gpu/drm/msm/dp/dp_utils.c   | 25 
   drivers/gpu/drm/msm/dp/dp_utils.h   | 14 +
   7 files changed, 197 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..bfc6f53ae167f 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,99 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
  return 0;
   }

+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, 
struct dp_sdp *vsc_sdp)
+{
+   struct dp_catalog_private *catalog;
+   u32 header[2];
+   u32 val;
+   int i;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   dp_utils_pack_sdp_header(_sdp->sdp_header, header);
+
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
+
+   for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
+   val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i 
+ 2] << 16) |
+  (vsc_sdp->db[i + 3] << 24));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
+   }
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(c

Re: [PATCH v5 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-22 Thread Paloma Arellano



On 2/22/2024 1:18 PM, Dmitry Baryshkov wrote:

On Thu, 22 Feb 2024 at 21:40, Paloma Arellano  wrote:

Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v5:
 - Slightly modify use of drm_dp_vsc_sdp_pack()
 - Remove dp_catalog NULL checks
 - Modify dp_utils_pack_sdp_header() to more clearly pack the
   header buffer
 - Move dp_utils_pack_sdp_header() inside of
   dp_catalog_panel_send_vsc_sdp to clearly show the relationship
   between the header buffer and the vsc_sdp struct
 - Due to the last point, remove the dp_utils_pack_vsc_sdp()
   function and only call drm_dp_vsc_sdp_pack() in
   dp_panel_setup_vsc_sdp_yuv_420()

Changes in v4:
 - Remove struct msm_dp_sdp_with_parity
 - Use dp_utils_pack_sdp_header() to pack the SDP header and
   parity bytes into a buffer
 - Use this buffer when writing the VSC SDP data in
   dp_catalog_panel_send_vsc_sdp()
 - Write to all of the MMSS_DP_GENERIC0 registers instead of just
   the ones with non-zero values

Changes in v3:
 - Create a new struct, msm_dp_sdp_with_parity, which holds the
   packing information for VSC SDP
 - Use drm_dp_vsc_sdp_pack() to pack the data into the new
   msm_dp_sdp_with_parity struct instead of specifically packing
   for YUV420 format
 - Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP
   data using the new msm_dp_sdp_with_parity struct

Changes in v2:
 - Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
 - Remove dp_sdp from the dp_catalog struct since this data is
   being allocated at the point used
 - Create a new function in dp_utils to pack the VSC SDP data
   into a buffer
 - Create a new function that packs the SDP header bytes into a
   buffer. This function is made generic so that it can be
   utilized by dp_audio
   header bytes into a buffer
 - Create a new function in dp_utils that takes the packed buffer
   and writes to the DP_GENERIC0_* registers
 - Split the dp_catalog_panel_config_vsc_sdp() function into two
   to disable/enable sending VSC SDP packets
 - Check the DP HW version using the original useage of
   dp_catalog_hw_revision() and correct the version checking
   logic
 - Rename dp_panel_setup_vsc_sdp() to
   dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
   currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
  drivers/gpu/drm/msm/dp/dp_catalog.c | 93 +
  drivers/gpu/drm/msm/dp/dp_catalog.h |  6 ++
  drivers/gpu/drm/msm/dp/dp_ctrl.c|  4 ++
  drivers/gpu/drm/msm/dp/dp_panel.c   | 52 
  drivers/gpu/drm/msm/dp/dp_reg.h |  3 +
  drivers/gpu/drm/msm/dp/dp_utils.c   | 25 
  drivers/gpu/drm/msm/dp/dp_utils.h   | 14 +
  7 files changed, 197 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..bfc6f53ae167f 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,99 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
 return 0;
  }

+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, 
struct dp_sdp *vsc_sdp)
+{
+   struct dp_catalog_private *catalog;
+   u32 header[2];
+   u32 val;
+   int i;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   dp_utils_pack_sdp_header(_sdp->sdp_header, header);
+
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
+
+   for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
+   val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i 
+ 2] << 16) |
+  (vsc_sdp->db[i + 3] << 24));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
+   }
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+   }
+}
+
+void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct 
dp_sdp *vsc_sdp)
+{
+   struct dp_

[PATCH v5 06/19] drm/msm/dp: rename wide_bus_en to wide_bus_supported

2024-02-22 Thread Paloma Arellano
Rename wide_bus_en to wide_bus_supported in dp_display_private to
correctly establish that the parameter is referencing if wide bus is
supported instead of enabled.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 42 ++---
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index c8e1bbebdffe2..792191f67717f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -114,7 +114,7 @@ struct dp_display_private {
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
 
-   bool wide_bus_en;
+   bool wide_bus_supported;
 
struct dp_audio *audio;
 };
@@ -123,7 +123,7 @@ struct msm_dp_desc {
phys_addr_t io_start;
unsigned int id;
unsigned int connector_type;
-   bool wide_bus_en;
+   bool wide_bus_supported;
 };
 
 static const struct msm_dp_desc sc7180_dp_descs[] = {
@@ -132,8 +132,8 @@ static const struct msm_dp_desc sc7180_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc7280_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
{}
 };
 
@@ -145,22 +145,22 @@ static const struct msm_dp_desc sc8180x_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc8280xp_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
{}
 };
 
 static const struct msm_dp_desc sc8280xp_edp_descs[] = {
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id

[PATCH v5 10/19] drm/msm/dp: program config ctrl for YUV420 over DP

2024-02-22 Thread Paloma Arellano
Change relevant DP controller related programming for YUV420 cases.
Program the configuration control register to indicate YUV420.

Changes in v2:
- Create a new patch only for configuration control programming

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index fb588fde298a2..6692d81adb195 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -128,6 +128,9 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private 
*ctrl)
/* Default-> LSCLK DIV: 1/4 LCLK  */
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
 
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
+
/* Scrambler reset enable */
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
config |= DP_CONFIGURATION_CTRL_ASSR;
-- 
2.39.2



[PATCH v5 19/19] drm/msm/dp: allow YUV420 mode for DP connector when CDM available

2024-02-22 Thread Paloma Arellano
All the components of YUV420 over DP are added. Therefore, let's mark the
connector property as true for DP connector when the DP type is not eDP
and when there is a CDM block available.

Changes in v3:
- Move setting the connector's ycbcr_420_allowed parameter so
  that it is not dependent on if the dp_display is not eDP

Changes in v2:
- Check for if dp_catalog has a CDM block available instead of
  checking if VSC SDP is allowed when setting the dp connector's
  ycbcr_420_allowed parameter

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 +++-
 drivers/gpu/drm/msm/dp/dp_display.c | 4 ++--
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +-
 drivers/gpu/drm/msm/dp/dp_drm.h | 3 ++-
 drivers/gpu/drm/msm/msm_drv.h   | 5 +++--
 5 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 723cc1d821431..8d326fb36550a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -565,6 +565,7 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
 {
struct drm_encoder *encoder = NULL;
struct msm_display_info info;
+   bool yuv_supported;
int rc;
int i;
 
@@ -583,7 +584,8 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
return PTR_ERR(encoder);
}
 
-   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder);
+   yuv_supported = !!dpu_kms->catalog->cdm;
+   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder, 
yuv_supported);
if (rc) {
DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);
return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index b5a67835ce6d1..a435847f1d948 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1472,7 +1472,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 }
 
 int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
-   struct drm_encoder *encoder)
+   struct drm_encoder *encoder, bool yuv_supported)
 {
struct dp_display_private *dp_priv;
int ret;
@@ -1488,7 +1488,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return ret;
}
 
-   dp_display->connector = dp_drm_connector_init(dp_display, encoder);
+   dp_display->connector = dp_drm_connector_init(dp_display, encoder, 
yuv_supported);
if (IS_ERR(dp_display->connector)) {
ret = PTR_ERR(dp_display->connector);
DRM_DEV_ERROR(dev->dev,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 46e6889037e88..a819a4ff76a9f 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -353,7 +353,8 @@ int dp_bridge_init(struct msm_dp *dp_display, struct 
drm_device *dev,
 }
 
 /* connector initialization */
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder)
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported)
 {
struct drm_connector *connector = NULL;
 
@@ -364,6 +365,9 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
if (!dp_display->is_edp)
drm_connector_attach_dp_subconnector_property(connector);
 
+   if (yuv_supported)
+   connector->ycbcr_420_allowed = true;
+
drm_connector_attach_encoder(connector, encoder);
 
return connector;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index b3d684db2383b..45e57ac25a4d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -19,7 +19,8 @@ struct msm_dp_bridge {
 
 #define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
 
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder);
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported);
 int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder);
 
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b876ebd48effe..37335777f5c09 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -385,7 +385,7 @@ static inline struct drm_dsc_config 
*msm_dsi_get_dsc_config(struct msm_dsi *msm_
 int __init msm_dp_register

[PATCH v5 08/19] drm/msm/dp: check if VSC SDP is supported in DP programming

2024-02-22 Thread Paloma Arellano
In the DP driver, check if VSC SDP is supported and propagate this value
to dp_panel. In dp_display's dp_mode, the out_fmt_is_yuv_420 parameter
must also utilize this value since YUV420 is only allowed when VSC SDP
is supported.

Changes in v2:
- Move DP programming when VSC SDP is supported to this patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 5 -
 drivers/gpu/drm/msm/dp/dp_panel.c   | 1 +
 drivers/gpu/drm/msm/dp/dp_panel.h   | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 1a84f68e2b59a..4b1b79b74bc72 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1596,8 +1596,10 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
+   struct dp_panel *dp_panel;
 
dp_display = container_of(dp, struct dp_display_private, dp_display);
+   dp_panel = dp_display->panel;
 
memset(_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
 
@@ -1618,7 +1620,8 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
 
dp_display->dp_mode.out_fmt_is_yuv_420 =
-   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode) &&
+   dp_panel->vsc_sdp_supported;
 
/* populate wide_bus_support to different layers */
dp_display->ctrl->wide_bus_en =
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c 
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd1..db1942794f1a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -53,6 +53,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
if (rc)
return rc;
 
+   dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, 
dpcd);
link_info = _panel->link_info;
link_info->revision = dpcd[DP_DPCD_REV];
major = (link_info->revision >> 4) & 0x0f;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index 6ec68be9f2366..e843f5062d1f6 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -46,6 +46,7 @@ struct dp_panel {
struct dp_display_mode dp_mode;
struct dp_panel_psr psr_cap;
bool video_test;
+   bool vsc_sdp_supported;
 
u32 vic;
u32 max_dp_lanes;
-- 
2.39.2



[PATCH v5 14/19] drm/msm/dpu: add support of new peripheral flush mechanism

2024-02-22 Thread Paloma Arellano
From: Kuogee Hsieh 

Introduce a peripheral flushing mechanism to decouple peripheral
metadata flushing from timing engine related flush.

Changes in v2:
- Fixed some misalignment issues

Signed-off-by: Kuogee Hsieh 
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 17 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 10 ++
 2 files changed, 27 insertions(+)

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 e76565c3e6a43..a06f69d0b257d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -39,6 +39,7 @@
 #define   CTL_WB_FLUSH  0x108
 #define   CTL_INTF_FLUSH0x110
 #define   CTL_CDM_FLUSH0x114
+#define   CTL_PERIPH_FLUSH  0x128
 #define   CTL_INTF_MASTER   0x134
 #define   CTL_DSPP_n_FLUSH(n)   ((0x13C) + ((n) * 4))
 
@@ -49,6 +50,7 @@
 #define  MERGE_3D_IDX   23
 #define  DSC_IDX22
 #define CDM_IDX 26
+#define  PERIPH_IDX 30
 #define  INTF_IDX   31
 #define WB_IDX  16
 #define  DSPP_IDX   29  /* From DPU hw rev 7.x.x */
@@ -151,6 +153,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct 
dpu_hw_ctl *ctx)
ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
}
 
+   if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+   DPU_REG_WRITE(>hw, CTL_PERIPH_FLUSH,
+ ctx->pending_periph_flush_mask);
+
if (ctx->pending_flush_mask & BIT(DSC_IDX))
DPU_REG_WRITE(>hw, CTL_DSC_FLUSH,
  ctx->pending_dsc_flush_mask);
@@ -311,6 +317,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_v1(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)
 {
@@ -680,6 +693,10 @@ 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_v1;
+
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;
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 ff85b5ee0acf8..ef56280bea932 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -122,6 +122,15 @@ struct dpu_hw_ctl_ops {
void (*update_pending_flush_intf)(struct dpu_hw_ctl *ctx,
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
@@ -264,6 +273,7 @@ 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_dspp_flush_mask[DSPP_MAX - DSPP_0];
u32 pending_dsc_flush_mask;
-- 
2.39.2



[PATCH v5 09/19] drm/msm/dpu: move widebus logic to its own API

2024-02-22 Thread Paloma Arellano
Widebus enablement is decided by the interfaces based on their specific
checks and that already happens with DSI/DP specific helpers. Let's
invoke these helpers from dpu_encoder_is_widebus_enabled() to make it
cleaner overall.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 +++
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1905e8653b77a..b53a1b545742b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -221,9 +221,21 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
 
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
 {
-   const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+   const struct dpu_encoder_virt *dpu_enc;
+   struct msm_drm_private *priv = drm_enc->dev->dev_private;
+   const struct msm_display_info *disp_info;
+   int index;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   index = disp_info->h_tile_instance[0];
+
+   if (disp_info->intf_type == INTF_DP)
+   return msm_dp_wide_bus_available(priv->dp[index]);
+   else if (disp_info->intf_type == INTF_DSI)
+   return msm_dsi_wide_bus_enabled(priv->dsi[index]);
 
-   return dpu_enc->wide_bus_en;
+   return false;
 }
 
 bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc)
@@ -1195,26 +1207,17 @@ static void dpu_encoder_virt_atomic_enable(struct 
drm_encoder *drm_enc,
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
struct drm_display_mode *cur_mode = NULL;
-   struct msm_drm_private *priv = drm_enc->dev->dev_private;
-   struct msm_display_info *disp_info;
-   int index;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
-   disp_info = _enc->disp_info;
-   index = disp_info->h_tile_instance[0];
-
dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc);
 
atomic_set(_enc->frame_done_timeout_cnt, 0);
 
-   if (disp_info->intf_type == INTF_DP)
-   dpu_enc->wide_bus_en = 
msm_dp_wide_bus_available(priv->dp[index]);
-   else if (disp_info->intf_type == INTF_DSI)
-   dpu_enc->wide_bus_en = 
msm_dsi_wide_bus_enabled(priv->dsi[index]);
-
mutex_lock(_enc->enc_lock);
cur_mode = _enc->base.crtc->state->adjusted_mode;
 
+   dpu_enc->wide_bus_en = dpu_encoder_is_widebus_enabled(drm_enc);
+
trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
 cur_mode->vdisplay);
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index fe6b1d312a742..67aef59c1f99c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -156,6 +156,10 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
  */
 int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
 
+/**
+ * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled
+ * @drm_enc:Pointer to previously created drm encoder structure
+ */
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
 
 /**
-- 
2.39.2



[PATCH v5 18/19] drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420

2024-02-22 Thread Paloma Arellano
Reserve CDM blocks for DP if the mode format is YUV420. Currently this
reservation only works for writeback and DP if the format is YUV420. But
this can be easily extented to other YUV formats for DP.

Changes in v2:
- Minor code simplification

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 +
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 84778adc7f791..e636215c8f834 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -635,6 +635,7 @@ static int dpu_encoder_virt_atomic_check(
struct dpu_kms *dpu_kms;
struct drm_display_mode *adj_mode;
struct msm_display_topology topology;
+   struct msm_display_info *disp_info;
struct dpu_global_state *global_state;
struct drm_framebuffer *fb;
struct drm_dsc_config *dsc;
@@ -651,6 +652,7 @@ static int dpu_encoder_virt_atomic_check(
DPU_DEBUG_ENC(dpu_enc, "\n");
 
priv = drm_enc->dev->dev_private;
+   disp_info = _enc->disp_info;
dpu_kms = to_dpu_kms(priv->kms);
adj_mode = _state->adjusted_mode;
global_state = dpu_kms_get_global_state(crtc_state->state);
@@ -678,21 +680,24 @@ static int dpu_encoder_virt_atomic_check(
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, 
crtc_state, dsc);
 
/*
-* Use CDM only for writeback at the moment as other interfaces cannot 
handle it.
-* if writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
+* Use CDM only for writeback or DP at the moment as other interfaces 
cannot handle it.
+* If writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
 * earlier.
 */
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
fb = conn_state->writeback_job->fb;
 
if (fb && 
DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb
topology.needs_cdm = true;
-   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
-   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
+   } else if (disp_info->intf_type == INTF_DP) {
+   if 
(msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
+   topology.needs_cdm = true;
}
 
+   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
+   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
/*
 * Release and Allocate resources on every modeset
 * Dont allocate when active is false.
@@ -1133,7 +1138,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct 
drm_encoder *drm_enc,
 
dpu_enc->dsc_mask = dsc_mask;
 
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if ((dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) ||
+   dpu_enc->disp_info.intf_type == INTF_DP) {
struct dpu_hw_blk *hw_cdm = NULL;
 
dpu_rm_get_assigned_resources(_kms->rm, global_state,
-- 
2.39.2



[PATCH v5 16/19] drm/msm/dpu: modify encoder programming for CDM over DP

2024-02-22 Thread Paloma Arellano
Adjust the encoder format programming in the case of video mode for DP
to accommodate CDM related changes.

Changes in v4:
- Remove hw_cdm check in dpu_encoder_needs_periph_flush()
- Remove hw_cdm check when getting the fmt_fourcc in
  dpu_encoder_phys_vid_enable()

Changes in v2:
- Move timing engine programming to a separate patch from this
  one
- Move update_pending_flush_periph() invocation completely to
  this patch
- Change the logic of dpu_encoder_get_drm_fmt() so that it only
  calls drm_mode_is_420_only() instead of doing additional
  unnecessary checks
- Create new functions msm_dp_needs_periph_flush() and it's
  supporting function dpu_encoder_needs_periph_flush() to check
  if the mode is YUV420 and VSC SDP is enabled before doing a
  peripheral flush

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 35 +++
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  | 13 +++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  | 16 +
 drivers/gpu/drm/msm/dp/dp_display.c   | 18 ++
 drivers/gpu/drm/msm/msm_drv.h | 17 -
 5 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index b53a1b545742b..84778adc7f791 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -218,6 +218,41 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
 };
 
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct drm_display_info *info;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   info = _enc->connector->display_info;
+   mode = _enc->cached_mode;
+
+   if (drm_mode_is_420_only(info, mode))
+   return DRM_FORMAT_YUV420;
+
+   return DRM_FORMAT_RGB888;
+}
+
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct msm_display_info *disp_info;
+   struct msm_drm_private *priv;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   priv = drm_enc->dev->dev_private;
+   mode = _enc->cached_mode;
+
+   return phys_enc->hw_intf->cap->type == INTF_DP &&
+  
msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode);
+}
 
 bool dpu_encoder_is_widebus_enabled(const 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 f43d57d9c74e1..211a3d90eb690 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -341,6 +341,19 @@ static inline enum dpu_3d_blend_mode 
dpu_encoder_helper_get_3d_blend_mode(
  */
 unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_get_drm_fmt - return DRM fourcc format
+ * @phys_enc: Pointer to physical encoder structure
+ */
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
+
+/**
+ * dpu_encoder_needs_periph_flush - return true if physical encoder requires
+ * peripheral flush
+ * @phys_enc: Pointer to physical encoder structure
+ */
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc);
+
 /**
  * dpu_encoder_helper_split_config - split display configuration helper 
function
  * This helper function may be used by physical encoders to configure
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 f02411b062c4c..86c57c8b7e784 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
@@ -415,8 +415,12 @@ static int dpu_encoder_phys_vid_control_vblank_irq(
 static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
 {
struct dpu_hw_ctl *ctl;
+   const struct dpu_format *fmt;
+   u32 fmt_fourcc;
 
ctl = phys_enc->hw_ctl;
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+   fmt = dpu_get_dpu_format(fmt_fourcc);
 
DPU_DEBUG_VIDENC(phys_enc, "\n");
 
@@ -425,6 +429,8 @@ static void dpu_encoder_phys_vid_enable(struct 
dpu_encoder_phys *phys_enc)
 
dpu_encoder_helper_split_config(phys_enc, phys_enc->hw_intf->idx);
 
+   dpu_encoder_helper_phys_setup_cdm(phys_enc, fmt, CDM_CDWN_OUTP

[PATCH v5 07/19] drm/msm/dp: store mode YUV420 information to be used by rest of DP

2024-02-22 Thread Paloma Arellano
Wide bus is not supported when the mode is YUV420 in DP. In preparation
for changing the DPU programming to reflect this, the value and
assignment location of wide_bus_en for the DP submodules must be
changed. Move it from boot time in dp_init_sub_modules() to run time in
dp_display_mode_set.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 17 +
 drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 792191f67717f..1a84f68e2b59a 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -785,10 +785,6 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
goto error_ctrl;
}
 
-   /* populate wide_bus_supported to different layers */
-   dp->ctrl->wide_bus_en = dp->wide_bus_supported;
-   dp->catalog->wide_bus_en = dp->wide_bus_supported;
-
return rc;
 
 error_ctrl:
@@ -809,6 +805,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
drm_mode_copy(>panel->dp_mode.drm_mode, >drm_mode);
dp->panel->dp_mode.bpp = mode->bpp;
dp->panel->dp_mode.capabilities = mode->capabilities;
+   dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
dp_panel_init_panel_info(dp->panel);
return 0;
 }
@@ -1403,6 +1400,9 @@ bool msm_dp_wide_bus_available(const struct msm_dp 
*dp_display)
 
dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+   if (dp->dp_mode.out_fmt_is_yuv_420)
+   return false;
+
return dp->wide_bus_supported;
 }
 
@@ -1616,6 +1616,15 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
 
dp_display->dp_mode.h_active_low =
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+
+   dp_display->dp_mode.out_fmt_is_yuv_420 =
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+
+   /* populate wide_bus_support to different layers */
+   dp_display->ctrl->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
+   dp_display->catalog->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
 }
 
 void dp_bridge_hpd_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index a0dfc579c5f9f..6ec68be9f2366 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -19,6 +19,7 @@ struct dp_display_mode {
u32 bpp;
u32 h_active_low;
u32 v_active_low;
+   bool out_fmt_is_yuv_420;
 };
 
 struct dp_panel_in {
-- 
2.39.2



[PATCH v5 05/19] drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder

2024-02-22 Thread Paloma Arellano
Move dpu_encoder_helper_phys_setup_cdm to dpu_encoder in preparation for
implementing YUV420 over DP, which requires CDM compatibility.

Changes in v2:
- Slightly change the wording of the commit text to make clear
  that YUV over DP requires CDM

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 78 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  9 ++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 83 ---
 3 files changed, 87 insertions(+), 83 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 8932f38a41b2d..1905e8653b77a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2117,6 +2117,84 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
ctl->ops.clear_pending_flush(ctl);
 }
 
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output_type)
+{
+   struct dpu_hw_cdm *hw_cdm;
+   struct dpu_hw_cdm_cfg *cdm_cfg;
+   struct dpu_hw_pingpong *hw_pp;
+   int ret;
+
+   if (!phys_enc)
+   return;
+
+   cdm_cfg = _enc->cdm_cfg;
+   hw_pp = phys_enc->hw_pp;
+   hw_cdm = phys_enc->hw_cdm;
+
+   if (!hw_cdm)
+   return;
+
+   if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
+   DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", 
DRMID(phys_enc->parent),
+ dpu_fmt->base.pixel_format);
+   if (hw_cdm->ops.bind_pingpong_blk)
+   hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
+
+   return;
+   }
+
+   memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
+
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
+   cdm_cfg->output_fmt = dpu_fmt;
+   cdm_cfg->output_type = output_type;
+   cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
+   CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
+   cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
+
+   /* enable 10 bit logic */
+   switch (cdm_cfg->output_fmt->chroma_sample) {
+   case DPU_CHROMA_RGB:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_H2V1:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_420:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
+   break;
+   case DPU_CHROMA_H1V2:
+   default:
+   DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
+ DRMID(phys_enc->parent));
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   }
+
+   DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
+ DRMID(phys_enc->parent), cdm_cfg->output_width,
+ cdm_cfg->output_height, 
cdm_cfg->output_fmt->base.pixel_format,
+ cdm_cfg->output_type, cdm_cfg->output_bit_depth,
+ cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
+
+   if (hw_cdm->ops.enable) {
+   cdm_cfg->pp_id = hw_pp->idx;
+   ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
+   if (ret < 0) {
+   DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
+ DRMID(phys_enc->parent), ret);
+   return;
+   }
+   }
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int _dpu_encoder_status_show(struct seq_file *s, void *data)
 {
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 204d7cc3c1de8..f43d57d9c74e1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -381,6 +381,15 @@ int dpu_encoder_helper_wait_for_irq(struct 
dpu_encoder_phys *phys_enc,
  */
 void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
+ * @phys_enc: Pointer to physical encoder
+ * @output_type: HDMI/WB
+ */
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output

[PATCH v5 17/19] drm/msm/dpu: modify timing engine programming for YUV420 over DP

2024-02-22 Thread Paloma Arellano
Adjust the encoder timing engine setup programming in the case of video
mode for YUV420 over DP to accommodate CDM.

Changes in v3:
- Move drm_display_mode's hskew division to another patch
- Minor cleanup

Changes in v2:
- Move timing engine programming to this patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 8 ++--
 1 file changed, 6 insertions(+), 2 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 86c57c8b7e784..5cb816ea4dcc0 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
@@ -236,7 +236,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
struct drm_display_mode mode;
struct dpu_hw_intf_timing_params timing_params = { 0 };
const struct dpu_format *fmt = NULL;
-   u32 fmt_fourcc = DRM_FORMAT_RGB888;
+   u32 fmt_fourcc;
unsigned long lock_flags;
struct dpu_hw_intf_cfg intf_cfg = { 0 };
 
@@ -255,7 +255,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
drm_mode_debug_printmodeline();
 
-   if (phys_enc->split_role != ENC_ROLE_SOLO) {
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+
+   if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == 
DRM_FORMAT_YUV420) {
mode.hdisplay >>= 1;
mode.htotal >>= 1;
mode.hsync_start >>= 1;
@@ -275,6 +277,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
fmt = dpu_get_dpu_format(fmt_fourcc);
DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);
 
+   if (phys_enc->hw_cdm)
+   intf_cfg.cdm = phys_enc->hw_cdm->idx;
intf_cfg.intf = phys_enc->hw_intf->idx;
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
-- 
2.39.2



[PATCH v5 15/19] drm/msm/dp: enable SDP and SDE periph flush update

2024-02-22 Thread Paloma Arellano
DP controller can be setup to operate in either SDP update flush mode or
peripheral flush mode based on the DP controller hardware version.

Starting in DP v1.2, the hardware documents require the use of
peripheral flush mode for SDP packets such as PPS OR VSC SDP packets.

In-line with this guidance, lets program the DP controller to use
peripheral flush mode starting DP v1.2

Changes in v4:
- Clear up that DP_MAINLINK_CTRL_FLUSH_MODE register requires
  the use of bits [24:23]
- Modify macros DP_MAINLINK_FLUSH_MODE_UPDATE_SDP and
  DP_MAINLINK_FLUSH_MODE_SDP_PERIPH_UPDATE to explicitly set
  their values in the bits of DP_MAINLINK_CTRL_FLUSH_MODE_MASK

Changes in v3:
- Clear up that the DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE
  macro is setting bits [24:23] to a value of 3

Changes in v2:
- Use the original dp_catalog_hw_revision() function to
  correctly check the DP HW version

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 17 +
 drivers/gpu/drm/msm/dp/dp_catalog.h |  1 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  1 +
 drivers/gpu/drm/msm/dp/dp_reg.h |  6 ++
 4 files changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index bfc6f53ae167f..e5e7c04557707 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -440,6 +440,23 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
 }
 
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog)
+{
+   u32 mainlink_ctrl, hw_revision;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision >= DP_HW_VERSION_1_2)
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
+   else
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
+}
+
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
bool fixed_nvid, bool is_ycbcr_420)
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 3605252effb59..47f80bb39ccd3 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -98,6 +98,7 @@ 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_ctrl(struct dp_catalog *dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool 
enable);
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog);
 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,
u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index a42b29f9902c1..a17b9a22858da 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -165,6 +165,7 @@ static void dp_ctrl_configure_source_params(struct 
dp_ctrl_private *ctrl)
 
dp_catalog_ctrl_lane_mapping(ctrl->catalog);
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+   dp_catalog_setup_peripheral_flush(ctrl->catalog);
 
dp_ctrl_config_ctrl(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index aa9f6c3e4ddeb..3835c7f5cb984 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -6,6 +6,9 @@
 #ifndef _DP_REG_H_
 #define _DP_REG_H_
 
+#include 
+#include 
+
 /* DP_TX Registers */
 #define REG_DP_HW_VERSION  (0x)
 
@@ -102,6 +105,9 @@
 #define DP_MAINLINK_CTRL_ENABLE(0x0001)
 #define DP_MAINLINK_CTRL_RESET (0x0002)
 #define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER   (0x0010)
+#define DP_MAINLINK_CTRL_FLUSH_MODE_MASK   GENMASK(24, 23)
+#define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP  
FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 1)
+#define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE   
FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 3)
 #define DP_MAINLINK_FB_BOUNDARY_SEL(0x0200)
 
 #define REG_DP_STATE_CTRL  (0x0004)
-- 
2.39.2



[PATCH v5 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-22 Thread Paloma Arellano
Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v5:
- Slightly modify use of drm_dp_vsc_sdp_pack()
- Remove dp_catalog NULL checks
- Modify dp_utils_pack_sdp_header() to more clearly pack the
  header buffer
- Move dp_utils_pack_sdp_header() inside of
  dp_catalog_panel_send_vsc_sdp to clearly show the relationship
  between the header buffer and the vsc_sdp struct
- Due to the last point, remove the dp_utils_pack_vsc_sdp()
  function and only call drm_dp_vsc_sdp_pack() in
  dp_panel_setup_vsc_sdp_yuv_420()

Changes in v4:
- Remove struct msm_dp_sdp_with_parity
- Use dp_utils_pack_sdp_header() to pack the SDP header and
  parity bytes into a buffer
- Use this buffer when writing the VSC SDP data in
  dp_catalog_panel_send_vsc_sdp()
- Write to all of the MMSS_DP_GENERIC0 registers instead of just
  the ones with non-zero values

Changes in v3:
- Create a new struct, msm_dp_sdp_with_parity, which holds the
  packing information for VSC SDP
- Use drm_dp_vsc_sdp_pack() to pack the data into the new
  msm_dp_sdp_with_parity struct instead of specifically packing
  for YUV420 format
- Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP
  data using the new msm_dp_sdp_with_parity struct

Changes in v2:
- Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
- Remove dp_sdp from the dp_catalog struct since this data is
  being allocated at the point used
- Create a new function in dp_utils to pack the VSC SDP data
  into a buffer
- Create a new function that packs the SDP header bytes into a
  buffer. This function is made generic so that it can be
  utilized by dp_audio
  header bytes into a buffer
- Create a new function in dp_utils that takes the packed buffer
  and writes to the DP_GENERIC0_* registers
- Split the dp_catalog_panel_config_vsc_sdp() function into two
  to disable/enable sending VSC SDP packets
- Check the DP HW version using the original useage of
  dp_catalog_hw_revision() and correct the version checking
  logic
- Rename dp_panel_setup_vsc_sdp() to
  dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
  currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 93 +
 drivers/gpu/drm/msm/dp/dp_catalog.h |  6 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  4 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   | 52 
 drivers/gpu/drm/msm/dp/dp_reg.h |  3 +
 drivers/gpu/drm/msm/dp/dp_utils.c   | 25 
 drivers/gpu/drm/msm/dp/dp_utils.h   | 14 +
 7 files changed, 197 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..bfc6f53ae167f 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,99 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
return 0;
 }
 
+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, 
struct dp_sdp *vsc_sdp)
+{
+   struct dp_catalog_private *catalog;
+   u32 header[2];
+   u32 val;
+   int i;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   dp_utils_pack_sdp_header(_sdp->sdp_header, header);
+
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
+
+   for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
+   val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | 
(vsc_sdp->db[i + 2] << 16) |
+  (vsc_sdp->db[i + 3] << 24));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
+   }
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+   }
+}
+
+void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct 
dp_sdp *vsc_sdp)
+{
+   struct dp_catalog_private *catalog;
+   u32 cfg, cfg2, misc;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   cfg = dp_read_link(c

[PATCH v5 04/19] drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP

2024-02-22 Thread Paloma Arellano
Generalize dpu_encoder_helper_phys_setup_cdm to be compatible with DP.

Changes in v2:
- Minor formatting changes
- Move the modification of the dimensions for CDM setup to a new
  patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  4 +--
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 27 ++-
 2 files changed, 16 insertions(+), 15 deletions(-)

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 993f263433314..204d7cc3c1de8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -154,6 +154,7 @@ enum dpu_intr_idx {
  * @hw_wb: Hardware interface to the wb registers
  * @hw_cdm:Hardware interface to the CDM registers
  * @dpu_kms:   Pointer to the dpu_kms top level
+ * @cdm_cfg:   CDM block config needed to store WB/DP block's CDM 
configuration
  * @cached_mode:   DRM mode cached at mode_set time, acted on in enable
  * @vblank_ctl_lock:   Vblank ctl mutex lock to protect vblank_refcount
  * @enabled:   Whether the encoder has enabled and running a mode
@@ -184,6 +185,7 @@ struct dpu_encoder_phys {
struct dpu_hw_wb *hw_wb;
struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms;
+   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role;
@@ -213,7 +215,6 @@ static inline int dpu_encoder_phys_inc_pending(struct 
dpu_encoder_phys *phys)
  * @wbirq_refcount: Reference count of writeback interrupt
  * @wb_done_timeout_cnt: number of wb done irq timeout errors
  * @wb_cfg:  writeback block config to store fb related details
- * @cdm_cfg: cdm block config needed to store writeback block's CDM 
configuration
  * @wb_conn: backpointer to writeback connector
  * @wb_job: backpointer to current writeback job
  * @dest:   dpu buffer layout for current writeback output buffer
@@ -223,7 +224,6 @@ struct dpu_encoder_phys_wb {
atomic_t wbirq_refcount;
int wb_done_timeout_cnt;
struct dpu_hw_wb_cfg wb_cfg;
-   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_writeback_connector *wb_conn;
struct drm_writeback_job *wb_job;
struct dpu_hw_fmt_layout dest;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index ec9e053d3947d..072fc6950e496 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -269,28 +269,21 @@ static void dpu_encoder_phys_wb_setup_ctl(struct 
dpu_encoder_phys *phys_enc)
  * This API does not handle 
DPU_CHROMA_H1V2.
  * @phys_enc:Pointer to physical encoder
  */
-static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc)
+static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc,
+ const struct dpu_format *dpu_fmt,
+ u32 output_type)
 {
struct dpu_hw_cdm *hw_cdm;
struct dpu_hw_cdm_cfg *cdm_cfg;
struct dpu_hw_pingpong *hw_pp;
-   struct dpu_encoder_phys_wb *wb_enc;
-   const struct msm_format *format;
-   const struct dpu_format *dpu_fmt;
-   struct drm_writeback_job *wb_job;
int ret;
 
if (!phys_enc)
return;
 
-   wb_enc = to_dpu_encoder_phys_wb(phys_enc);
-   cdm_cfg = _enc->cdm_cfg;
+   cdm_cfg = _enc->cdm_cfg;
hw_pp = phys_enc->hw_pp;
hw_cdm = phys_enc->hw_cdm;
-   wb_job = wb_enc->wb_job;
-
-   format = msm_framebuffer_format(wb_enc->wb_job->fb);
-   dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, 
wb_job->fb->modifier);
 
if (!hw_cdm)
return;
@@ -309,7 +302,7 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
-   cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
+   cdm_cfg->output_type = output_type;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
@@ -462,6 +455,14 @@ static void dpu_encoder_phys_wb_setup(
struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
struct drm_display_mode mode = phys_enc->cached_mode;
struct drm_framebuffer *fb = NULL;
+   struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+   struct drm_writeback_job *wb_job;
+   const stru

[PATCH v5 11/19] drm/msm/dp: change clock related programming for YUV420 over DP

2024-02-22 Thread Paloma Arellano
Change all relevant DP controller related programming for YUV420 cases.
Namely, change the pixel clock math to consider YUV420 and modify the
MVID programming to consider YUV420.

Changes in v2:
- Move configuration control programming to a different commit
- Slight code simplification
- Add VSC SDP check when doing mode_pclk_khz division in
  dp_bridge_mode_valid

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 5 -
 drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 9 ++---
 drivers/gpu/drm/msm/dp/dp_display.c | 4 
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5142aeb705a44..5d84c089e520a 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -442,7 +442,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
 
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
-   bool fixed_nvid)
+   bool fixed_nvid, bool is_ycbcr_420)
 {
u32 pixel_m, pixel_n;
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
@@ -485,6 +485,9 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog 
*dp_catalog,
nvid = temp;
}
 
+   if (is_ycbcr_420)
+   mvid /= 2;
+
if (link_rate_hbr2 == rate)
nvid *= 2;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 38786e855b51a..6cb5e2a243de2 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -96,7 +96,7 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog 
*dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(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,
-   u32 stream_rate_khz, bool fixed_nvid);
+   u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
 int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 
pattern);
 u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 6692d81adb195..bffb7bac2c2c8 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -955,7 +955,7 @@ static void dp_ctrl_calc_tu_parameters(struct 
dp_ctrl_private *ctrl,
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
in.nlanes = ctrl->link->link_params.num_lanes;
in.bpp = ctrl->panel->dp_mode.bpp;
-   in.pixel_enc = 444;
+   in.pixel_enc = ctrl->panel->dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
in.dsc_en = 0;
in.async_en = 0;
in.fec_en = 0;
@@ -1761,6 +1761,8 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
ctrl->link->link_params.rate = rate;
ctrl->link->link_params.num_lanes =
ctrl->panel->link_info.num_lanes;
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   pixel_rate >>= 1;
}
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1876,7 +1878,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock;
 
-   if (dp_ctrl->wide_bus_en)
+   if (dp_ctrl->wide_bus_en || ctrl->panel->dp_mode.out_fmt_is_yuv_420)
pixel_rate >>= 1;
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1915,7 +1917,8 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
dp_catalog_ctrl_config_msa(ctrl->catalog,
ctrl->link->link_params.rate,
-   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
+   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl),
+   ctrl->panel->dp_mode.out_fmt_is_yuv_420);
 
dp_ctrl_setup_tr_unit(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 4b1b79b74bc72..3b7c3a7fd4993 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -934,6 +934,10 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = _display->panel->link_info;
 
+   if (drm_mode_is_420

[PATCH v5 12/19] drm/msm/dp: move parity calculation to dp_utils

2024-02-22 Thread Paloma Arellano
Parity calculation is necessary for VSC SDP implementation. Therefore
create new files dp_utils.c and dp_utils.h and move the parity
calculating functions here. This ensures that they are usable by SDP
programming in both dp_catalog.c and dp_audio.c

Changes in v3:
- Change ordering of the header byte macros

Changes in v2:
- Create new files dp_utils.c and dp_utils.h
- Move the parity calculation to these new files instead of
  having them in dp_catalog.c and dp_catalog.h

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/Makefile  |   3 +-
 drivers/gpu/drm/msm/dp/dp_audio.c | 101 +-
 drivers/gpu/drm/msm/dp/dp_utils.c |  73 +
 drivers/gpu/drm/msm/dp/dp_utils.h |  22 +++
 4 files changed, 112 insertions(+), 87 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b1173128b5b97..998b155e4a979 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -129,7 +129,8 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_panel.o \
dp/dp_parser.o \
dp/dp_power.o \
-   dp/dp_audio.o
+   dp/dp_audio.o \
+   dp/dp_utils.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c 
b/drivers/gpu/drm/msm/dp/dp_audio.c
index 4a2e479723a85..7634e4b742084 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -15,13 +15,7 @@
 #include "dp_audio.h"
 #include "dp_panel.h"
 #include "dp_display.h"
-
-#define HEADER_BYTE_2_BIT   0
-#define PARITY_BYTE_2_BIT   8
-#define HEADER_BYTE_1_BIT  16
-#define PARITY_BYTE_1_BIT  24
-#define HEADER_BYTE_3_BIT  16
-#define PARITY_BYTE_3_BIT  24
+#include "dp_utils.h"
 
 struct dp_audio_private {
struct platform_device *audio_pdev;
@@ -36,71 +30,6 @@ struct dp_audio_private {
struct dp_audio dp_audio;
 };
 
-static u8 dp_audio_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 u8 dp_audio_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 u8 dp_audio_calculate_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 & 0xFF00) > 0 ? 8 : 2;
-
-   for (i = 0; i < num_byte; i++) {
-   iData = (data >> i*4) & 0xF;
-
-   ci = iData ^ x1;
-   x1 = x0 ^ dp_audio_get_g1_value(ci);
-   x0 = dp_audio_get_g0_value(ci);
-   }
-
-   parity_byte = x1 | (x0 << 4);
-
-   return parity_byte;
-}
-
 static u32 dp_audio_get_header(struct dp_catalog *catalog,
enum dp_catalog_audio_sdp_type sdp,
enum dp_catalog_audio_header_type header)
@@ -134,7 +63,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
 
new_value = 0x02;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -147,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
value = dp_audio_get_header(catalog,
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
new_value = value;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -162,7 +91,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
 
new_value = audio->channels - 1;
-   parity_byt

[PATCH v5 03/19] drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup

2024-02-22 Thread Paloma Arellano
Modify the output width and height parameters of hw_cdm to utilize the
physical encoder's data instead of obtaining the information from the
framebuffer. CDM is to be set up to utilize the actual output data since
at CDM setup, there is no difference between the two sources.

Changes in v2:
- Move the modification of the dimensions for CDM setup to this
  new patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 4cd2d9e3131a4..ec9e053d3947d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -306,8 +306,8 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
 
memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
 
-   cdm_cfg->output_width = wb_job->fb->width;
-   cdm_cfg->output_height = wb_job->fb->height;
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
-- 
2.39.2



[PATCH v5 02/19] drm/msm/dpu: add division of drm_display_mode's hskew parameter

2024-02-22 Thread Paloma Arellano
Setting up the timing engine when the physical encoder has a split role
neglects dividing the drm_display_mode's hskew parameter. Let's fix this
since this must also be done in preparation for implementing YUV420 over
DP.

Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support")
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 6 --
 1 file changed, 4 insertions(+), 2 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 f562beb6f7971..f02411b062c4c 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
@@ -260,12 +260,14 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
mode.htotal >>= 1;
mode.hsync_start >>= 1;
mode.hsync_end >>= 1;
+   mode.hskew >>= 1;
 
DPU_DEBUG_VIDENC(phys_enc,
-   "split_role %d, halve horizontal %d %d %d %d\n",
+   "split_role %d, halve horizontal %d %d %d %d %d\n",
phys_enc->split_role,
mode.hdisplay, mode.htotal,
-   mode.hsync_start, mode.hsync_end);
+   mode.hsync_start, mode.hsync_end,
+   mode.hskew);
}
 
drm_mode_to_intf_timing_params(phys_enc, , _params);
-- 
2.39.2



[PATCH v5 01/19] drm/msm/dpu: allow certain formats for CDM for DP

2024-02-22 Thread Paloma Arellano
CDM block supports formats other than H1V2 for DP. Since we are now
adding support for CDM over DP, relax the checks to allow all other
formats for DP other than H1V2.

Changes in v2:
- Add fixes tag
- Move patch to top of series

Fixes: 0afac0ba6024 ("drm/msm/dpu: add dpu_hw_cdm abstraction for CDM block")
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
index e9cdc7934a499..9016b3ade6bc3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct 
dpu_hw_cdm_cfg *cdm)
dpu_hw_cdm_setup_cdwn(ctx, cdm);
 
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
-   if (fmt->chroma_sample != DPU_CHROMA_H1V2)
+   if (fmt->chroma_sample == DPU_CHROMA_H1V2)
return -EINVAL; /*unsupported format */
opmode = CDM_HDMI_PACK_OP_MODE_EN;
opmode |= (fmt->chroma_sample << 1);
-- 
2.39.2



[PATCH v5 00/19] Add support for CDM over DP

2024-02-22 Thread Paloma Arellano
The Chroma Down Sampling (CDM) block is a hardware component in the DPU
pipeline that includes a CSC block capable of converting RGB input from
the DPU to YUV data.

This block can be used with either HDMI, DP, or writeback interfaces.
This series adds support for the CDM block to be used with DP in
YUV420 mode format.

This series allows selection of the YUV420 format for monitors which support
certain resolutions only in YUV420 thus unblocking the validation of many
other resolutions which were previously filtered out if the connector did
not support YUV420.

This was validated using a DP connected monitor requiring the use of
YUV420 format.

This series is dependent on [1], [2], and [3]:
[1] https://patchwork.freedesktop.org/series/118831/
[2] https://patchwork.freedesktop.org/series/129395/
[3] https://patchwork.freedesktop.org/series/129864/

Changes in v5:
- Slightly modify use of drm_dp_vsc_sdp_pack()
- Remove dp_catalog NULL checks
- Modify dp_utils_pack_sdp_header() to cleanly pack the header
  buffer
- Remove the dp_utils_pack_vsc_sdp() function and only call
  drm_dp_vsc_sdp_pack() in dp_panel_setup_vsc_sdp_yuv_420()
- To clearly show the relationship between the header buffer and
  vsc_sdp struct, move dp_utils_pack_sdp_header() inside of
  dp_catalog_panel_send_vsc_sdp()

Changes in v4:
- Use dp_utils_pack_sdp_header() to pack the SDP header and
  parity bytes into a buffer
- Use this buffer when writing the VSC SDP data in
  dp_catalog_panel_send_vsc_sdp() and write to all the
  MMSS_DP_GENERIC0 registers
- Clear up that DP_MAINLINK_CTRL_FLUSH_MODE register requires
  the use of bits [24:23]
- Modify certain macros to explicitly set their values in the
  bits of DP_MAINLINK_CTRL_FLUSH_MODE_MASK
- Remove hw_cdm check in dpu_encoder_needs_periph_flush() and
  dpu_encoder_phys_vid_enable()

Changes in v3:
- Change ordering of the header byte macros in dp_utils.h
- Create a new struct, msm_dp_sdp_with_parity
- Utilize drm_dp_vsc_sdp_pack() from a new added dependency of
  series [3] to pack the VSC SDP data into the new
  msm_dp_sdp_with_parity struct instead of packing only for
  YUV420
- Modify dp_catalog_panel_send_vsc_sdp() so that it sends the VSC SDP 
data
  using the new msm_dp_sdp_with_parity struct
- Clear up that the DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE macro is 
setting
  multiple bits and not just one
- Move the connector's ycbcr_420_allowed parameter so it is no longer
  dependent on if the dp_display is not eDP

Changes in v2:
- Minor formatting changes throughout
- Move 'fixes' patch to the top
- Move VSC SDP support check API from dp_panel.c to drm_dp_helper.c
- Create a separate patch for modifying the dimensions for CDM setup to 
be
  non-WB specific
- Remove a patch that modified the INTF_CONFIG2 register in favor of 
having
  this series be dependent on [2]
- Separate configuration ctrl programming from clock related 
programming into
  two patches
- Add a VSC SDP check in dp_bridge_mode_valid()
- Move parity calculation functions to new files dp_utils.c and 
dp_utils.h
- Remove dp_catalog_hw_revision() changes and utilize the original 
version of
  the function when checking the DP hardware version
- Create separate packing and programming functions for the VSC SDP
- Make the packing header bytes function generic so it can be used with
  dp_audio.c
- Create two separate enable/disable VSC SDP functions instead of 
having one
  with the ability to do both
- Move timing engine programming to a separate patch from original 
encoder
  programming patch
- Move update_pending_flush_periph() code to be in the same patch as the
  encoder programming
- Create new API's to check if the dpu encoder needs a peripheral flush
- Allow YUV420 modes for the DP connector when there's a CDM block 
available
  instead of checking if VSC SDP is supported

Kuogee Hsieh (1):
  drm/msm/dpu: add support of new peripheral flush mechanism

Paloma Arellano (18):
  drm/msm/dpu: allow certain formats for CDM for DP
  drm/msm/dpu: add division of drm_display_mode's hskew parameter
  drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup
  drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP
  drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder
  drm/msm/dp: rename wide_bus_en to wide_bus_supported
  drm/msm/dp: store mode YUV420 information to be used by rest of DP
  drm/msm/dp: check if VSC SDP is supported in DP programming
  drm/msm/dpu: move widebus logic to its own API
  drm/msm/dp: program config ctrl

Re: [PATCH v4 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-20 Thread Paloma Arellano



On 2/20/2024 10:09 AM, Dmitry Baryshkov wrote:

On Tue, 20 Feb 2024 at 19:55, Paloma Arellano  wrote:


On 2/17/2024 12:56 AM, Dmitry Baryshkov wrote:

On Sat, 17 Feb 2024 at 01:03, Paloma Arellano  wrote:

+   }
+
+   panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+   catalog = panel->catalog;
+   dp_mode = _panel->dp_mode;
+
+   memset(_sdp_data, 0, sizeof(vsc_sdp_data));
+
+   /* VSC SDP header as per table 2-118 of DP 1.4 specification */
+   vsc_sdp_data.sdp_type = DP_SDP_VSC;
+   vsc_sdp_data.revision = 0x05;
+   vsc_sdp_data.length = 0x13;
+
+   /* VSC SDP Payload for DB16 */
+   vsc_sdp_data.pixelformat = DP_PIXELFORMAT_YUV420;
+   vsc_sdp_data.colorimetry = DP_COLORIMETRY_DEFAULT;
+
+   /* VSC SDP Payload for DB17 */
+   vsc_sdp_data.bpc = dp_mode->bpp / 3;
+   vsc_sdp_data.dynamic_range = DP_DYNAMIC_RANGE_CTA;
+
+   /* VSC SDP Payload for DB18 */
+   vsc_sdp_data.content_type = DP_CONTENT_TYPE_GRAPHICS;
+
+   len = dp_utils_pack_vsc_sdp(_sdp_data, _sdp, header);
+   if (len < 0) {
+   DRM_ERROR("unable to pack vsc sdp\n");
+   return len;
+   }

So, at this point we have the header data both in vsc_sdp.sdp_header
and in the packed header. The relationship between them becomes less
obvious. Could you please pack dp_sdp_header into u32[2] just before
writing it? It really makes little sense to pass both at the same
time.


Just want to clear some stuff up. Do you want to call the
dp_utils_pack_sdp_header() function right before
dp_catalog_panel_send_vsc_sdp()? The point of putting the
dp_utils_pack_sdp_header() function inside dp_utils_pack_vsc_sdp() is so
that all of the packing could be in the same location. Although I agree
that we are passing the same values twice, I believe that having it the
way it is currently is better since it shows that the
drm_dp_vsc_sdp_pack() and dp_utils_pack_sdp_header() are related since
they're packing the data to the set of GENERIC0 registers.

I'm perfectly fine with dp_utils_pack_sdp_header() being called from
within dp_catalog_panel_send_vsc_sdp(). This way you are not passing
extra data and it is perfectly clear how the SDP header is handled
before being written to the hardware.



Ack. Sounds good, I'll implement it that way






Re: [PATCH v4 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-20 Thread Paloma Arellano



On 2/17/2024 12:56 AM, Dmitry Baryshkov wrote:

On Sat, 17 Feb 2024 at 01:03, Paloma Arellano  wrote:

Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v4:
 - Remove struct msm_dp_sdp_with_parity
 - Use dp_utils_pack_sdp_header() to pack the SDP header and
   parity bytes into a buffer
 - Use this buffer when writing the VSC SDP data in
   dp_catalog_panel_send_vsc_sdp()
 - Write to all of the MMSS_DP_GENERIC0 registers instead of just
   the ones with non-zero values

Changes in v3:
 - Create a new struct, msm_dp_sdp_with_parity, which holds the
   packing information for VSC SDP
 - Use drm_dp_vsc_sdp_pack() to pack the data into the new
   msm_dp_sdp_with_parity struct instead of specifically packing
   for YUV420 format
 - Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP
   data using the new msm_dp_sdp_with_parity struct

Changes in v2:
 - Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
 - Remove dp_sdp from the dp_catalog struct since this data is
   being allocated at the point used
 - Create a new function in dp_utils to pack the VSC SDP data
   into a buffer
 - Create a new function that packs the SDP header bytes into a
   buffer. This function is made generic so that it can be
   utilized by dp_audio
   header bytes into a buffer
 - Create a new function in dp_utils that takes the packed buffer
   and writes to the DP_GENERIC0_* registers
 - Split the dp_catalog_panel_config_vsc_sdp() function into two
   to disable/enable sending VSC SDP packets
 - Check the DP HW version using the original useage of
   dp_catalog_hw_revision() and correct the version checking
   logic
 - Rename dp_panel_setup_vsc_sdp() to
   dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
   currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
  drivers/gpu/drm/msm/dp/dp_catalog.c | 107 
  drivers/gpu/drm/msm/dp/dp_catalog.h |   7 ++
  drivers/gpu/drm/msm/dp/dp_ctrl.c|   4 ++
  drivers/gpu/drm/msm/dp/dp_panel.c   |  55 ++
  drivers/gpu/drm/msm/dp/dp_reg.h |   3 +
  drivers/gpu/drm/msm/dp/dp_utils.c   |  56 +++
  drivers/gpu/drm/msm/dp/dp_utils.h   |   4 ++
  7 files changed, 236 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..c6e57812a239e 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,113 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
 return 0;
  }

+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, 
struct dp_sdp *vsc_sdp,
+ u32 *header)
+{
+   struct dp_catalog_private *catalog;
+   u32 val;
+   int i;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }

We are two or three levels deep in the dp_catalog. Do we really need
to check that dp_catalog is not NULL?

Side note: I think we should drop most of such checks. They add
nothing, just clobber the code.



Ack. The dp_catalog checks do seem unnecessary.






+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
+
+   for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
+   val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i 
+ 2] << 16) |
+  (vsc_sdp->db[i + 3] << 24));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
+   }
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+   }
+}
+
+void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct 
dp_sdp *vsc_sdp,
+u32 *header)
+{
+   struct dp_catalog_private *catalog;
+   u32 cfg, cfg2, misc;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }

[PATCH v4 17/19] drm/msm/dpu: modify timing engine programming for YUV420 over DP

2024-02-16 Thread Paloma Arellano
Adjust the encoder timing engine setup programming in the case of video
mode for YUV420 over DP to accommodate CDM.

Changes in v3:
- Move drm_display_mode's hskew division to another patch
- Minor cleanup

Changes in v2:
- Move timing engine programming to this patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 8 ++--
 1 file changed, 6 insertions(+), 2 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 86c57c8b7e784..5cb816ea4dcc0 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
@@ -236,7 +236,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
struct drm_display_mode mode;
struct dpu_hw_intf_timing_params timing_params = { 0 };
const struct dpu_format *fmt = NULL;
-   u32 fmt_fourcc = DRM_FORMAT_RGB888;
+   u32 fmt_fourcc;
unsigned long lock_flags;
struct dpu_hw_intf_cfg intf_cfg = { 0 };
 
@@ -255,7 +255,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
drm_mode_debug_printmodeline();
 
-   if (phys_enc->split_role != ENC_ROLE_SOLO) {
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+
+   if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == 
DRM_FORMAT_YUV420) {
mode.hdisplay >>= 1;
mode.htotal >>= 1;
mode.hsync_start >>= 1;
@@ -275,6 +277,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
fmt = dpu_get_dpu_format(fmt_fourcc);
DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);
 
+   if (phys_enc->hw_cdm)
+   intf_cfg.cdm = phys_enc->hw_cdm->idx;
intf_cfg.intf = phys_enc->hw_intf->idx;
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
-- 
2.39.2



[PATCH v4 18/19] drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420

2024-02-16 Thread Paloma Arellano
Reserve CDM blocks for DP if the mode format is YUV420. Currently this
reservation only works for writeback and DP if the format is YUV420. But
this can be easily extented to other YUV formats for DP.

Changes in v2:
- Minor code simplification

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 +
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 84778adc7f791..e636215c8f834 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -635,6 +635,7 @@ static int dpu_encoder_virt_atomic_check(
struct dpu_kms *dpu_kms;
struct drm_display_mode *adj_mode;
struct msm_display_topology topology;
+   struct msm_display_info *disp_info;
struct dpu_global_state *global_state;
struct drm_framebuffer *fb;
struct drm_dsc_config *dsc;
@@ -651,6 +652,7 @@ static int dpu_encoder_virt_atomic_check(
DPU_DEBUG_ENC(dpu_enc, "\n");
 
priv = drm_enc->dev->dev_private;
+   disp_info = _enc->disp_info;
dpu_kms = to_dpu_kms(priv->kms);
adj_mode = _state->adjusted_mode;
global_state = dpu_kms_get_global_state(crtc_state->state);
@@ -678,21 +680,24 @@ static int dpu_encoder_virt_atomic_check(
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, 
crtc_state, dsc);
 
/*
-* Use CDM only for writeback at the moment as other interfaces cannot 
handle it.
-* if writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
+* Use CDM only for writeback or DP at the moment as other interfaces 
cannot handle it.
+* If writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
 * earlier.
 */
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
fb = conn_state->writeback_job->fb;
 
if (fb && 
DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb
topology.needs_cdm = true;
-   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
-   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
+   } else if (disp_info->intf_type == INTF_DP) {
+   if 
(msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
+   topology.needs_cdm = true;
}
 
+   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
+   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
/*
 * Release and Allocate resources on every modeset
 * Dont allocate when active is false.
@@ -1133,7 +1138,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct 
drm_encoder *drm_enc,
 
dpu_enc->dsc_mask = dsc_mask;
 
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if ((dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) ||
+   dpu_enc->disp_info.intf_type == INTF_DP) {
struct dpu_hw_blk *hw_cdm = NULL;
 
dpu_rm_get_assigned_resources(_kms->rm, global_state,
-- 
2.39.2



[PATCH v4 19/19] drm/msm/dp: allow YUV420 mode for DP connector when CDM available

2024-02-16 Thread Paloma Arellano
All the components of YUV420 over DP are added. Therefore, let's mark the
connector property as true for DP connector when the DP type is not eDP
and when there is a CDM block available.

Changes in v3:
- Move setting the connector's ycbcr_420_allowed parameter so
  that it is not dependent on if the dp_display is not eDP

Changes in v2:
- Check for if dp_catalog has a CDM block available instead of
  checking if VSC SDP is allowed when setting the dp connector's
  ycbcr_420_allowed parameter

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 +++-
 drivers/gpu/drm/msm/dp/dp_display.c | 4 ++--
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +-
 drivers/gpu/drm/msm/dp/dp_drm.h | 3 ++-
 drivers/gpu/drm/msm/msm_drv.h   | 5 +++--
 5 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 723cc1d821431..8d326fb36550a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -565,6 +565,7 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
 {
struct drm_encoder *encoder = NULL;
struct msm_display_info info;
+   bool yuv_supported;
int rc;
int i;
 
@@ -583,7 +584,8 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
return PTR_ERR(encoder);
}
 
-   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder);
+   yuv_supported = !!dpu_kms->catalog->cdm;
+   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder, 
yuv_supported);
if (rc) {
DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);
return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index b5a67835ce6d1..a435847f1d948 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1472,7 +1472,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 }
 
 int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
-   struct drm_encoder *encoder)
+   struct drm_encoder *encoder, bool yuv_supported)
 {
struct dp_display_private *dp_priv;
int ret;
@@ -1488,7 +1488,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return ret;
}
 
-   dp_display->connector = dp_drm_connector_init(dp_display, encoder);
+   dp_display->connector = dp_drm_connector_init(dp_display, encoder, 
yuv_supported);
if (IS_ERR(dp_display->connector)) {
ret = PTR_ERR(dp_display->connector);
DRM_DEV_ERROR(dev->dev,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 46e6889037e88..a819a4ff76a9f 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -353,7 +353,8 @@ int dp_bridge_init(struct msm_dp *dp_display, struct 
drm_device *dev,
 }
 
 /* connector initialization */
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder)
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported)
 {
struct drm_connector *connector = NULL;
 
@@ -364,6 +365,9 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
if (!dp_display->is_edp)
drm_connector_attach_dp_subconnector_property(connector);
 
+   if (yuv_supported)
+   connector->ycbcr_420_allowed = true;
+
drm_connector_attach_encoder(connector, encoder);
 
return connector;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index b3d684db2383b..45e57ac25a4d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -19,7 +19,8 @@ struct msm_dp_bridge {
 
 #define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
 
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder);
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported);
 int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder);
 
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b876ebd48effe..37335777f5c09 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -385,7 +385,7 @@ static inline struct drm_dsc_config 
*msm_dsi_get_dsc_config(struct msm_dsi *msm_
 int __init msm_dp_register

[PATCH v4 12/19] drm/msm/dp: move parity calculation to dp_utils

2024-02-16 Thread Paloma Arellano
Parity calculation is necessary for VSC SDP implementation. Therefore
create new files dp_utils.c and dp_utils.h and move the parity
calculating functions here. This ensures that they are usable by SDP
programming in both dp_catalog.c and dp_audio.c

Changes in v3:
- Change ordering of the header byte macros

Changes in v2:
- Create new files dp_utils.c and dp_utils.h
- Move the parity calculation to these new files instead of
  having them in dp_catalog.c and dp_catalog.h

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/Makefile  |   3 +-
 drivers/gpu/drm/msm/dp/dp_audio.c | 101 +-
 drivers/gpu/drm/msm/dp/dp_utils.c |  73 +
 drivers/gpu/drm/msm/dp/dp_utils.h |  22 +++
 4 files changed, 112 insertions(+), 87 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b1173128b5b97..998b155e4a979 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -129,7 +129,8 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_panel.o \
dp/dp_parser.o \
dp/dp_power.o \
-   dp/dp_audio.o
+   dp/dp_audio.o \
+   dp/dp_utils.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c 
b/drivers/gpu/drm/msm/dp/dp_audio.c
index 4a2e479723a85..7634e4b742084 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -15,13 +15,7 @@
 #include "dp_audio.h"
 #include "dp_panel.h"
 #include "dp_display.h"
-
-#define HEADER_BYTE_2_BIT   0
-#define PARITY_BYTE_2_BIT   8
-#define HEADER_BYTE_1_BIT  16
-#define PARITY_BYTE_1_BIT  24
-#define HEADER_BYTE_3_BIT  16
-#define PARITY_BYTE_3_BIT  24
+#include "dp_utils.h"
 
 struct dp_audio_private {
struct platform_device *audio_pdev;
@@ -36,71 +30,6 @@ struct dp_audio_private {
struct dp_audio dp_audio;
 };
 
-static u8 dp_audio_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 u8 dp_audio_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 u8 dp_audio_calculate_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 & 0xFF00) > 0 ? 8 : 2;
-
-   for (i = 0; i < num_byte; i++) {
-   iData = (data >> i*4) & 0xF;
-
-   ci = iData ^ x1;
-   x1 = x0 ^ dp_audio_get_g1_value(ci);
-   x0 = dp_audio_get_g0_value(ci);
-   }
-
-   parity_byte = x1 | (x0 << 4);
-
-   return parity_byte;
-}
-
 static u32 dp_audio_get_header(struct dp_catalog *catalog,
enum dp_catalog_audio_sdp_type sdp,
enum dp_catalog_audio_header_type header)
@@ -134,7 +63,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
 
new_value = 0x02;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -147,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
value = dp_audio_get_header(catalog,
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
new_value = value;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -162,7 +91,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
 
new_value = audio->channels - 1;
-   parity_byt

[PATCH v4 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-16 Thread Paloma Arellano
Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v4:
- Remove struct msm_dp_sdp_with_parity
- Use dp_utils_pack_sdp_header() to pack the SDP header and
  parity bytes into a buffer
- Use this buffer when writing the VSC SDP data in
  dp_catalog_panel_send_vsc_sdp()
- Write to all of the MMSS_DP_GENERIC0 registers instead of just
  the ones with non-zero values

Changes in v3:
- Create a new struct, msm_dp_sdp_with_parity, which holds the
  packing information for VSC SDP
- Use drm_dp_vsc_sdp_pack() to pack the data into the new
  msm_dp_sdp_with_parity struct instead of specifically packing
  for YUV420 format
- Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP
  data using the new msm_dp_sdp_with_parity struct

Changes in v2:
- Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
- Remove dp_sdp from the dp_catalog struct since this data is
  being allocated at the point used
- Create a new function in dp_utils to pack the VSC SDP data
  into a buffer
- Create a new function that packs the SDP header bytes into a
  buffer. This function is made generic so that it can be
  utilized by dp_audio
  header bytes into a buffer
- Create a new function in dp_utils that takes the packed buffer
  and writes to the DP_GENERIC0_* registers
- Split the dp_catalog_panel_config_vsc_sdp() function into two
  to disable/enable sending VSC SDP packets
- Check the DP HW version using the original useage of
  dp_catalog_hw_revision() and correct the version checking
  logic
- Rename dp_panel_setup_vsc_sdp() to
  dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
  currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 107 
 drivers/gpu/drm/msm/dp/dp_catalog.h |   7 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|   4 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  55 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |   3 +
 drivers/gpu/drm/msm/dp/dp_utils.c   |  56 +++
 drivers/gpu/drm/msm/dp/dp_utils.h   |   4 ++
 7 files changed, 236 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..c6e57812a239e 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,113 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
return 0;
 }
 
+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, 
struct dp_sdp *vsc_sdp,
+ u32 *header)
+{
+   struct dp_catalog_private *catalog;
+   u32 val;
+   int i;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
+
+   for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
+   val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | 
(vsc_sdp->db[i + 2] << 16) |
+  (vsc_sdp->db[i + 3] << 24));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
+   }
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+   }
+}
+
+void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct 
dp_sdp *vsc_sdp,
+u32 *header)
+{
+   struct dp_catalog_private *catalog;
+   u32 cfg, cfg2, misc;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
+   cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
+   misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
+
+   cfg |= GEN0_SDP_EN;
+   dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg);
+
+   cfg2 |= GENERIC0_SDPSIZE_VALID;
+   dp_write_link(cat

[PATCH v4 01/19] drm/msm/dpu: allow certain formats for CDM for DP

2024-02-16 Thread Paloma Arellano
CDM block supports formats other than H1V2 for DP. Since we are now
adding support for CDM over DP, relax the checks to allow all other
formats for DP other than H1V2.

Changes in v2:
- Add fixes tag
- Move patch to top of series

Fixes: 0afac0ba6024 ("drm/msm/dpu: add dpu_hw_cdm abstraction for CDM block")
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
index e9cdc7934a499..9016b3ade6bc3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct 
dpu_hw_cdm_cfg *cdm)
dpu_hw_cdm_setup_cdwn(ctx, cdm);
 
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
-   if (fmt->chroma_sample != DPU_CHROMA_H1V2)
+   if (fmt->chroma_sample == DPU_CHROMA_H1V2)
return -EINVAL; /*unsupported format */
opmode = CDM_HDMI_PACK_OP_MODE_EN;
opmode |= (fmt->chroma_sample << 1);
-- 
2.39.2



[PATCH v4 11/19] drm/msm/dp: change clock related programming for YUV420 over DP

2024-02-16 Thread Paloma Arellano
Change all relevant DP controller related programming for YUV420 cases.
Namely, change the pixel clock math to consider YUV420 and modify the
MVID programming to consider YUV420.

Changes in v2:
- Move configuration control programming to a different commit
- Slight code simplification
- Add VSC SDP check when doing mode_pclk_khz division in
  dp_bridge_mode_valid

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 5 -
 drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 9 ++---
 drivers/gpu/drm/msm/dp/dp_display.c | 4 
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5142aeb705a44..5d84c089e520a 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -442,7 +442,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
 
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
-   bool fixed_nvid)
+   bool fixed_nvid, bool is_ycbcr_420)
 {
u32 pixel_m, pixel_n;
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
@@ -485,6 +485,9 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog 
*dp_catalog,
nvid = temp;
}
 
+   if (is_ycbcr_420)
+   mvid /= 2;
+
if (link_rate_hbr2 == rate)
nvid *= 2;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 38786e855b51a..6cb5e2a243de2 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -96,7 +96,7 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog 
*dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(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,
-   u32 stream_rate_khz, bool fixed_nvid);
+   u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
 int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 
pattern);
 u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 6692d81adb195..bffb7bac2c2c8 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -955,7 +955,7 @@ static void dp_ctrl_calc_tu_parameters(struct 
dp_ctrl_private *ctrl,
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
in.nlanes = ctrl->link->link_params.num_lanes;
in.bpp = ctrl->panel->dp_mode.bpp;
-   in.pixel_enc = 444;
+   in.pixel_enc = ctrl->panel->dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
in.dsc_en = 0;
in.async_en = 0;
in.fec_en = 0;
@@ -1761,6 +1761,8 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
ctrl->link->link_params.rate = rate;
ctrl->link->link_params.num_lanes =
ctrl->panel->link_info.num_lanes;
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   pixel_rate >>= 1;
}
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1876,7 +1878,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock;
 
-   if (dp_ctrl->wide_bus_en)
+   if (dp_ctrl->wide_bus_en || ctrl->panel->dp_mode.out_fmt_is_yuv_420)
pixel_rate >>= 1;
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1915,7 +1917,8 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
dp_catalog_ctrl_config_msa(ctrl->catalog,
ctrl->link->link_params.rate,
-   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
+   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl),
+   ctrl->panel->dp_mode.out_fmt_is_yuv_420);
 
dp_ctrl_setup_tr_unit(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 4b1b79b74bc72..3b7c3a7fd4993 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -934,6 +934,10 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = _display->panel->link_info;
 
+   if (drm_mode_is_420

[PATCH v4 14/19] drm/msm/dpu: add support of new peripheral flush mechanism

2024-02-16 Thread Paloma Arellano
From: Kuogee Hsieh 

Introduce a peripheral flushing mechanism to decouple peripheral
metadata flushing from timing engine related flush.

Changes in v2:
- Fixed some misalignment issues

Signed-off-by: Kuogee Hsieh 
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 17 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 10 ++
 2 files changed, 27 insertions(+)

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 e76565c3e6a43..a06f69d0b257d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -39,6 +39,7 @@
 #define   CTL_WB_FLUSH  0x108
 #define   CTL_INTF_FLUSH0x110
 #define   CTL_CDM_FLUSH0x114
+#define   CTL_PERIPH_FLUSH  0x128
 #define   CTL_INTF_MASTER   0x134
 #define   CTL_DSPP_n_FLUSH(n)   ((0x13C) + ((n) * 4))
 
@@ -49,6 +50,7 @@
 #define  MERGE_3D_IDX   23
 #define  DSC_IDX22
 #define CDM_IDX 26
+#define  PERIPH_IDX 30
 #define  INTF_IDX   31
 #define WB_IDX  16
 #define  DSPP_IDX   29  /* From DPU hw rev 7.x.x */
@@ -151,6 +153,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct 
dpu_hw_ctl *ctx)
ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
}
 
+   if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+   DPU_REG_WRITE(>hw, CTL_PERIPH_FLUSH,
+ ctx->pending_periph_flush_mask);
+
if (ctx->pending_flush_mask & BIT(DSC_IDX))
DPU_REG_WRITE(>hw, CTL_DSC_FLUSH,
  ctx->pending_dsc_flush_mask);
@@ -311,6 +317,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_v1(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)
 {
@@ -680,6 +693,10 @@ 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_v1;
+
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;
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 ff85b5ee0acf8..ef56280bea932 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -122,6 +122,15 @@ struct dpu_hw_ctl_ops {
void (*update_pending_flush_intf)(struct dpu_hw_ctl *ctx,
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
@@ -264,6 +273,7 @@ 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_dspp_flush_mask[DSPP_MAX - DSPP_0];
u32 pending_dsc_flush_mask;
-- 
2.39.2



[PATCH v4 16/19] drm/msm/dpu: modify encoder programming for CDM over DP

2024-02-16 Thread Paloma Arellano
Adjust the encoder format programming in the case of video mode for DP
to accommodate CDM related changes.

Changes in v4:
- Remove hw_cdm check in dpu_encoder_needs_periph_flush()
- Remove hw_cdm check when getting the fmt_fourcc in
  dpu_encoder_phys_vid_enable()

Changes in v2:
- Move timing engine programming to a separate patch from this
  one
- Move update_pending_flush_periph() invocation completely to
  this patch
- Change the logic of dpu_encoder_get_drm_fmt() so that it only
  calls drm_mode_is_420_only() instead of doing additional
  unnecessary checks
- Create new functions msm_dp_needs_periph_flush() and it's
  supporting function dpu_encoder_needs_periph_flush() to check
  if the mode is YUV420 and VSC SDP is enabled before doing a
  peripheral flush

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 35 +++
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  | 13 +++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  | 16 +
 drivers/gpu/drm/msm/dp/dp_display.c   | 18 ++
 drivers/gpu/drm/msm/msm_drv.h | 17 -
 5 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index b53a1b545742b..84778adc7f791 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -218,6 +218,41 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
 };
 
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct drm_display_info *info;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   info = _enc->connector->display_info;
+   mode = _enc->cached_mode;
+
+   if (drm_mode_is_420_only(info, mode))
+   return DRM_FORMAT_YUV420;
+
+   return DRM_FORMAT_RGB888;
+}
+
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct msm_display_info *disp_info;
+   struct msm_drm_private *priv;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   priv = drm_enc->dev->dev_private;
+   mode = _enc->cached_mode;
+
+   return phys_enc->hw_intf->cap->type == INTF_DP &&
+  
msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode);
+}
 
 bool dpu_encoder_is_widebus_enabled(const 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 f43d57d9c74e1..211a3d90eb690 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -341,6 +341,19 @@ static inline enum dpu_3d_blend_mode 
dpu_encoder_helper_get_3d_blend_mode(
  */
 unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_get_drm_fmt - return DRM fourcc format
+ * @phys_enc: Pointer to physical encoder structure
+ */
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
+
+/**
+ * dpu_encoder_needs_periph_flush - return true if physical encoder requires
+ * peripheral flush
+ * @phys_enc: Pointer to physical encoder structure
+ */
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc);
+
 /**
  * dpu_encoder_helper_split_config - split display configuration helper 
function
  * This helper function may be used by physical encoders to configure
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 f02411b062c4c..86c57c8b7e784 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
@@ -415,8 +415,12 @@ static int dpu_encoder_phys_vid_control_vblank_irq(
 static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
 {
struct dpu_hw_ctl *ctl;
+   const struct dpu_format *fmt;
+   u32 fmt_fourcc;
 
ctl = phys_enc->hw_ctl;
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+   fmt = dpu_get_dpu_format(fmt_fourcc);
 
DPU_DEBUG_VIDENC(phys_enc, "\n");
 
@@ -425,6 +429,8 @@ static void dpu_encoder_phys_vid_enable(struct 
dpu_encoder_phys *phys_enc)
 
dpu_encoder_helper_split_config(phys_enc, phys_enc->hw_intf->idx);
 
+   dpu_encoder_helper_phys_setup_cdm(phys_enc, fmt, CDM_CDWN_OUTPUT_HDMI);
+
dpu_encoder_p

[PATCH v4 15/19] drm/msm/dp: enable SDP and SDE periph flush update

2024-02-16 Thread Paloma Arellano
DP controller can be setup to operate in either SDP update flush mode or
peripheral flush mode based on the DP controller hardware version.

Starting in DP v1.2, the hardware documents require the use of
peripheral flush mode for SDP packets such as PPS OR VSC SDP packets.

In-line with this guidance, lets program the DP controller to use
peripheral flush mode starting DP v1.2

Changes in v4:
- Clear up that DP_MAINLINK_CTRL_FLUSH_MODE register requires
  the use of bits [24:23]
- Modify macros DP_MAINLINK_FLUSH_MODE_UPDATE_SDP and
  DP_MAINLINK_FLUSH_MODE_SDP_PERIPH_UPDATE to explicitly set
  their values in the bits of DP_MAINLINK_CTRL_FLUSH_MODE_MASK

Changes in v3:
- Clear up that the DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE
  macro is setting bits [24:23] to a value of 3

Changes in v2:
- Use the original dp_catalog_hw_revision() function to
  correctly check the DP HW version

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 17 +
 drivers/gpu/drm/msm/dp/dp_catalog.h |  1 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  1 +
 drivers/gpu/drm/msm/dp/dp_reg.h |  6 ++
 4 files changed, 25 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index c6e57812a239e..6619a20ffa923 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -440,6 +440,23 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
 }
 
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog)
+{
+   u32 mainlink_ctrl, hw_revision;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision >= DP_HW_VERSION_1_2)
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
+   else
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
+}
+
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
bool fixed_nvid, bool is_ycbcr_420)
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 4bdc087410a68..8ad0672157df8 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -98,6 +98,7 @@ 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_ctrl(struct dp_catalog *dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool 
enable);
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog);
 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,
u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index a42b29f9902c1..a17b9a22858da 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -165,6 +165,7 @@ static void dp_ctrl_configure_source_params(struct 
dp_ctrl_private *ctrl)
 
dp_catalog_ctrl_lane_mapping(ctrl->catalog);
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+   dp_catalog_setup_peripheral_flush(ctrl->catalog);
 
dp_ctrl_config_ctrl(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index aa9f6c3e4ddeb..3835c7f5cb984 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -6,6 +6,9 @@
 #ifndef _DP_REG_H_
 #define _DP_REG_H_
 
+#include 
+#include 
+
 /* DP_TX Registers */
 #define REG_DP_HW_VERSION  (0x)
 
@@ -102,6 +105,9 @@
 #define DP_MAINLINK_CTRL_ENABLE(0x0001)
 #define DP_MAINLINK_CTRL_RESET (0x0002)
 #define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER   (0x0010)
+#define DP_MAINLINK_CTRL_FLUSH_MODE_MASK   GENMASK(24, 23)
+#define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP  
FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 1)
+#define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE   
FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 3)
 #define DP_MAINLINK_FB_BOUNDARY_SEL(0x0200)
 
 #define REG_DP_STATE_CTRL  (0x0004)
-- 
2.39.2



[PATCH v4 09/19] drm/msm/dpu: move widebus logic to its own API

2024-02-16 Thread Paloma Arellano
Widebus enablement is decided by the interfaces based on their specific
checks and that already happens with DSI/DP specific helpers. Let's
invoke these helpers from dpu_encoder_is_widebus_enabled() to make it
cleaner overall.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 +++
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1905e8653b77a..b53a1b545742b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -221,9 +221,21 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
 
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
 {
-   const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+   const struct dpu_encoder_virt *dpu_enc;
+   struct msm_drm_private *priv = drm_enc->dev->dev_private;
+   const struct msm_display_info *disp_info;
+   int index;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   index = disp_info->h_tile_instance[0];
+
+   if (disp_info->intf_type == INTF_DP)
+   return msm_dp_wide_bus_available(priv->dp[index]);
+   else if (disp_info->intf_type == INTF_DSI)
+   return msm_dsi_wide_bus_enabled(priv->dsi[index]);
 
-   return dpu_enc->wide_bus_en;
+   return false;
 }
 
 bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc)
@@ -1195,26 +1207,17 @@ static void dpu_encoder_virt_atomic_enable(struct 
drm_encoder *drm_enc,
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
struct drm_display_mode *cur_mode = NULL;
-   struct msm_drm_private *priv = drm_enc->dev->dev_private;
-   struct msm_display_info *disp_info;
-   int index;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
-   disp_info = _enc->disp_info;
-   index = disp_info->h_tile_instance[0];
-
dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc);
 
atomic_set(_enc->frame_done_timeout_cnt, 0);
 
-   if (disp_info->intf_type == INTF_DP)
-   dpu_enc->wide_bus_en = 
msm_dp_wide_bus_available(priv->dp[index]);
-   else if (disp_info->intf_type == INTF_DSI)
-   dpu_enc->wide_bus_en = 
msm_dsi_wide_bus_enabled(priv->dsi[index]);
-
mutex_lock(_enc->enc_lock);
cur_mode = _enc->base.crtc->state->adjusted_mode;
 
+   dpu_enc->wide_bus_en = dpu_encoder_is_widebus_enabled(drm_enc);
+
trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
 cur_mode->vdisplay);
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index fe6b1d312a742..67aef59c1f99c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -156,6 +156,10 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
  */
 int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
 
+/**
+ * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled
+ * @drm_enc:Pointer to previously created drm encoder structure
+ */
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
 
 /**
-- 
2.39.2



[PATCH v4 10/19] drm/msm/dp: program config ctrl for YUV420 over DP

2024-02-16 Thread Paloma Arellano
Change relevant DP controller related programming for YUV420 cases.
Program the configuration control register to indicate YUV420.

Changes in v2:
- Create a new patch only for configuration control programming

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index fb588fde298a2..6692d81adb195 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -128,6 +128,9 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private 
*ctrl)
/* Default-> LSCLK DIV: 1/4 LCLK  */
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
 
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
+
/* Scrambler reset enable */
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
config |= DP_CONFIGURATION_CTRL_ASSR;
-- 
2.39.2



[PATCH v4 05/19] drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder

2024-02-16 Thread Paloma Arellano
Move dpu_encoder_helper_phys_setup_cdm to dpu_encoder in preparation for
implementing YUV420 over DP, which requires CDM compatibility.

Changes in v2:
- Slightly change the wording of the commit text to make clear
  that YUV over DP requires CDM

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 78 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  9 ++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 83 ---
 3 files changed, 87 insertions(+), 83 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 8932f38a41b2d..1905e8653b77a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2117,6 +2117,84 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
ctl->ops.clear_pending_flush(ctl);
 }
 
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output_type)
+{
+   struct dpu_hw_cdm *hw_cdm;
+   struct dpu_hw_cdm_cfg *cdm_cfg;
+   struct dpu_hw_pingpong *hw_pp;
+   int ret;
+
+   if (!phys_enc)
+   return;
+
+   cdm_cfg = _enc->cdm_cfg;
+   hw_pp = phys_enc->hw_pp;
+   hw_cdm = phys_enc->hw_cdm;
+
+   if (!hw_cdm)
+   return;
+
+   if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
+   DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", 
DRMID(phys_enc->parent),
+ dpu_fmt->base.pixel_format);
+   if (hw_cdm->ops.bind_pingpong_blk)
+   hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
+
+   return;
+   }
+
+   memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
+
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
+   cdm_cfg->output_fmt = dpu_fmt;
+   cdm_cfg->output_type = output_type;
+   cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
+   CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
+   cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
+
+   /* enable 10 bit logic */
+   switch (cdm_cfg->output_fmt->chroma_sample) {
+   case DPU_CHROMA_RGB:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_H2V1:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_420:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
+   break;
+   case DPU_CHROMA_H1V2:
+   default:
+   DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
+ DRMID(phys_enc->parent));
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   }
+
+   DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
+ DRMID(phys_enc->parent), cdm_cfg->output_width,
+ cdm_cfg->output_height, 
cdm_cfg->output_fmt->base.pixel_format,
+ cdm_cfg->output_type, cdm_cfg->output_bit_depth,
+ cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
+
+   if (hw_cdm->ops.enable) {
+   cdm_cfg->pp_id = hw_pp->idx;
+   ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
+   if (ret < 0) {
+   DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
+ DRMID(phys_enc->parent), ret);
+   return;
+   }
+   }
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int _dpu_encoder_status_show(struct seq_file *s, void *data)
 {
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 204d7cc3c1de8..f43d57d9c74e1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -381,6 +381,15 @@ int dpu_encoder_helper_wait_for_irq(struct 
dpu_encoder_phys *phys_enc,
  */
 void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
+ * @phys_enc: Pointer to physical encoder
+ * @output_type: HDMI/WB
+ */
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output

[PATCH v4 07/19] drm/msm/dp: store mode YUV420 information to be used by rest of DP

2024-02-16 Thread Paloma Arellano
Wide bus is not supported when the mode is YUV420 in DP. In preparation
for changing the DPU programming to reflect this, the value and
assignment location of wide_bus_en for the DP submodules must be
changed. Move it from boot time in dp_init_sub_modules() to run time in
dp_display_mode_set.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 17 +
 drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 792191f67717f..1a84f68e2b59a 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -785,10 +785,6 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
goto error_ctrl;
}
 
-   /* populate wide_bus_supported to different layers */
-   dp->ctrl->wide_bus_en = dp->wide_bus_supported;
-   dp->catalog->wide_bus_en = dp->wide_bus_supported;
-
return rc;
 
 error_ctrl:
@@ -809,6 +805,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
drm_mode_copy(>panel->dp_mode.drm_mode, >drm_mode);
dp->panel->dp_mode.bpp = mode->bpp;
dp->panel->dp_mode.capabilities = mode->capabilities;
+   dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
dp_panel_init_panel_info(dp->panel);
return 0;
 }
@@ -1403,6 +1400,9 @@ bool msm_dp_wide_bus_available(const struct msm_dp 
*dp_display)
 
dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+   if (dp->dp_mode.out_fmt_is_yuv_420)
+   return false;
+
return dp->wide_bus_supported;
 }
 
@@ -1616,6 +1616,15 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
 
dp_display->dp_mode.h_active_low =
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+
+   dp_display->dp_mode.out_fmt_is_yuv_420 =
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+
+   /* populate wide_bus_support to different layers */
+   dp_display->ctrl->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
+   dp_display->catalog->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
 }
 
 void dp_bridge_hpd_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index a0dfc579c5f9f..6ec68be9f2366 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -19,6 +19,7 @@ struct dp_display_mode {
u32 bpp;
u32 h_active_low;
u32 v_active_low;
+   bool out_fmt_is_yuv_420;
 };
 
 struct dp_panel_in {
-- 
2.39.2



[PATCH v4 04/19] drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP

2024-02-16 Thread Paloma Arellano
Generalize dpu_encoder_helper_phys_setup_cdm to be compatible with DP.

Changes in v2:
- Minor formatting changes
- Move the modification of the dimensions for CDM setup to a new
  patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  4 +--
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 27 ++-
 2 files changed, 16 insertions(+), 15 deletions(-)

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 993f263433314..204d7cc3c1de8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -154,6 +154,7 @@ enum dpu_intr_idx {
  * @hw_wb: Hardware interface to the wb registers
  * @hw_cdm:Hardware interface to the CDM registers
  * @dpu_kms:   Pointer to the dpu_kms top level
+ * @cdm_cfg:   CDM block config needed to store WB/DP block's CDM 
configuration
  * @cached_mode:   DRM mode cached at mode_set time, acted on in enable
  * @vblank_ctl_lock:   Vblank ctl mutex lock to protect vblank_refcount
  * @enabled:   Whether the encoder has enabled and running a mode
@@ -184,6 +185,7 @@ struct dpu_encoder_phys {
struct dpu_hw_wb *hw_wb;
struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms;
+   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role;
@@ -213,7 +215,6 @@ static inline int dpu_encoder_phys_inc_pending(struct 
dpu_encoder_phys *phys)
  * @wbirq_refcount: Reference count of writeback interrupt
  * @wb_done_timeout_cnt: number of wb done irq timeout errors
  * @wb_cfg:  writeback block config to store fb related details
- * @cdm_cfg: cdm block config needed to store writeback block's CDM 
configuration
  * @wb_conn: backpointer to writeback connector
  * @wb_job: backpointer to current writeback job
  * @dest:   dpu buffer layout for current writeback output buffer
@@ -223,7 +224,6 @@ struct dpu_encoder_phys_wb {
atomic_t wbirq_refcount;
int wb_done_timeout_cnt;
struct dpu_hw_wb_cfg wb_cfg;
-   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_writeback_connector *wb_conn;
struct drm_writeback_job *wb_job;
struct dpu_hw_fmt_layout dest;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index ec9e053d3947d..072fc6950e496 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -269,28 +269,21 @@ static void dpu_encoder_phys_wb_setup_ctl(struct 
dpu_encoder_phys *phys_enc)
  * This API does not handle 
DPU_CHROMA_H1V2.
  * @phys_enc:Pointer to physical encoder
  */
-static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc)
+static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc,
+ const struct dpu_format *dpu_fmt,
+ u32 output_type)
 {
struct dpu_hw_cdm *hw_cdm;
struct dpu_hw_cdm_cfg *cdm_cfg;
struct dpu_hw_pingpong *hw_pp;
-   struct dpu_encoder_phys_wb *wb_enc;
-   const struct msm_format *format;
-   const struct dpu_format *dpu_fmt;
-   struct drm_writeback_job *wb_job;
int ret;
 
if (!phys_enc)
return;
 
-   wb_enc = to_dpu_encoder_phys_wb(phys_enc);
-   cdm_cfg = _enc->cdm_cfg;
+   cdm_cfg = _enc->cdm_cfg;
hw_pp = phys_enc->hw_pp;
hw_cdm = phys_enc->hw_cdm;
-   wb_job = wb_enc->wb_job;
-
-   format = msm_framebuffer_format(wb_enc->wb_job->fb);
-   dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, 
wb_job->fb->modifier);
 
if (!hw_cdm)
return;
@@ -309,7 +302,7 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
-   cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
+   cdm_cfg->output_type = output_type;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
@@ -462,6 +455,14 @@ static void dpu_encoder_phys_wb_setup(
struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
struct drm_display_mode mode = phys_enc->cached_mode;
struct drm_framebuffer *fb = NULL;
+   struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+   struct drm_writeback_job *wb_job;
+   const stru

[PATCH v4 06/19] drm/msm/dp: rename wide_bus_en to wide_bus_supported

2024-02-16 Thread Paloma Arellano
Rename wide_bus_en to wide_bus_supported in dp_display_private to
correctly establish that the parameter is referencing if wide bus is
supported instead of enabled.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 42 ++---
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index c8e1bbebdffe2..792191f67717f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -114,7 +114,7 @@ struct dp_display_private {
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
 
-   bool wide_bus_en;
+   bool wide_bus_supported;
 
struct dp_audio *audio;
 };
@@ -123,7 +123,7 @@ struct msm_dp_desc {
phys_addr_t io_start;
unsigned int id;
unsigned int connector_type;
-   bool wide_bus_en;
+   bool wide_bus_supported;
 };
 
 static const struct msm_dp_desc sc7180_dp_descs[] = {
@@ -132,8 +132,8 @@ static const struct msm_dp_desc sc7180_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc7280_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
{}
 };
 
@@ -145,22 +145,22 @@ static const struct msm_dp_desc sc8180x_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc8280xp_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
{}
 };
 
 static const struct msm_dp_desc sc8280xp_edp_descs[] = {
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id

[PATCH v4 08/19] drm/msm/dp: check if VSC SDP is supported in DP programming

2024-02-16 Thread Paloma Arellano
In the DP driver, check if VSC SDP is supported and propagate this value
to dp_panel. In dp_display's dp_mode, the out_fmt_is_yuv_420 parameter
must also utilize this value since YUV420 is only allowed when VSC SDP
is supported.

Changes in v2:
- Move DP programming when VSC SDP is supported to this patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 5 -
 drivers/gpu/drm/msm/dp/dp_panel.c   | 1 +
 drivers/gpu/drm/msm/dp/dp_panel.h   | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 1a84f68e2b59a..4b1b79b74bc72 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1596,8 +1596,10 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
+   struct dp_panel *dp_panel;
 
dp_display = container_of(dp, struct dp_display_private, dp_display);
+   dp_panel = dp_display->panel;
 
memset(_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
 
@@ -1618,7 +1620,8 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
 
dp_display->dp_mode.out_fmt_is_yuv_420 =
-   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode) &&
+   dp_panel->vsc_sdp_supported;
 
/* populate wide_bus_support to different layers */
dp_display->ctrl->wide_bus_en =
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c 
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd1..db1942794f1a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -53,6 +53,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
if (rc)
return rc;
 
+   dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, 
dpcd);
link_info = _panel->link_info;
link_info->revision = dpcd[DP_DPCD_REV];
major = (link_info->revision >> 4) & 0x0f;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index 6ec68be9f2366..e843f5062d1f6 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -46,6 +46,7 @@ struct dp_panel {
struct dp_display_mode dp_mode;
struct dp_panel_psr psr_cap;
bool video_test;
+   bool vsc_sdp_supported;
 
u32 vic;
u32 max_dp_lanes;
-- 
2.39.2



[PATCH v4 03/19] drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup

2024-02-16 Thread Paloma Arellano
Modify the output width and height parameters of hw_cdm to utilize the
physical encoder's data instead of obtaining the information from the
framebuffer. CDM is to be set up to utilize the actual output data since
at CDM setup, there is no difference between the two sources.

Changes in v2:
- Move the modification of the dimensions for CDM setup to this
  new patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 4cd2d9e3131a4..ec9e053d3947d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -306,8 +306,8 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
 
memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
 
-   cdm_cfg->output_width = wb_job->fb->width;
-   cdm_cfg->output_height = wb_job->fb->height;
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
-- 
2.39.2



[PATCH v4 02/19] drm/msm/dpu: add division of drm_display_mode's hskew parameter

2024-02-16 Thread Paloma Arellano
Setting up the timing engine when the physical encoder has a split role
neglects dividing the drm_display_mode's hskew parameter. Let's fix this
since this must also be done in preparation for implementing YUV420 over
DP.

Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support")
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 6 --
 1 file changed, 4 insertions(+), 2 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 f562beb6f7971..f02411b062c4c 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
@@ -260,12 +260,14 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
mode.htotal >>= 1;
mode.hsync_start >>= 1;
mode.hsync_end >>= 1;
+   mode.hskew >>= 1;
 
DPU_DEBUG_VIDENC(phys_enc,
-   "split_role %d, halve horizontal %d %d %d %d\n",
+   "split_role %d, halve horizontal %d %d %d %d %d\n",
phys_enc->split_role,
mode.hdisplay, mode.htotal,
-   mode.hsync_start, mode.hsync_end);
+   mode.hsync_start, mode.hsync_end,
+   mode.hskew);
}
 
drm_mode_to_intf_timing_params(phys_enc, , _params);
-- 
2.39.2



[PATCH v4 00/19] Add support for CDM over DP

2024-02-16 Thread Paloma Arellano
The Chroma Down Sampling (CDM) block is a hardware component in the DPU
pipeline that includes a CSC block capable of converting RGB input from
the DPU to YUV data.

This block can be used with either HDMI, DP, or writeback interfaces.
This series adds support for the CDM block to be used with DP in
YUV420 mode format.

This series allows selection of the YUV420 format for monitors which support
certain resolutions only in YUV420 thus unblocking the validation of many
other resolutions which were previously filtered out if the connector did
not support YUV420.

This was validated using a DP connected monitor requiring the use of
YUV420 format.

This series is dependent on [1], [2], and [3]:
[1] https://patchwork.freedesktop.org/series/118831/
[2] https://patchwork.freedesktop.org/series/129395/
[3] https://patchwork.freedesktop.org/series/129864/

Changes in v4:
- Use dp_utils_pack_sdp_header() to pack the SDP header and
  parity bytes into a buffer
- Use this buffer when writing the VSC SDP data in
  dp_catalog_panel_send_vsc_sdp() and write to all the
  MMSS_DP_GENERIC0 registers
- Clear up that DP_MAINLINK_CTRL_FLUSH_MODE register requires
  the use of bits [24:23]
- Modify certain macros to explicitly set their values in the
  bits of DP_MAINLINK_CTRL_FLUSH_MODE_MASK
- Remove hw_cdm check in dpu_encoder_needs_periph_flush() and
  dpu_encoder_phys_vid_enable()

Changes in v3:
- Change ordering of the header byte macros in dp_utils.h
- Create a new struct, msm_dp_sdp_with_parity
- Utilize drm_dp_vsc_sdp_pack() from a new added dependency of
  series [3] to pack the VSC SDP data into the new
  msm_dp_sdp_with_parity struct instead of packing only for
  YUV420
- Modify dp_catalog_panel_send_vsc_sdp() so that it sends the VSC SDP 
data
  using the new msm_dp_sdp_with_parity struct
- Clear up that the DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE macro is 
setting
  multiple bits and not just one
- Move the connector's ycbcr_420_allowed parameter so it is no longer
  dependent on if the dp_display is not eDP

Changes in v2:
- Minor formatting changes throughout
- Move 'fixes' patch to the top
- Move VSC SDP support check API from dp_panel.c to drm_dp_helper.c
- Create a separate patch for modifying the dimensions for CDM setup to 
be
  non-WB specific
- Remove a patch that modified the INTF_CONFIG2 register in favor of 
having
  this series be dependent on [2]
- Separate configuration ctrl programming from clock related 
programming into
  two patches
- Add a VSC SDP check in dp_bridge_mode_valid()
- Move parity calculation functions to new files dp_utils.c and 
dp_utils.h
- Remove dp_catalog_hw_revision() changes and utilize the original 
version of
  the function when checking the DP hardware version
- Create separate packing and programming functions for the VSC SDP
- Make the packing header bytes function generic so it can be used with
  dp_audio.c
- Create two separate enable/disable VSC SDP functions instead of 
having one
  with the ability to do both
- Move timing engine programming to a separate patch from original 
encoder
  programming patch
- Move update_pending_flush_periph() code to be in the same patch as the
  encoder programming
- Create new API's to check if the dpu encoder needs a peripheral flush
- Allow YUV420 modes for the DP connector when there's a CDM block 
available
  instead of checking if VSC SDP is supported

Kuogee Hsieh (1):
  drm/msm/dpu: add support of new peripheral flush mechanism

Paloma Arellano (18):
  drm/msm/dpu: allow certain formats for CDM for DP
  drm/msm/dpu: add division of drm_display_mode's hskew parameter
  drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup
  drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP
  drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder
  drm/msm/dp: rename wide_bus_en to wide_bus_supported
  drm/msm/dp: store mode YUV420 information to be used by rest of DP
  drm/msm/dp: check if VSC SDP is supported in DP programming
  drm/msm/dpu: move widebus logic to its own API
  drm/msm/dp: program config ctrl for YUV420 over DP
  drm/msm/dp: change clock related programming for YUV420 over DP
  drm/msm/dp: move parity calculation to dp_utils
  drm/msm/dp: add VSC SDP support for YUV420 over DP
  drm/msm/dp: enable SDP and SDE periph flush update
  drm/msm/dpu: modify encoder programming for CDM over DP
  drm/msm/dpu: modify timing engine programming for YUV420 over DP
  drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420
  drm/msm/dp: allow YUV420 mode for DP connector when CDM available

 drivers/gpu/drm/msm/Makefile

Re: [PATCH v3 16/19] drm/msm/dpu: modify encoder programming for CDM over DP

2024-02-15 Thread Paloma Arellano



On 2/15/2024 7:47 AM, Abhinav Kumar wrote:



On 2/15/2024 12:45 AM, Dmitry Baryshkov wrote:
On Wed, 14 Feb 2024 at 20:04, Paloma Arellano 
 wrote:


Adjust the encoder format programming in the case of video mode for DP
to accommodate CDM related changes.

Changes in v2:
 - Move timing engine programming to a separate patch from this
   one
 - Move update_pending_flush_periph() invocation completely to
   this patch
 - Change the logic of dpu_encoder_get_drm_fmt() so that it 
only

   calls drm_mode_is_420_only() instead of doing additional
   unnecessary checks
 - Create new functions msm_dp_needs_periph_flush() and it's
   supporting function dpu_encoder_needs_periph_flush() to 
check

   if the mode is YUV420 and VSC SDP is enabled before doing a
   peripheral flush

Signed-off-by: Paloma Arellano 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 35 
+++

  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  | 13 +++
  .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  | 19 ++
  drivers/gpu/drm/msm/dp/dp_display.c   | 18 ++
  drivers/gpu/drm/msm/msm_drv.h | 17 -
  5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c

index 7e7796561009a..6280c6be6dca9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -222,6 +222,41 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
  };

+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct drm_display_info *info;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   info = _enc->connector->display_info;
+   mode = _enc->cached_mode;
+
+   if (drm_mode_is_420_only(info, mode))
+   return DRM_FORMAT_YUV420;
+
+   return DRM_FORMAT_RGB888;
+}
+
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct msm_display_info *disp_info;
+   struct msm_drm_private *priv;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   priv = drm_enc->dev->dev_private;
+   mode = _enc->cached_mode;
+
+   return phys_enc->hw_intf->cap->type == INTF_DP && 
phys_enc->hw_cdm &&
+ msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], 
mode);

+}

  bool dpu_encoder_is_widebus_enabled(const 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 f43d57d9c74e1..211a3d90eb690 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -341,6 +341,19 @@ static inline enum dpu_3d_blend_mode 
dpu_encoder_helper_get_3d_blend_mode(

   */
  unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys 
*phys_enc);


+/**
+ * dpu_encoder_get_drm_fmt - return DRM fourcc format
+ * @phys_enc: Pointer to physical encoder structure
+ */
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
+
+/**
+ * dpu_encoder_needs_periph_flush - return true if physical encoder 
requires

+ * peripheral flush
+ * @phys_enc: Pointer to physical encoder structure
+ */
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys 
*phys_enc);

+
  /**
   * dpu_encoder_helper_split_config - split display configuration 
helper function
   * This helper function may be used by physical encoders to 
configure
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 f02411b062c4c..e29bc4bd39208 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
@@ -415,8 +415,15 @@ static int 
dpu_encoder_phys_vid_control_vblank_irq(
  static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys 
*phys_enc)

  {
 struct dpu_hw_ctl *ctl;
+   struct dpu_hw_cdm *hw_cdm;
+   const struct dpu_format *fmt = NULL;
+   u32 fmt_fourcc = DRM_FORMAT_RGB888;

 ctl = phys_enc->hw_ctl;
+   hw_cdm = phys_enc->hw_cdm;
+   if (hw_cdm)


I thought that Abhinav proposed to drop the if(hw_cdm) condition here.
LGTM otherwise.



Yes I did.

This needs to be fixed in v4.



Ack, I must have forgotten to drop it, but I'll do it in the v4




+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+   fmt = 

[PATCH v3 16/19] drm/msm/dpu: modify encoder programming for CDM over DP

2024-02-14 Thread Paloma Arellano
Adjust the encoder format programming in the case of video mode for DP
to accommodate CDM related changes.

Changes in v2:
- Move timing engine programming to a separate patch from this
  one
- Move update_pending_flush_periph() invocation completely to
  this patch
- Change the logic of dpu_encoder_get_drm_fmt() so that it only
  calls drm_mode_is_420_only() instead of doing additional
  unnecessary checks
- Create new functions msm_dp_needs_periph_flush() and it's
  supporting function dpu_encoder_needs_periph_flush() to check
  if the mode is YUV420 and VSC SDP is enabled before doing a
  peripheral flush

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 35 +++
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  | 13 +++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  | 19 ++
 drivers/gpu/drm/msm/dp/dp_display.c   | 18 ++
 drivers/gpu/drm/msm/msm_drv.h | 17 -
 5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 7e7796561009a..6280c6be6dca9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -222,6 +222,41 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
 };
 
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct drm_display_info *info;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   info = _enc->connector->display_info;
+   mode = _enc->cached_mode;
+
+   if (drm_mode_is_420_only(info, mode))
+   return DRM_FORMAT_YUV420;
+
+   return DRM_FORMAT_RGB888;
+}
+
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct msm_display_info *disp_info;
+   struct msm_drm_private *priv;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   priv = drm_enc->dev->dev_private;
+   mode = _enc->cached_mode;
+
+   return phys_enc->hw_intf->cap->type == INTF_DP && phys_enc->hw_cdm &&
+  
msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode);
+}
 
 bool dpu_encoder_is_widebus_enabled(const 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 f43d57d9c74e1..211a3d90eb690 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -341,6 +341,19 @@ static inline enum dpu_3d_blend_mode 
dpu_encoder_helper_get_3d_blend_mode(
  */
 unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_get_drm_fmt - return DRM fourcc format
+ * @phys_enc: Pointer to physical encoder structure
+ */
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
+
+/**
+ * dpu_encoder_needs_periph_flush - return true if physical encoder requires
+ * peripheral flush
+ * @phys_enc: Pointer to physical encoder structure
+ */
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc);
+
 /**
  * dpu_encoder_helper_split_config - split display configuration helper 
function
  * This helper function may be used by physical encoders to configure
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 f02411b062c4c..e29bc4bd39208 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
@@ -415,8 +415,15 @@ static int dpu_encoder_phys_vid_control_vblank_irq(
 static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
 {
struct dpu_hw_ctl *ctl;
+   struct dpu_hw_cdm *hw_cdm;
+   const struct dpu_format *fmt = NULL;
+   u32 fmt_fourcc = DRM_FORMAT_RGB888;
 
ctl = phys_enc->hw_ctl;
+   hw_cdm = phys_enc->hw_cdm;
+   if (hw_cdm)
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+   fmt = dpu_get_dpu_format(fmt_fourcc);
 
DPU_DEBUG_VIDENC(phys_enc, "\n");
 
@@ -425,6 +432,8 @@ static void dpu_encoder_phys_vid_enable(struct 
dpu_encoder_phys *phys_enc)
 
dpu_encoder_helper_split_config(phys_enc, phys_enc->hw_intf->idx);
 
+   dpu_encoder_helper_phys_setup_cdm(phys_enc, fmt, CDM_CDWN_OUTPUT_HDMI);
+
dpu_encoder_ph

[PATCH v3 19/19] drm/msm/dp: allow YUV420 mode for DP connector when CDM available

2024-02-14 Thread Paloma Arellano
All the components of YUV420 over DP are added. Therefore, let's mark the
connector property as true for DP connector when the DP type is not eDP
and when there is a CDM block available.

Changes in v3:
- Move setting the connector's ycbcr_420_allowed parameter so
  that it is not dependent on if the dp_display is not eDP

Changes in v2:
- Check for if dp_catalog has a CDM block available instead of
  checking if VSC SDP is allowed when setting the dp connector's
  ycbcr_420_allowed parameter

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 +++-
 drivers/gpu/drm/msm/dp/dp_display.c | 4 ++--
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +-
 drivers/gpu/drm/msm/dp/dp_drm.h | 3 ++-
 drivers/gpu/drm/msm/msm_drv.h   | 5 +++--
 5 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 723cc1d821431..8d326fb36550a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -565,6 +565,7 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
 {
struct drm_encoder *encoder = NULL;
struct msm_display_info info;
+   bool yuv_supported;
int rc;
int i;
 
@@ -583,7 +584,8 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
return PTR_ERR(encoder);
}
 
-   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder);
+   yuv_supported = !!dpu_kms->catalog->cdm;
+   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder, 
yuv_supported);
if (rc) {
DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);
return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index ebcc76ef1d590..9b9f5f2921903 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1471,7 +1471,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 }
 
 int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
-   struct drm_encoder *encoder)
+   struct drm_encoder *encoder, bool yuv_supported)
 {
struct dp_display_private *dp_priv;
int ret;
@@ -1487,7 +1487,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return ret;
}
 
-   dp_display->connector = dp_drm_connector_init(dp_display, encoder);
+   dp_display->connector = dp_drm_connector_init(dp_display, encoder, 
yuv_supported);
if (IS_ERR(dp_display->connector)) {
ret = PTR_ERR(dp_display->connector);
DRM_DEV_ERROR(dev->dev,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 46e6889037e88..a819a4ff76a9f 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -353,7 +353,8 @@ int dp_bridge_init(struct msm_dp *dp_display, struct 
drm_device *dev,
 }
 
 /* connector initialization */
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder)
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported)
 {
struct drm_connector *connector = NULL;
 
@@ -364,6 +365,9 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
if (!dp_display->is_edp)
drm_connector_attach_dp_subconnector_property(connector);
 
+   if (yuv_supported)
+   connector->ycbcr_420_allowed = true;
+
drm_connector_attach_encoder(connector, encoder);
 
return connector;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index b3d684db2383b..45e57ac25a4d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -19,7 +19,8 @@ struct msm_dp_bridge {
 
 #define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
 
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder);
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported);
 int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder);
 
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b876ebd48effe..37335777f5c09 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -385,7 +385,7 @@ static inline struct drm_dsc_config 
*msm_dsi_get_dsc_config(struct msm_dsi *msm_
 int __init msm_dp_register(void);
 void __exit msm_dp_unregi

[PATCH v3 15/19] drm/msm/dp: enable SDP and SDE periph flush update

2024-02-14 Thread Paloma Arellano
DP controller can be setup to operate in either SDP update flush mode or
peripheral flush mode based on the DP controller hardware version.

Starting in DP v1.2, the hardware documents require the use of
peripheral flush mode for SDP packets such as PPS OR VSC SDP packets.

In-line with this guidance, lets program the DP controller to use
peripheral flush mode starting DP v1.2

Changes in v3:
- Clear up that the DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE
  macro is setting bits [24:23] to a value of 3

Changes in v2:
- Use the original dp_catalog_hw_revision() function to
  correctly check the DP HW version

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 17 +
 drivers/gpu/drm/msm/dp/dp_catalog.h |  1 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  1 +
 drivers/gpu/drm/msm/dp/dp_reg.h |  5 +
 4 files changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 61d5317efe683..823eeba7e71d3 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -440,6 +440,23 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
 }
 
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog)
+{
+   u32 mainlink_ctrl, hw_revision;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision >= DP_HW_VERSION_1_2)
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
+   else
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
+}
+
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
bool fixed_nvid, bool is_ycbcr_420)
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 4bf08c27a9bf3..eb05a37837beb 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -98,6 +98,7 @@ 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_ctrl(struct dp_catalog *dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool 
enable);
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog);
 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,
u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index beef86b1aaf81..f1e7b0a5ee5d1 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -170,6 +170,7 @@ static void dp_ctrl_configure_source_params(struct 
dp_ctrl_private *ctrl)
 
dp_catalog_ctrl_lane_mapping(ctrl->catalog);
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+   dp_catalog_setup_peripheral_flush(ctrl->catalog);
 
dp_ctrl_config_ctrl(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 2983756c125cd..d4fb8572cd1e4 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -6,6 +6,9 @@
 #ifndef _DP_REG_H_
 #define _DP_REG_H_
 
+#include 
+#include 
+
 /* DP_TX Registers */
 #define REG_DP_HW_VERSION  (0x)
 
@@ -102,6 +105,8 @@
 #define DP_MAINLINK_CTRL_ENABLE(0x0001)
 #define DP_MAINLINK_CTRL_RESET (0x0002)
 #define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER   (0x0010)
+#define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP  (0x0080)
+#define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE   FIELD_PREP(GENMASK(24, 
23), 3)
 #define DP_MAINLINK_FB_BOUNDARY_SEL(0x0200)
 
 #define REG_DP_STATE_CTRL  (0x0004)
-- 
2.39.2



[PATCH v3 18/19] drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420

2024-02-14 Thread Paloma Arellano
Reserve CDM blocks for DP if the mode format is YUV420. Currently this
reservation only works for writeback and DP if the format is YUV420. But
this can be easily extented to other YUV formats for DP.

Changes in v2:
- Minor code simplification

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 +
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 6280c6be6dca9..ec53e5f4a696d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -639,6 +639,7 @@ static int dpu_encoder_virt_atomic_check(
struct dpu_kms *dpu_kms;
struct drm_display_mode *adj_mode;
struct msm_display_topology topology;
+   struct msm_display_info *disp_info;
struct dpu_global_state *global_state;
struct drm_framebuffer *fb;
struct drm_dsc_config *dsc;
@@ -655,6 +656,7 @@ static int dpu_encoder_virt_atomic_check(
DPU_DEBUG_ENC(dpu_enc, "\n");
 
priv = drm_enc->dev->dev_private;
+   disp_info = _enc->disp_info;
dpu_kms = to_dpu_kms(priv->kms);
adj_mode = _state->adjusted_mode;
global_state = dpu_kms_get_global_state(crtc_state->state);
@@ -682,21 +684,24 @@ static int dpu_encoder_virt_atomic_check(
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, 
crtc_state, dsc);
 
/*
-* Use CDM only for writeback at the moment as other interfaces cannot 
handle it.
-* if writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
+* Use CDM only for writeback or DP at the moment as other interfaces 
cannot handle it.
+* If writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
 * earlier.
 */
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
fb = conn_state->writeback_job->fb;
 
if (fb && 
DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb
topology.needs_cdm = true;
-   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
-   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
+   } else if (disp_info->intf_type == INTF_DP) {
+   if 
(msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
+   topology.needs_cdm = true;
}
 
+   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
+   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
/*
 * Release and Allocate resources on every modeset
 * Dont allocate when active is false.
@@ -1137,7 +1142,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct 
drm_encoder *drm_enc,
 
dpu_enc->dsc_mask = dsc_mask;
 
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if ((dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) ||
+   dpu_enc->disp_info.intf_type == INTF_DP) {
struct dpu_hw_blk *hw_cdm = NULL;
 
dpu_rm_get_assigned_resources(_kms->rm, global_state,
-- 
2.39.2



[PATCH v3 17/19] drm/msm/dpu: modify timing engine programming for YUV420 over DP

2024-02-14 Thread Paloma Arellano
Adjust the encoder timing engine setup programming in the case of video
mode for YUV420 over DP to accommodate CDM.

Changes in v3:
- Move drm_display_mode's hskew division to another patch
- Minor cleanup

Changes in v2:
- Move timing engine programming to this patch

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 8 ++--
 1 file changed, 6 insertions(+), 2 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 e29bc4bd39208..04df501d23bfa 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
@@ -236,7 +236,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
struct drm_display_mode mode;
struct dpu_hw_intf_timing_params timing_params = { 0 };
const struct dpu_format *fmt = NULL;
-   u32 fmt_fourcc = DRM_FORMAT_RGB888;
+   u32 fmt_fourcc;
unsigned long lock_flags;
struct dpu_hw_intf_cfg intf_cfg = { 0 };
 
@@ -255,7 +255,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
drm_mode_debug_printmodeline();
 
-   if (phys_enc->split_role != ENC_ROLE_SOLO) {
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+
+   if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == 
DRM_FORMAT_YUV420) {
mode.hdisplay >>= 1;
mode.htotal >>= 1;
mode.hsync_start >>= 1;
@@ -275,6 +277,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
fmt = dpu_get_dpu_format(fmt_fourcc);
DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);
 
+   if (phys_enc->hw_cdm)
+   intf_cfg.cdm = phys_enc->hw_cdm->idx;
intf_cfg.intf = phys_enc->hw_intf->idx;
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
-- 
2.39.2



[PATCH v3 10/19] drm/msm/dp: program config ctrl for YUV420 over DP

2024-02-14 Thread Paloma Arellano
Change relevant DP controller related programming for YUV420 cases.
Program the configuration control register to indicate YUV420.

Changes in v2:
- Create a new patch only for configuration control programming

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 77a8d9366ed7b..da8f0d9f98718 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -128,6 +128,9 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private 
*ctrl)
/* Default-> LSCLK DIV: 1/4 LCLK  */
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
 
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
+
/* Scrambler reset enable */
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
config |= DP_CONFIGURATION_CTRL_ASSR;
-- 
2.39.2



[PATCH v3 14/19] drm/msm/dpu: add support of new peripheral flush mechanism

2024-02-14 Thread Paloma Arellano
From: Kuogee Hsieh 

Introduce a peripheral flushing mechanism to decouple peripheral
metadata flushing from timing engine related flush.

Changes in v2:
- Fixed some misalignment issues

Signed-off-by: Kuogee Hsieh 
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 17 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 10 ++
 2 files changed, 27 insertions(+)

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 e76565c3e6a43..a06f69d0b257d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -39,6 +39,7 @@
 #define   CTL_WB_FLUSH  0x108
 #define   CTL_INTF_FLUSH0x110
 #define   CTL_CDM_FLUSH0x114
+#define   CTL_PERIPH_FLUSH  0x128
 #define   CTL_INTF_MASTER   0x134
 #define   CTL_DSPP_n_FLUSH(n)   ((0x13C) + ((n) * 4))
 
@@ -49,6 +50,7 @@
 #define  MERGE_3D_IDX   23
 #define  DSC_IDX22
 #define CDM_IDX 26
+#define  PERIPH_IDX 30
 #define  INTF_IDX   31
 #define WB_IDX  16
 #define  DSPP_IDX   29  /* From DPU hw rev 7.x.x */
@@ -151,6 +153,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct 
dpu_hw_ctl *ctx)
ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
}
 
+   if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+   DPU_REG_WRITE(>hw, CTL_PERIPH_FLUSH,
+ ctx->pending_periph_flush_mask);
+
if (ctx->pending_flush_mask & BIT(DSC_IDX))
DPU_REG_WRITE(>hw, CTL_DSC_FLUSH,
  ctx->pending_dsc_flush_mask);
@@ -311,6 +317,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_v1(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)
 {
@@ -680,6 +693,10 @@ 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_v1;
+
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;
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 ff85b5ee0acf8..ef56280bea932 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -122,6 +122,15 @@ struct dpu_hw_ctl_ops {
void (*update_pending_flush_intf)(struct dpu_hw_ctl *ctx,
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
@@ -264,6 +273,7 @@ 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_dspp_flush_mask[DSPP_MAX - DSPP_0];
u32 pending_dsc_flush_mask;
-- 
2.39.2



[PATCH v3 08/19] drm/msm/dp: check if VSC SDP is supported in DP programming

2024-02-14 Thread Paloma Arellano
In the DP driver, check if VSC SDP is supported and propagate this value
to dp_panel. In dp_display's dp_mode, the out_fmt_is_yuv_420 parameter
must also utilize this value since YUV420 is only allowed when VSC SDP
is supported.

Changes in v2:
- Move DP programming when VSC SDP is supported to this patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 5 -
 drivers/gpu/drm/msm/dp/dp_panel.c   | 1 +
 drivers/gpu/drm/msm/dp/dp_panel.h   | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index ddac55f45a722..6323dc08d5eb8 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1595,8 +1595,10 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
+   struct dp_panel *dp_panel;
 
dp_display = container_of(dp, struct dp_display_private, dp_display);
+   dp_panel = dp_display->panel;
 
memset(_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
 
@@ -1617,7 +1619,8 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
 
dp_display->dp_mode.out_fmt_is_yuv_420 =
-   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode) &&
+   dp_panel->vsc_sdp_supported;
 
/* populate wide_bus_support to different layers */
dp_display->ctrl->wide_bus_en =
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c 
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd1..db1942794f1a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -53,6 +53,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
if (rc)
return rc;
 
+   dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, 
dpcd);
link_info = _panel->link_info;
link_info->revision = dpcd[DP_DPCD_REV];
major = (link_info->revision >> 4) & 0x0f;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index 6ec68be9f2366..e843f5062d1f6 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -46,6 +46,7 @@ struct dp_panel {
struct dp_display_mode dp_mode;
struct dp_panel_psr psr_cap;
bool video_test;
+   bool vsc_sdp_supported;
 
u32 vic;
u32 max_dp_lanes;
-- 
2.39.2



[PATCH v3 01/19] drm/msm/dpu: allow certain formats for CDM for DP

2024-02-14 Thread Paloma Arellano
CDM block supports formats other than H1V2 for DP. Since we are now
adding support for CDM over DP, relax the checks to allow all other
formats for DP other than H1V2.

Changes in v2:
- Add fixes tag
- Move patch to top of series

Fixes: 0afac0ba6024 ("drm/msm/dpu: add dpu_hw_cdm abstraction for CDM block")
Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
index e9cdc7934a499..9016b3ade6bc3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct 
dpu_hw_cdm_cfg *cdm)
dpu_hw_cdm_setup_cdwn(ctx, cdm);
 
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
-   if (fmt->chroma_sample != DPU_CHROMA_H1V2)
+   if (fmt->chroma_sample == DPU_CHROMA_H1V2)
return -EINVAL; /*unsupported format */
opmode = CDM_HDMI_PACK_OP_MODE_EN;
opmode |= (fmt->chroma_sample << 1);
-- 
2.39.2



[PATCH v3 11/19] drm/msm/dp: change clock related programming for YUV420 over DP

2024-02-14 Thread Paloma Arellano
Change all relevant DP controller related programming for YUV420 cases.
Namely, change the pixel clock math to consider YUV420 and modify the
MVID programming to consider YUV420.

Changes in v2:
- Move configuration control programming to a different commit
- Slight code simplification
- Add VSC SDP check when doing mode_pclk_khz division in
  dp_bridge_mode_valid

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 5 -
 drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 9 ++---
 drivers/gpu/drm/msm/dp/dp_display.c | 4 
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5142aeb705a44..5d84c089e520a 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -442,7 +442,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
 
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
-   bool fixed_nvid)
+   bool fixed_nvid, bool is_ycbcr_420)
 {
u32 pixel_m, pixel_n;
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
@@ -485,6 +485,9 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog 
*dp_catalog,
nvid = temp;
}
 
+   if (is_ycbcr_420)
+   mvid /= 2;
+
if (link_rate_hbr2 == rate)
nvid *= 2;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 38786e855b51a..6cb5e2a243de2 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -96,7 +96,7 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog 
*dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(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,
-   u32 stream_rate_khz, bool fixed_nvid);
+   u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
 int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 
pattern);
 u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index da8f0d9f98718..209cf2a35642f 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -960,7 +960,7 @@ static void dp_ctrl_calc_tu_parameters(struct 
dp_ctrl_private *ctrl,
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
in.nlanes = ctrl->link->link_params.num_lanes;
in.bpp = ctrl->panel->dp_mode.bpp;
-   in.pixel_enc = 444;
+   in.pixel_enc = ctrl->panel->dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
in.dsc_en = 0;
in.async_en = 0;
in.fec_en = 0;
@@ -1766,6 +1766,8 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
ctrl->link->link_params.rate = rate;
ctrl->link->link_params.num_lanes =
ctrl->panel->link_info.num_lanes;
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   pixel_rate >>= 1;
}
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1881,7 +1883,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock;
 
-   if (dp_ctrl->wide_bus_en)
+   if (dp_ctrl->wide_bus_en || ctrl->panel->dp_mode.out_fmt_is_yuv_420)
pixel_rate >>= 1;
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1920,7 +1922,8 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
dp_catalog_ctrl_config_msa(ctrl->catalog,
ctrl->link->link_params.rate,
-   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
+   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl),
+   ctrl->panel->dp_mode.out_fmt_is_yuv_420);
 
dp_ctrl_setup_tr_unit(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 6323dc08d5eb8..4b04388719363 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -933,6 +933,10 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = _display->panel->link_info;
 
+   if (drm_mode_is_420

[PATCH v3 09/19] drm/msm/dpu: move widebus logic to its own API

2024-02-14 Thread Paloma Arellano
Widebus enablement is decided by the interfaces based on their specific
checks and that already happens with DSI/DP specific helpers. Let's
invoke these helpers from dpu_encoder_is_widebus_enabled() to make it
cleaner overall.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 +++
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 3c55d6290b708..7e7796561009a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -225,9 +225,21 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
 
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
 {
-   const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+   const struct dpu_encoder_virt *dpu_enc;
+   struct msm_drm_private *priv = drm_enc->dev->dev_private;
+   const struct msm_display_info *disp_info;
+   int index;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   index = disp_info->h_tile_instance[0];
+
+   if (disp_info->intf_type == INTF_DP)
+   return msm_dp_wide_bus_available(priv->dp[index]);
+   else if (disp_info->intf_type == INTF_DSI)
+   return msm_dsi_wide_bus_enabled(priv->dsi[index]);
 
-   return dpu_enc->wide_bus_en;
+   return false;
 }
 
 bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc)
@@ -1199,26 +1211,17 @@ static void dpu_encoder_virt_atomic_enable(struct 
drm_encoder *drm_enc,
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
struct drm_display_mode *cur_mode = NULL;
-   struct msm_drm_private *priv = drm_enc->dev->dev_private;
-   struct msm_display_info *disp_info;
-   int index;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
-   disp_info = _enc->disp_info;
-   index = disp_info->h_tile_instance[0];
-
dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc);
 
atomic_set(_enc->frame_done_timeout_cnt, 0);
 
-   if (disp_info->intf_type == INTF_DP)
-   dpu_enc->wide_bus_en = 
msm_dp_wide_bus_available(priv->dp[index]);
-   else if (disp_info->intf_type == INTF_DSI)
-   dpu_enc->wide_bus_en = 
msm_dsi_wide_bus_enabled(priv->dsi[index]);
-
mutex_lock(_enc->enc_lock);
cur_mode = _enc->base.crtc->state->adjusted_mode;
 
+   dpu_enc->wide_bus_en = dpu_encoder_is_widebus_enabled(drm_enc);
+
trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
 cur_mode->vdisplay);
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index fe6b1d312a742..67aef59c1f99c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -156,6 +156,10 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
  */
 int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
 
+/**
+ * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled
+ * @drm_enc:Pointer to previously created drm encoder structure
+ */
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
 
 /**
-- 
2.39.2



[PATCH v3 04/19] drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP

2024-02-14 Thread Paloma Arellano
Generalize dpu_encoder_helper_phys_setup_cdm to be compatible with DP.

Changes in v2:
- Minor formatting changes
- Move the modification of the dimensions for CDM setup to a new
  patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  4 +--
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 27 ++-
 2 files changed, 16 insertions(+), 15 deletions(-)

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 993f263433314..204d7cc3c1de8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -154,6 +154,7 @@ enum dpu_intr_idx {
  * @hw_wb: Hardware interface to the wb registers
  * @hw_cdm:Hardware interface to the CDM registers
  * @dpu_kms:   Pointer to the dpu_kms top level
+ * @cdm_cfg:   CDM block config needed to store WB/DP block's CDM 
configuration
  * @cached_mode:   DRM mode cached at mode_set time, acted on in enable
  * @vblank_ctl_lock:   Vblank ctl mutex lock to protect vblank_refcount
  * @enabled:   Whether the encoder has enabled and running a mode
@@ -184,6 +185,7 @@ struct dpu_encoder_phys {
struct dpu_hw_wb *hw_wb;
struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms;
+   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role;
@@ -213,7 +215,6 @@ static inline int dpu_encoder_phys_inc_pending(struct 
dpu_encoder_phys *phys)
  * @wbirq_refcount: Reference count of writeback interrupt
  * @wb_done_timeout_cnt: number of wb done irq timeout errors
  * @wb_cfg:  writeback block config to store fb related details
- * @cdm_cfg: cdm block config needed to store writeback block's CDM 
configuration
  * @wb_conn: backpointer to writeback connector
  * @wb_job: backpointer to current writeback job
  * @dest:   dpu buffer layout for current writeback output buffer
@@ -223,7 +224,6 @@ struct dpu_encoder_phys_wb {
atomic_t wbirq_refcount;
int wb_done_timeout_cnt;
struct dpu_hw_wb_cfg wb_cfg;
-   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_writeback_connector *wb_conn;
struct drm_writeback_job *wb_job;
struct dpu_hw_fmt_layout dest;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index ec9e053d3947d..072fc6950e496 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -269,28 +269,21 @@ static void dpu_encoder_phys_wb_setup_ctl(struct 
dpu_encoder_phys *phys_enc)
  * This API does not handle 
DPU_CHROMA_H1V2.
  * @phys_enc:Pointer to physical encoder
  */
-static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc)
+static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc,
+ const struct dpu_format *dpu_fmt,
+ u32 output_type)
 {
struct dpu_hw_cdm *hw_cdm;
struct dpu_hw_cdm_cfg *cdm_cfg;
struct dpu_hw_pingpong *hw_pp;
-   struct dpu_encoder_phys_wb *wb_enc;
-   const struct msm_format *format;
-   const struct dpu_format *dpu_fmt;
-   struct drm_writeback_job *wb_job;
int ret;
 
if (!phys_enc)
return;
 
-   wb_enc = to_dpu_encoder_phys_wb(phys_enc);
-   cdm_cfg = _enc->cdm_cfg;
+   cdm_cfg = _enc->cdm_cfg;
hw_pp = phys_enc->hw_pp;
hw_cdm = phys_enc->hw_cdm;
-   wb_job = wb_enc->wb_job;
-
-   format = msm_framebuffer_format(wb_enc->wb_job->fb);
-   dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, 
wb_job->fb->modifier);
 
if (!hw_cdm)
return;
@@ -309,7 +302,7 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
-   cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
+   cdm_cfg->output_type = output_type;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
@@ -462,6 +455,14 @@ static void dpu_encoder_phys_wb_setup(
struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
struct drm_display_mode mode = phys_enc->cached_mode;
struct drm_framebuffer *fb = NULL;
+   struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+   struct drm_writeback_job *wb_job;
+   const stru

[PATCH v3 05/19] drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder

2024-02-14 Thread Paloma Arellano
Move dpu_encoder_helper_phys_setup_cdm to dpu_encoder in preparation for
implementing YUV420 over DP, which requires CDM compatibility.

Changes in v2:
- Slightly change the wording of the commit text to make clear
  that YUV over DP requires CDM

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 78 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  9 ++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 83 ---
 3 files changed, 87 insertions(+), 83 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 467f874979d5c..3c55d6290b708 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2121,6 +2121,84 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
ctl->ops.clear_pending_flush(ctl);
 }
 
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output_type)
+{
+   struct dpu_hw_cdm *hw_cdm;
+   struct dpu_hw_cdm_cfg *cdm_cfg;
+   struct dpu_hw_pingpong *hw_pp;
+   int ret;
+
+   if (!phys_enc)
+   return;
+
+   cdm_cfg = _enc->cdm_cfg;
+   hw_pp = phys_enc->hw_pp;
+   hw_cdm = phys_enc->hw_cdm;
+
+   if (!hw_cdm)
+   return;
+
+   if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
+   DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", 
DRMID(phys_enc->parent),
+ dpu_fmt->base.pixel_format);
+   if (hw_cdm->ops.bind_pingpong_blk)
+   hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
+
+   return;
+   }
+
+   memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
+
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
+   cdm_cfg->output_fmt = dpu_fmt;
+   cdm_cfg->output_type = output_type;
+   cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
+   CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
+   cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
+
+   /* enable 10 bit logic */
+   switch (cdm_cfg->output_fmt->chroma_sample) {
+   case DPU_CHROMA_RGB:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_H2V1:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_420:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
+   break;
+   case DPU_CHROMA_H1V2:
+   default:
+   DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
+ DRMID(phys_enc->parent));
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   }
+
+   DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
+ DRMID(phys_enc->parent), cdm_cfg->output_width,
+ cdm_cfg->output_height, 
cdm_cfg->output_fmt->base.pixel_format,
+ cdm_cfg->output_type, cdm_cfg->output_bit_depth,
+ cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
+
+   if (hw_cdm->ops.enable) {
+   cdm_cfg->pp_id = hw_pp->idx;
+   ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
+   if (ret < 0) {
+   DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
+ DRMID(phys_enc->parent), ret);
+   return;
+   }
+   }
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int _dpu_encoder_status_show(struct seq_file *s, void *data)
 {
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 204d7cc3c1de8..f43d57d9c74e1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -381,6 +381,15 @@ int dpu_encoder_helper_wait_for_irq(struct 
dpu_encoder_phys *phys_enc,
  */
 void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
+ * @phys_enc: Pointer to physical encoder
+ * @output_type: HDMI/WB
+ */
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output

[PATCH v3 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-14 Thread Paloma Arellano
Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v3:
- Create a new struct, msm_dp_sdp_with_parity, which holds the
  packing information for VSC SDP
- Use drm_dp_vsc_sdp_pack() to pack the data into the new
  msm_dp_sdp_with_parity struct instead of specifically packing
  for YUV420 format
- Modify dp_catalog_panel_send_vsc_sdp() to send the VSC SDP
  data using the new msm_dp_sdp_with_parity struct

Changes in v2:
- Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
- Remove dp_sdp from the dp_catalog struct since this data is
  being allocated at the point used
- Create a new function in dp_utils to pack the VSC SDP data
  into a buffer
- Create a new function that packs the SDP header bytes into a
  buffer. This function is made generic so that it can be
  utilized by dp_audio
  header bytes into a buffer
- Create a new function in dp_utils that takes the packed buffer
  and writes to the DP_GENERIC0_* registers
- Split the dp_catalog_panel_config_vsc_sdp() function into two
  to disable/enable sending VSC SDP packets
- Check the DP HW version using the original useage of
  dp_catalog_hw_revision() and correct the version checking
  logic
- Rename dp_panel_setup_vsc_sdp() to
  dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
  currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 113 
 drivers/gpu/drm/msm/dp/dp_catalog.h |   7 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|   4 +
 drivers/gpu/drm/msm/dp/dp_panel.c   |  55 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |   3 +
 drivers/gpu/drm/msm/dp/dp_utils.c   |  48 
 drivers/gpu/drm/msm/dp/dp_utils.h   |  18 +
 7 files changed, 248 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..61d5317efe683 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,119 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
return 0;
 }
 
+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog,
+ struct msm_dp_sdp_with_parity 
*msm_dp_sdp)
+{
+   struct dp_catalog_private *catalog;
+   u32 val;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   val = ((msm_dp_sdp->vsc_sdp.sdp_header.HB0) << HEADER_BYTE_0_BIT |
+  (msm_dp_sdp->pb.PB0 << PARITY_BYTE_0_BIT) |
+  (msm_dp_sdp->vsc_sdp.sdp_header.HB1) << HEADER_BYTE_1_BIT |
+  (msm_dp_sdp->pb.PB1 << PARITY_BYTE_1_BIT));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, val);
+
+   val = ((msm_dp_sdp->vsc_sdp.sdp_header.HB2) << HEADER_BYTE_2_BIT |
+  (msm_dp_sdp->pb.PB2 << PARITY_BYTE_2_BIT) |
+  (msm_dp_sdp->vsc_sdp.sdp_header.HB3) << HEADER_BYTE_3_BIT |
+  (msm_dp_sdp->pb.PB3 << PARITY_BYTE_3_BIT));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, val);
+
+   val = ((msm_dp_sdp->vsc_sdp.db[16]) | (msm_dp_sdp->vsc_sdp.db[17] << 8) 
|
+  (msm_dp_sdp->vsc_sdp.db[18] << 16));
+   dp_write_link(catalog, MMSS_DP_GENERIC0_6, val);
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+   }
+}
+
+void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog,
+struct msm_dp_sdp_with_parity *msm_dp_sdp)
+{
+   struct dp_catalog_private *catalog;
+   u32 cfg, cfg2, misc;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
+   cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
+   misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
+
+   cfg |= GEN0_SDP_EN;
+   dp_write_link(

[PATCH v3 00/19] Add support for CDM over DP

2024-02-14 Thread Paloma Arellano
The Chroma Down Sampling (CDM) block is a hardware component in the DPU
pipeline that includes a CSC block capable of converting RGB input from
the DPU to YUV data.

This block can be used with either HDMI, DP, or writeback interfaces.
This series adds support for the CDM block to be used with DP in
YUV420 mode format.

This series allows selection of the YUV420 format for monitors which support
certain resolutions only in YUV420 thus unblocking the validation of many
other resolutions which were previously filtered out if the connector did
not support YUV420.

This was validated using a DP connected monitor requiring the use of
YUV420 format.

This series is dependent on [1], [2], and [3]:
[1] https://patchwork.freedesktop.org/series/118831/
[2] https://patchwork.freedesktop.org/series/129395/
[3] https://patchwork.freedesktop.org/series/129864/

Changes in v3:
- Change ordering of the header byte macros in dp_utils.h
- Create a new struct, msm_dp_sdp_with_parity
- Utilize drm_dp_vsc_sdp_pack() from a new added dependency of
  series [3] to pack the VSC SDP data into the new
  msm_dp_sdp_with_parity struct instead of packing only for
  YUV420
- Modify dp_catalog_panel_send_vsc_sdp() so that it sends the VSC SDP 
data
  using the new msm_dp_sdp_with_parity struct
- Clear up that the DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE macro is 
setting
  multiple bits and not just one
- Move the connector's ycbcr_420_allowed parameter so it is no longer
  dependent on if the dp_display is not eDP

Changes in v2:
- Minor formatting changes throughout
- Move 'fixes' patch to the top
- Move VSC SDP support check API from dp_panel.c to drm_dp_helper.c
- Create a separate patch for modifying the dimensions for CDM setup to 
be
  non-WB specific
- Remove a patch that modified the INTF_CONFIG2 register in favor of 
having
  this series be dependent on [2]
- Separate configuration ctrl programming from clock related 
programming into
  two patches
- Add a VSC SDP check in dp_bridge_mode_valid()
- Move parity calculation functions to new files dp_utils.c and 
dp_utils.h
- Remove dp_catalog_hw_revision() changes and utilize the original 
version of
  the function when checking the DP hardware version
- Create separate packing and programming functions for the VSC SDP
- Make the packing header bytes function generic so it can be used with
  dp_audio.c
- Create two separate enable/disable VSC SDP functions instead of 
having one
  with the ability to do both
- Move timing engine programming to a separate patch from original 
encoder
  programming patch
- Move update_pending_flush_periph() code to be in the same patch as the
  encoder programming
- Create new API's to check if the dpu encoder needs a peripheral flush
- Allow YUV420 modes for the DP connector when there's a CDM block 
available
  instead of checking if VSC SDP is supported

Kuogee Hsieh (1):
  drm/msm/dpu: add support of new peripheral flush mechanism

Paloma Arellano (18):
  drm/msm/dpu: allow certain formats for CDM for DP
  drm/msm/dpu: add division of drm_display_mode's hskew parameter
  drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup
  drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP
  drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder
  drm/msm/dp: rename wide_bus_en to wide_bus_supported
  drm/msm/dp: store mode YUV420 information to be used by rest of DP
  drm/msm/dp: check if VSC SDP is supported in DP programming
  drm/msm/dpu: move widebus logic to its own API
  drm/msm/dp: program config ctrl for YUV420 over DP
  drm/msm/dp: change clock related programming for YUV420 over DP
  drm/msm/dp: move parity calculation to dp_utils
  drm/msm/dp: add VSC SDP support for YUV420 over DP
  drm/msm/dp: enable SDP and SDE periph flush update
  drm/msm/dpu: modify encoder programming for CDM over DP
  drm/msm/dpu: modify timing engine programming for YUV420 over DP
  drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420
  drm/msm/dp: allow YUV420 mode for DP connector when CDM available

 drivers/gpu/drm/msm/Makefile  |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 164 +++---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h   |   4 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  26 ++-
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  |  33 +++-
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 100 +--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c|   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c|  17 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h|  10 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c   |   4 +-
 drivers/gpu/drm/msm/dp/dp_audio.c | 101

[PATCH v3 02/19] drm/msm/dpu: add division of drm_display_mode's hskew parameter

2024-02-14 Thread Paloma Arellano
Setting up the timing engine when the physical encoder has a split role
neglects dividing the drm_display_mode's hskew parameter. Let's fix this
since this must also be done in preparation for implementing YUV420 over
DP.

Fixes: 25fdd5933e4c ("drm/msm: Add SDM845 DPU support")
Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 6 --
 1 file changed, 4 insertions(+), 2 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 f562beb6f7971..f02411b062c4c 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
@@ -260,12 +260,14 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
mode.htotal >>= 1;
mode.hsync_start >>= 1;
mode.hsync_end >>= 1;
+   mode.hskew >>= 1;
 
DPU_DEBUG_VIDENC(phys_enc,
-   "split_role %d, halve horizontal %d %d %d %d\n",
+   "split_role %d, halve horizontal %d %d %d %d %d\n",
phys_enc->split_role,
mode.hdisplay, mode.htotal,
-   mode.hsync_start, mode.hsync_end);
+   mode.hsync_start, mode.hsync_end,
+   mode.hskew);
}
 
drm_mode_to_intf_timing_params(phys_enc, , _params);
-- 
2.39.2



[PATCH v3 12/19] drm/msm/dp: move parity calculation to dp_utils

2024-02-14 Thread Paloma Arellano
Parity calculation is necessary for VSC SDP implementation. Therefore
create new files dp_utils.c and dp_utils.h and move the parity
calculating functions here. This ensures that they are usable by SDP
programming in both dp_catalog.c and dp_audio.c

Changes in v3:
- Change ordering of the header byte macros

Changes in v2:
- Create new files dp_utils.c and dp_utils.h
- Move the parity calculation to these new files instead of
  having them in dp_catalog.c and dp_catalog.h

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/Makefile  |   3 +-
 drivers/gpu/drm/msm/dp/dp_audio.c | 101 +-
 drivers/gpu/drm/msm/dp/dp_utils.c |  73 +
 drivers/gpu/drm/msm/dp/dp_utils.h |  22 +++
 4 files changed, 112 insertions(+), 87 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b1173128b5b97..998b155e4a979 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -129,7 +129,8 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_panel.o \
dp/dp_parser.o \
dp/dp_power.o \
-   dp/dp_audio.o
+   dp/dp_audio.o \
+   dp/dp_utils.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c 
b/drivers/gpu/drm/msm/dp/dp_audio.c
index 4a2e479723a85..7634e4b742084 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -15,13 +15,7 @@
 #include "dp_audio.h"
 #include "dp_panel.h"
 #include "dp_display.h"
-
-#define HEADER_BYTE_2_BIT   0
-#define PARITY_BYTE_2_BIT   8
-#define HEADER_BYTE_1_BIT  16
-#define PARITY_BYTE_1_BIT  24
-#define HEADER_BYTE_3_BIT  16
-#define PARITY_BYTE_3_BIT  24
+#include "dp_utils.h"
 
 struct dp_audio_private {
struct platform_device *audio_pdev;
@@ -36,71 +30,6 @@ struct dp_audio_private {
struct dp_audio dp_audio;
 };
 
-static u8 dp_audio_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 u8 dp_audio_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 u8 dp_audio_calculate_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 & 0xFF00) > 0 ? 8 : 2;
-
-   for (i = 0; i < num_byte; i++) {
-   iData = (data >> i*4) & 0xF;
-
-   ci = iData ^ x1;
-   x1 = x0 ^ dp_audio_get_g1_value(ci);
-   x0 = dp_audio_get_g0_value(ci);
-   }
-
-   parity_byte = x1 | (x0 << 4);
-
-   return parity_byte;
-}
-
 static u32 dp_audio_get_header(struct dp_catalog *catalog,
enum dp_catalog_audio_sdp_type sdp,
enum dp_catalog_audio_header_type header)
@@ -134,7 +63,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
 
new_value = 0x02;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -147,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
value = dp_audio_get_header(catalog,
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
new_value = value;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -162,7 +91,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
 
new_value = audio->channels - 1;
-   parity_byt

[PATCH v3 06/19] drm/msm/dp: rename wide_bus_en to wide_bus_supported

2024-02-14 Thread Paloma Arellano
Rename wide_bus_en to wide_bus_supported in dp_display_private to
correctly establish that the parameter is referencing if wide bus is
supported instead of enabled.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 42 ++---
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index d37d599aec273..9df2a8b21021e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -113,7 +113,7 @@ struct dp_display_private {
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
 
-   bool wide_bus_en;
+   bool wide_bus_supported;
 
struct dp_audio *audio;
 };
@@ -122,7 +122,7 @@ struct msm_dp_desc {
phys_addr_t io_start;
unsigned int id;
unsigned int connector_type;
-   bool wide_bus_en;
+   bool wide_bus_supported;
 };
 
 static const struct msm_dp_desc sc7180_dp_descs[] = {
@@ -131,8 +131,8 @@ static const struct msm_dp_desc sc7180_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc7280_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
{}
 };
 
@@ -144,22 +144,22 @@ static const struct msm_dp_desc sc8180x_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc8280xp_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
{}
 };
 
 static const struct msm_dp_desc sc8280xp_edp_descs[] = {
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id

[PATCH v3 03/19] drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup

2024-02-14 Thread Paloma Arellano
Modify the output width and height parameters of hw_cdm to utilize the
physical encoder's data instead of obtaining the information from the
framebuffer. CDM is to be set up to utilize the actual output data since
at CDM setup, there is no difference between the two sources.

Changes in v2:
- Move the modification of the dimensions for CDM setup to this
  new patch

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 4cd2d9e3131a4..ec9e053d3947d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -306,8 +306,8 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
 
memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
 
-   cdm_cfg->output_width = wb_job->fb->width;
-   cdm_cfg->output_height = wb_job->fb->height;
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
-- 
2.39.2



[PATCH v3 07/19] drm/msm/dp: store mode YUV420 information to be used by rest of DP

2024-02-14 Thread Paloma Arellano
Wide bus is not supported when the mode is YUV420 in DP. In preparation
for changing the DPU programming to reflect this, the value and
assignment location of wide_bus_en for the DP submodules must be
changed. Move it from boot time in dp_init_sub_modules() to run time in
dp_display_mode_set.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 17 +
 drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 9df2a8b21021e..ddac55f45a722 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -784,10 +784,6 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
goto error_ctrl;
}
 
-   /* populate wide_bus_supported to different layers */
-   dp->ctrl->wide_bus_en = dp->wide_bus_supported;
-   dp->catalog->wide_bus_en = dp->wide_bus_supported;
-
return rc;
 
 error_ctrl:
@@ -808,6 +804,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
drm_mode_copy(>panel->dp_mode.drm_mode, >drm_mode);
dp->panel->dp_mode.bpp = mode->bpp;
dp->panel->dp_mode.capabilities = mode->capabilities;
+   dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
dp_panel_init_panel_info(dp->panel);
return 0;
 }
@@ -1402,6 +1399,9 @@ bool msm_dp_wide_bus_available(const struct msm_dp 
*dp_display)
 
dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+   if (dp->dp_mode.out_fmt_is_yuv_420)
+   return false;
+
return dp->wide_bus_supported;
 }
 
@@ -1615,6 +1615,15 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
 
dp_display->dp_mode.h_active_low =
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+
+   dp_display->dp_mode.out_fmt_is_yuv_420 =
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+
+   /* populate wide_bus_support to different layers */
+   dp_display->ctrl->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
+   dp_display->catalog->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
 }
 
 void dp_bridge_hpd_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index a0dfc579c5f9f..6ec68be9f2366 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -19,6 +19,7 @@ struct dp_display_mode {
u32 bpp;
u32 h_active_low;
u32 v_active_low;
+   bool out_fmt_is_yuv_420;
 };
 
 struct dp_panel_in {
-- 
2.39.2



Re: [PATCH v2 17/19] drm/msm/dpu: modify timing engine programming for YUV420 over DP

2024-02-12 Thread Paloma Arellano



On 2/10/2024 2:50 AM, Dmitry Baryshkov wrote:

On Sat, 10 Feb 2024 at 03:52, Paloma Arellano  wrote:

Adjust the encoder timing engine setup programming in the case of video
mode for YUV420 over DP to accommodate CDM.

Changes in v2:
 - Move timing engine programming to this patch

Signed-off-by: Paloma Arellano 
---
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 16 
  1 file changed, 12 insertions(+), 4 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 3f102b2813ca8..fb46d907312a7 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
@@ -235,8 +235,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
  {
 struct drm_display_mode mode;
 struct dpu_hw_intf_timing_params timing_params = { 0 };
+   struct dpu_hw_cdm *hw_cdm;
 const struct dpu_format *fmt = NULL;
-   u32 fmt_fourcc = DRM_FORMAT_RGB888;
+   u32 fmt_fourcc;
 unsigned long lock_flags;
 struct dpu_hw_intf_cfg intf_cfg = { 0 };

@@ -255,17 +256,21 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
 DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
 drm_mode_debug_printmodeline();

-   if (phys_enc->split_role != ENC_ROLE_SOLO) {
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+
+   if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == 
DRM_FORMAT_YUV420) {
 mode.hdisplay >>= 1;
 mode.htotal >>= 1;
 mode.hsync_start >>= 1;
 mode.hsync_end >>= 1;
+   mode.hskew >>= 1;

hskew change seems to warrant a separate patch with Fixes for
25fdd5933e4c ("drm/msm: Add SDM845 DPU support")



Ack





 DPU_DEBUG_VIDENC(phys_enc,
-   "split_role %d, halve horizontal %d %d %d %d\n",
+   "split_role %d, halve horizontal %d %d %d %d %d\n",
 phys_enc->split_role,
 mode.hdisplay, mode.htotal,
-   mode.hsync_start, mode.hsync_end);
+   mode.hsync_start, mode.hsync_end,
+   mode.hskew);
 }

 drm_mode_to_intf_timing_params(phys_enc, , _params);
@@ -273,6 +278,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
 fmt = dpu_get_dpu_format(fmt_fourcc);
 DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);

+   hw_cdm = phys_enc->hw_cdm;
+   if (hw_cdm)
+   intf_cfg.cdm = hw_cdm->idx;

No need for a separate local variable.



Ack





 intf_cfg.intf = phys_enc->hw_intf->idx;
 intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
 intf_cfg.stream_sel = 0; /* Don't care value for video mode */
--
2.39.2





Re: [PATCH v2 15/19] drm/msm/dp: enable SDP and SDE periph flush update

2024-02-12 Thread Paloma Arellano



On 2/10/2024 10:15 PM, Dmitry Baryshkov wrote:

On Sun, 11 Feb 2024 at 06:12, Abhinav Kumar  wrote:



On 2/10/2024 2:11 PM, Dmitry Baryshkov wrote:

On Sat, 10 Feb 2024 at 23:49, Abhinav Kumar  wrote:



On 2/10/2024 2:16 AM, Dmitry Baryshkov wrote:

On Sat, 10 Feb 2024 at 03:52, Paloma Arellano  wrote:

DP controller can be setup to operate in either SDP update flush mode or
peripheral flush mode based on the DP controller hardware version.

Starting in DP v1.2, the hardware documents require the use of
peripheral flush mode for SDP packets such as PPS OR VSC SDP packets.

In-line with this guidance, lets program the DP controller to use
peripheral flush mode starting DP v1.2

Changes in v2:
   - Use the original dp_catalog_hw_revision() function to
 correctly check the DP HW version

Signed-off-by: Paloma Arellano 
---
drivers/gpu/drm/msm/dp/dp_catalog.c | 17 +
drivers/gpu/drm/msm/dp/dp_catalog.h |  1 +
drivers/gpu/drm/msm/dp/dp_ctrl.c|  1 +
drivers/gpu/drm/msm/dp/dp_reg.h |  2 ++
4 files changed, 21 insertions(+)





diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 2983756c125cd..6ac66532b47a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -102,6 +102,8 @@
#define DP_MAINLINK_CTRL_ENABLE(0x0001)
#define DP_MAINLINK_CTRL_RESET (0x0002)
#define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER   (0x0010)
+#define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP  (0x0080)
+#define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE   (0x0180)

Just one bit here, please.


hmm  so the periph flush bits are 24:23 and we need a value of 3 to
select peripheral flush which translates to 0x0180.

How do you suggest to break this up?

Then FIELD_PREP(something_mask, 3). Otherwise it is too easy to
consider it to be DP_MAINLINK_FLUSH_MODE_UPDATE_SDP | BIT(24)


Sure, FIELD_PREP() works. I was confused when you said one bit :)

I was also confused, as I wrote, thus I thought that there are one-bit
values in this reg.



Ack, will change

-Paloma




#define DP_MAINLINK_FB_BOUNDARY_SEL(0x0200)

#define REG_DP_STATE_CTRL  (0x0004)
--
2.39.2











Re: [PATCH v2 12/19] drm/msm/dp: move parity calculation to dp_utils

2024-02-12 Thread Paloma Arellano



On 2/10/2024 1:55 AM, Dmitry Baryshkov wrote:

On Sat, 10 Feb 2024 at 03:52, Paloma Arellano  wrote:

Parity calculation is necessary for VSC SDP implementation. Therefore
create new files dp_utils.c and dp_utils.h and move the parity
calculating functions here. This ensures that they are usable by SDP
programming in both dp_catalog.c and dp_audio.c

Changes in v2:
 - Create new files dp_utils.c and dp_utils.h
 - Move the parity calculation to these new files instead of
   having them in dp_catalog.c and dp_catalog.h

Signed-off-by: Paloma Arellano 
---
  drivers/gpu/drm/msm/Makefile  |   3 +-
  drivers/gpu/drm/msm/dp/dp_audio.c | 101 +-
  drivers/gpu/drm/msm/dp/dp_utils.c |  71 +
  drivers/gpu/drm/msm/dp/dp_utils.h |  22 +++
  4 files changed, 110 insertions(+), 87 deletions(-)
  create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.c
  create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.h

[skipped]


diff --git a/drivers/gpu/drm/msm/dp/dp_utils.h 
b/drivers/gpu/drm/msm/dp/dp_utils.h
new file mode 100644
index 0..c062e29d07898
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_utils.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DP_UTILS_H_
+#define _DP_UTILS_H_
+
+#define HEADER_BYTE_0_BIT   0
+#define PARITY_BYTE_0_BIT   8
+#define HEADER_BYTE_2_BIT   0
+#define PARITY_BYTE_2_BIT   8
+#define HEADER_BYTE_1_BIT  16
+#define PARITY_BYTE_1_BIT  24
+#define HEADER_BYTE_3_BIT  16
+#define PARITY_BYTE_3_BIT  24

Nit: it is usually 0-1-2-3 rather than 0-2-1-3.

With that fixed:

Reviewed-by: Dmitry Baryshkov 



Ack.





+
+u8 dp_utils_get_g0_value(u8 data);
+u8 dp_utils_get_g1_value(u8 data);
+u8 dp_utils_calculate_parity(u32 data);
+
+#endif /* _DP_UTILS_H_ */
--
2.39.2





[PATCH v2 02/19] drm/msm/dp: add an API to indicate if sink supports VSC SDP

2024-02-09 Thread Paloma Arellano
YUV420 format is supported only in the VSC SDP packet and not through
MSA. Hence add an API which indicates the sink support which can be used
by the rest of the DP programming.

Changes in v2:
- Move VSC SDP support check API from dp_panel.c to
  drm_dp_helper.c

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/display/drm_dp_helper.c | 21 +
 include/drm/display/drm_dp_helper.h |  1 +
 2 files changed, 22 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_dp_helper.c 
b/drivers/gpu/drm/display/drm_dp_helper.c
index d72b6f9a352c1..c6ee0f9ab5f8f 100644
--- a/drivers/gpu/drm/display/drm_dp_helper.c
+++ b/drivers/gpu/drm/display/drm_dp_helper.c
@@ -2917,6 +2917,27 @@ void drm_dp_vsc_sdp_log(const char *level, struct device 
*dev,
 }
 EXPORT_SYMBOL(drm_dp_vsc_sdp_log);
 
+/**
+ * drm_dp_vsc_sdp_supported() - check if vsc sdp is supported
+ * @aux: DisplayPort AUX channel
+ * @dpcd: DisplayPort configuration data
+ *
+ * Returns true if vsc sdp is supported, else returns false
+ */
+bool drm_dp_vsc_sdp_supported(struct drm_dp_aux *aux, const u8 
dpcd[DP_RECEIVER_CAP_SIZE])
+{
+   u8 rx_feature;
+
+   if (drm_dp_dpcd_readb(aux, DP_DPRX_FEATURE_ENUMERATION_LIST, 
_feature) != 1) {
+   drm_dbg_dp(aux->drm_dev, "failed to read 
DP_DPRX_FEATURE_ENUMERATION_LIST\n");
+   return false;
+   }
+
+   return (dpcd[DP_DPCD_REV] >= DP_DPCD_REV_13) &&
+   !!(rx_feature & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED);
+}
+EXPORT_SYMBOL(drm_dp_vsc_sdp_supported);
+
 /**
  * drm_dp_get_pcon_max_frl_bw() - maximum frl supported by PCON
  * @dpcd: DisplayPort configuration data
diff --git a/include/drm/display/drm_dp_helper.h 
b/include/drm/display/drm_dp_helper.h
index 863b2e7add29e..948381b2b0b1b 100644
--- a/include/drm/display/drm_dp_helper.h
+++ b/include/drm/display/drm_dp_helper.h
@@ -100,6 +100,7 @@ struct drm_dp_vsc_sdp {
 
 void drm_dp_vsc_sdp_log(const char *level, struct device *dev,
const struct drm_dp_vsc_sdp *vsc);
+bool drm_dp_vsc_sdp_supported(struct drm_dp_aux *aux, const u8 
dpcd[DP_RECEIVER_CAP_SIZE]);
 
 int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]);
 
-- 
2.39.2



[PATCH v2 10/19] drm/msm/dp: program config ctrl for YUV420 over DP

2024-02-09 Thread Paloma Arellano
Change relevant DP controller related programming for YUV420 cases.
Program the configuration control register to indicate YUV420.

Changes in v2:
- Create a new patch only for configuration control programming

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 77a8d9366ed7b..da8f0d9f98718 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -128,6 +128,9 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private 
*ctrl)
/* Default-> LSCLK DIV: 1/4 LCLK  */
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
 
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
+
/* Scrambler reset enable */
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
config |= DP_CONFIGURATION_CTRL_ASSR;
-- 
2.39.2



[PATCH v2 16/19] drm/msm/dpu: modify encoder programming for CDM over DP

2024-02-09 Thread Paloma Arellano
Adjust the encoder format programming in the case of video mode for DP
to accommodate CDM related changes.

Changes in v2:
- Move timing engine programming to a separate patch from this
  one
- Move update_pending_flush_periph() invocation completely to
  this patch
- Change the logic of dpu_encoder_get_drm_fmt() so that it only
  calls drm_mode_is_420_only() instead of doing additional
  unnecessary checks
- Create new functions msm_dp_needs_periph_flush() and it's
  supporting function dpu_encoder_needs_periph_flush() to check
  if the mode is YUV420 and VSC SDP is enabled before doing a
  peripheral flush

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 35 +++
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  | 13 +++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  | 19 ++
 drivers/gpu/drm/msm/dp/dp_display.c   | 18 ++
 drivers/gpu/drm/msm/msm_drv.h | 17 -
 5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 7e7796561009a..6280c6be6dca9 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -222,6 +222,41 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
 };
 
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct drm_display_info *info;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   info = _enc->connector->display_info;
+   mode = _enc->cached_mode;
+
+   if (drm_mode_is_420_only(info, mode))
+   return DRM_FORMAT_YUV420;
+
+   return DRM_FORMAT_RGB888;
+}
+
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
+{
+   struct drm_encoder *drm_enc;
+   struct dpu_encoder_virt *dpu_enc;
+   struct msm_display_info *disp_info;
+   struct msm_drm_private *priv;
+   struct drm_display_mode *mode;
+
+   drm_enc = phys_enc->parent;
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   priv = drm_enc->dev->dev_private;
+   mode = _enc->cached_mode;
+
+   return phys_enc->hw_intf->cap->type == INTF_DP && phys_enc->hw_cdm &&
+  
msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode);
+}
 
 bool dpu_encoder_is_widebus_enabled(const 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 f43d57d9c74e1..211a3d90eb690 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -341,6 +341,19 @@ static inline enum dpu_3d_blend_mode 
dpu_encoder_helper_get_3d_blend_mode(
  */
 unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_get_drm_fmt - return DRM fourcc format
+ * @phys_enc: Pointer to physical encoder structure
+ */
+u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
+
+/**
+ * dpu_encoder_needs_periph_flush - return true if physical encoder requires
+ * peripheral flush
+ * @phys_enc: Pointer to physical encoder structure
+ */
+bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc);
+
 /**
  * dpu_encoder_helper_split_config - split display configuration helper 
function
  * This helper function may be used by physical encoders to configure
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 f562beb6f7971..3f102b2813ca8 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
@@ -413,8 +413,15 @@ static int dpu_encoder_phys_vid_control_vblank_irq(
 static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
 {
struct dpu_hw_ctl *ctl;
+   struct dpu_hw_cdm *hw_cdm;
+   const struct dpu_format *fmt = NULL;
+   u32 fmt_fourcc = DRM_FORMAT_RGB888;
 
ctl = phys_enc->hw_ctl;
+   hw_cdm = phys_enc->hw_cdm;
+   if (hw_cdm)
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+   fmt = dpu_get_dpu_format(fmt_fourcc);
 
DPU_DEBUG_VIDENC(phys_enc, "\n");
 
@@ -423,6 +430,8 @@ static void dpu_encoder_phys_vid_enable(struct 
dpu_encoder_phys *phys_enc)
 
dpu_encoder_helper_split_config(phys_enc, phys_enc->hw_intf->idx);
 
+   dpu_encoder_helper_phys_setup_cdm(phys_enc, fmt, CDM_CDWN_OUTPUT_HDMI);
+
dpu_encoder_ph

[PATCH v2 03/19] drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup

2024-02-09 Thread Paloma Arellano
Modify the output width and height parameters of hw_cdm to utilize the
physical encoder's data instead of obtaining the information from the
framebuffer. CDM is to be set up to utilize the actual output data since
at CDM setup, there is no difference between the two sources.

Changes in v2:
- Move the modification of the dimensions for CDM setup to this
  new patch

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 4cd2d9e3131a4..ec9e053d3947d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -306,8 +306,8 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
 
memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
 
-   cdm_cfg->output_width = wb_job->fb->width;
-   cdm_cfg->output_height = wb_job->fb->height;
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
-- 
2.39.2



[PATCH v2 00/19] Add support for CDM over DP

2024-02-09 Thread Paloma Arellano
The Chroma Down Sampling (CDM) block is a hardware component in the DPU
pipeline that includes a CSC block capable of converting RGB input from
the DPU to YUV data.

This block can be used with either HDMI, DP, or writeback interfaces.
This series adds support for the CDM block to be used with DP in
YUV420 mode format.

This series allows selection of the YUV420 format for monitors which support
certain resolutions only in YUV420 thus unblocking the validation of many
other resolutions which were previously filtered out if the connector did
not support YUV420.

This was validated using a DP connected monitor requiring the use of
YUV420 format.

This series is dependent on [1] and [2]:
[1] https://patchwork.freedesktop.org/series/118831/
[2] https://patchwork.freedesktop.org/series/129395/

Changes in v2:
- Minor formatting changes throughout
- Move 'fixes' patch to the top
- Move VSC SDP support check API from dp_panel.c to drm_dp_helper.c
- Create a separate patch for modifying the dimensions for CDM setup to 
be
  non-WB specific
- Remove a patch that modified the INTF_CONFIG2 register in favor of 
having
  this series be dependent on [2]
- Separate configuration ctrl programming from clock related 
programming into
  two patches
- Add a VSC SDP check in dp_bridge_mode_valid()
- Move parity calculation functions to new files dp_utils.c and 
dp_utils.h
- Remove dp_catalog_hw_revision() changes and utilize the original 
version of
  the function when checking the DP hardware version
- Create separate packing and programming functions for the VSC SDP
- Make the packing header bytes function generic so it can be used with
  dp_audio.c
- Create two separate enable/disable VSC SDP functions instead of 
having one
  with the ability to do both
- Move timing engine programming to a separate patch from original 
encoder
  programming patch
- Move update_pending_flush_periph() code to be in the same patch as the
  encoder programming
- Create new API's to check if the dpu encoder needs a peripheral flush
- Allow YUV420 modes for the DP connector when there's a CDM block 
available
  instead of checking if VSC SDP is supported

Kuogee Hsieh (1):
  drm/msm/dpu: add support of new peripheral flush mechanism

Paloma Arellano (18):
  drm/msm/dpu: allow certain formats for CDM for DP
  drm/msm/dp: add an API to indicate if sink supports VSC SDP
  drm/msm/dpu: pass mode dimensions instead of fb size in CDM setup
  drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP
  drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder
  drm/msm/dp: rename wide_bus_en to wide_bus_supported
  drm/msm/dp: store mode YUV420 information to be used by rest of DP
  drm/msm/dp: check if VSC SDP is supported in DP programming
  drm/msm/dpu: move widebus logic to its own API
  drm/msm/dp: program config ctrl for YUV420 over DP
  drm/msm/dp: change clock related programming for YUV420 over DP
  drm/msm/dp: move parity calculation to dp_utils
  drm/msm/dp: add VSC SDP support for YUV420 over DP
  drm/msm/dp: enable SDP and SDE periph flush update
  drm/msm/dpu: modify encoder programming for CDM over DP
  drm/msm/dpu: modify timing engine programming for YUV420 over DP
  drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420
  drm/msm/dp: allow YUV420 mode for DP connector when CDM available

 drivers/gpu/drm/display/drm_dp_helper.c   |  21 +++
 drivers/gpu/drm/msm/Makefile  |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 164 +++---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h   |   4 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  26 ++-
 .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c  |  35 +++-
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 100 +--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c|   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c|  17 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h|  10 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c   |   4 +-
 drivers/gpu/drm/msm/dp/dp_audio.c | 101 ++-
 drivers/gpu/drm/msm/dp/dp_catalog.c   | 127 +-
 drivers/gpu/drm/msm/dp/dp_catalog.h   |   9 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c  |  17 +-
 drivers/gpu/drm/msm/dp/dp_display.c   |  82 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c   |   8 +-
 drivers/gpu/drm/msm/dp/dp_drm.h   |   3 +-
 drivers/gpu/drm/msm/dp/dp_panel.c |  60 +++
 drivers/gpu/drm/msm/dp/dp_panel.h |   2 +
 drivers/gpu/drm/msm/dp/dp_reg.h   |   5 +
 drivers/gpu/drm/msm/dp/dp_utils.c | 151 
 drivers/gpu/drm/msm/dp/dp_utils.h |  25 +++
 drivers/gpu/drm/msm/msm_drv.h |  22 ++-
 include/drm/display/drm_dp_helper.h

[PATCH v2 14/19] drm/msm/dpu: add support of new peripheral flush mechanism

2024-02-09 Thread Paloma Arellano
From: Kuogee Hsieh 

Introduce a peripheral flushing mechanism to decouple peripheral
metadata flushing from timing engine related flush.

Changes in v2:
- Fixed some misalignment issues

Signed-off-by: Kuogee Hsieh 
Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 17 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 10 ++
 2 files changed, 27 insertions(+)

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 e76565c3e6a43..a06f69d0b257d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -39,6 +39,7 @@
 #define   CTL_WB_FLUSH  0x108
 #define   CTL_INTF_FLUSH0x110
 #define   CTL_CDM_FLUSH0x114
+#define   CTL_PERIPH_FLUSH  0x128
 #define   CTL_INTF_MASTER   0x134
 #define   CTL_DSPP_n_FLUSH(n)   ((0x13C) + ((n) * 4))
 
@@ -49,6 +50,7 @@
 #define  MERGE_3D_IDX   23
 #define  DSC_IDX22
 #define CDM_IDX 26
+#define  PERIPH_IDX 30
 #define  INTF_IDX   31
 #define WB_IDX  16
 #define  DSPP_IDX   29  /* From DPU hw rev 7.x.x */
@@ -151,6 +153,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct 
dpu_hw_ctl *ctx)
ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
}
 
+   if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+   DPU_REG_WRITE(>hw, CTL_PERIPH_FLUSH,
+ ctx->pending_periph_flush_mask);
+
if (ctx->pending_flush_mask & BIT(DSC_IDX))
DPU_REG_WRITE(>hw, CTL_DSC_FLUSH,
  ctx->pending_dsc_flush_mask);
@@ -311,6 +317,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_v1(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)
 {
@@ -680,6 +693,10 @@ 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_v1;
+
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;
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 ff85b5ee0acf8..ef56280bea932 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -122,6 +122,15 @@ struct dpu_hw_ctl_ops {
void (*update_pending_flush_intf)(struct dpu_hw_ctl *ctx,
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
@@ -264,6 +273,7 @@ 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_dspp_flush_mask[DSPP_MAX - DSPP_0];
u32 pending_dsc_flush_mask;
-- 
2.39.2



[PATCH v2 13/19] drm/msm/dp: add VSC SDP support for YUV420 over DP

2024-02-09 Thread Paloma Arellano
Add support to pack and send the VSC SDP packet for DP. This therefore
allows the transmision of format information to the sinks which is
needed for YUV420 support over DP.

Changes in v2:
- Rename GENERIC0_SDPSIZE macro to GENERIC0_SDPSIZE_VALID
- Remove dp_sdp from the dp_catalog struct since this data is
  being allocated at the point used
- Create a new function in dp_utils to pack the VSC SDP data
  into a buffer
- Create a new function that packs the SDP header bytes into a
  buffer. This function is made generic so that it can be
  utilized by dp_audio
  header bytes into a buffer
- Create a new function in dp_utils that takes the packed buffer
  and writes to the DP_GENERIC0_* registers
- Split the dp_catalog_panel_config_vsc_sdp() function into two
  to disable/enable sending VSC SDP packets
- Check the DP HW version using the original useage of
  dp_catalog_hw_revision() and correct the version checking
  logic
- Rename dp_panel_setup_vsc_sdp() to
  dp_panel_setup_vsc_sdp_yuv_420() to explicitly state that
  currently VSC SDP is only being set up to support YUV420 modes

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 105 
 drivers/gpu/drm/msm/dp/dp_catalog.h |   6 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|   4 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  59 
 drivers/gpu/drm/msm/dp/dp_reg.h |   3 +
 drivers/gpu/drm/msm/dp/dp_utils.c   |  80 +
 drivers/gpu/drm/msm/dp/dp_utils.h   |   3 +
 7 files changed, 260 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5d84c089e520a..0f28a4897b7b7 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -901,6 +901,111 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog 
*dp_catalog)
return 0;
 }
 
+static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, u32 
*buffer)
+{
+   struct dp_catalog_private *catalog;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   dp_write_link(catalog, MMSS_DP_GENERIC0_0, buffer[0]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_1, buffer[1]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_2, buffer[2]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_3, buffer[3]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_4, buffer[4]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_5, buffer[5]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_6, buffer[6]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_7, buffer[7]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_8, buffer[8]);
+   dp_write_link(catalog, MMSS_DP_GENERIC0_9, buffer[9]);
+}
+
+static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 hw_revision;
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= 
DP_HW_VERSION_1_0) {
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
+   }
+}
+
+void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, u32 
*gen_buffer)
+{
+   struct dp_catalog_private *catalog;
+   u32 cfg, cfg2, misc;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_catalog_private, 
dp_catalog);
+
+   cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
+   cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
+   misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
+
+   cfg |= GEN0_SDP_EN;
+   dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg);
+
+   cfg2 |= GENERIC0_SDPSIZE_VALID;
+   dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2);
+
+   dp_catalog_panel_send_vsc_sdp(dp_catalog, gen_buffer);
+
+   /* indicates presence of VSC (BIT(6) of MISC1) */
+   misc |= DP_MISC1_VSC_SDP;
+
+   drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=1\n");
+
+   pr_debug("misc settings = 0x%x\n", misc);
+   dp_write_link(catalog, REG_DP_MISC1_MISC0, misc);
+
+   dp_catalog_panel_update_sdp(dp_catalog);
+}
+
+void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog;
+   u32 cfg, cfg2, misc;
+
+   if (!dp_catalog) {
+   DRM_ERROR("invalid input\n");
+   return;
+   }
+
+   catalog = container_of(dp_catalog, struct dp_

[PATCH v2 19/19] drm/msm/dp: allow YUV420 mode for DP connector when CDM available

2024-02-09 Thread Paloma Arellano
All the components of YUV420 over DP are added. Therefore, let's mark the
connector property as true for DP connector when the DP type is not eDP
and when there is a CDM block available.

Changes in v2:
- Check for if dp_catalog has a CDM block available instead of
  checking if VSC SDP is allowed when setting the dp connector's
  ycbcr_420_allowed parameter

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 4 +++-
 drivers/gpu/drm/msm/dp/dp_display.c | 4 ++--
 drivers/gpu/drm/msm/dp/dp_drm.c | 8 ++--
 drivers/gpu/drm/msm/dp/dp_drm.h | 3 ++-
 drivers/gpu/drm/msm/msm_drv.h   | 5 +++--
 5 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 723cc1d821431..beeaabe499abf 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -565,6 +565,7 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
 {
struct drm_encoder *encoder = NULL;
struct msm_display_info info;
+   bool yuv_supported;
int rc;
int i;
 
@@ -583,7 +584,8 @@ static int _dpu_kms_initialize_displayport(struct 
drm_device *dev,
return PTR_ERR(encoder);
}
 
-   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder);
+   yuv_supported = !!(dpu_kms->catalog->cdm);
+   rc = msm_dp_modeset_init(priv->dp[i], dev, encoder, 
yuv_supported);
if (rc) {
DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);
return rc;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index ebcc76ef1d590..9b9f5f2921903 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1471,7 +1471,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 }
 
 int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
-   struct drm_encoder *encoder)
+   struct drm_encoder *encoder, bool yuv_supported)
 {
struct dp_display_private *dp_priv;
int ret;
@@ -1487,7 +1487,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return ret;
}
 
-   dp_display->connector = dp_drm_connector_init(dp_display, encoder);
+   dp_display->connector = dp_drm_connector_init(dp_display, encoder, 
yuv_supported);
if (IS_ERR(dp_display->connector)) {
ret = PTR_ERR(dp_display->connector);
DRM_DEV_ERROR(dev->dev,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 46e6889037e88..ab0d0d13b5e2c 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -353,7 +353,8 @@ int dp_bridge_init(struct msm_dp *dp_display, struct 
drm_device *dev,
 }
 
 /* connector initialization */
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder)
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported)
 {
struct drm_connector *connector = NULL;
 
@@ -361,8 +362,11 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
if (IS_ERR(connector))
return connector;
 
-   if (!dp_display->is_edp)
+   if (!dp_display->is_edp) {
drm_connector_attach_dp_subconnector_property(connector);
+   if (yuv_supported)
+   connector->ycbcr_420_allowed = true;
+   }
 
drm_connector_attach_encoder(connector, encoder);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index b3d684db2383b..45e57ac25a4d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -19,7 +19,8 @@ struct msm_dp_bridge {
 
 #define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
 
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder);
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct 
drm_encoder *encoder,
+   bool yuv_supported);
 int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder);
 
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b876ebd48effe..37335777f5c09 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -385,7 +385,7 @@ static inline struct drm_dsc_config 
*msm_dsi_get_dsc_config(struct msm_dsi *msm_
 int __init msm_dp_register(void);
 void __exit msm_dp_unregister(void);
 int msm_dp_modeset_init(str

[PATCH v2 07/19] drm/msm/dp: store mode YUV420 information to be used by rest of DP

2024-02-09 Thread Paloma Arellano
Wide bus is not supported when the mode is YUV420 in DP. In preparation
for changing the DPU programming to reflect this, the value and
assignment location of wide_bus_en for the DP submodules must be
changed. Move it from boot time in dp_init_sub_modules() to run time in
dp_display_mode_set.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 17 +
 drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 9df2a8b21021e..ddac55f45a722 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -784,10 +784,6 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
goto error_ctrl;
}
 
-   /* populate wide_bus_supported to different layers */
-   dp->ctrl->wide_bus_en = dp->wide_bus_supported;
-   dp->catalog->wide_bus_en = dp->wide_bus_supported;
-
return rc;
 
 error_ctrl:
@@ -808,6 +804,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
drm_mode_copy(>panel->dp_mode.drm_mode, >drm_mode);
dp->panel->dp_mode.bpp = mode->bpp;
dp->panel->dp_mode.capabilities = mode->capabilities;
+   dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
dp_panel_init_panel_info(dp->panel);
return 0;
 }
@@ -1402,6 +1399,9 @@ bool msm_dp_wide_bus_available(const struct msm_dp 
*dp_display)
 
dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+   if (dp->dp_mode.out_fmt_is_yuv_420)
+   return false;
+
return dp->wide_bus_supported;
 }
 
@@ -1615,6 +1615,15 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
 
dp_display->dp_mode.h_active_low =
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+
+   dp_display->dp_mode.out_fmt_is_yuv_420 =
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+
+   /* populate wide_bus_support to different layers */
+   dp_display->ctrl->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
+   dp_display->catalog->wide_bus_en =
+   dp_display->dp_mode.out_fmt_is_yuv_420 ? false : 
dp_display->wide_bus_supported;
 }
 
 void dp_bridge_hpd_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index a0dfc579c5f9f..6ec68be9f2366 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -19,6 +19,7 @@ struct dp_display_mode {
u32 bpp;
u32 h_active_low;
u32 v_active_low;
+   bool out_fmt_is_yuv_420;
 };
 
 struct dp_panel_in {
-- 
2.39.2



[PATCH v2 17/19] drm/msm/dpu: modify timing engine programming for YUV420 over DP

2024-02-09 Thread Paloma Arellano
Adjust the encoder timing engine setup programming in the case of video
mode for YUV420 over DP to accommodate CDM.

Changes in v2:
- Move timing engine programming to this patch

Signed-off-by: Paloma Arellano 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 16 
 1 file changed, 12 insertions(+), 4 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 3f102b2813ca8..fb46d907312a7 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
@@ -235,8 +235,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
 {
struct drm_display_mode mode;
struct dpu_hw_intf_timing_params timing_params = { 0 };
+   struct dpu_hw_cdm *hw_cdm;
const struct dpu_format *fmt = NULL;
-   u32 fmt_fourcc = DRM_FORMAT_RGB888;
+   u32 fmt_fourcc;
unsigned long lock_flags;
struct dpu_hw_intf_cfg intf_cfg = { 0 };
 
@@ -255,17 +256,21 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
drm_mode_debug_printmodeline();
 
-   if (phys_enc->split_role != ENC_ROLE_SOLO) {
+   fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
+
+   if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == 
DRM_FORMAT_YUV420) {
mode.hdisplay >>= 1;
mode.htotal >>= 1;
mode.hsync_start >>= 1;
mode.hsync_end >>= 1;
+   mode.hskew >>= 1;
 
DPU_DEBUG_VIDENC(phys_enc,
-   "split_role %d, halve horizontal %d %d %d %d\n",
+   "split_role %d, halve horizontal %d %d %d %d %d\n",
phys_enc->split_role,
mode.hdisplay, mode.htotal,
-   mode.hsync_start, mode.hsync_end);
+   mode.hsync_start, mode.hsync_end,
+   mode.hskew);
}
 
drm_mode_to_intf_timing_params(phys_enc, , _params);
@@ -273,6 +278,9 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
fmt = dpu_get_dpu_format(fmt_fourcc);
DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);
 
+   hw_cdm = phys_enc->hw_cdm;
+   if (hw_cdm)
+   intf_cfg.cdm = hw_cdm->idx;
intf_cfg.intf = phys_enc->hw_intf->idx;
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
-- 
2.39.2



[PATCH v2 18/19] drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420

2024-02-09 Thread Paloma Arellano
Reserve CDM blocks for DP if the mode format is YUV420. Currently this
reservation only works for writeback and DP if the format is YUV420. But
this can be easily extented to other YUV formats for DP.

Changes in v2:
- Minor code simplification

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 22 +
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 6280c6be6dca9..ec53e5f4a696d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -639,6 +639,7 @@ static int dpu_encoder_virt_atomic_check(
struct dpu_kms *dpu_kms;
struct drm_display_mode *adj_mode;
struct msm_display_topology topology;
+   struct msm_display_info *disp_info;
struct dpu_global_state *global_state;
struct drm_framebuffer *fb;
struct drm_dsc_config *dsc;
@@ -655,6 +656,7 @@ static int dpu_encoder_virt_atomic_check(
DPU_DEBUG_ENC(dpu_enc, "\n");
 
priv = drm_enc->dev->dev_private;
+   disp_info = _enc->disp_info;
dpu_kms = to_dpu_kms(priv->kms);
adj_mode = _state->adjusted_mode;
global_state = dpu_kms_get_global_state(crtc_state->state);
@@ -682,21 +684,24 @@ static int dpu_encoder_virt_atomic_check(
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, 
crtc_state, dsc);
 
/*
-* Use CDM only for writeback at the moment as other interfaces cannot 
handle it.
-* if writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
+* Use CDM only for writeback or DP at the moment as other interfaces 
cannot handle it.
+* If writeback itself cannot handle cdm for some reason it will fail 
in its atomic_check()
 * earlier.
 */
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
fb = conn_state->writeback_job->fb;
 
if (fb && 
DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb
topology.needs_cdm = true;
-   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
-   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
-   crtc_state->mode_changed = true;
+   } else if (disp_info->intf_type == INTF_DP) {
+   if 
(msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
+   topology.needs_cdm = true;
}
 
+   if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
+   else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
+   crtc_state->mode_changed = true;
/*
 * Release and Allocate resources on every modeset
 * Dont allocate when active is false.
@@ -1137,7 +1142,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct 
drm_encoder *drm_enc,
 
dpu_enc->dsc_mask = dsc_mask;
 
-   if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+   if ((dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) ||
+   dpu_enc->disp_info.intf_type == INTF_DP) {
struct dpu_hw_blk *hw_cdm = NULL;
 
dpu_rm_get_assigned_resources(_kms->rm, global_state,
-- 
2.39.2



[PATCH v2 15/19] drm/msm/dp: enable SDP and SDE periph flush update

2024-02-09 Thread Paloma Arellano
DP controller can be setup to operate in either SDP update flush mode or
peripheral flush mode based on the DP controller hardware version.

Starting in DP v1.2, the hardware documents require the use of
peripheral flush mode for SDP packets such as PPS OR VSC SDP packets.

In-line with this guidance, lets program the DP controller to use
peripheral flush mode starting DP v1.2

Changes in v2:
- Use the original dp_catalog_hw_revision() function to
  correctly check the DP HW version

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 17 +
 drivers/gpu/drm/msm/dp/dp_catalog.h |  1 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  1 +
 drivers/gpu/drm/msm/dp/dp_reg.h |  2 ++
 4 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 0f28a4897b7b7..bc64dde5b7459 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -440,6 +440,23 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
 }
 
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog)
+{
+   u32 mainlink_ctrl, hw_revision;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   hw_revision = dp_catalog_hw_revision(dp_catalog);
+   if (hw_revision >= DP_HW_VERSION_1_2)
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
+   else
+   mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
+}
+
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
bool fixed_nvid, bool is_ycbcr_420)
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 5b3a7ba40d55f..9e2b05544f610 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -98,6 +98,7 @@ 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_ctrl(struct dp_catalog *dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool 
enable);
+void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog);
 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,
u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index beef86b1aaf81..f1e7b0a5ee5d1 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -170,6 +170,7 @@ static void dp_ctrl_configure_source_params(struct 
dp_ctrl_private *ctrl)
 
dp_catalog_ctrl_lane_mapping(ctrl->catalog);
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
+   dp_catalog_setup_peripheral_flush(ctrl->catalog);
 
dp_ctrl_config_ctrl(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 2983756c125cd..6ac66532b47a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -102,6 +102,8 @@
 #define DP_MAINLINK_CTRL_ENABLE(0x0001)
 #define DP_MAINLINK_CTRL_RESET (0x0002)
 #define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER   (0x0010)
+#define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP  (0x0080)
+#define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE   (0x0180)
 #define DP_MAINLINK_FB_BOUNDARY_SEL(0x0200)
 
 #define REG_DP_STATE_CTRL  (0x0004)
-- 
2.39.2



[PATCH v2 04/19] drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP

2024-02-09 Thread Paloma Arellano
Generalize dpu_encoder_helper_phys_setup_cdm to be compatible with DP.

Changes in v2:
- Minor formatting changes
- Move the modification of the dimesions for CDM setup to a new
  patch

Signed-off-by: Paloma Arellano 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  4 +--
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 27 ++-
 2 files changed, 16 insertions(+), 15 deletions(-)

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 993f263433314..204d7cc3c1de8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -154,6 +154,7 @@ enum dpu_intr_idx {
  * @hw_wb: Hardware interface to the wb registers
  * @hw_cdm:Hardware interface to the CDM registers
  * @dpu_kms:   Pointer to the dpu_kms top level
+ * @cdm_cfg:   CDM block config needed to store WB/DP block's CDM 
configuration
  * @cached_mode:   DRM mode cached at mode_set time, acted on in enable
  * @vblank_ctl_lock:   Vblank ctl mutex lock to protect vblank_refcount
  * @enabled:   Whether the encoder has enabled and running a mode
@@ -184,6 +185,7 @@ struct dpu_encoder_phys {
struct dpu_hw_wb *hw_wb;
struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms;
+   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role;
@@ -213,7 +215,6 @@ static inline int dpu_encoder_phys_inc_pending(struct 
dpu_encoder_phys *phys)
  * @wbirq_refcount: Reference count of writeback interrupt
  * @wb_done_timeout_cnt: number of wb done irq timeout errors
  * @wb_cfg:  writeback block config to store fb related details
- * @cdm_cfg: cdm block config needed to store writeback block's CDM 
configuration
  * @wb_conn: backpointer to writeback connector
  * @wb_job: backpointer to current writeback job
  * @dest:   dpu buffer layout for current writeback output buffer
@@ -223,7 +224,6 @@ struct dpu_encoder_phys_wb {
atomic_t wbirq_refcount;
int wb_done_timeout_cnt;
struct dpu_hw_wb_cfg wb_cfg;
-   struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_writeback_connector *wb_conn;
struct drm_writeback_job *wb_job;
struct dpu_hw_fmt_layout dest;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index ec9e053d3947d..072fc6950e496 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -269,28 +269,21 @@ static void dpu_encoder_phys_wb_setup_ctl(struct 
dpu_encoder_phys *phys_enc)
  * This API does not handle 
DPU_CHROMA_H1V2.
  * @phys_enc:Pointer to physical encoder
  */
-static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc)
+static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys 
*phys_enc,
+ const struct dpu_format *dpu_fmt,
+ u32 output_type)
 {
struct dpu_hw_cdm *hw_cdm;
struct dpu_hw_cdm_cfg *cdm_cfg;
struct dpu_hw_pingpong *hw_pp;
-   struct dpu_encoder_phys_wb *wb_enc;
-   const struct msm_format *format;
-   const struct dpu_format *dpu_fmt;
-   struct drm_writeback_job *wb_job;
int ret;
 
if (!phys_enc)
return;
 
-   wb_enc = to_dpu_encoder_phys_wb(phys_enc);
-   cdm_cfg = _enc->cdm_cfg;
+   cdm_cfg = _enc->cdm_cfg;
hw_pp = phys_enc->hw_pp;
hw_cdm = phys_enc->hw_cdm;
-   wb_job = wb_enc->wb_job;
-
-   format = msm_framebuffer_format(wb_enc->wb_job->fb);
-   dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, 
wb_job->fb->modifier);
 
if (!hw_cdm)
return;
@@ -309,7 +302,7 @@ static void dpu_encoder_helper_phys_setup_cdm(struct 
dpu_encoder_phys *phys_enc)
cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
cdm_cfg->output_fmt = dpu_fmt;
-   cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
+   cdm_cfg->output_type = output_type;
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
@@ -462,6 +455,14 @@ static void dpu_encoder_phys_wb_setup(
struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
struct drm_display_mode mode = phys_enc->cached_mode;
struct drm_framebuffer *fb = NULL;
+   struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+   struct drm_writeback_job *wb_job;
+   const struct msm_format *format;
+   cons

[PATCH v2 12/19] drm/msm/dp: move parity calculation to dp_utils

2024-02-09 Thread Paloma Arellano
Parity calculation is necessary for VSC SDP implementation. Therefore
create new files dp_utils.c and dp_utils.h and move the parity
calculating functions here. This ensures that they are usable by SDP
programming in both dp_catalog.c and dp_audio.c

Changes in v2:
- Create new files dp_utils.c and dp_utils.h
- Move the parity calculation to these new files instead of
  having them in dp_catalog.c and dp_catalog.h

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/Makefile  |   3 +-
 drivers/gpu/drm/msm/dp/dp_audio.c | 101 +-
 drivers/gpu/drm/msm/dp/dp_utils.c |  71 +
 drivers/gpu/drm/msm/dp/dp_utils.h |  22 +++
 4 files changed, 110 insertions(+), 87 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.c
 create mode 100644 drivers/gpu/drm/msm/dp/dp_utils.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b1173128b5b97..998b155e4a979 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -129,7 +129,8 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_panel.o \
dp/dp_parser.o \
dp/dp_power.o \
-   dp/dp_audio.o
+   dp/dp_audio.o \
+   dp/dp_utils.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
 
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c 
b/drivers/gpu/drm/msm/dp/dp_audio.c
index 4a2e479723a85..7634e4b742084 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -15,13 +15,7 @@
 #include "dp_audio.h"
 #include "dp_panel.h"
 #include "dp_display.h"
-
-#define HEADER_BYTE_2_BIT   0
-#define PARITY_BYTE_2_BIT   8
-#define HEADER_BYTE_1_BIT  16
-#define PARITY_BYTE_1_BIT  24
-#define HEADER_BYTE_3_BIT  16
-#define PARITY_BYTE_3_BIT  24
+#include "dp_utils.h"
 
 struct dp_audio_private {
struct platform_device *audio_pdev;
@@ -36,71 +30,6 @@ struct dp_audio_private {
struct dp_audio dp_audio;
 };
 
-static u8 dp_audio_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 u8 dp_audio_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 u8 dp_audio_calculate_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 & 0xFF00) > 0 ? 8 : 2;
-
-   for (i = 0; i < num_byte; i++) {
-   iData = (data >> i*4) & 0xF;
-
-   ci = iData ^ x1;
-   x1 = x0 ^ dp_audio_get_g1_value(ci);
-   x0 = dp_audio_get_g0_value(ci);
-   }
-
-   parity_byte = x1 | (x0 << 4);
-
-   return parity_byte;
-}
-
 static u32 dp_audio_get_header(struct dp_catalog *catalog,
enum dp_catalog_audio_sdp_type sdp,
enum dp_catalog_audio_header_type header)
@@ -134,7 +63,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
 
new_value = 0x02;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -147,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
value = dp_audio_get_header(catalog,
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
new_value = value;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
drm_dbg_dp(audio->drm_dev,
@@ -162,7 +91,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private 
*audio)
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
 
new_value = audio->channels - 1;
-   parity_byte = dp_audio_calculate_parity(new_value);
+   parity_byte = dp_utils_calculate_parity(new_value);
value |= ((new_value 

[PATCH v2 08/19] drm/msm/dp: check if VSC SDP is supported in DP programming

2024-02-09 Thread Paloma Arellano
In the DP driver, check if VSC SDP is supported and propagate this value
to dp_panel. In dp_display's dp_mode, the out_fmt_is_yuv_420 parameter
must also utilize this value since YUV420 is only allowed when VSC SDP
is supported.

Changes in v2:
- Move DP programming when VSC SDP is supported to this patch

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 5 -
 drivers/gpu/drm/msm/dp/dp_panel.c   | 1 +
 drivers/gpu/drm/msm/dp/dp_panel.h   | 1 +
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index ddac55f45a722..6323dc08d5eb8 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1595,8 +1595,10 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
+   struct dp_panel *dp_panel;
 
dp_display = container_of(dp, struct dp_display_private, dp_display);
+   dp_panel = dp_display->panel;
 
memset(_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
 
@@ -1617,7 +1619,8 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
 
dp_display->dp_mode.out_fmt_is_yuv_420 =
-   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode);
+   drm_mode_is_420_only(>connector->display_info, 
adjusted_mode) &&
+   dp_panel->vsc_sdp_supported;
 
/* populate wide_bus_support to different layers */
dp_display->ctrl->wide_bus_en =
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c 
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd1..db1942794f1a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -53,6 +53,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
if (rc)
return rc;
 
+   dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, 
dpcd);
link_info = _panel->link_info;
link_info->revision = dpcd[DP_DPCD_REV];
major = (link_info->revision >> 4) & 0x0f;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h
index 6ec68be9f2366..e843f5062d1f6 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -46,6 +46,7 @@ struct dp_panel {
struct dp_display_mode dp_mode;
struct dp_panel_psr psr_cap;
bool video_test;
+   bool vsc_sdp_supported;
 
u32 vic;
u32 max_dp_lanes;
-- 
2.39.2



[PATCH v2 11/19] drm/msm/dp: change clock related programming for YUV420 over DP

2024-02-09 Thread Paloma Arellano
Change all relevant DP controller related programming for YUV420 cases.
Namely, change the pixel clock math to consider YUV420 and modify the
MVID programming to consider YUV420.

Changes in v2:
- Move configuration control progamming to a different commit
- Slight code simplification
- Add VSC SDP check when doing mode_pclk_khz division in
  dp_bridge_mode_valid

Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 5 -
 drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 9 ++---
 drivers/gpu/drm/msm/dp/dp_display.c | 4 
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5142aeb705a44..5d84c089e520a 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -442,7 +442,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog 
*dp_catalog,
 
 void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
u32 rate, u32 stream_rate_khz,
-   bool fixed_nvid)
+   bool fixed_nvid, bool is_ycbcr_420)
 {
u32 pixel_m, pixel_n;
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
@@ -485,6 +485,9 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog 
*dp_catalog,
nvid = temp;
}
 
+   if (is_ycbcr_420)
+   mvid /= 2;
+
if (link_rate_hbr2 == rate)
nvid *= 2;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 38786e855b51a..6cb5e2a243de2 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -96,7 +96,7 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog 
*dp_catalog, bool enable);
 void dp_catalog_ctrl_psr_mainlink_enable(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,
-   u32 stream_rate_khz, bool fixed_nvid);
+   u32 stream_rate_khz, bool fixed_nvid, bool 
is_ycbcr_420);
 int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 
pattern);
 u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index da8f0d9f98718..209cf2a35642f 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -960,7 +960,7 @@ static void dp_ctrl_calc_tu_parameters(struct 
dp_ctrl_private *ctrl,
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
in.nlanes = ctrl->link->link_params.num_lanes;
in.bpp = ctrl->panel->dp_mode.bpp;
-   in.pixel_enc = 444;
+   in.pixel_enc = ctrl->panel->dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
in.dsc_en = 0;
in.async_en = 0;
in.fec_en = 0;
@@ -1766,6 +1766,8 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
ctrl->link->link_params.rate = rate;
ctrl->link->link_params.num_lanes =
ctrl->panel->link_info.num_lanes;
+   if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
+   pixel_rate >>= 1;
}
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1881,7 +1883,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock;
 
-   if (dp_ctrl->wide_bus_en)
+   if (dp_ctrl->wide_bus_en || ctrl->panel->dp_mode.out_fmt_is_yuv_420)
pixel_rate >>= 1;
 
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
@@ -1920,7 +1922,8 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 
dp_catalog_ctrl_config_msa(ctrl->catalog,
ctrl->link->link_params.rate,
-   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
+   pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl),
+   ctrl->panel->dp_mode.out_fmt_is_yuv_420);
 
dp_ctrl_setup_tr_unit(ctrl);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 6323dc08d5eb8..4b04388719363 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -933,6 +933,10 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = _display->panel->link_info;
 
+   if (drm_mode_is_420_only(>connector->display_info

[PATCH v2 06/19] drm/msm/dp: rename wide_bus_en to wide_bus_supported

2024-02-09 Thread Paloma Arellano
Rename wide_bus_en to wide_bus_supported in dp_display_private to
correctly establish that the parameter is referencing if wide bus is
supported instead of enabled.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 42 ++---
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index d37d599aec273..9df2a8b21021e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -113,7 +113,7 @@ struct dp_display_private {
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
 
-   bool wide_bus_en;
+   bool wide_bus_supported;
 
struct dp_audio *audio;
 };
@@ -122,7 +122,7 @@ struct msm_dp_desc {
phys_addr_t io_start;
unsigned int id;
unsigned int connector_type;
-   bool wide_bus_en;
+   bool wide_bus_supported;
 };
 
 static const struct msm_dp_desc sc7180_dp_descs[] = {
@@ -131,8 +131,8 @@ static const struct msm_dp_desc sc7180_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc7280_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
{}
 };
 
@@ -144,22 +144,22 @@ static const struct msm_dp_desc sc8180x_dp_descs[] = {
 };
 
 static const struct msm_dp_desc sc8280xp_dp_descs[] = {
-   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+   { .io_start = 0x0ae9, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209, .id = MSM_DP_CONTROLLER_0, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
{}
 };
 
 static const struct msm_dp_desc sc8280xp_edp_descs[] = {
-   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-   { .io_start = 0x220a, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+   { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x0aea, .id = MSM_DP_CONTROLLER_3, .connector_type = 
DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+   { .io_start = 0x2209a000, .id

[PATCH v2 09/19] drm/msm/dpu: move widebus logic to its own API

2024-02-09 Thread Paloma Arellano
Widebus enablement is decided by the interfaces based on their specific
checks and that already happens with DSI/DP specific helpers. Let's
invoke these helpers from dpu_encoder_is_widebus_enabled() to make it
cleaner overall.

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 29 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  4 +++
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 3c55d6290b708..7e7796561009a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -225,9 +225,21 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
 
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
 {
-   const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
+   const struct dpu_encoder_virt *dpu_enc;
+   struct msm_drm_private *priv = drm_enc->dev->dev_private;
+   const struct msm_display_info *disp_info;
+   int index;
+
+   dpu_enc = to_dpu_encoder_virt(drm_enc);
+   disp_info = _enc->disp_info;
+   index = disp_info->h_tile_instance[0];
+
+   if (disp_info->intf_type == INTF_DP)
+   return msm_dp_wide_bus_available(priv->dp[index]);
+   else if (disp_info->intf_type == INTF_DSI)
+   return msm_dsi_wide_bus_enabled(priv->dsi[index]);
 
-   return dpu_enc->wide_bus_en;
+   return false;
 }
 
 bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc)
@@ -1199,26 +1211,17 @@ static void dpu_encoder_virt_atomic_enable(struct 
drm_encoder *drm_enc,
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
struct drm_display_mode *cur_mode = NULL;
-   struct msm_drm_private *priv = drm_enc->dev->dev_private;
-   struct msm_display_info *disp_info;
-   int index;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
-   disp_info = _enc->disp_info;
-   index = disp_info->h_tile_instance[0];
-
dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc);
 
atomic_set(_enc->frame_done_timeout_cnt, 0);
 
-   if (disp_info->intf_type == INTF_DP)
-   dpu_enc->wide_bus_en = 
msm_dp_wide_bus_available(priv->dp[index]);
-   else if (disp_info->intf_type == INTF_DSI)
-   dpu_enc->wide_bus_en = 
msm_dsi_wide_bus_enabled(priv->dsi[index]);
-
mutex_lock(_enc->enc_lock);
cur_mode = _enc->base.crtc->state->adjusted_mode;
 
+   dpu_enc->wide_bus_en = dpu_encoder_is_widebus_enabled(drm_enc);
+
trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
 cur_mode->vdisplay);
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index fe6b1d312a742..67aef59c1f99c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -156,6 +156,10 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
  */
 int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
 
+/**
+ * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled
+ * @drm_enc:Pointer to previously created drm encoder structure
+ */
 bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
 
 /**
-- 
2.39.2



[PATCH v2 05/19] drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder

2024-02-09 Thread Paloma Arellano
Move dpu_encoder_helper_phys_setup_cdm to dpu_encoder in preparation for
implementing YUV420 over DP, which requires CDM compatibility.

Changes in v2:
- Slightly change the wording of the commit text to make clear
  that YUV over DP requires CDM

Signed-off-by: Paloma Arellano 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c   | 78 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  9 ++
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 83 ---
 3 files changed, 87 insertions(+), 83 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 467f874979d5c..3c55d6290b708 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2121,6 +2121,84 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
ctl->ops.clear_pending_flush(ctl);
 }
 
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output_type)
+{
+   struct dpu_hw_cdm *hw_cdm;
+   struct dpu_hw_cdm_cfg *cdm_cfg;
+   struct dpu_hw_pingpong *hw_pp;
+   int ret;
+
+   if (!phys_enc)
+   return;
+
+   cdm_cfg = _enc->cdm_cfg;
+   hw_pp = phys_enc->hw_pp;
+   hw_cdm = phys_enc->hw_cdm;
+
+   if (!hw_cdm)
+   return;
+
+   if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
+   DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", 
DRMID(phys_enc->parent),
+ dpu_fmt->base.pixel_format);
+   if (hw_cdm->ops.bind_pingpong_blk)
+   hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
+
+   return;
+   }
+
+   memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
+
+   cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+   cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
+   cdm_cfg->output_fmt = dpu_fmt;
+   cdm_cfg->output_type = output_type;
+   cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
+   CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
+   cdm_cfg->csc_cfg = _csc10_rgb2yuv_601l;
+
+   /* enable 10 bit logic */
+   switch (cdm_cfg->output_fmt->chroma_sample) {
+   case DPU_CHROMA_RGB:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_H2V1:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   case DPU_CHROMA_420:
+   cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
+   break;
+   case DPU_CHROMA_H1V2:
+   default:
+   DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
+ DRMID(phys_enc->parent));
+   cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
+   cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
+   break;
+   }
+
+   DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
+ DRMID(phys_enc->parent), cdm_cfg->output_width,
+ cdm_cfg->output_height, 
cdm_cfg->output_fmt->base.pixel_format,
+ cdm_cfg->output_type, cdm_cfg->output_bit_depth,
+ cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
+
+   if (hw_cdm->ops.enable) {
+   cdm_cfg->pp_id = hw_pp->idx;
+   ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
+   if (ret < 0) {
+   DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
+ DRMID(phys_enc->parent), ret);
+   return;
+   }
+   }
+}
+
 #ifdef CONFIG_DEBUG_FS
 static int _dpu_encoder_status_show(struct seq_file *s, void *data)
 {
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 204d7cc3c1de8..f43d57d9c74e1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -381,6 +381,15 @@ int dpu_encoder_helper_wait_for_irq(struct 
dpu_encoder_phys *phys_enc,
  */
 void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
 
+/**
+ * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
+ * @phys_enc: Pointer to physical encoder
+ * @output_type: HDMI/WB
+ */
+void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output

[PATCH v2 01/19] drm/msm/dpu: allow certain formats for CDM for DP

2024-02-09 Thread Paloma Arellano
CDM block supports formats other than H1V2 for DP. Since we are now
adding support for CDM over DP, relax the checks to allow all other
formats for DP other than H1V2.

Changes in v2:
- Add fixes tag
- Move patch to top of series

Fixes: 0afac0ba6024 ("drm/msm/dpu: add dpu_hw_cdm abstraction for CDM block")
Signed-off-by: Paloma Arellano 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
index e9cdc7934a499..9016b3ade6bc3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct 
dpu_hw_cdm_cfg *cdm)
dpu_hw_cdm_setup_cdwn(ctx, cdm);
 
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
-   if (fmt->chroma_sample != DPU_CHROMA_H1V2)
+   if (fmt->chroma_sample == DPU_CHROMA_H1V2)
return -EINVAL; /*unsupported format */
opmode = CDM_HDMI_PACK_OP_MODE_EN;
opmode |= (fmt->chroma_sample << 1);
-- 
2.39.2



Re: [PATCH v4 1/5] drm/msm/dpu: split irq_control into irq_enable and _disable

2024-02-09 Thread Paloma Arellano



On 2/8/2024 7:20 AM, Dmitry Baryshkov wrote:

The single helper for both enable and disable cases is too complicated,
especially if we start adding more code to these helpers. Split it into
irq_enable and irq_disable cases.

Reviewed-by: Abhinav Kumar 
Signed-off-by: Dmitry Baryshkov 


Tested-by: Paloma Arellano 




Re: [PATCH v4 3/5] drm/msm/dpu: drop dpu_encoder_phys_ops.atomic_mode_set

2024-02-09 Thread Paloma Arellano



On 2/8/2024 7:20 AM, Dmitry Baryshkov wrote:

The atomic_mode_set() callback only sets the phys_enc's IRQ data. As the
INTF and WB are statically allocated to each encoder/phys_enc, drop the
atomic_mode_set callback and set the IRQs during encoder init.

For the CMD panel usecase some of IRQ indexes depend on the selected
resources. Move setting them to the irq_enable() callback.

Reviewed-by: Abhinav Kumar 
Tested-by: Abhinav Kumar  # sc7280
Signed-off-by: Dmitry Baryshkov 


Tested-by: Paloma Arellano 




Re: [PATCH v4 2/5] drm/msm/dpu: split _dpu_encoder_resource_control_helper()

2024-02-09 Thread Paloma Arellano



On 2/8/2024 7:20 AM, Dmitry Baryshkov wrote:

Follow the _dpu_encoder_irq_control() change and split the
_dpu_encoder_resource_control_helper() into enable and disable parts.

Reviewed-by: Abhinav Kumar 
Signed-off-by: Dmitry Baryshkov 


Tested-by: Paloma Arellano 




Re: [PATCH v4 4/5] drm/msm/dpu: move writeback's atomic_check to dpu_writeback.c

2024-02-09 Thread Paloma Arellano



On 2/8/2024 7:20 AM, Dmitry Baryshkov wrote:

dpu_encoder_phys_wb is the only user of encoder's atomic_check callback.
Move corresponding checks to drm_writeback_connector's implementation
and drop the dpu_encoder_phys_wb_atomic_check() function.

Signed-off-by: Dmitry Baryshkov 



Tested-by: Paloma Arellano 




Re: [PATCH v4 5/5] drm/msm/dpu: drop dpu_encoder_phys_ops::atomic_check()

2024-02-09 Thread Paloma Arellano



On 2/8/2024 7:20 AM, Dmitry Baryshkov wrote:

Writeback was the last user of dpu_encoder_phys_ops's atomic_check()
callback. As the code was moved to the dpu_writeback.c, the callback
becomes unused. Drop it now.

Reviewed-by: Abhinav Kumar 
Signed-off-by: Dmitry Baryshkov 



Tested-by: Paloma Arellano 




Re: [PATCH 15/17] drm/msm/dpu: allow certain formats for CDM for DP

2024-02-08 Thread Paloma Arellano



On 1/25/2024 1:58 PM, Dmitry Baryshkov wrote:

On 25/01/2024 21:38, Paloma Arellano wrote:

CDM block supports formats other than H1V2 for DP. Since we are now
adding support for CDM over DP, relax the checks to allow all other
formats for DP other than H1V2.

Signed-off-by: Paloma Arellano 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c

index e9cdc7934a499..9016b3ade6bc3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c
@@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm 
*ctx, struct dpu_hw_cdm_cfg *cdm)

  dpu_hw_cdm_setup_cdwn(ctx, cdm);
    if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
-    if (fmt->chroma_sample != DPU_CHROMA_H1V2)
+    if (fmt->chroma_sample == DPU_CHROMA_H1V2)
  return -EINVAL; /*unsupported format */


This means that the original check was incorrect. Please add 
corresponding Fixes tag and move to the top of the patchset.



Ack.





  opmode = CDM_HDMI_PACK_OP_MODE_EN;
  opmode |= (fmt->chroma_sample << 1);




Re: [PATCH v4 4/5] drm/msm/dpu: move writeback's atomic_check to dpu_writeback.c

2024-02-08 Thread Paloma Arellano



On 2/8/2024 10:49 AM, Abhinav Kumar wrote:



On 2/8/2024 7:20 AM, Dmitry Baryshkov wrote:

dpu_encoder_phys_wb is the only user of encoder's atomic_check callback.
Move corresponding checks to drm_writeback_connector's implementation
and drop the dpu_encoder_phys_wb_atomic_check() function.

Signed-off-by: Dmitry Baryshkov 
---
  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c    | 54 
---

  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c    |  9 ++--
  drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c  | 61 
+-

  drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h  |  3 +-
  4 files changed, 68 insertions(+), 59 deletions(-)






+
+    crtc = conn_state->crtc;
+    if (!crtc)
+    return 0;
+


This should fix the crash and rest of the change LGTM

Reviewed-by: Abhinav Kumar 

Tested-by: Paloma Arellano 



Please give us a couple of days to re-test this and give our Tested-by 
as we plan to rebase CDM over DP on top of this and post V2.


Re: [PATCH 12/17] drm/msm/dpu: add support of new peripheral flush mechanism

2024-02-08 Thread Paloma Arellano



On 1/27/2024 9:42 PM, Dmitry Baryshkov wrote:

On Sun, 28 Jan 2024 at 07:41, Paloma Arellano  wrote:


On 1/25/2024 1:49 PM, Dmitry Baryshkov wrote:

On 25/01/2024 21:38, Paloma Arellano wrote:

From: Kuogee Hsieh 

Introduce a peripheral flushing mechanism to decouple peripheral
metadata flushing from timing engine related flush.

Signed-off-by: Kuogee Hsieh 
Signed-off-by: Paloma Arellano 
---
   .../drm/msm/disp/dpu1/dpu_encoder_phys_vid.c|  3 +++
   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c  | 17 +
   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h  | 10 ++
   3 files changed, 30 insertions(+)

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 d0f56c5c4cce9..e284bf448bdda 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
@@ -437,6 +437,9 @@ 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 (ctl->ops.update_pending_flush_periph &&
phys_enc->hw_intf->cap->type == INTF_DP)
+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 e76565c3e6a43..bf45afeb616d3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -39,6 +39,7 @@
   #define   CTL_WB_FLUSH  0x108
   #define   CTL_INTF_FLUSH0x110
   #define   CTL_CDM_FLUSH0x114
+#define   CTL_PERIPH_FLUSH  0x128
   #define   CTL_INTF_MASTER   0x134
   #define   CTL_DSPP_n_FLUSH(n)   ((0x13C) + ((n) * 4))
   @@ -49,6 +50,7 @@
   #define  MERGE_3D_IDX   23
   #define  DSC_IDX22
   #define CDM_IDX 26
+#define  PERIPH_IDX 30
   #define  INTF_IDX   31
   #define WB_IDX  16
   #define  DSPP_IDX   29  /* From DPU hw rev 7.x.x */
@@ -151,6 +153,10 @@ static inline void
dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
   ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
   }
   +if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
+DPU_REG_WRITE(>hw, CTL_PERIPH_FLUSH,
+  ctx->pending_periph_flush_mask);
+
   if (ctx->pending_flush_mask & BIT(DSC_IDX))
   DPU_REG_WRITE(>hw, CTL_DSC_FLUSH,
 ctx->pending_dsc_flush_mask);
@@ -311,6 +317,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)

I assume this is _v1.
Also the argument is misaligned.

Ack.


I noticed that the placement of the 'enum dpu_intf intf' argument aligns 
with the other dpu_hw_ctl_update_pending_flush_* functions argument 
position. Is this alright, or should I align the argument with the first 
parentheses?




+{
+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)
   {
@@ -680,6 +693,10 @@ 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;

What about the pre-active platforms?

Pre-active does not need a peripheral flush.

Ack.


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 ff85b5ee0acf8..5d86c560b6d3f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -122,6 +122,15 @@ struct dpu_hw_ctl_ops {
   void (*update_pending_flush_intf)(struct dpu_hw_ctl *ctx,
   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);
+
   /**

Re: [PATCH 05/17] drm/msm/dp: add an API to indicate if sink supports VSC SDP

2024-01-29 Thread Paloma Arellano



On 1/26/2024 6:40 PM, Dmitry Baryshkov wrote:

On Sat, 27 Jan 2024 at 02:58, Paloma Arellano  wrote:


On 1/25/2024 1:23 PM, Dmitry Baryshkov wrote:

On 25/01/2024 21:38, Paloma Arellano wrote:

YUV420 format is supported only in the VSC SDP packet and not through
MSA. Hence add an API which indicates the sink support which can be used
by the rest of the DP programming.

This API ideally should go to drm/display/drm_dp_helper.c

I'm not familiar how other vendors are checking if VSC SDP is supported.
So in moving this API, I'm going to let the other vendors make the
changes themselves.

Let me show it for you:

bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp)
{
 u8 dprx = 0;

 if (drm_dp_dpcd_readb(_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST,
   ) != 1)
 return false;
 return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED;
}



Signed-off-by: Paloma Arellano 
---
   drivers/gpu/drm/msm/dp/dp_display.c |  3 ++-
   drivers/gpu/drm/msm/dp/dp_panel.c   | 35 +
   drivers/gpu/drm/msm/dp/dp_panel.h   |  1 +
   3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c
b/drivers/gpu/drm/msm/dp/dp_display.c
index ddac55f45a722..f6b3b6ca242f8 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1617,7 +1617,8 @@ void dp_bridge_mode_set(struct drm_bridge
*drm_bridge,
   !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
 dp_display->dp_mode.out_fmt_is_yuv_420 =
- drm_mode_is_420_only(>connector->display_info, adjusted_mode);
+ drm_mode_is_420_only(>connector->display_info, adjusted_mode) &&
+dp_panel_vsc_sdp_supported(dp_display->panel);
 /* populate wide_bus_support to different layers */
   dp_display->ctrl->wide_bus_en =
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd1..af7820b6d35ec 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -17,6 +17,9 @@ struct dp_panel_private {
   struct dp_link *link;
   struct dp_catalog *catalog;
   bool panel_on;
+bool vsc_supported;
+u8 major;
+u8 minor;
   };
 static void dp_panel_read_psr_cap(struct dp_panel_private *panel)
@@ -43,9 +46,10 @@ static void dp_panel_read_psr_cap(struct
dp_panel_private *panel)
   static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
   {
   int rc;
+ssize_t rlen;
   struct dp_panel_private *panel;
   struct dp_link_info *link_info;
-u8 *dpcd, major, minor;
+u8 *dpcd, rx_feature;
 panel = container_of(dp_panel, struct dp_panel_private,
dp_panel);
   dpcd = dp_panel->dpcd;
@@ -53,10 +57,19 @@ static int dp_panel_read_dpcd(struct dp_panel
*dp_panel)
   if (rc)
   return rc;
   +rlen = drm_dp_dpcd_read(panel->aux,
DP_DPRX_FEATURE_ENUMERATION_LIST, _feature, 1);
+if (rlen != 1) {
+panel->vsc_supported = false;
+pr_debug("failed to read DP_DPRX_FEATURE_ENUMERATION_LIST\n");
+} else {
+panel->vsc_supported = !!(rx_feature &
DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED);
+pr_debug("vsc=%d\n", panel->vsc_supported);
+}
+
   link_info = _panel->link_info;
   link_info->revision = dpcd[DP_DPCD_REV];
-major = (link_info->revision >> 4) & 0x0f;
-minor = link_info->revision & 0x0f;
+panel->major = (link_info->revision >> 4) & 0x0f;
+panel->minor = link_info->revision & 0x0f;
 link_info->rate = drm_dp_max_link_rate(dpcd);
   link_info->num_lanes = drm_dp_max_lane_count(dpcd);
@@ -69,7 +82,7 @@ static int dp_panel_read_dpcd(struct dp_panel
*dp_panel)
   if (link_info->rate > dp_panel->max_dp_link_rate)
   link_info->rate = dp_panel->max_dp_link_rate;
   -drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor);
+drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", panel->major,
panel->minor);
   drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate);
   drm_dbg_dp(panel->drm_dev, "lane_count=%d\n",
link_info->num_lanes);
   @@ -280,6 +293,20 @@ void dp_panel_tpg_config(struct dp_panel
*dp_panel, bool enable)
   dp_catalog_panel_tpg_enable(catalog,
>dp_panel.dp_mode.drm_mode);
   }
   +bool dp_panel_vsc_sdp_supported(struct dp_panel *dp_panel)
+{
+struct dp_panel_private *panel;
+
+if (!dp_panel) {
+pr_err("invalid input\n");
+return false;
+}
+
+panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+return panel->major >= 1 && panel->minor >= 3 &&
panel->vsc_supported;

Anyway, this check is incorrect. Please compare the whole 

Re: [PATCH 01/17] drm/msm/dpu: allow dpu_encoder_helper_phys_setup_cdm to work for DP

2024-01-29 Thread Paloma Arellano



On 1/28/2024 9:12 PM, Dmitry Baryshkov wrote:

On Mon, 29 Jan 2024 at 06:33, Abhinav Kumar  wrote:



On 1/28/2024 8:12 PM, Dmitry Baryshkov wrote:

On Mon, 29 Jan 2024 at 06:01, Abhinav Kumar  wrote:



On 1/28/2024 7:23 PM, Dmitry Baryshkov wrote:

On Mon, 29 Jan 2024 at 05:06, Abhinav Kumar  wrote:



On 1/26/2024 4:39 PM, Paloma Arellano wrote:

On 1/25/2024 1:14 PM, Dmitry Baryshkov wrote:

On 25/01/2024 21:38, Paloma Arellano wrote:

Generalize dpu_encoder_helper_phys_setup_cdm to be compatible with DP.

Signed-off-by: Paloma Arellano 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h  |  4 +--
 .../drm/msm/disp/dpu1/dpu_encoder_phys_wb.c   | 31 ++-
 2 files changed, 18 insertions(+), 17 deletions(-)

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 993f263433314..37ac385727c3b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -153,6 +153,7 @@ enum dpu_intr_idx {
  * @hw_intf:Hardware interface to the intf registers
  * @hw_wb:Hardware interface to the wb registers
  * @hw_cdm:Hardware interface to the CDM registers
+ * @cdm_cfg:CDM block config needed to store WB/DP block's CDM
configuration

Please realign the description.

Ack

  * @dpu_kms:Pointer to the dpu_kms top level
  * @cached_mode:DRM mode cached at mode_set time, acted on in
enable
  * @vblank_ctl_lock:Vblank ctl mutex lock to protect
vblank_refcount
@@ -183,6 +184,7 @@ struct dpu_encoder_phys {
 struct dpu_hw_intf *hw_intf;
 struct dpu_hw_wb *hw_wb;
 struct dpu_hw_cdm *hw_cdm;
+struct dpu_hw_cdm_cfg cdm_cfg;

It might be slightly better to move it after all the pointers, so
after the dpu_kms.

Ack

 struct dpu_kms *dpu_kms;
 struct drm_display_mode cached_mode;
 struct mutex vblank_ctl_lock;
@@ -213,7 +215,6 @@ static inline int
dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
  * @wbirq_refcount: Reference count of writeback interrupt
  * @wb_done_timeout_cnt: number of wb done irq timeout errors
  * @wb_cfg:  writeback block config to store fb related details
- * @cdm_cfg: cdm block config needed to store writeback block's CDM
configuration
  * @wb_conn: backpointer to writeback connector
  * @wb_job: backpointer to current writeback job
  * @dest:   dpu buffer layout for current writeback output buffer
@@ -223,7 +224,6 @@ struct dpu_encoder_phys_wb {
 atomic_t wbirq_refcount;
 int wb_done_timeout_cnt;
 struct dpu_hw_wb_cfg wb_cfg;
-struct dpu_hw_cdm_cfg cdm_cfg;
 struct drm_writeback_connector *wb_conn;
 struct drm_writeback_job *wb_job;
 struct dpu_hw_fmt_layout dest;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 4cd2d9e3131a4..072fc6950e496 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -269,28 +269,21 @@ static void
dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc)
  * This API does not handle
DPU_CHROMA_H1V2.
  * @phys_enc:Pointer to physical encoder
  */
-static void dpu_encoder_helper_phys_setup_cdm(struct
dpu_encoder_phys *phys_enc)
+static void dpu_encoder_helper_phys_setup_cdm(struct
dpu_encoder_phys *phys_enc,
+  const struct dpu_format *dpu_fmt,
+  u32 output_type)
 {
 struct dpu_hw_cdm *hw_cdm;
 struct dpu_hw_cdm_cfg *cdm_cfg;
 struct dpu_hw_pingpong *hw_pp;
-struct dpu_encoder_phys_wb *wb_enc;
-const struct msm_format *format;
-const struct dpu_format *dpu_fmt;
-struct drm_writeback_job *wb_job;
 int ret;
   if (!phys_enc)
 return;
 -wb_enc = to_dpu_encoder_phys_wb(phys_enc);
-cdm_cfg = _enc->cdm_cfg;
+cdm_cfg = _enc->cdm_cfg;
 hw_pp = phys_enc->hw_pp;
 hw_cdm = phys_enc->hw_cdm;
-wb_job = wb_enc->wb_job;
-
-format = msm_framebuffer_format(wb_enc->wb_job->fb);
-dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format,
wb_job->fb->modifier);
   if (!hw_cdm)
 return;
@@ -306,10 +299,10 @@ static void
dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc)
   memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
 -cdm_cfg->output_width = wb_job->fb->width;
-cdm_cfg->output_height = wb_job->fb->height;
+cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
+cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;

This is a semantic change. Instead of passing the FB size, this passes
the mode dimensions. They are not guaranteed to be the same,
especially 

Re: [PATCH 16/17] drm/msm/dpu: reserve CDM blocks for DP if mode is YUV420

2024-01-27 Thread Paloma Arellano



On 1/25/2024 2:01 PM, Dmitry Baryshkov wrote:

On 25/01/2024 21:38, Paloma Arellano wrote:

Reserve CDM blocks for DP if the mode format is YUV420. Currently this
reservation only works for writeback and DP if the format is YUV420. But
this can be easily extented to other YUV formats for DP.

Signed-off-by: Paloma Arellano 
---
  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 20 +---
  1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c

index 99ec53446ad21..c7dcda3d54ae6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -613,6 +613,7 @@ static int dpu_encoder_virt_atomic_check(
  struct dpu_kms *dpu_kms;
  struct drm_display_mode *adj_mode;
  struct msm_display_topology topology;
+    struct msm_display_info *disp_info;
  struct dpu_global_state *global_state;
  struct drm_framebuffer *fb;
  struct drm_dsc_config *dsc;
@@ -629,6 +630,7 @@ static int dpu_encoder_virt_atomic_check(
  DPU_DEBUG_ENC(dpu_enc, "\n");
    priv = drm_enc->dev->dev_private;
+    disp_info = _enc->disp_info;
  dpu_kms = to_dpu_kms(priv->kms);
  adj_mode = _state->adjusted_mode;
  global_state = dpu_kms_get_global_state(crtc_state->state);
@@ -656,8 +658,8 @@ static int dpu_encoder_virt_atomic_check(
  topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, 
crtc_state, dsc);

    /*
- * Use CDM only for writeback at the moment as other interfaces 
cannot handle it.
- * if writeback itself cannot handle cdm for some reason it will 
fail in its atomic_check()
+ * Use CDM only for writeback or DP at the moment as other 
interfaces cannot handle it.
+ * If writeback itself cannot handle cdm for some reason it will 
fail in its atomic_check()

   * earlier.
   */
  if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {

@@ -665,12 +667,15 @@ static int dpu_encoder_virt_atomic_check(
    if (fb && 
DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb

  topology.needs_cdm = true;
-    if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
-    crtc_state->mode_changed = true;
-    else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
-    crtc_state->mode_changed = true;
+    } else if (dpu_enc->disp_info.intf_type == INTF_DP) {


You can use disp_info directly here.

Ack


+    if 
(msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], 
adj_mode))

+    topology.needs_cdm = true;
  }
  +    if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
+    crtc_state->mode_changed = true;
+    else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
+    crtc_state->mode_changed = true;
  /*
   * Release and Allocate resources on every modeset
   * Dont allocate when active is false.
@@ -,7 +1116,8 @@ static void 
dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,

    dpu_enc->dsc_mask = dsc_mask;
  -    if (dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) {
+    if ((dpu_enc->disp_info.intf_type == INTF_WB && 
conn_state->writeback_job) ||

+    dpu_enc->disp_info.intf_type == INTF_DP) {
  struct dpu_hw_blk *hw_cdm = NULL;
    dpu_rm_get_assigned_resources(_kms->rm, global_state,




  1   2   >