Re: [PATCH v2 2/3] drm/msm/dsi: Set PHY usescase (and mode) before registering DSI host

2025-02-09 Thread Dmitry Baryshkov
On Sun, Feb 09, 2025 at 10:42:53PM +0100, Marijn Suijten wrote:
> Ordering issues here cause an uninitialized (default STANDALONE)
> usecase to be programmed (which appears to be a MUX) in some cases
> when msm_dsi_host_register() is called, leading to the slave PLL in
> bonded-DSI mode to source from a clock parent (dsi1vco) that is off.
> 
> This should seemingly not be a problem as the actual dispcc clocks from
> DSI1 that are muxed in the clock tree of DSI0 are way further down, this
> bit still seems to have an effect on them somehow and causes the right
> side of the panel controlled by DSI1 to not function.
> 
> In an ideal world this code is refactored to no longer have such
> error-prone calls "across subsystems", and instead model the "PLL src"
> register field as a regular mux so that changing the clock parents
> programmatically or in DTS via `assigned-clock-parents` has the
> desired effect.
> But for the avid reader, the clocks that we *are* muxing into DSI0's
> tree are way further down, so if this bit turns out to be a simple mux
> between dsiXvco and out_div, that shouldn't have any effect as this
> whole tree is off anyway.
> 
> Signed-off-by: Marijn Suijten 
> ---
>  drivers/gpu/drm/msm/dsi/dsi_manager.c | 30 +++---
>  1 file changed, 19 insertions(+), 11 deletions(-)


Fixes: 57bf43389337 ("drm/msm/dsi: Pass down use case to PHY")
Reviewed-by: Dmitry Baryshkov 

> 
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c 
> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index 
> a210b7c9e5ca281a46fbdb226e25832719a684ea..b93205c034e4acc73d536deeddce6ebd694b4a80
>  100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -74,17 +74,33 @@ static int dsi_mgr_setup_components(int id)
>   int ret;
>  
>   if (!IS_BONDED_DSI()) {
> + /* Set the usecase before calling msm_dsi_host_register(), 
> which would
> +  * already program the PLL source mux based on a default 
> usecase.
> +  */
> + msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
> + msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
> +
>   ret = msm_dsi_host_register(msm_dsi->host);
>   if (ret)
>   return ret;
> -
> - msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
> - msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
>   } else if (other_dsi) {
>   struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ?
>   msm_dsi : other_dsi;
>   struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ?
>   other_dsi : msm_dsi;
> +
> + /* PLL0 is to drive both DSI link clocks in bonded DSI mode.
> +  *
> + /* Set the usecase before calling msm_dsi_host_register(), 
> which would
> +  * already program the PLL source mux based on a default 
> usecase.
> +  */
> + msm_dsi_phy_set_usecase(clk_master_dsi->phy,
> + MSM_DSI_PHY_MASTER);
> + msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
> + MSM_DSI_PHY_SLAVE);
> + msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
> + msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy);
> +
>   /* Register slave host first, so that slave DSI device
>* has a chance to probe, and do not block the master
>* DSI device's probe.
> @@ -98,14 +114,6 @@ static int dsi_mgr_setup_components(int id)
>   ret = msm_dsi_host_register(master_link_dsi->host);
>   if (ret)
>   return ret;
> -
> - /* PLL0 is to drive both 2 DSI link clocks in bonded DSI mode. 
> */
> - msm_dsi_phy_set_usecase(clk_master_dsi->phy,
> - MSM_DSI_PHY_MASTER);
> - msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
> - MSM_DSI_PHY_SLAVE);
> - msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
> - msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy);
>   }
>  
>   return 0;
> 
> -- 
> 2.48.1
> 

-- 
With best wishes
Dmitry


Re: [PATCH v2 3/3] drm/msm/dpu: Remove arbitrary limit of 1 interface in DSC topology

2025-02-09 Thread Dmitry Baryshkov
On Sun, Feb 09, 2025 at 10:42:54PM +0100, Marijn Suijten wrote:
> When DSC is enabled the number of interfaces is forced to be 1, and
> documented that it is a "power-optimal" layout to use two DSC encoders
> together with two Layer Mixers.  However, the same layout (two DSC
> hard-slice encoders with two LMs) is also used when the display is
> fed with data over two instead of one interface (common on 4k@120Hz
> smartphone panels with Dual-DSI).  Solve this by simply removing the
> num_intf = 1 assignment as the count is already calculated by computing
> the number of physical encoders within the virtual encoder.
> 
> Fixes: 7e9cc175b159 ("drm/msm/disp/dpu1: Add support for DSC in topology")
> Signed-off-by: Marijn Suijten 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 7 ---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 

Reviewed-by: Dmitry Baryshkov 

-- 
With best wishes
Dmitry


[PATCH v2 1/3] drm/msm/dsi: Use existing per-interface slice count in DSC timing

2025-02-09 Thread Marijn Suijten
When configuring the timing of DSI hosts (interfaces) in
dsi_timing_setup() all values written to registers are taking
bonded-mode into account by dividing the original mode width by 2
(half the data is sent over each of the two DSI hosts), but the full
width instead of the interface width is passed as hdisplay parameter to
dsi_update_dsc_timing().

Currently only msm_dsc_get_slices_per_intf() is called within
dsi_update_dsc_timing() with the `hdisplay` argument which clearly
documents that it wants the width of a single interface (which, again,
in bonded DSI mode is half the total width of the mode) resulting in all
subsequent values to be completely off.

However, as soon as we start to pass the halved hdisplay
into dsi_update_dsc_timing() we might as well discard
msm_dsc_get_slices_per_intf() since the value it calculates is already
available in dsc->slice_count which is per-interface by the current
design of MSM DPU/DSI implementations and their use of the DRM DSC
helpers.

Fixes: 08802f515c3c ("drm/msm/dsi: Add support for DSC configuration")
Signed-off-by: Marijn Suijten 
---
 drivers/gpu/drm/msm/dsi/dsi_host.c   |  8 
 drivers/gpu/drm/msm/msm_dsc_helper.h | 11 ---
 2 files changed, 4 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c 
b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 
007311c21fdaa0462b05d53cd8a2aad0269b1727..42e100a8adca09d7b55afce0e2553e76d898744f
 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -846,7 +846,7 @@ static void dsi_ctrl_enable(struct msm_dsi_host *msm_host,
dsi_write(msm_host, REG_DSI_CPHY_MODE_CTRL, BIT(0));
 }
 
-static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool 
is_cmd_mode, u32 hdisplay)
+static void dsi_update_dsc_timing(struct msm_dsi_host *msm_host, bool 
is_cmd_mode)
 {
struct drm_dsc_config *dsc = msm_host->dsc;
u32 reg, reg_ctrl, reg_ctrl2;
@@ -858,7 +858,7 @@ static void dsi_update_dsc_timing(struct msm_dsi_host 
*msm_host, bool is_cmd_mod
/* first calculate dsc parameters and then program
 * compress mode registers
 */
-   slice_per_intf = msm_dsc_get_slices_per_intf(dsc, hdisplay);
+   slice_per_intf = dsc->slice_count;
 
total_bytes_per_intf = dsc->slice_chunk_size * slice_per_intf;
bytes_per_pkt = dsc->slice_chunk_size; /* * slice_per_pkt; */
@@ -991,7 +991,7 @@ static void dsi_timing_setup(struct msm_dsi_host *msm_host, 
bool is_bonded_dsi)
 
if (msm_host->mode_flags & MIPI_DSI_MODE_VIDEO) {
if (msm_host->dsc)
-   dsi_update_dsc_timing(msm_host, false, mode->hdisplay);
+   dsi_update_dsc_timing(msm_host, false);
 
dsi_write(msm_host, REG_DSI_ACTIVE_H,
DSI_ACTIVE_H_START(ha_start) |
@@ -1012,7 +1012,7 @@ static void dsi_timing_setup(struct msm_dsi_host 
*msm_host, bool is_bonded_dsi)
DSI_ACTIVE_VSYNC_VPOS_END(vs_end));
} else {/* command mode */
if (msm_host->dsc)
-   dsi_update_dsc_timing(msm_host, true, mode->hdisplay);
+   dsi_update_dsc_timing(msm_host, true);
 
/* image data and 1 byte write_memory_start cmd */
if (!msm_host->dsc)
diff --git a/drivers/gpu/drm/msm/msm_dsc_helper.h 
b/drivers/gpu/drm/msm/msm_dsc_helper.h
index 
b9049fe1e2790703a6f42dd7e6cd3fa5eea29389..63f95523b2cbb48f822210ac47cdd3526f231a89
 100644
--- a/drivers/gpu/drm/msm/msm_dsc_helper.h
+++ b/drivers/gpu/drm/msm/msm_dsc_helper.h
@@ -12,17 +12,6 @@
 #include 
 #include 
 
-/**
- * msm_dsc_get_slices_per_intf() - calculate number of slices per interface
- * @dsc: Pointer to drm dsc config struct
- * @intf_width: interface width in pixels
- * Returns: Integer representing the number of slices for the given interface
- */
-static inline u32 msm_dsc_get_slices_per_intf(const struct drm_dsc_config 
*dsc, u32 intf_width)
-{
-   return DIV_ROUND_UP(intf_width, dsc->slice_width);
-}
-
 /**
  * msm_dsc_get_bytes_per_line() - calculate bytes per line
  * @dsc: Pointer to drm dsc config struct

-- 
2.48.1



[PATCH v2 2/3] drm/msm/dsi: Set PHY usescase (and mode) before registering DSI host

2025-02-09 Thread Marijn Suijten
Ordering issues here cause an uninitialized (default STANDALONE)
usecase to be programmed (which appears to be a MUX) in some cases
when msm_dsi_host_register() is called, leading to the slave PLL in
bonded-DSI mode to source from a clock parent (dsi1vco) that is off.

This should seemingly not be a problem as the actual dispcc clocks from
DSI1 that are muxed in the clock tree of DSI0 are way further down, this
bit still seems to have an effect on them somehow and causes the right
side of the panel controlled by DSI1 to not function.

In an ideal world this code is refactored to no longer have such
error-prone calls "across subsystems", and instead model the "PLL src"
register field as a regular mux so that changing the clock parents
programmatically or in DTS via `assigned-clock-parents` has the
desired effect.
But for the avid reader, the clocks that we *are* muxing into DSI0's
tree are way further down, so if this bit turns out to be a simple mux
between dsiXvco and out_div, that shouldn't have any effect as this
whole tree is off anyway.

Signed-off-by: Marijn Suijten 
---
 drivers/gpu/drm/msm/dsi/dsi_manager.c | 30 +++---
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c 
b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index 
a210b7c9e5ca281a46fbdb226e25832719a684ea..b93205c034e4acc73d536deeddce6ebd694b4a80
 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -74,17 +74,33 @@ static int dsi_mgr_setup_components(int id)
int ret;
 
if (!IS_BONDED_DSI()) {
+   /* Set the usecase before calling msm_dsi_host_register(), 
which would
+* already program the PLL source mux based on a default 
usecase.
+*/
+   msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
+   msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
+
ret = msm_dsi_host_register(msm_dsi->host);
if (ret)
return ret;
-
-   msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE);
-   msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
} else if (other_dsi) {
struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ?
msm_dsi : other_dsi;
struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ?
other_dsi : msm_dsi;
+
+   /* PLL0 is to drive both DSI link clocks in bonded DSI mode.
+*
+   /* Set the usecase before calling msm_dsi_host_register(), 
which would
+* already program the PLL source mux based on a default 
usecase.
+*/
+   msm_dsi_phy_set_usecase(clk_master_dsi->phy,
+   MSM_DSI_PHY_MASTER);
+   msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
+   MSM_DSI_PHY_SLAVE);
+   msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
+   msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy);
+
/* Register slave host first, so that slave DSI device
 * has a chance to probe, and do not block the master
 * DSI device's probe.
@@ -98,14 +114,6 @@ static int dsi_mgr_setup_components(int id)
ret = msm_dsi_host_register(master_link_dsi->host);
if (ret)
return ret;
-
-   /* PLL0 is to drive both 2 DSI link clocks in bonded DSI mode. 
*/
-   msm_dsi_phy_set_usecase(clk_master_dsi->phy,
-   MSM_DSI_PHY_MASTER);
-   msm_dsi_phy_set_usecase(clk_slave_dsi->phy,
-   MSM_DSI_PHY_SLAVE);
-   msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy);
-   msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy);
}
 
return 0;

-- 
2.48.1



[PATCH v2 3/3] drm/msm/dpu: Remove arbitrary limit of 1 interface in DSC topology

2025-02-09 Thread Marijn Suijten
When DSC is enabled the number of interfaces is forced to be 1, and
documented that it is a "power-optimal" layout to use two DSC encoders
together with two Layer Mixers.  However, the same layout (two DSC
hard-slice encoders with two LMs) is also used when the display is
fed with data over two instead of one interface (common on 4k@120Hz
smartphone panels with Dual-DSI).  Solve this by simply removing the
num_intf = 1 assignment as the count is already calculated by computing
the number of physical encoders within the virtual encoder.

Fixes: 7e9cc175b159 ("drm/msm/disp/dpu1: Add support for DSC in topology")
Signed-off-by: Marijn Suijten 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 
b585cd17462345f94bcc2ddd57902cc7c312ae63..b0870318471bd7cceda70fd15ea7bcc8658af604
 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -686,20 +686,21 @@ static struct msm_display_topology 
dpu_encoder_get_topology(
 
if (dsc) {
/*
-* Use 2 DSC encoders and 2 layer mixers per single interface
+* Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces
 * when Display Stream Compression (DSC) is enabled,
 * and when enough DSC blocks are available.
 * This is power-optimal and can drive up to (including) 4k
 * screens.
 */
-   if (dpu_kms->catalog->dsc_count >= 2) {
+   WARN(topology.num_intf > 2,
+"DSC topology cannot support more than 2 interfaces\n");
+   if (intf_count >= 2 || dpu_kms->catalog->dsc_count >= 2) {
topology.num_dsc = 2;
topology.num_lm = 2;
} else {
topology.num_dsc = 1;
topology.num_lm = 1;
}
-   topology.num_intf = 1;
}
 
return topology;

-- 
2.48.1



[PATCH v2 0/3] drm/msm: Initial fixes for DUALPIPE (+DSC) topology

2025-02-09 Thread Marijn Suijten
This series covers a step-up towards supporting the DUALPIPE DSC
topology, also known as 2:2:2 topology (on active-CTL hardware).  It
involves 2 layer mixers, 2 DSC compression encoders, and 2 interfaces
(on DSI, this is called bonded-DSI) where bandwidth constraints (e.g. 4k
panels at 120Hz) require two interfaces to transmit pixel data.

Enabling this topology will be hard(er) than downstream as hacking a
layout type in DTS won't be describing the hardware, but "dynamically"
determining it at runtime may pose some of a challenge that is left to a
future series.  Such changes will also involve the 1:1:1 topology needed
for constrained hardware like the Fairphone 5 on SC7280 with access to
only one DSC encoder and thus ruled out of the current 2:2:1 topology.

Likewise, the patches and discussions around improving active-CTL
configuration to support bonded interfaces (that share a single CTL
block) are still in full swing and hence elided from this series, apart
from one patch to fix the ACTIVE_DSC register coding to support updates,
so that it is not forgotten about.

This issue and successful resolution of all the problems is discussed
and demonstrated in https://gitlab.freedesktop.org/drm/msm/-/issues/41.

Signed-off-by: Marijn Suijten 
---
Changes in v2:
- Dropped patches that were applied;
- dsi_mgr_setup_components() now sets both the usecase and phy_mode
  prior to calling msm_dsi_host_register(), and for non-bonded too;
- Added patch to remove a forced num_intf = 1 when DSC is enabled;
- Reworked hdisplay/2 "fix" when calculating "DSC timing" to instead use
  dsc->slice_count, allowing us to remove msm_dsc_get_slices_per_intf()
  entirely;
- Link to v1: 
https://lore.kernel.org/r/20240417-drm-msm-initial-dualpipe-dsc-fixes-v1-0-78ae3ee9a...@somainline.org

Depends on:
- 
https://lore.kernel.org/linux-arm-msm/20250122-dpu-111-topology-v2-1-505e95964...@somainline.org/
  (only to prevent conflicts with the patch that removes a hardcoded
   num_intf = 1;).

---
Marijn Suijten (3):
  drm/msm/dsi: Use existing per-interface slice count in DSC timing
  drm/msm/dsi: Set PHY usescase (and mode) before registering DSI host
  drm/msm/dpu: Remove arbitrary limit of 1 interface in DSC topology

 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c |  7 ---
 drivers/gpu/drm/msm/dsi/dsi_host.c  |  8 
 drivers/gpu/drm/msm/dsi/dsi_manager.c   | 30 ++---
 drivers/gpu/drm/msm/msm_dsc_helper.h| 11 ---
 4 files changed, 27 insertions(+), 29 deletions(-)
---
base-commit: ed58d103e6da15a442ff87567898768dc3a66987
change-id: 20240416-drm-msm-initial-dualpipe-dsc-fixes-3f0715b03bf4
prerequisite-message-id: 
<20250122-dpu-111-topology-v2-1-505e95964...@somainline.org>
prerequisite-patch-id: 9ed44ae089b173f452a6603e6739b0b3bf2d9274

Best regards,
-- 
Marijn Suijten 



Re: [PATCH] drm/msm/dpu: Fix uninitialized variable

2025-02-09 Thread Dmitry Baryshkov
On Sun, Feb 09, 2025 at 10:32:33PM -0500, Ethan Carter Edwards wrote:
> There is a possibility for an uninitialized *ret* variable to be
> returned in some code paths.
> 
> Fix this by initializing *ret* to 0.
> 
> Addresses-Coverity-ID: 1642546 ("Uninitialized scalar variable")
> Fixes: 774bcfb731765d ("drm/msm/dpu: add support for virtual planes")
> Signed-off-by: Ethan Carter Edwards 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> index 
> 098abc2c0003cde90ce6219c97ee18fa055a92a5..74edaa9ecee72111b70f32b832486aeebe545a28
>  100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
> @@ -1164,7 +1164,7 @@ int dpu_assign_plane_resources(struct dpu_global_state 
> *global_state,
>  unsigned int num_planes)
>  {
>   unsigned int i;
> - int ret;
> + int ret = 0;

Thanks, but I think it better to make the function return ret from
within the loop and return explicit 0 if there was no error.

>  
>   for (i = 0; i < num_planes; i++) {
>   struct drm_plane_state *plane_state = states[i];
> 
> ---
> base-commit: a64dcfb451e254085a7daee5fe51bf22959d52d3
> change-id: 20250209-dpu-c3fac78fc617
> 
> Best regards,
> -- 
> Ethan Carter Edwards 
> 

-- 
With best wishes
Dmitry


Re: [PATCH v2] drm/msm/dpu: Fix uninitialized variable

2025-02-09 Thread Dmitry Baryshkov
On Sun, Feb 09, 2025 at 10:51:54PM -0500, Ethan Carter Edwards wrote:
> There is a possibility for an uninitialized *ret* variable to be
> returned in some code paths.
> 
> Fix this by initializing *ret* to 0.
> 
> Addresses-Coverity-ID: 1642546 ("Uninitialized scalar variable")
> Fixes: 774bcfb731765d ("drm/msm/dpu: add support for virtual planes")
> Signed-off-by: Ethan Carter Edwards 
> ---
> Changes in v2:
> - Return explicit 0 when no error occurs
> - Add hardening mailing lists
> - Link to v1: 
> https://lore.kernel.org/r/20250209-dpu-v1-1-0db666884...@ethancedwards.com
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 7 +++
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 

Reviewed-by: Dmitry Baryshkov 

-- 
With best wishes
Dmitry


Re: [PATCH v2 2/3] drm/msm/dsi: Set PHY usescase (and mode) before registering DSI host

2025-02-09 Thread Abhinav Kumar




On 2/9/2025 1:42 PM, Marijn Suijten wrote:

Ordering issues here cause an uninitialized (default STANDALONE)
usecase to be programmed (which appears to be a MUX) in some cases
when msm_dsi_host_register() is called, leading to the slave PLL in
bonded-DSI mode to source from a clock parent (dsi1vco) that is off.

This should seemingly not be a problem as the actual dispcc clocks from
DSI1 that are muxed in the clock tree of DSI0 are way further down, this
bit still seems to have an effect on them somehow and causes the right
side of the panel controlled by DSI1 to not function.

In an ideal world this code is refactored to no longer have such
error-prone calls "across subsystems", and instead model the "PLL src"
register field as a regular mux so that changing the clock parents
programmatically or in DTS via `assigned-clock-parents` has the
desired effect.
But for the avid reader, the clocks that we *are* muxing into DSI0's
tree are way further down, so if this bit turns out to be a simple mux
between dsiXvco and out_div, that shouldn't have any effect as this
whole tree is off anyway.

Signed-off-by: Marijn Suijten 
---
  drivers/gpu/drm/msm/dsi/dsi_manager.c | 30 +++---
  1 file changed, 19 insertions(+), 11 deletions(-)



Reviewed-by: Abhinav Kumar 


[PATCH v2 1/3] drm/display: bridge-connector: add DisplayPort bridges

2025-02-09 Thread Dmitry Baryshkov
DRM HDMI Codec framework is useful not only for the HDMI bridges, but
also for the DisplayPort bridges. Add new DRM_BRIDGE_OP_DisplayPort
define in order to distinguish DP bridges. Create HDMI codec device
automatically for DP bridges which have declared audio support.

Note, unlike HDMI devices, which already have a framework to handle HPD
notifications in a standard way, DP drivers don't (yet?) have such a
framework. As such it is necessary to manually call
drm_connector_hdmi_audio_plugged_notify(). This requirement hopefully
can be lifted later on, if/when DRM framework gets better DisplayPort
ports support in the core layer.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 66 --
 include/drm/drm_bridge.h   | 14 +-
 2 files changed, 65 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c 
b/drivers/gpu/drm/display/drm_bridge_connector.c
index 
30c736fc0067e31a97db242e5b16ea8a5b4cf359..5e031395b801f9a1371dcb4ac09f3da23e4615dd
 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -98,6 +98,13 @@ struct drm_bridge_connector {
 * HDMI connector infrastructure, if any (see &DRM_BRIDGE_OP_HDMI).
 */
struct drm_bridge *bridge_hdmi;
+   /**
+* @bridge_dp:
+*
+* The bridge in the chain that implements necessary support for the
+* DisplayPort connector infrastructure, if any (see 
&DRM_BRIDGE_OP_DisplayPort).
+*/
+   struct drm_bridge *bridge_dp;
 };
 
 #define to_drm_bridge_connector(x) \
@@ -496,6 +503,25 @@ static const struct drm_connector_hdmi_audio_funcs 
drm_bridge_connector_hdmi_aud
.mute_stream = drm_bridge_connector_audio_mute_stream,
 };
 
+static int drm_bridge_connector_hdmi_audio_init(struct drm_connector 
*connector,
+   struct drm_bridge *bridge)
+{
+   if (!bridge->hdmi_audio_max_i2s_playback_channels &&
+   !bridge->hdmi_audio_spdif_playback)
+   return 0;
+
+   if (!bridge->funcs->hdmi_audio_prepare ||
+   !bridge->funcs->hdmi_audio_shutdown)
+   return -EINVAL;
+
+   return drm_connector_hdmi_audio_init(connector,
+bridge->hdmi_audio_dev,
+
&drm_bridge_connector_hdmi_audio_funcs,
+
bridge->hdmi_audio_max_i2s_playback_channels,
+bridge->hdmi_audio_spdif_playback,
+bridge->hdmi_audio_dai_port);
+}
+
 /* 
-
  * Bridge Connector Initialisation
  */
@@ -564,6 +590,8 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
if (bridge->ops & DRM_BRIDGE_OP_HDMI) {
if (bridge_connector->bridge_hdmi)
return ERR_PTR(-EBUSY);
+   if (bridge_connector->bridge_dp)
+   return ERR_PTR(-EINVAL);
if (!bridge->funcs->hdmi_write_infoframe ||
!bridge->funcs->hdmi_clear_infoframe)
return ERR_PTR(-EINVAL);
@@ -576,6 +604,16 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
max_bpc = bridge->max_bpc;
}
 
+   if (bridge->ops & DRM_BRIDGE_OP_DisplayPort) {
+   if (bridge_connector->bridge_dp)
+   return ERR_PTR(-EBUSY);
+   if (bridge_connector->bridge_hdmi)
+   return ERR_PTR(-EINVAL);
+
+   bridge_connector->bridge_dp = bridge;
+
+   }
+
if (!drm_bridge_get_next_bridge(bridge))
connector_type = bridge->type;
 
@@ -612,21 +650,21 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
if (ret)
return ERR_PTR(ret);
 
-   if (bridge->hdmi_audio_max_i2s_playback_channels ||
-   bridge->hdmi_audio_spdif_playback) {
-   if (!bridge->funcs->hdmi_audio_prepare ||
-   !bridge->funcs->hdmi_audio_shutdown)
-   return ERR_PTR(-EINVAL);
+   ret = drm_bridge_connector_hdmi_audio_init(connector, bridge);
+   if (ret)
+   return ERR_PTR(ret);
+   } else if (bridge_connector->bridge_dp) {
+   bridge = bridge_connector->bridge_dp;
 
-   ret = drm_connector_hdmi_audio_init(connector,
-   
bridge->hdmi_audio_dev,
-

[PATCH v2 3/3] drm/msm/dp: reuse generic HDMI codec implementation

2025-02-09 Thread Dmitry Baryshkov
The MSM DisplayPort driver implements several HDMI codec functions
in the driver, e.g. it manually manages HDMI codec device registration,
returning ELD and plugged_cb support. In order to reduce code
duplication reuse drm_hdmi_audio_* helpers and drm_bridge_connector
integration.

As a part of this change, also drop the call to
drm_connector_attach_dp_subconnector_property(), it is now being handled
by the drm_bridge_connector.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/Kconfig |   1 +
 drivers/gpu/drm/msm/dp/dp_audio.c   | 131 
 drivers/gpu/drm/msm/dp/dp_audio.h   |  27 ++--
 drivers/gpu/drm/msm/dp/dp_display.c |  31 ++---
 drivers/gpu/drm/msm/dp/dp_display.h |   6 --
 drivers/gpu/drm/msm/dp/dp_drm.c |  11 ++-
 6 files changed, 34 insertions(+), 173 deletions(-)

diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 
7ec833b6d8292f8cb26cfe5582812f2754cd4d35..fe36a3bcfe03994952d1b5e1b423e923e3e3b014
 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -104,6 +104,7 @@ config DRM_MSM_DPU
 config DRM_MSM_DP
bool "Enable DisplayPort support in MSM DRM driver"
depends on DRM_MSM
+   select DRM_DISPLAY_HDMI_AUDIO_HELPER
select RATIONAL
default y
help
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c 
b/drivers/gpu/drm/msm/dp/dp_audio.c
index 
70fdc9fe228a7149546accd8479a9e4397f3d5dd..f8bfb908f9b4bf93ad5480f0785e3aed23dde160
 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -13,13 +13,13 @@
 
 #include "dp_catalog.h"
 #include "dp_audio.h"
+#include "dp_drm.h"
 #include "dp_panel.h"
 #include "dp_reg.h"
 #include "dp_display.h"
 #include "dp_utils.h"
 
 struct msm_dp_audio_private {
-   struct platform_device *audio_pdev;
struct platform_device *pdev;
struct drm_device *drm_dev;
struct msm_dp_catalog *catalog;
@@ -160,24 +160,11 @@ static void msm_dp_audio_enable(struct 
msm_dp_audio_private *audio, bool enable)
msm_dp_catalog_audio_enable(catalog, enable);
 }
 
-static struct msm_dp_audio_private *msm_dp_audio_get_data(struct 
platform_device *pdev)
+static struct msm_dp_audio_private *msm_dp_audio_get_data(struct msm_dp 
*msm_dp_display)
 {
struct msm_dp_audio *msm_dp_audio;
-   struct msm_dp *msm_dp_display;
-
-   if (!pdev) {
-   DRM_ERROR("invalid input\n");
-   return ERR_PTR(-ENODEV);
-   }
-
-   msm_dp_display = platform_get_drvdata(pdev);
-   if (!msm_dp_display) {
-   DRM_ERROR("invalid input\n");
-   return ERR_PTR(-ENODEV);
-   }
 
msm_dp_audio = msm_dp_display->msm_dp_audio;
-
if (!msm_dp_audio) {
DRM_ERROR("invalid msm_dp_audio data\n");
return ERR_PTR(-EINVAL);
@@ -186,68 +173,16 @@ static struct msm_dp_audio_private 
*msm_dp_audio_get_data(struct platform_device
return container_of(msm_dp_audio, struct msm_dp_audio_private, 
msm_dp_audio);
 }
 
-static int msm_dp_audio_hook_plugged_cb(struct device *dev, void *data,
-   hdmi_codec_plugged_cb fn,
-   struct device *codec_dev)
-{
-
-   struct platform_device *pdev;
-   struct msm_dp *msm_dp_display;
-
-   pdev = to_platform_device(dev);
-   if (!pdev) {
-   pr_err("invalid input\n");
-   return -ENODEV;
-   }
-
-   msm_dp_display = platform_get_drvdata(pdev);
-   if (!msm_dp_display) {
-   pr_err("invalid input\n");
-   return -ENODEV;
-   }
-
-   return msm_dp_display_set_plugged_cb(msm_dp_display, fn, codec_dev);
-}
-
-static int msm_dp_audio_get_eld(struct device *dev,
-   void *data, uint8_t *buf, size_t len)
-{
-   struct platform_device *pdev;
-   struct msm_dp *msm_dp_display;
-
-   pdev = to_platform_device(dev);
-
-   if (!pdev) {
-   DRM_ERROR("invalid input\n");
-   return -ENODEV;
-   }
-
-   msm_dp_display = platform_get_drvdata(pdev);
-   if (!msm_dp_display) {
-   DRM_ERROR("invalid input\n");
-   return -ENODEV;
-   }
-
-   mutex_lock(&msm_dp_display->connector->eld_mutex);
-   memcpy(buf, msm_dp_display->connector->eld,
-   min(sizeof(msm_dp_display->connector->eld), len));
-   mutex_unlock(&msm_dp_display->connector->eld_mutex);
-
-   return 0;
-}
-
-int msm_dp_audio_hw_params(struct device *dev,
-   void *data,
-   struct hdmi_codec_daifmt *daifmt,
-   struct hdmi_codec_params *params)
+int msm_dp_audio_prepare(struct drm_connector *connector,
+struct drm_bridge *bridge,
+struct hdmi_codec_daifmt *daifmt,
+struct hdmi_codec_params *params)
 {
int rc = 0;
struct msm_dp_audio_private *audio;
-   struct platform_device *pdev;
struct msm_d

[PATCH v2 0/3] drm/bridge: reuse DRM HDMI Audio helpers for DisplayPort bridges

2025-02-09 Thread Dmitry Baryshkov
A lot of DisplayPort bridges use HDMI Codec in order to provide audio
support. Present DRM HDMI Audio support has been written with the HDMI
and in particular DRM HDMI Connector framework support, however those
audio helpers can be easily reused for DisplayPort drivers too.

Patches by Hermes Wu that targeted implementing HDMI Audio support in
the iTE IT6506 driver pointed out the necessity of allowing one to use
generic audio helpers for DisplayPort drivers, as otherwise each driver
has to manually (and correctly) implement the get_eld() and plugged_cb
support.

Implement necessary integration in drm_bridge_connector and provide an
example implementation in the msm/dp driver.

The plan is to land core parts via the drm-misc-next tree and msm patch
via the msm-next tree.

Signed-off-by: Dmitry Baryshkov 
---
Changes in v2:
- Added drm_connector_attach_dp_subconnector_property() patches
- Link to v1: 
https://lore.kernel.org/r/20250206-dp-hdmi-audio-v1-0-8aa14a8c0...@linaro.org

---
Dmitry Baryshkov (3):
  drm/display: bridge-connector: add DisplayPort bridges
  drm/display: bridge_connector: add DisplayPort subconnector property
  drm/msm/dp: reuse generic HDMI codec implementation

 drivers/gpu/drm/display/drm_bridge_connector.c |  68 ++---
 drivers/gpu/drm/msm/Kconfig|   1 +
 drivers/gpu/drm/msm/dp/dp_audio.c  | 131 +++--
 drivers/gpu/drm/msm/dp/dp_audio.h  |  27 ++---
 drivers/gpu/drm/msm/dp/dp_display.c|  31 ++
 drivers/gpu/drm/msm/dp/dp_display.h|   6 --
 drivers/gpu/drm/msm/dp/dp_drm.c|  11 ++-
 include/drm/drm_bridge.h   |  14 ++-
 8 files changed, 101 insertions(+), 188 deletions(-)
---
base-commit: ed58d103e6da15a442ff87567898768dc3a66987
change-id: 20250206-dp-hdmi-audio-15d9fdbebb9f

Best regards,
-- 
Dmitry Baryshkov 



[PATCH v2 2/3] drm/display: bridge_connector: add DisplayPort subconnector property

2025-02-09 Thread Dmitry Baryshkov
Create the DisplayPort subconnector property for DP connectors managed
through drm_bridge_connector, removing the need to create it manually by
the drivers.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c 
b/drivers/gpu/drm/display/drm_bridge_connector.c
index 
5e031395b801f9a1371dcb4ac09f3da23e4615dd..df9e6b46b40454385f7023310327c5c99d5c6a5a
 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -662,6 +662,8 @@ struct drm_connector *drm_bridge_connector_init(struct 
drm_device *drm,
if (ret)
return ERR_PTR(ret);
 
+   drm_connector_attach_dp_subconnector_property(connector);
+
ret = drm_bridge_connector_hdmi_audio_init(connector, bridge);
if (ret)
return ERR_PTR(ret);

-- 
2.39.5



Re: [PATCH v2] drm/msm/dp: account for widebus and yuv420 during mode validation

2025-02-09 Thread Dale Whinham

On 06/02/2025 19:46, Abhinav Kumar wrote:

Widebus allows the DP controller to operate in 2 pixel per clock mode.
The mode validation logic validates the mode->clock against the max
DP pixel clock. However the max DP pixel clock limit assumes widebus
is already enabled. Adjust the mode validation logic to only compare
the adjusted pixel clock which accounts for widebus against the max DP
pixel clock. Also fix the mode validation logic for YUV420 modes as in
that case as well, only half the pixel clock is needed.

Fixes: 757a2f36ab09 ("drm/msm/dp: enable widebus feature for display port")
Fixes: 6db6e5606576 ("drm/msm/dp: change clock related programming for YUV420 over 
DP")
Reviewed-by: Dmitry Baryshkov 
Signed-off-by: Abhinav Kumar 
Reviewed-by: Dmitry Baryshkov 
---
Changes in v2:
- move msm_dp_wide_bus_available() to the next line
- Link to v1: 
https://lore.kernel.org/r/20250128-dp-widebus-fix-v1-1-b66d22655...@quicinc.com
---
  drivers/gpu/drm/msm/dp/dp_display.c | 11 ++-
  drivers/gpu/drm/msm/dp/dp_drm.c |  5 -
  2 files changed, 10 insertions(+), 6 deletions(-)


This patch fixes a CLOCK_HIGH mode rejection error on the Microsoft 
Surface Pro 11 (OLED panel) which I had previously been working-around 
by raising DP_MAX_PIXEL_CLK_KHZ.


Tested-by: Dale Whinham 

--
Best regards,
Dale


Re: [PATCH v3] drm/bridge-connector: handle subconnector types

2025-02-09 Thread Dmitry Baryshkov
On Fri, Jan 17, 2025 at 11:50:50AM +0200, Dmitry Baryshkov wrote:
> If the created connector type supports subconnector type property,
> create and attach corresponding it. The default subtype value is 0,
> which maps to the DRM_MODE_SUBCONNECTOR_Unknown type. Also remove
> subconnector creation from the msm_dp driver to prevent having duplicate
> properties on the DP connectors.
> 
> Signed-off-by: Dmitry Baryshkov 
> ---
> This is a leftover of my previous attempt to implement USB-C DisplayPort
> uABI. The idea was dropped, but I consider this part still to be useful,
> as it allows one to register corresponding subconnector properties and
> also to export the subconnector type.
> ---
> Changes in v3:
> - Rebased on top of linux-next
> - Drop subconnector property from msm_dp driver
> - Link to v2: 
> https://lore.kernel.org/r/20230903214934.2877259-1-dmitry.barysh...@linaro.org
> 
> Changes in v2:
> - Dropped all DP and USB-related patches
> - Dropped the patch adding default subtype to
>   drm_connector_attach_dp_subconnector_property()
> - Replaced creation of TV subconnector property with the check that it
>   was created beforehand (Neil, Laurent)
> - Link to v1: 
> https://lore.kernel.org/r/20230729004913.215872-1-dmitry.barysh...@linaro.org/
> ---
>  drivers/gpu/drm/display/drm_bridge_connector.c | 28 
> +-
>  drivers/gpu/drm/msm/dp/dp_drm.c|  3 ---
>  include/drm/drm_bridge.h   |  4 
>  3 files changed, 31 insertions(+), 4 deletions(-)

It seems this isn't getting any response. Also we don't have (and don't
expect) DVI-I and TV bridges. Let me merge DP part to [1] and drop other
parts.

https://lore.kernel.org/linux-arm-msm/20250206-dp-hdmi-audio-v1-0-8aa14a8c0...@linaro.org

-- 
With best wishes
Dmitry


Re: [PATCH v3 2/2] arm64: dts: qcom: sa8775p-ride: Enable Adreno 663 GPU

2025-02-09 Thread Dmitry Baryshkov
On Wed, Nov 13, 2024 at 02:18:43AM +0530, Akhil P Oommen wrote:
> On 10/30/2024 12:32 PM, Akhil P Oommen wrote:
> > From: Puranam V G Tejaswi 
> > 
> > Enable GPU for sa8775p-ride platform and provide path for zap
> > shader.
> > 
> > Signed-off-by: Puranam V G Tejaswi 
> > Signed-off-by: Akhil P Oommen 
> > Reviewed-by: Dmitry Baryshkov 
> > ---
> >  arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi | 8 
> >  1 file changed, 8 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi 
> > b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi
> > index 0c1b21def4b6..4901163df8f3 100644
> > --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi
> > @@ -407,6 +407,14 @@ queue3 {
> > };
> >  };
> >  
> > +&gpu {
> > +   status = "okay";
> > +};
> > +
> > +&gpu_zap_shader {
> > +   firmware-name = "qcom/sa8775p/a663_zap.mbn";
> > +};
> > +
> >  &i2c11 {
> > clock-frequency = <40>;
> > pinctrl-0 = <&qup_i2c11_default>;
> > 
> 
> Bjorn,
> 
> Please ignore this patch for now. This is probably not the right
> platform dtsi file where gpu should be enabled. I am discussing about
> this internally. Will send a revision or a new patch based on the
> conclusion.

Akhil, any updates on this?

-- 
With best wishes
Dmitry