[PATCH 2/2] drm/i915/display/dp: 128/132b DP-capable with SST

2024-01-26 Thread Arun R Murthy
With a value of '0' read from MSTM_CAP register MST to be enabled.
DP2.1 SCR updates the spec for 128/132b DP capable supporting only one
stream and not supporting single stream sideband MSG.
The underlying protocol will be MST to enable use of MTP.

Signed-off-by: Arun R Murthy 
---
 drivers/gpu/drm/i915/display/intel_dp.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 9ff0cbd9c0df..05722f10cdd7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4037,9 +4037,15 @@ intel_dp_configure_mst(struct intel_dp *intel_dp)
 
if (!intel_dp_mst_source_support(intel_dp))
return;
-
-   intel_dp->is_mst = sink_can_mst &&
-   i915->display.params.enable_dp_mst;
+   /*
+* Even if dpcd reg MSTM_CAP is 0, if the sink supports UHBR rates then
+* DP2.1 can be enabled with underlying protocol using MST for MTP
+* TODO: Need to accommodate MSTM_CAP bit[0]=0, bit[1]=1 condition, i.e
+* one stream with single stream sideband msg.
+*/
+   intel_dp->is_mst = (sink_can_mst || 
(intel_dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] &
+DP_CAP_ANSI_128B132B)) &&
+   i915->display.params.enable_dp_mst;
 
drm_dp_mst_topology_mgr_set_mst(_dp->mst_mgr,
intel_dp->is_mst);
-- 
2.25.1



[PATCH 1/2] drm/display/dp: Check for MSTM_CAP before MSTM_CTRL write

2024-01-26 Thread Arun R Murthy
With DP2.1, multistream packetization and the underneth MST protocol
will be required for SST. So check for MSTM_CAP to see if MST is really
required and skip the MSTM_CTRL write so that we ensure that only the
underneth protocol and the multistream packetization will be enabled and
sink will not be confused by a corresponding dpcd write.

Signed-off-by: Arun R Murthy 
---
 drivers/gpu/drm/display/drm_dp_mst_topology.c | 26 +++
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c 
b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 8ca01a6bf645..22d81732a978 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -3666,10 +3666,11 @@ int drm_dp_mst_topology_mgr_set_mst(struct 
drm_dp_mst_topology_mgr *mgr, bool ms
mgr->mst_primary = mstb;
drm_dp_mst_topology_get_mstb(mgr->mst_primary);
 
-   ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-DP_MST_EN |
-DP_UP_REQ_EN |
-DP_UPSTREAM_IS_SRC);
+   if (drm_dp_read_mst_cap(mgr->aux, mgr->dpcd))
+   ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
+DP_MST_EN |
+DP_UP_REQ_EN |
+DP_UPSTREAM_IS_SRC);
if (ret < 0)
goto out_unlock;
 
@@ -3684,7 +3685,8 @@ int drm_dp_mst_topology_mgr_set_mst(struct 
drm_dp_mst_topology_mgr *mgr, bool ms
mstb = mgr->mst_primary;
mgr->mst_primary = NULL;
/* this can fail if the device is gone */
-   drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
+   if (drm_dp_read_mst_cap(mgr->aux, mgr->dpcd))
+   drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0);
ret = 0;
mgr->payload_id_table_cleared = false;
 
@@ -3724,8 +3726,9 @@ drm_dp_mst_topology_mgr_invalidate_mstb(struct 
drm_dp_mst_branch *mstb)
 void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr)
 {
mutex_lock(>lock);
-   drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-  DP_MST_EN | DP_UPSTREAM_IS_SRC);
+   if (drm_dp_read_mst_cap(mgr->aux, mgr->dpcd))
+   drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
+  DP_MST_EN | DP_UPSTREAM_IS_SRC);
mutex_unlock(>lock);
flush_work(>up_req_work);
flush_work(>work);
@@ -3773,10 +3776,11 @@ int drm_dp_mst_topology_mgr_resume(struct 
drm_dp_mst_topology_mgr *mgr,
goto out_fail;
}
 
-   ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-DP_MST_EN |
-DP_UP_REQ_EN |
-DP_UPSTREAM_IS_SRC);
+   if (drm_dp_read_mst_cap(mgr->aux, mgr->dpcd))
+   ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
+DP_MST_EN |
+DP_UP_REQ_EN |
+DP_UPSTREAM_IS_SRC);
if (ret < 0) {
drm_dbg_kms(mgr->dev, "mst write failed - undocked during 
suspend?\n");
goto out_fail;
-- 
2.25.1



Re: [PATCH 07/17] drm/msm/dpu: disallow widebus en in INTF_CONFIG2 when DP is YUV420

2024-01-26 Thread Dmitry Baryshkov
On Thu, 25 Jan 2024 at 23:26, Dmitry Baryshkov
 wrote:
>
> On 25/01/2024 21:38, Paloma Arellano wrote:
> > INTF_CONFIG2 register cannot have widebus enabled when DP format is
> > YUV420. Therefore, program the INTF to send 1 ppc.
>
> I think this is handled in the DP driver, where we disallow wide bus for
> YUV 4:2:0 modes.

Maybe this needs some explanation from my side:
I think it will be better to have separate conditionals for setting
HCTL_EN and for DATABUS_WIDEN.


>
> >
> > Signed-off-by: Paloma Arellano 
> > ---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c | 4 +++-
> >   1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
> > b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
> > index 6bba531d6dc41..bfb93f02fe7c1 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
> > @@ -168,7 +168,9 @@ static void dpu_hw_intf_setup_timing_engine(struct 
> > dpu_hw_intf *ctx,
> >* video timing. It is recommended to enable it for all cases, except
> >* if compression is enabled in 1 pixel per clock mode
> >*/
> > - if (p->wide_bus_en)
> > + if (dp_intf && fmt->base.pixel_format == DRM_FORMAT_YUV420)
> > + intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
> > + else if (p->wide_bus_en)
> >   intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
> >
> >   data_width = p->width;
>
> --
> With best wishes
> Dmitry
>


--
With best wishes
Dmitry


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

2024-01-26 Thread Dmitry Baryshkov
On Sat, 27 Jan 2024 at 05:57, Abhinav Kumar  wrote:
>
>
>
> 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;
> > }
> >
>
> Even AMD has similar logic:
>
> 6145stream->use_vsc_sdp_for_colorimetry = false;
> 6146if (aconnector->dc_sink->sink_signal ==
> SIGNAL_TYPE_DISPLAY_PORT_MST) {
> 6147stream->use_vsc_sdp_for_colorimetry =
> 6148
> aconnector->dc_sink->is_vsc_sdp_colorimetry_supported;
> 6149} else {
> 6150if
> (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED)
> 6151stream->use_vsc_sdp_for_colorimetry = true;
> 6152}
>
> But it will be harder to untangle this compared to intel's code.
>
> I am fine with adding an API to drm_dp_helper which indicates presence
> of VSC SDP but I would prefer leaving it to other vendors to use it in
> the way they would like and only keep msm usage in this series.

SGTM

>
>
>
> >
> >>>
> 
>  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;
> 

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

2024-01-26 Thread Abhinav Kumar




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;
}



Even AMD has similar logic:

6145stream->use_vsc_sdp_for_colorimetry = false;
6146 		if (aconnector->dc_sink->sink_signal == 
SIGNAL_TYPE_DISPLAY_PORT_MST) {

6147stream->use_vsc_sdp_for_colorimetry =
6148
aconnector->dc_sink->is_vsc_sdp_colorimetry_supported;
6149} else {
6150 			if 
(stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED)

6151stream->use_vsc_sdp_for_colorimetry = true;
6152}

But it will be harder to untangle this compared to intel's code.

I am fine with adding an API to drm_dp_helper which indicates presence 
of VSC SDP but I would prefer leaving it to other vendors to use it in 
the way they would like and only keep msm usage in this series.










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 

Re: [PATCH V2 2/2] phy: freescale: add Samsung HDMI PHY

2024-01-26 Thread Adam Ford
On Mon, Jan 8, 2024 at 9:03 AM Alexander Stein
 wrote:
>
> Hi Adam,
>
> thanks for pushing this forward.
>
> Am Samstag, 6. Januar 2024, 23:19:05 CET schrieb Adam Ford:
> > From: Lucas Stach 
> >
> > This adds the driver for the Samsung HDMI PHY found on the
> > i.MX8MP SoC.
> >
> > Signed-off-by: Lucas Stach 
> > Signed-off-by: Adam Ford 
> > ---
> > V2:  Fixed some whitespace found from checkpatch
> >  Change error handling when enabling apbclk to use dev_err_probe
> >  Rebase on Linux-Next
> >
> >  I (Adam) tried to help move this along, so I took Lucas' patch and
> >  attempted to apply fixes based on feedback.  I don't have
> >  all the history, so apologies for that.
> >
> > diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
> > index 853958fb2c06..5c2b73042dfc 100644
> > --- a/drivers/phy/freescale/Kconfig
> > +++ b/drivers/phy/freescale/Kconfig
> > @@ -35,6 +35,12 @@ config PHY_FSL_IMX8M_PCIE
> > Enable this to add support for the PCIE PHY as found on
> > i.MX8M family of SOCs.
> >
> > +config PHY_FSL_SAMSUNG_HDMI_PHY
> > + tristate "Samsung HDMI PHY support"
> > + depends on OF && HAS_IOMEM
> > + help
> > +   Enable this to add support for the Samsung HDMI PHY in i.MX8MP.
> > +
> >  endif
> >
> >  config PHY_FSL_LYNX_28G
> > diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
> > index cedb328bc4d2..dbcafdcc8751 100644
> > --- a/drivers/phy/freescale/Makefile
> > +++ b/drivers/phy/freescale/Makefile
> > @@ -3,4 +3,5 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)  += 
> > phy-fsl-imx8mq-usb.o
> >  obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o
> >  obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY)+= phy-fsl-imx8-mipi-dphy.o
> >  obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o
> > +obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY)  += phy-fsl-samsung-hdmi.o
> >  obj-$(CONFIG_PHY_FSL_LYNX_28G)   += phy-fsl-lynx-28g.o
>
> I don't know if there was different feedback already. But I would have added
> the entry sorted alphabetically, thus after CONFIG_PHY_FSL_LYNX_28G. Same 
> goes,
> for Kconfig as well.

The Makefile is easy to rearrange, but Kconfig is already out of
alphabetical order, and PHY_FSL_SAMSUNG_HDMI_PHY is encapsulated in an
if statement, so it cannot go after PHY_FSL_LYNX_28G.  It is
alphabetical after PHY_FSL_IMX8M.

>
> > diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
> > b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c new file mode 100644
> > index ..54e93ea898f7
> > --- /dev/null
> > +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
> > @@ -0,0 +1,1078 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright 2020 NXP
> > + * Copyright 2022 Pengutronix, Lucas Stach 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define HDMI_TX_CONTROL0 0x200
> > +#define  HDMI_TX_CONTROL_PHY_PWRDWN  BIT(3)
>
> These defines are unused here.

I can drop these.
>
> > +
> > +#define PHY_REG_33   0x84
> > +#define  REG33_MODE_SET_DONE BIT(7)
> > +#define  REG33_FIX_DABIT(1)
> > +
> > +#define PHY_REG_34   0x88
> > +#define  REG34_PHY_READY BIT(7)
> > +#define  REG34_PLL_LOCK  BIT(6)
> > +#define  REG34_PHY_CLK_READY BIT(5)
> > +
> > +
> > +#define PHY_PLL_REGS_NUM 48
> > +
> > +struct phy_config {
> > + u32 clk_rate;
> > + u8 regs[PHY_PLL_REGS_NUM];
>
> Shouldn't reg be aligned along clk_rate?

Why so?  They appear to just be structures where individual parts are
read/written individually.  Looking at another HDMI phy driver, it's
not really any different.

>
> Despite that. Tested on TQMa8MPQL/MBa8MPxL + Full-HD HDMI monitor.
>
> Tested-by: Alexander Stein 
>

Thanks for testing.

adam
> Best regards,
> Alexander
>


>
>
> --
> TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
> Amtsgericht München, HRB 105018
> Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
> http://www.tq-group.com/
>
>


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

2024-01-26 Thread Dmitry Baryshkov
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 

Re: [PATCH 04/17] drm/msm/dp: store mode YUV420 information to be used by rest of DP

2024-01-26 Thread Dmitry Baryshkov
On Sat, 27 Jan 2024 at 02:48, Paloma Arellano  wrote:
>
>
> On 1/25/2024 1:20 PM, Dmitry Baryshkov wrote:
> > On 25/01/2024 21:38, Paloma Arellano wrote:
> >> 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 
> >> ---
> >>   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;
> >
> > Why do we need it in dp_panel too?
> Not sure if you saw in the other later patches, but I use the
> out_fmt_is_yuv_420 derived from dp_panel throughout dp_ctrl.c and dp_panel.c

Reviewed-by: Dmitry Baryshkov 

> >
> >> dp_panel_init_panel_info(dp->panel);
> >>   return 0;
> >>   }


-- 
With best wishes
Dmitry


Re: [PATCH 02/17] drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder

2024-01-26 Thread Dmitry Baryshkov
On Sat, 27 Jan 2024 at 02:44, Paloma Arellano  wrote:
>
>
> On 1/25/2024 1:16 PM, Dmitry Baryshkov wrote:
> > On 25/01/2024 21:38, Paloma Arellano wrote:
> >> Move dpu_encoder_helper_phys_setup_cdm to dpu_encoder in preparation for
> >> implementing CDM compatibility for DP.
> >
> > Nit: s/CDM compatibility/YUV support/. It might make sense to spell it
> > out that YUV over DP requires CDM.
> Ack
> >
> >>
> >> Signed-off-by: Paloma Arellano 
> >> ---
> >>   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   | 84 ---
> >>   3 files changed, 87 insertions(+), 84 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> index 83380bc92a00a..6cef98f046ea6 100644
> >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> @@ -2114,6 +2114,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)
> >
> > My email client suggests that the parameters are not idented properly
> > anymore.
> On my editor it appears to be aligned correctly. Running checkpatch.pl
> doesn't give any warnings either. So perhaps it's the email client.

Checked, you are correct here.

> >

[skipped]

> >>* dpu_encoder_phys_wb_atomic_check - verify and fixup given atomic
> >> states
> >>* @phys_enc:Pointer to physical encoder
> >> @@ -399,7 +316,6 @@ static int dpu_encoder_phys_wb_atomic_check(
> >>   return
> >> drm_atomic_helper_check_wb_connector_state(conn_state->connector,
> >> conn_state->state);
> >>   }
> >>   -
> >
> > irrelevant, please drop.
> Ack

With this fixed:

Reviewed-by: Dmitry Baryshkov 

> >
> >>   /**
> >>* _dpu_encoder_phys_wb_update_flush - flush hardware update
> >>* @phys_enc:Pointer to physical encoder
> >



-- 
With best wishes
Dmitry


RE: Making drm_gpuvm work across gpu devices

2024-01-26 Thread Zeng, Oak
Regarding the idea of expanding userptr to support migration, we explored this 
idea long time ago. It provides similar functions of the system allocator but 
its interface is not as convenient as system allocator. Besides the shared 
virtual address space, another benefit of a system allocator is, you can 
offload cpu program to gpu easier, you don’t need to call driver specific API 
(such as register_userptr and vm_bind in this case) for memory allocation.

We also scoped the implementation. It turned out to be big, and not as 
beautiful as hmm. Why we gave up this approach.

From: Christian König 
Sent: Friday, January 26, 2024 7:52 AM
To: Thomas Hellström ; Daniel Vetter 

Cc: Brost, Matthew ; Felix Kuehling 
; Welty, Brian ; Ghimiray, Himal 
Prasad ; Zeng, Oak ; 
Gupta, saurabhg ; Danilo Krummrich ; 
dri-devel@lists.freedesktop.org; Bommu, Krishnaiah 
; Dave Airlie ; 
Vishwanathapura, Niranjana ; 
intel...@lists.freedesktop.org
Subject: Re: Making drm_gpuvm work across gpu devices

Am 26.01.24 um 09:21 schrieb Thomas Hellström:


Hi, all



On Thu, 2024-01-25 at 19:32 +0100, Daniel Vetter wrote:

On Wed, Jan 24, 2024 at 09:33:12AM +0100, Christian König wrote:

Am 23.01.24 um 20:37 schrieb Zeng, Oak:

[SNIP]

Yes most API are per device based.



One exception I know is actually the kfd SVM API. If you look at

the svm_ioctl function, it is per-process based. Each kfd_process

represent a process across N gpu devices.



Yeah and that was a big mistake in my opinion. We should really not

do that

ever again.



Need to say, kfd SVM represent a shared virtual address space

across CPU and all GPU devices on the system. This is by the

definition of SVM (shared virtual memory). This is very different

from our legacy gpu *device* driver which works for only one

device (i.e., if you want one device to access another device's

memory, you will have to use dma-buf export/import etc).



Exactly that thinking is what we have currently found as blocker

for a

virtualization projects. Having SVM as device independent feature

which

somehow ties to the process address space turned out to be an

extremely bad

idea.



The background is that this only works for some use cases but not

all of

them.



What's working much better is to just have a mirror functionality

which says

that a range A..B of the process address space is mapped into a

range C..D

of the GPU address space.



Those ranges can then be used to implement the SVM feature required

for

higher level APIs and not something you need at the UAPI or even

inside the

low level kernel memory management.



When you talk about migrating memory to a device you also do this

on a per

device basis and *not* tied to the process address space. If you

then get

crappy performance because userspace gave contradicting information

where to

migrate memory then that's a bug in userspace and not something the

kernel

should try to prevent somehow.



[SNIP]

I think if you start using the same drm_gpuvm for multiple

devices you

will sooner or later start to run into the same mess we have

seen with

KFD, where we moved more and more functionality from the KFD to

the DRM

render node because we found that a lot of the stuff simply

doesn't work

correctly with a single object to maintain the state.

As I understand it, KFD is designed to work across devices. A

single pseudo /dev/kfd device represent all hardware gpu devices.

That is why during kfd open, many pdd (process device data) is

created, each for one hardware device for this process.



Yes, I'm perfectly aware of that. And I can only repeat myself that

I see

this design as a rather extreme failure. And I think it's one of

the reasons

why NVidia is so dominant with Cuda.



This whole approach KFD takes was designed with the idea of

extending the

CPU process into the GPUs, but this idea only works for a few use

cases and

is not something we should apply to drivers in general.



A very good example are virtualization use cases where you end up

with CPU

address != GPU address because the VAs are actually coming from the

guest VM

and not the host process.



SVM is a high level concept of OpenCL, Cuda, ROCm etc.. This should

not have

any influence on the design of the kernel UAPI.



If you want to do something similar as KFD for Xe I think you need

to get

explicit permission to do this from Dave and Daniel and maybe even

Linus.



I think the one and only one exception where an SVM uapi like in kfd

makes

sense, is if the _hardware_ itself, not the software stack defined

semantics that you've happened to build on top of that hw, enforces a

1:1

mapping with the cpu process address space.



Which means your hardware is using PASID, IOMMU based translation,

PCI-ATS

(address translation services) or whatever your hw calls it and has

_no_

device-side pagetables on top. Which from what I've seen all devices

with

device-memory have, simply because they need some place 

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

2024-01-26 Thread Paloma Arellano



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.




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;

+}
+
  void dp_panel_dump_regs(struct dp_panel *dp_panel)
  {
  struct dp_catalog *catalog;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h 
b/drivers/gpu/drm/msm/dp/dp_panel.h

index 6ec68be9f2366..590eca5ce304b 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -66,6 +66,7 @@ int dp_panel_get_modes(struct dp_panel *dp_panel,
  struct drm_connector *connector);
  void dp_panel_handle_sink_request(struct dp_panel *dp_panel);
  void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable);
+bool dp_panel_vsc_sdp_supported(struct dp_panel *dp_panel);
    /**
   * is_link_rate_valid() - validates the link rate




Re: [PATCH 04/17] drm/msm/dp: store mode YUV420 information to be used by rest of DP

2024-01-26 Thread Paloma Arellano



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

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

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 
---
  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;


Why do we need it in dp_panel too?
Not sure if you saw in the other later patches, but I use the 
out_fmt_is_yuv_420 derived from dp_panel throughout dp_ctrl.c and dp_panel.c



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 {




Re: [PATCH 02/17] drm/msm/dpu: move dpu_encoder_helper_phys_setup_cdm to dpu_encoder

2024-01-26 Thread Paloma Arellano



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

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

Move dpu_encoder_helper_phys_setup_cdm to dpu_encoder in preparation for
implementing CDM compatibility for DP.


Nit: s/CDM compatibility/YUV support/. It might make sense to spell it 
out that YUV over DP requires CDM.

Ack




Signed-off-by: Paloma Arellano 
---
  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   | 84 ---
  3 files changed, 87 insertions(+), 84 deletions(-)

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

index 83380bc92a00a..6cef98f046ea6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2114,6 +2114,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)


My email client suggests that the parameters are not idented properly 
anymore.
On my editor it appears to be aligned correctly. Running checkpatch.pl 
doesn't give any warnings either. So perhaps it's the email client.



+{
+    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 37ac385727c3b..310944303a056 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_type);


Again, indentation.

See comment above



+
  /**
   * dpu_encoder_vblank_callback - Notify virtual encoder of vblank 
IRQ reception

   * @drm_enc:    Pointer to drm encoder structure
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c 

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

2024-01-26 Thread Paloma Arellano



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 for the WB case.



  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 

RE: Re: [PATCH 0/4] Fixing live video input in ZynqMP DPSUB

2024-01-26 Thread Klymenko, Anatoliy



> -Original Message-
> From: Maxime Ripard 
> Sent: Friday, January 26, 2024 4:26 AM
> To: Laurent Pinchart 
> Cc: Klymenko, Anatoliy ;
> maarten.lankho...@linux.intel.com; tzimmerm...@suse.de; airl...@gmail.com;
> dan...@ffwll.ch; Simek, Michal ; dri-
> de...@lists.freedesktop.org; linux-arm-ker...@lists.infradead.org; linux-
> ker...@vger.kernel.org
> Subject: Re: Re: [PATCH 0/4] Fixing live video input in ZynqMP DPSUB
> 
> On Wed, Jan 17, 2024 at 04:23:43PM +0200, Laurent Pinchart wrote:
> > On Mon, Jan 15, 2024 at 09:28:39AM +0100, Maxime Ripard wrote:
> > > On Fri, Jan 12, 2024 at 03:42:18PM -0800, Anatoliy Klymenko wrote:
> > > > Patches 1/4,2/4,3/4 are minor fixes.
> > > >
> > > > DPSUB requires input live video format to be configured.
> > > > Patch 4/4: The DP Subsystem requires the input live video format to be
> > > > configured. In this patch we are assuming that the CRTC's bus format is 
> > > > fixed
> > > > and comes from the device tree. This is a proposed solution, as there 
> > > > are no
> api
> > > > to query CRTC output bus format.
> > > >
> > > > Is this a good approach to go with?
> > >
> > > I guess you would need to expand a bit on what "live video input" is? Is
> > > it some kind of mechanism to bypass memory and take your pixels straight
> > > from a FIFO from another device, or something else?
> >
> > Yes and no.
> >
> > The DPSUB integrates DMA engines, a blending engine (two planes), and a
> > DP encoder. The dpsub driver supports all of this, and creates a DRM
> > device. The DP encoder hardware always takes its input data from the
> > output of the blending engine.
> >
> > The blending engine can optionally take input data from a bus connected
> > to the FPGA fabric, instead of taking it from the DPSUB internal DMA
> > engines. When operating in that mode, the dpsub driver exposes the DP
> > encoder as a bridge, and internally programs the blending engine to
> > disable blending. Typically, the FPGA fabric will then contain a CRTC of
> > some sort, with a driver that will acquire the DP encoder bridge as
> > usually done.
> >
> > In this mode of operation, it is typical for the IP cores in FPGA fabric
> > to be synthesized with a fixed format (as that saves resources), while
> > the DPSUB supports multiple input formats.
> 
> Where is that CRTC driver? It's not clear to me why the format would
> need to be in the device tree at all. Format negociation between the
> CRTC and whatever comes next is already done in a number of drivers so
> it would be useful to have that kind of API outside of the bridge
> support.
> 
One example of such CRTC driver: 
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/gpu/drm/xlnx/xlnx_mixer.c
It's not upstreamed yet. Bus format negotiations here are handled by utilizing 
Xilinx-specific bridge framework. Ideally, it would be nice to rework this to 
comply with the upstream DRM bridge framework.

> > Bridge drivers in the upstream kernel work the other way around, with
> > the bridge hardware supporting a limited set of formats, and the CRTC
> > then being programmed with whatever the bridges chain needs. Here, the
> > negotiation needs to go the other way around, as the CRTC is the
> > limiting factor, not the bridge.
> 
> Sounds like there's something to rework in the API then?
> 
Adding an optional CRTC callback imposing CRTC specific bus format 
restrictions, which may be called from here 
https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/drm_bridge.c#L935 
would solve the problem.

> Maxime

--

Regards,
Anatoliy


Re: [PATCH] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-01-26 Thread Mario Limonciello

On 1/26/2024 16:22, Hamza Mahfooz wrote:

We want programs besides the compositor to be able to enable or disable
panel power saving features. However, since they are currently only
configurable through DRM properties, that isn't possible. So, to remedy
that issue introduce a new "panel_power_savings" sysfs attribute.

Cc: Mario Limonciello 
Signed-off-by: Hamza Mahfooz 
---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++
  1 file changed, 59 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index cd98b3565178..b3fcd833015d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6534,6 +6534,58 @@ amdgpu_dm_connector_atomic_duplicate_state(struct 
drm_connector *connector)
return _state->base;
  }
  
+static ssize_t panel_power_savings_show(struct device *device,

+   struct device_attribute *attr,
+   char *buf)
+{
+   struct drm_connector *connector = dev_get_drvdata(device);
+   struct drm_device *dev = connector->dev;
+   ssize_t val;
+
+   drm_modeset_lock(>mode_config.connection_mutex, NULL);
+   val = to_dm_connector_state(connector->state)->abm_level;
+   drm_modeset_unlock(>mode_config.connection_mutex);
+
+   return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t panel_power_savings_store(struct device *device,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   struct drm_connector *connector = dev_get_drvdata(device);
+   struct drm_device *dev = connector->dev;
+   long val;
+   int ret;
+
+   ret = kstrtol(buf, 0, );
+
+   if (ret)
+   return ret;
+
+   if (val < 0 || val > 4)
+   return -EINVAL;
+
+   drm_modeset_lock(>mode_config.connection_mutex, NULL);
+   to_dm_connector_state(connector->state)->abm_level = val ?:
+   ABM_LEVEL_IMMEDIATE_DISABLE;
+   drm_modeset_unlock(>mode_config.connection_mutex);
+
+   return count;
+}
+


To make this more discoverable I think you want some kerneldoc.


+static DEVICE_ATTR_RW(panel_power_savings);
+
+static struct attribute *amdgpu_attrs[] = {
+   _attr_panel_power_savings.attr,
+   NULL
+};
+
+static const struct attribute_group amdgpu_group = {
+   .name = "amdgpu",
+   .attrs = amdgpu_attrs
+};
+
  static int
  amdgpu_dm_connector_late_register(struct drm_connector *connector)
  {
@@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct drm_connector 
*connector)
to_amdgpu_dm_connector(connector);
int r;
  
+	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {

+   r = sysfs_create_group(>kdev->kobj,
+  _group);
+   if (r)
+   return r;
+   }
+


I think there should be some matching code sysfs_remove_group(), maybe 
in early_unregister() callback.



amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
  
  	if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||




Re: [PATCH RESEND v3 15/15] drm/msm/dp: drop dp_parser

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Finally drop separate "parsing" submodule. There is no need in it
anymore. All submodules handle DT properties directly rather than
passing them via the separate structure pointer.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/Makefile|  1 -
  drivers/gpu/drm/msm/dp/dp_aux.h |  1 +
  drivers/gpu/drm/msm/dp/dp_catalog.h |  1 -
  drivers/gpu/drm/msm/dp/dp_ctrl.h|  3 +-
  drivers/gpu/drm/msm/dp/dp_debug.c   |  1 -
  drivers/gpu/drm/msm/dp/dp_display.c | 18 +--
  drivers/gpu/drm/msm/dp/dp_display.h |  2 ++
  drivers/gpu/drm/msm/dp/dp_parser.c  | 61 -
  drivers/gpu/drm/msm/dp/dp_parser.h  | 39 
  9 files changed, 12 insertions(+), 115 deletions(-)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 8dbdf3fba69e..543e04fa72e3 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -127,7 +127,6 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_drm.o \
dp/dp_link.o \
dp/dp_panel.o \
-   dp/dp_parser.o \
dp/dp_audio.o
  
  msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index 16d9b1758748..f47d591c1f54 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -16,6 +16,7 @@ void dp_aux_init(struct drm_dp_aux *dp_aux);
  void dp_aux_deinit(struct drm_dp_aux *dp_aux);
  void dp_aux_reconfig(struct drm_dp_aux *dp_aux);
  
+struct phy;

  struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
  struct phy *phy,
  bool is_edp);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 989e4c4fd6fa..a724a986b6ee 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -8,7 +8,6 @@
  
  #include 
  
-#include "dp_parser.h"

  #include "disp/msm_disp_snapshot.h"
  
  /* interrupts */

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 6e9f375b856a..fa014cee7e21 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -9,7 +9,6 @@
  #include "dp_aux.h"
  #include "dp_panel.h"
  #include "dp_link.h"
-#include "dp_parser.h"
  #include "dp_catalog.h"
  
  struct dp_ctrl {

@@ -17,6 +16,8 @@ struct dp_ctrl {
bool wide_bus_en;
  };
  
+struct phy;

+
  int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
  int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train);
  void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c 
b/drivers/gpu/drm/msm/dp/dp_debug.c
index 6c281dc095b9..ac68554801a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -9,7 +9,6 @@
  #include 
  #include 
  
-#include "dp_parser.h"

  #include "dp_catalog.h"
  #include "dp_aux.h"
  #include "dp_ctrl.h"
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index de1306a88748..67956e34436d 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -9,12 +9,12 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  
  #include "msm_drv.h"

  #include "msm_kms.h"
-#include "dp_parser.h"
  #include "dp_ctrl.h"
  #include "dp_catalog.h"
  #include "dp_aux.h"
@@ -87,7 +87,6 @@ struct dp_display_private {
struct drm_device *drm_dev;
struct dentry *root;
  
-	struct dp_parser  *parser;

struct dp_catalog *catalog;
struct drm_dp_aux *aux;
struct dp_link*link;
@@ -704,14 +703,11 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
struct dp_panel_in panel_in = {
.dev = dev,
};
+   struct phy *phy;
  
-	dp->parser = dp_parser_get(dp->dp_display.pdev);

-   if (IS_ERR(dp->parser)) {
-   rc = PTR_ERR(dp->parser);
-   DRM_ERROR("failed to initialize parser, rc = %d\n", rc);
-   dp->parser = NULL;
-   goto error;
-   }
+   phy = devm_phy_get(dev, "dp");
+   if (IS_ERR(phy))
+   return PTR_ERR(phy);
  
  	dp->catalog = dp_catalog_get(dev);

if (IS_ERR(dp->catalog)) {
@@ -722,7 +718,7 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
}
  
  	dp->aux = dp_aux_get(dev, dp->catalog,

-dp->parser->phy,
+phy,
 dp->dp_display.is_edp);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
@@ -753,7 +749,7 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
  
  	dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,

   dp->catalog,
-  

Re: [PATCH RESEND v3 14/15] drm/msm/dp: move next_bridge handling to dp_display

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Remove two levels of indirection and fetch next bridge directly in
dp_display_probe_tail().

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_display.c | 43 -
  drivers/gpu/drm/msm/dp/dp_parser.c  | 14 
  drivers/gpu/drm/msm/dp/dp_parser.h  | 14 
  3 files changed, 14 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index f19cb8c7e8cb..de1306a88748 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1195,16 +1195,25 @@ static const struct msm_dp_desc 
*dp_display_get_desc(struct platform_device *pde
return NULL;
  }
  
-static int dp_display_get_next_bridge(struct msm_dp *dp);

-
  static int dp_display_probe_tail(struct device *dev)
  {
struct msm_dp *dp = dev_get_drvdata(dev);
int ret;
  
-	ret = dp_display_get_next_bridge(dp);

-   if (ret)
-   return ret;
+   /*
+* External bridges are mandatory for eDP interfaces: one has to
+* provide at least an eDP panel (which gets wrapped into panel-bridge).
+*
+* For DisplayPort interfaces external bridges are optional, so
+* silently ignore an error if one is not present (-ENODEV).
+*/
+   dp->next_bridge = devm_drm_of_get_bridge(>pdev->dev, 
dp->pdev->dev.of_node, 1, 0);
+   if (IS_ERR(dp->next_bridge)) {
+   ret = PTR_ERR(dp->next_bridge);
+   dp->next_bridge = NULL;
+   if (dp->is_edp || ret != -ENODEV)
+   return ret;
+   }
  
  	ret = component_add(dev, _display_comp_ops);

if (ret)
@@ -1397,30 +1406,6 @@ void dp_display_debugfs_init(struct msm_dp *dp_display, 
struct dentry *root, boo
}
  }
  
-static int dp_display_get_next_bridge(struct msm_dp *dp)

-{
-   int rc;
-   struct dp_display_private *dp_priv;
-
-   dp_priv = container_of(dp, struct dp_display_private, dp_display);
-
-   /*
-* External bridges are mandatory for eDP interfaces: one has to
-* provide at least an eDP panel (which gets wrapped into panel-bridge).
-*
-* For DisplayPort interfaces external bridges are optional, so
-* silently ignore an error if one is not present (-ENODEV).
-*/
-   rc = devm_dp_parser_find_next_bridge(>pdev->dev, dp_priv->parser);
-   if (!dp->is_edp && rc == -ENODEV)
-   return 0;
-
-   if (!rc)
-   dp->next_bridge = dp_priv->parser->next_bridge;
-
-   return rc;
-}
-
  int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
  {
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c 
b/drivers/gpu/drm/msm/dp/dp_parser.c
index aa135d5cedbd..f95ab3c5c72c 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -24,20 +24,6 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
return 0;
  }
  
-int devm_dp_parser_find_next_bridge(struct device *dev, struct dp_parser *parser)

-{
-   struct platform_device *pdev = parser->pdev;
-   struct drm_bridge *bridge;
-
-   bridge = devm_drm_of_get_bridge(dev, pdev->dev.of_node, 1, 0);
-   if (IS_ERR(bridge))
-   return PTR_ERR(bridge);
-
-   parser->next_bridge = bridge;
-
-   return 0;
-}
-
  static int dp_parser_parse(struct dp_parser *parser)
  {
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 21a66932e35e..38fd335d5950 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -21,7 +21,6 @@
  struct dp_parser {
struct platform_device *pdev;
struct phy *phy;
-   struct drm_bridge *next_bridge;
  };
  
  /**

@@ -37,17 +36,4 @@ struct dp_parser {
   */
  struct dp_parser *dp_parser_get(struct platform_device *pdev);
  
-/**

- * devm_dp_parser_find_next_bridge() - find an additional bridge to DP
- *
- * @dev: device to tie bridge lifetime to
- * @parser: dp_parser data from client
- *
- * This function is used to find any additional bridge attached to
- * the DP controller. The eDP interface requires a panel bridge.
- *
- * Return: 0 if able to get the bridge, otherwise negative errno for failure.
- */
-int devm_dp_parser_find_next_bridge(struct device *dev, struct dp_parser 
*parser);
-
  #endif



Re: [PATCH RESEND v3 13/15] drm/msm/dp: move link property handling to dp_panel

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Instead of passing link properties through the separate struct, parse
them directly in the dp_panel.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_display.c |  8 -
  drivers/gpu/drm/msm/dp/dp_display.h |  1 -
  drivers/gpu/drm/msm/dp/dp_panel.c   | 66 +
  drivers/gpu/drm/msm/dp/dp_parser.c  | 54 --
  drivers/gpu/drm/msm/dp/dp_parser.h  |  4 ---
  5 files changed, 66 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 5ad96989c5f2..f19cb8c7e8cb 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -356,12 +356,6 @@ static int dp_display_process_hpd_high(struct 
dp_display_private *dp)
int rc = 0;
struct edid *edid;
  
-	dp->panel->max_dp_lanes = dp->parser->max_dp_lanes;

-   dp->panel->max_dp_link_rate = dp->parser->max_dp_link_rate;
-
-   drm_dbg_dp(dp->drm_dev, "max_lanes=%d max_link_rate=%d\n",
-   dp->panel->max_dp_lanes, dp->panel->max_dp_link_rate);
-
rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
goto end;
@@ -381,8 +375,6 @@ static int dp_display_process_hpd_high(struct 
dp_display_private *dp)
dp->audio_supported = drm_detect_monitor_audio(edid);
dp_panel_handle_sink_request(dp->panel);
  
-	dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes;

-
/*
 * set sink to normal operation mode -- D0
 * before dpcd read
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h 
b/drivers/gpu/drm/msm/dp/dp_display.h
index 102f3507d824..70759dd1bfd0 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -28,7 +28,6 @@ struct msm_dp {
  
  	bool wide_bus_en;
  
-	u32 max_dp_lanes;

struct dp_audio *dp_audio;
bool psr_supported;
  };
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c 
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd..8242541a81b9 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -7,8 +7,12 @@
  
  #include 

  #include 
+#include 
  #include 
  
+#define DP_MAX_NUM_DP_LANES	4

+#define DP_LINK_RATE_HBR2  54 /* kbytes */
+
  struct dp_panel_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -138,6 +142,9 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
  
  	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
  
+	drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n",

+   dp_panel->max_dp_lanes, dp_panel->max_dp_link_rate);
+
rc = dp_panel_read_dpcd(dp_panel);
if (rc) {
DRM_ERROR("read dpcd failed %d\n", rc);
@@ -386,10 +393,65 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel)
return 0;
  }
  
+static u32 dp_panel_link_frequencies(struct device_node *of_node)

+{
+   struct device_node *endpoint;
+   u64 frequency = 0;
+   int cnt;
+
+   endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */
+   if (!endpoint)
+   return 0;
+
+   cnt = of_property_count_u64_elems(endpoint, "link-frequencies");
+
+   if (cnt > 0)
+   of_property_read_u64_index(endpoint, "link-frequencies",
+   cnt - 1, );
+   of_node_put(endpoint);
+
+   do_div(frequency,
+   10 * /* from symbol rate to link rate */
+   1000); /* kbytes */
+
+   return frequency;
+}
+
+static int dp_panel_parse_dt(struct dp_panel *dp_panel)
+{
+   struct dp_panel_private *panel;
+   struct device_node *of_node;
+   int cnt;
+
+   panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+   of_node = panel->dev->of_node;
+
+   /*
+* data-lanes is the property of dp_out endpoint
+*/
+   cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, 
DP_MAX_NUM_DP_LANES);
+   if (cnt < 0) {
+   /* legacy code, data-lanes is the property of mdss_dp node */
+   cnt = drm_of_get_data_lanes_count(of_node, 1, 
DP_MAX_NUM_DP_LANES);
+   }
+
+   if (cnt > 0)
+   dp_panel->max_dp_lanes = cnt;
+   else
+   dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
+
+   dp_panel->max_dp_link_rate = dp_panel_link_frequencies(of_node);
+   if (!dp_panel->max_dp_link_rate)
+   dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2;
+
+   return 0;
+}
+
  struct dp_panel *dp_panel_get(struct dp_panel_in *in)
  {
struct dp_panel_private *panel;
struct dp_panel *dp_panel;
+   int ret;
  
  	if (!in->dev || !in->catalog || !in->aux || !in->link) {

DRM_ERROR("invalid input\n");
@@ -408,6 +470,10 @@ struct 

Re: [PATCH RESEND v3 12/15] drm/msm/dp: move all IO handling to dp_catalog

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Rather than parsing the I/O addresses from dp_parser and then passing
them via a struct pointer to dp_catalog, handle I/O region parsing in
dp_catalog and drop it from dp_parser.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_catalog.c | 125 ++--
  drivers/gpu/drm/msm/dp/dp_catalog.h |   2 +-
  drivers/gpu/drm/msm/dp/dp_display.c |   6 +-
  drivers/gpu/drm/msm/dp/dp_parser.c  |  73 +
  drivers/gpu/drm/msm/dp/dp_parser.h  |  26 +---
  5 files changed, 114 insertions(+), 118 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 4c6207797c99..541aac2cb246 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -7,6 +7,7 @@
  
  #include 

  #include 
+#include 
  #include 
  #include 
  #include 
@@ -53,10 +54,31 @@
(PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
  
+#define DP_DEFAULT_AHB_OFFSET	0x

+#define DP_DEFAULT_AHB_SIZE0x0200
+#define DP_DEFAULT_AUX_OFFSET  0x0200
+#define DP_DEFAULT_AUX_SIZE0x0200
+#define DP_DEFAULT_LINK_OFFSET 0x0400
+#define DP_DEFAULT_LINK_SIZE   0x0C00
+#define DP_DEFAULT_P0_OFFSET   0x1000
+#define DP_DEFAULT_P0_SIZE 0x0400
+
+struct dss_io_region {
+   size_t len;
+   void __iomem *base;
+};
+
+struct dss_io_data {
+   struct dss_io_region ahb;
+   struct dss_io_region aux;
+   struct dss_io_region link;
+   struct dss_io_region p0;
+};
+
  struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
-   struct dp_io *io;
+   struct dss_io_data io;
u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
struct dp_catalog dp_catalog;
u8 aux_lut_cfg_index[PHY_AUX_CFG_MAX];
@@ -66,7 +88,7 @@ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, 
struct msm_disp_state *d
  {
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
-   struct dss_io_data *dss = >io->dp_controller;
+   struct dss_io_data *dss = >io;
  
  	msm_disp_snapshot_add_block(disp_state, dss->ahb.len, dss->ahb.base, "dp_ahb");

msm_disp_snapshot_add_block(disp_state, dss->aux.len, dss->aux.base, 
"dp_aux");
@@ -76,7 +98,7 @@ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, 
struct msm_disp_state *d
  
  static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32 offset)

  {
-   return readl_relaxed(catalog->io->dp_controller.aux.base + offset);
+   return readl_relaxed(catalog->io.aux.base + offset);
  }
  
  static inline void dp_write_aux(struct dp_catalog_private *catalog,

@@ -86,12 +108,12 @@ static inline void dp_write_aux(struct dp_catalog_private 
*catalog,
 * To make sure aux reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   writel(data, catalog->io->dp_controller.aux.base + offset);
+   writel(data, catalog->io.aux.base + offset);
  }
  
  static inline u32 dp_read_ahb(const struct dp_catalog_private *catalog, u32 offset)

  {
-   return readl_relaxed(catalog->io->dp_controller.ahb.base + offset);
+   return readl_relaxed(catalog->io.ahb.base + offset);
  }
  
  static inline void dp_write_ahb(struct dp_catalog_private *catalog,

@@ -101,7 +123,7 @@ static inline void dp_write_ahb(struct dp_catalog_private 
*catalog,
 * To make sure phy reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   writel(data, catalog->io->dp_controller.ahb.base + offset);
+   writel(data, catalog->io.ahb.base + offset);
  }
  
  static inline void dp_write_p0(struct dp_catalog_private *catalog,

@@ -111,7 +133,7 @@ static inline void dp_write_p0(struct dp_catalog_private 
*catalog,
 * To make sure interface reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   writel(data, catalog->io->dp_controller.p0.base + offset);
+   writel(data, catalog->io.p0.base + offset);
  }
  
  static inline u32 dp_read_p0(struct dp_catalog_private *catalog,

@@ -121,12 +143,12 @@ static inline u32 dp_read_p0(struct dp_catalog_private 
*catalog,
 * To make sure interface reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   return readl_relaxed(catalog->io->dp_controller.p0.base + offset);
+   return readl_relaxed(catalog->io.p0.base + offset);
  }
  
  static inline u32 dp_read_link(struct dp_catalog_private *catalog, u32 offset)

  {
-   return readl_relaxed(catalog->io->dp_controller.link.base + offset);
+   

[PATCH] drm/amd/display: add panel_power_savings sysfs entry to eDP connectors

2024-01-26 Thread Hamza Mahfooz
We want programs besides the compositor to be able to enable or disable
panel power saving features. However, since they are currently only
configurable through DRM properties, that isn't possible. So, to remedy
that issue introduce a new "panel_power_savings" sysfs attribute.

Cc: Mario Limonciello 
Signed-off-by: Hamza Mahfooz 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 59 +++
 1 file changed, 59 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index cd98b3565178..b3fcd833015d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6534,6 +6534,58 @@ amdgpu_dm_connector_atomic_duplicate_state(struct 
drm_connector *connector)
return _state->base;
 }
 
+static ssize_t panel_power_savings_show(struct device *device,
+   struct device_attribute *attr,
+   char *buf)
+{
+   struct drm_connector *connector = dev_get_drvdata(device);
+   struct drm_device *dev = connector->dev;
+   ssize_t val;
+
+   drm_modeset_lock(>mode_config.connection_mutex, NULL);
+   val = to_dm_connector_state(connector->state)->abm_level;
+   drm_modeset_unlock(>mode_config.connection_mutex);
+
+   return sysfs_emit(buf, "%lu\n", val);
+}
+
+static ssize_t panel_power_savings_store(struct device *device,
+struct device_attribute *attr,
+const char *buf, size_t count)
+{
+   struct drm_connector *connector = dev_get_drvdata(device);
+   struct drm_device *dev = connector->dev;
+   long val;
+   int ret;
+
+   ret = kstrtol(buf, 0, );
+
+   if (ret)
+   return ret;
+
+   if (val < 0 || val > 4)
+   return -EINVAL;
+
+   drm_modeset_lock(>mode_config.connection_mutex, NULL);
+   to_dm_connector_state(connector->state)->abm_level = val ?:
+   ABM_LEVEL_IMMEDIATE_DISABLE;
+   drm_modeset_unlock(>mode_config.connection_mutex);
+
+   return count;
+}
+
+static DEVICE_ATTR_RW(panel_power_savings);
+
+static struct attribute *amdgpu_attrs[] = {
+   _attr_panel_power_savings.attr,
+   NULL
+};
+
+static const struct attribute_group amdgpu_group = {
+   .name = "amdgpu",
+   .attrs = amdgpu_attrs
+};
+
 static int
 amdgpu_dm_connector_late_register(struct drm_connector *connector)
 {
@@ -6541,6 +6593,13 @@ amdgpu_dm_connector_late_register(struct drm_connector 
*connector)
to_amdgpu_dm_connector(connector);
int r;
 
+   if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+   r = sysfs_create_group(>kdev->kobj,
+  _group);
+   if (r)
+   return r;
+   }
+
amdgpu_dm_register_backlight_device(amdgpu_dm_connector);
 
if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
-- 
2.43.0



Re: [PATCH RESEND v3 11/15] drm/msm/dp: handle PHY directly in dp_ctrl

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

There is little point in going trough dp_parser->io indirection each
time the driver needs to access the PHY. Store the pointer directly in
dp_ctrl_private.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_ctrl.c| 37 +
  drivers/gpu/drm/msm/dp/dp_ctrl.h|  2 +-
  drivers/gpu/drm/msm/dp/dp_display.c |  3 ++-
  3 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 4aea72a2b8e8..fc7ce315ae41 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -76,9 +76,10 @@ struct dp_ctrl_private {
struct drm_dp_aux *aux;
struct dp_panel *panel;
struct dp_link *link;
-   struct dp_parser *parser;
struct dp_catalog *catalog;
  
+	struct phy *phy;

+
unsigned int num_core_clks;
struct clk_bulk_data *core_clks;
  
@@ -1028,7 +1029,7 @@ static int dp_ctrl_set_vx_px(struct dp_ctrl_private *ctrl,

phy_opts->dp.voltage[0] = v_level;
phy_opts->dp.pre[0] = p_level;
phy_opts->dp.set_voltages = 1;
-   phy_configure(ctrl->parser->io.phy, phy_opts);
+   phy_configure(ctrl->phy, phy_opts);
phy_opts->dp.set_voltages = 0;
  
  	return 0;

@@ -1442,7 +1443,7 @@ static void dp_ctrl_link_clk_disable(struct dp_ctrl 
*dp_ctrl)
  static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
  {
int ret = 0;
-   struct phy *phy = ctrl->parser->io.phy;
+   struct phy *phy = ctrl->phy;
const u8 *dpcd = ctrl->panel->dpcd;
  
  	ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;

@@ -1540,12 +1541,10 @@ void dp_ctrl_set_psr(struct dp_ctrl *dp_ctrl, bool 
enter)
  void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
  {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
  
  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
  
  	dp_catalog_ctrl_phy_reset(ctrl->catalog);

phy_init(phy);
@@ -1557,12 +1556,10 @@ void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
  void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl)
  {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
  
  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
  
  	dp_catalog_ctrl_phy_reset(ctrl->catalog);

phy_exit(phy);
@@ -1587,7 +1584,7 @@ static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private 
*ctrl)
  
  static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)

  {
-   struct phy *phy = ctrl->parser->io.phy;
+   struct phy *phy = ctrl->phy;
int ret = 0;
  
  	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);

@@ -1617,11 +1614,9 @@ static int dp_ctrl_reinitialize_mainlink(struct 
dp_ctrl_private *ctrl)
  
  static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)

  {
-   struct dp_io *dp_io;
struct phy *phy;
  
-	dp_io = >parser->io;

-   phy = dp_io->phy;
+   phy = ctrl->phy;
  
  	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
  
@@ -2047,12 +2042,10 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)

  void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
  {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
  
  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
  
  	/* set dongle to D3 (power off) mode */

dp_link_psm_config(ctrl->link, >panel->link_info, true);
@@ -2080,12 +2073,10 @@ void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
  void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl)
  {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
  
  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
  
  	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
  
@@ -2103,12 +2094,10 @@ void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl)

  void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
  {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
  
  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
  
  	dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
  
@@ -2225,7 +2214,7 @@ static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl)

  struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
struct dp_panel *panel, struct drm_dp_aux *aux,
struct 

Re: [PATCH RESEND v3 10/15] drm/msm/dp: remove PHY handling from dp_catalog.c

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Inline dp_catalog_aux_update_cfg() and call phy_calibrate() from dp_aux
functions directly.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_aux.c |  9 +++--
  drivers/gpu/drm/msm/dp/dp_aux.h |  1 +
  drivers/gpu/drm/msm/dp/dp_catalog.c | 12 
  drivers/gpu/drm/msm/dp/dp_catalog.h |  1 -
  drivers/gpu/drm/msm/dp/dp_display.c |  4 +++-
  5 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 03f4951c49f4..adbd5a367395 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -4,6 +4,7 @@
   */
  
  #include 

+#include 
  #include 
  
  #include "dp_reg.h"

@@ -23,6 +24,8 @@ struct dp_aux_private {
struct device *dev;
struct dp_catalog *catalog;
  
+	struct phy *phy;

+
struct mutex mutex;
struct completion comp;
  
@@ -336,7 +339,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,

if (aux->native) {
aux->retry_cnt++;
if (!(aux->retry_cnt % MAX_AUX_RETRIES))
-   dp_catalog_aux_update_cfg(aux->catalog);
+   phy_calibrate(aux->phy);
}
/* reset aux if link is in connected state */
if (dp_catalog_link_is_connected(aux->catalog))
@@ -439,7 +442,7 @@ void dp_aux_reconfig(struct drm_dp_aux *dp_aux)
  
  	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
  
-	dp_catalog_aux_update_cfg(aux->catalog);

+   phy_calibrate(aux->phy);
dp_catalog_aux_reset(aux->catalog);
  }
  
@@ -517,6 +520,7 @@ static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,

  }
  
  struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,

+ struct phy *phy,
  bool is_edp)
  {
struct dp_aux_private *aux;
@@ -537,6 +541,7 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct 
dp_catalog *catalog,
  
  	aux->dev = dev;

aux->catalog = catalog;
+   aux->phy = phy;
aux->retry_cnt = 0;
  
  	/*

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index 511305da4f66..16d9b1758748 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -17,6 +17,7 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux);
  void dp_aux_reconfig(struct drm_dp_aux *dp_aux);
  
  struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,

+ struct phy *phy,
  bool is_edp);
  void dp_aux_put(struct drm_dp_aux *aux);
  
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c

index e07651768805..4c6207797c99 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -7,8 +7,6 @@
  
  #include 

  #include 
-#include 
-#include 
  #include 
  #include 
  #include 
@@ -243,16 +241,6 @@ void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, 
bool enable)
dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
  }
  
-void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog)

-{
-   struct dp_catalog_private *catalog = container_of(dp_catalog,
-   struct dp_catalog_private, dp_catalog);
-   struct dp_io *dp_io = catalog->io;
-   struct phy *phy = dp_io->phy;
-
-   phy_calibrate(phy);
-}
-
  int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog)
  {
u32 state;
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index ba7c62ba7ca3..1f3f58d4b8de 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -84,7 +84,6 @@ int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, 
bool read);
  int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog);
  void dp_catalog_aux_reset(struct dp_catalog *dp_catalog);
  void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable);
-void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog);
  int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog);
  u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
  
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c

index 6fbbd0f93d13..c1a51c498e01 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -729,7 +729,9 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
goto error;
}
  
-	dp->aux = dp_aux_get(dev, dp->catalog, dp->dp_display.is_edp);

+   dp->aux = dp_aux_get(dev, dp->catalog,
+dp->parser->io.phy,
+dp->dp_display.is_edp);
if 

Re: [PATCH RESEND v3 09/15] drm/msm/dp: move phy_configure_opts to dp_ctrl

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

There is little point in sharing phy configuration structure between
several modules. Move it to dp_ctrl, which becomes the only submodule
re-configuring the PHY.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_catalog.c | 19 -
  drivers/gpu/drm/msm/dp/dp_catalog.h |  2 --
  drivers/gpu/drm/msm/dp/dp_ctrl.c| 41 -
  drivers/gpu/drm/msm/dp/dp_parser.h  |  3 ---
  4 files changed, 27 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5142aeb705a4..e07651768805 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -765,25 +765,6 @@ void dp_catalog_ctrl_phy_reset(struct dp_catalog 
*dp_catalog)
dp_write_ahb(catalog, REG_DP_PHY_CTRL, 0x0);
  }
  
-int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog,

-   u8 v_level, u8 p_level)
-{
-   struct dp_catalog_private *catalog = container_of(dp_catalog,
-   struct dp_catalog_private, dp_catalog);
-   struct dp_io *dp_io = catalog->io;
-   struct phy *phy = dp_io->phy;
-   struct phy_configure_opts_dp *opts_dp = _io->phy_opts.dp;
-
-   /* TODO: Update for all lanes instead of just first one */
-   opts_dp->voltage[0] = v_level;
-   opts_dp->pre[0] = p_level;
-   opts_dp->set_voltages = 1;
-   phy_configure(phy, _io->phy_opts);
-   opts_dp->set_voltages = 0;
-
-   return 0;
-}
-
  void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
u32 pattern)
  {
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 38786e855b51..ba7c62ba7ca3 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -111,8 +111,6 @@ void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, 
bool enter);
  u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog);
  u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog);
  void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
-int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8 v_level,
-   u8 p_level);
  int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog);
  u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog);
  void dp_catalog_ctrl_update_transfer_unit(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 e367eb8e5bea..4aea72a2b8e8 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -87,6 +87,8 @@ struct dp_ctrl_private {
  
  	struct clk *pixel_clk;
  
+	union phy_configure_opts phy_opts;

+
struct completion idle_comp;
struct completion psr_op_comp;
struct completion video_comp;
@@ -1017,6 +1019,21 @@ static int dp_ctrl_wait4video_ready(struct 
dp_ctrl_private *ctrl)
return ret;
  }
  
+static int dp_ctrl_set_vx_px(struct dp_ctrl_private *ctrl,

+u8 v_level, u8 p_level)
+{
+   union phy_configure_opts *phy_opts = >phy_opts;
+
+   /* TODO: Update for all lanes instead of just first one */
+   phy_opts->dp.voltage[0] = v_level;
+   phy_opts->dp.pre[0] = p_level;
+   phy_opts->dp.set_voltages = 1;
+   phy_configure(ctrl->parser->io.phy, phy_opts);
+   phy_opts->dp.set_voltages = 0;
+
+   return 0;
+}
+
  static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
  {
struct dp_link *link = ctrl->link;
@@ -1029,7 +1046,7 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private 
*ctrl)
drm_dbg_dp(ctrl->drm_dev,
"voltage level: %d emphasis level: %d\n",
voltage_swing_level, pre_emphasis_level);
-   ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
+   ret = dp_ctrl_set_vx_px(ctrl,
voltage_swing_level, pre_emphasis_level);
  
  	if (ret)

@@ -1425,16 +1442,14 @@ static void dp_ctrl_link_clk_disable(struct dp_ctrl 
*dp_ctrl)
  static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
  {
int ret = 0;
-   struct dp_io *dp_io = >parser->io;
-   struct phy *phy = dp_io->phy;
-   struct phy_configure_opts_dp *opts_dp = _io->phy_opts.dp;
+   struct phy *phy = ctrl->parser->io.phy;
const u8 *dpcd = ctrl->panel->dpcd;
  
-	opts_dp->lanes = ctrl->link->link_params.num_lanes;

-   opts_dp->link_rate = ctrl->link->link_params.rate / 100;
-   opts_dp->ssc = drm_dp_max_downspread(dpcd);
+   ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
+   ctrl->phy_opts.dp.link_rate = ctrl->link->link_params.rate / 100;
+   ctrl->phy_opts.dp.ssc = drm_dp_max_downspread(dpcd);
  
-	phy_configure(phy, _io->phy_opts);

+   

Re: Re: Re: [PATCH 3/5] drm/ttm: replace busy placement with flags v6

2024-01-26 Thread Lucas De Marchi

On Fri, Jan 26, 2024 at 04:16:58PM -0600, Lucas De Marchi wrote:

On Thu, Jan 18, 2024 at 05:38:16PM +0100, Thomas Hellström wrote:


On 1/17/24 13:27, Thomas Hellström wrote:


On 1/17/24 11:47, Thomas Hellström wrote:

Hi, Christian

Xe changes look good. Will send the series to xe ci to check for 
regressions.


Hmm, there are some checkpatch warnings about author / SOB email 
mismatch,


With those fixed, this patch is

Reviewed-by: Thomas Hellström 



it actually broke drm-tip now that this is merged:

../drivers/gpu/drm/xe/xe_bo.c:41:10: error: ‘struct ttm_placement’ has no 
member named ‘num_busy_placement’; did you mean ‘num_placement’
  41 | .num_busy_placement = 1,
 |  ^~
 |  num_placement
../drivers/gpu/drm/xe/xe_bo.c:41:31: error: excess elements in struct 
initializer [-Werror]
  41 | .num_busy_placement = 1,
 |   ^


Apparently a conflict with another patch that got applied a few days
ago: a201c6ee37d6 ("drm/xe/bo: Evict VRAM to TT rather than to system")


oh, no... apparently that commit is  from a long time ago. The problem
was that drm-misc-next was not yet in sync with drm-next. Thomas, do you
have a fixup for this to put in rerere?

Lucas De Marchi


Re: [PATCH RESEND v3 08/15] drm/msm/dp: split dp_ctrl_clk_enable into four functuions

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Split the dp_ctrl_clk_enable() beast into four functions, each of them
doing just a single item: enabling or disabling core or link clocks.
This allows us to cleanup the dss_module_power structure and makes
several dp_ctrl functions return void.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_ctrl.c| 220 +---
  drivers/gpu/drm/msm/dp/dp_ctrl.h|  16 +--
  drivers/gpu/drm/msm/dp/dp_display.c |   4 +-
  3 files changed, 108 insertions(+), 132 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index cfcf6136ffa6..e367eb8e5bea 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -69,11 +69,6 @@ struct dp_vc_tu_mapping_table {
u8 tu_size_minus1;
  };
  
-struct dss_module_power {

-   unsigned int num_clk;
-   struct clk_bulk_data *clocks;
-};
-
  struct dp_ctrl_private {
struct dp_ctrl dp_ctrl;
struct drm_device *drm_dev;
@@ -84,7 +79,12 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
  
-	struct dss_module_power mp[DP_MAX_PM];

+   unsigned int num_core_clks;
+   struct clk_bulk_data *core_clks;
+
+   unsigned int num_link_clks;
+   struct clk_bulk_data *link_clks;
+
struct clk *pixel_clk;
  
  	struct completion idle_comp;

@@ -96,15 +96,6 @@ struct dp_ctrl_private {
bool stream_clks_on;
  };
  
-static inline const char *dp_pm_name(enum dp_pm_type module)

-{
-   switch (module) {
-   case DP_CORE_PM:return "DP_CORE_PM";
-   case DP_CTRL_PM:return "DP_CTRL_PM";
-   default:return "???";
-   }
-}
-
  static int dp_aux_link_configure(struct drm_dp_aux *aux,
struct dp_link_info *link)
  {
@@ -1337,67 +1328,76 @@ static int dp_ctrl_setup_main_link(struct 
dp_ctrl_private *ctrl,
return ret;
  }
  
-int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,

-  enum dp_pm_type pm_type, bool enable)
+int dp_ctrl_core_clk_enable(struct dp_ctrl *dp_ctrl)
  {
struct dp_ctrl_private *ctrl;
-   struct dss_module_power *mp;
int ret = 0;
  
  	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
  
-	if (pm_type != DP_CORE_PM &&

-   pm_type != DP_CTRL_PM) {
-   DRM_ERROR("unsupported ctrl module: %s\n",
- dp_pm_name(pm_type));
-   return -EINVAL;
+   if (ctrl->core_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev, "core clks already enabled\n");
+   return 0;
}
  
-	if (enable) {

-   if (pm_type == DP_CORE_PM && ctrl->core_clks_on) {
-   drm_dbg_dp(ctrl->drm_dev,
-  "core clks already enabled\n");
-   return 0;
-   }
+   ret = clk_bulk_prepare_enable(ctrl->num_core_clks, ctrl->core_clks);
+   if (ret)
+   return ret;
  
-		if (pm_type == DP_CTRL_PM && ctrl->link_clks_on) {

-   drm_dbg_dp(ctrl->drm_dev,
-  "links clks already enabled\n");
-   return 0;
-   }
+   ctrl->core_clks_on = true;
  
-		if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {

-   drm_dbg_dp(ctrl->drm_dev,
-  "Enable core clks before link clks\n");
-   mp = >mp[DP_CORE_PM];
+   drm_dbg_dp(ctrl->drm_dev, "enable core clocks \n");
+   drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
+  ctrl->stream_clks_on ? "on" : "off",
+  ctrl->link_clks_on ? "on" : "off",
+  ctrl->core_clks_on ? "on" : "off");
  
-			ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);

-   if (ret)
-   return ret;
+   return 0;
+}
  
-			ctrl->core_clks_on = true;

-   }
+void dp_ctrl_core_clk_disable(struct dp_ctrl *dp_ctrl)
+{
+   struct dp_ctrl_private *ctrl;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+   clk_bulk_disable_unprepare(ctrl->num_core_clks, ctrl->core_clks);
+
+   ctrl->core_clks_on = false;
+
+   drm_dbg_dp(ctrl->drm_dev, "disable core clocks \n");
+   drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
+  ctrl->stream_clks_on ? "on" : "off",
+  ctrl->link_clks_on ? "on" : "off",
+  ctrl->core_clks_on ? "on" : "off");
+}
+
+static int dp_ctrl_link_clk_enable(struct dp_ctrl *dp_ctrl)
+{
+   struct dp_ctrl_private *ctrl;
+   int ret = 0;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+   if (ctrl->link_clks_on) {
+   

Re: [PATCH RESEND v3 07/15] drm/msm/dp: stop parsing clock names from DT

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

All supported platforms use the same clocks configuration. Instead of
parsing names from DT in a pretty complex manner, use the static
configuration. If at some point newer (or older) platforms have
different clock configuration, this clock config can be moved to the
device data.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_ctrl.c   |  73 ++--
  drivers/gpu/drm/msm/dp/dp_ctrl.h   |   6 ++
  drivers/gpu/drm/msm/dp/dp_parser.c | 112 -
  drivers/gpu/drm/msm/dp/dp_parser.h |  22 
  4 files changed, 63 insertions(+), 150 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 56a424a82a1b..cfcf6136ffa6 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -69,6 +69,11 @@ struct dp_vc_tu_mapping_table {
u8 tu_size_minus1;
  };
  
+struct dss_module_power {

+   unsigned int num_clk;
+   struct clk_bulk_data *clocks;
+};
+
  struct dp_ctrl_private {
struct dp_ctrl dp_ctrl;
struct drm_device *drm_dev;
@@ -79,6 +84,7 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
  
+	struct dss_module_power mp[DP_MAX_PM];

struct clk *pixel_clk;
  
  	struct completion idle_comp;

@@ -90,6 +96,15 @@ struct dp_ctrl_private {
bool stream_clks_on;
  };
  
+static inline const char *dp_pm_name(enum dp_pm_type module)

+{
+   switch (module) {
+   case DP_CORE_PM:return "DP_CORE_PM";
+   case DP_CTRL_PM:return "DP_CTRL_PM";
+   default:return "???";
+   }
+}
+
  static int dp_aux_link_configure(struct drm_dp_aux *aux,
struct dp_link_info *link)
  {
@@ -1334,7 +1349,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
if (pm_type != DP_CORE_PM &&
pm_type != DP_CTRL_PM) {
DRM_ERROR("unsupported ctrl module: %s\n",
- dp_parser_pm_name(pm_type));
+ dp_pm_name(pm_type));
return -EINVAL;
}
  
@@ -1354,7 +1369,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,

if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
drm_dbg_dp(ctrl->drm_dev,
   "Enable core clks before link clks\n");
-   mp = >parser->mp[DP_CORE_PM];
+   mp = >mp[DP_CORE_PM];
  
  			ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);

if (ret)
@@ -1364,7 +1379,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
}
}
  
-	mp = >parser->mp[pm_type];

+   mp = >mp[pm_type];
if (enable) {
ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (ret)
@@ -1380,7 +1395,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
  
  	drm_dbg_dp(ctrl->drm_dev, "%s clocks for %s\n",

   enable ? "enable" : "disable",
-  dp_parser_pm_name(pm_type));
+  dp_pm_name(pm_type));
drm_dbg_dp(ctrl->drm_dev,
   "stream_clks:%s link_clks:%s core_clks:%s\n",
   ctrl->stream_clks_on ? "on" : "off",
@@ -2158,30 +2173,56 @@ irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
return ret;
  }
  
+static const char *core_clks[] = {

+   "core_iface",
+   "core_aux",
+};
+
+static const char *ctrl_clks[] = {
+   "ctrl_link",
+   "ctrl_link_iface",
+};
+
  static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl)
  {
-   struct dp_ctrl_private *ctrl_private;
-   int rc = 0;
-   struct dss_module_power *core, *ctrl;
+   struct dp_ctrl_private *ctrl;
+   struct dss_module_power *core, *link;
struct device *dev;
+   int i, rc;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+   dev = ctrl->dev;
  
-	ctrl_private = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

-   dev = ctrl_private->dev;
+   core = >mp[DP_CORE_PM];
+   link = >mp[DP_CTRL_PM];
  
-	core = _private->parser->mp[DP_CORE_PM];

-   ctrl = _private->parser->mp[DP_CTRL_PM];
+   core->num_clk = ARRAY_SIZE(core_clks);
+   core->clocks = devm_kcalloc(dev, core->num_clk, sizeof(*core->clocks), 
GFP_KERNEL);
+   if (!core->clocks)
+   return -ENOMEM;
+
+   for (i = 0; i < core->num_clk; i++)
+   core->clocks[i].id = core_clks[i];
  
  	rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);

if (rc)
return rc;
  
-	rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);

+   link->num_clk = ARRAY_SIZE(ctrl_clks);
+   link->clocks = devm_kcalloc(dev, link->num_clk, sizeof(*link->clocks), 
GFP_KERNEL);
+   if (!link->clocks)
+  

Re: [PATCH RESEND v3 06/15] drm/msm/dp: simplify stream clocks handling

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

There is only a single DP_STREAM_PM clock, stream_pixel. Instead of
using a separate dss_module_power instance for this single clock, handle
this clock directly. This allows us to drop several wrapping functions.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_ctrl.c   | 91 --
  drivers/gpu/drm/msm/dp/dp_parser.c | 41 -
  drivers/gpu/drm/msm/dp/dp_parser.h |  2 -
  3 files changed, 47 insertions(+), 87 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index da29281c575b..56a424a82a1b 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -79,6 +79,8 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
  
+	struct clk *pixel_clk;

+
struct completion idle_comp;
struct completion psr_op_comp;
struct completion video_comp;
@@ -1320,27 +1322,6 @@ static int dp_ctrl_setup_main_link(struct 
dp_ctrl_private *ctrl,
return ret;
  }
  
-static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,

-   enum dp_pm_type module, char *name, unsigned long rate)
-{
-   u32 num = ctrl->parser->mp[module].num_clk;
-   struct clk_bulk_data *cfg = ctrl->parser->mp[module].clocks;
-
-   while (num && strcmp(cfg->id, name)) {
-   num--;
-   cfg++;
-   }
-
-   drm_dbg_dp(ctrl->drm_dev, "setting rate=%lu on clk=%s\n",
-   rate, name);
-
-   if (num)
-   clk_set_rate(cfg->clk, rate);
-   else
-   DRM_ERROR("%s clock doesn't exit to set rate %lu\n",
-   name, rate);
-}
-
  int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
   enum dp_pm_type pm_type, bool enable)
  {
@@ -1351,8 +1332,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
  
  	if (pm_type != DP_CORE_PM &&

-   pm_type != DP_CTRL_PM &&
-   pm_type != DP_STREAM_PM) {
+   pm_type != DP_CTRL_PM) {
DRM_ERROR("unsupported ctrl module: %s\n",
  dp_parser_pm_name(pm_type));
return -EINVAL;
@@ -1371,12 +1351,6 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
return 0;
}
  
-		if (pm_type == DP_STREAM_PM && ctrl->stream_clks_on) {

-   drm_dbg_dp(ctrl->drm_dev,
-  "pixel clks already enabled\n");
-   return 0;
-   }
-
if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
drm_dbg_dp(ctrl->drm_dev,
   "Enable core clks before link clks\n");
@@ -1401,8 +1375,6 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
  
  	if (pm_type == DP_CORE_PM)

ctrl->core_clks_on = enable;
-   else if (pm_type == DP_STREAM_PM)
-   ctrl->stream_clks_on = enable;
else
ctrl->link_clks_on = enable;
  
@@ -1734,14 +1706,23 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)

}
  
  	pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;

-   dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 
1000);
-
-   ret = dp_ctrl_clk_enable(>dp_ctrl, DP_STREAM_PM, true);
+   ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
-   DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
+   DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
return ret;
}
  
+	if (ctrl->stream_clks_on) {

+   drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
+   } else {
+   ret = clk_prepare_enable(ctrl->pixel_clk);
+   if (ret) {
+   DRM_ERROR("Failed to start pixel clocks. ret=%d\n", 
ret);
+   return ret;
+   }
+   ctrl->stream_clks_on = true;
+   }
+
dp_ctrl_send_phy_test_pattern(ctrl);
  
  	return 0;

@@ -1977,14 +1958,23 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
}
}
  
-	dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 1000);

-
-   ret = dp_ctrl_clk_enable(>dp_ctrl, DP_STREAM_PM, true);
+   ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
-   DRM_ERROR("Unable to start pixel clocks. ret=%d\n", ret);
+   DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
goto end;
}
  
+	if (ctrl->stream_clks_on) {

+   drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
+   } 

Re: [PATCH RESEND v3 05/15] drm/msm/dp: fold dp_power into dp_ctrl module

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

The dp_power submodule is limited to handling the clocks only following
previous cleanups. Fold it into the dp_ctrl submodule, removing one
unnecessary level of indirection.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/Makefile|   1 -
  drivers/gpu/drm/msm/dp/dp_ctrl.c| 150 +++
  drivers/gpu/drm/msm/dp/dp_ctrl.h|   6 +-
  drivers/gpu/drm/msm/dp/dp_display.c |  24 +
  drivers/gpu/drm/msm/dp/dp_power.c   | 170 
  drivers/gpu/drm/msm/dp/dp_power.h   |  74 
  6 files changed, 142 insertions(+), 283 deletions(-)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b1173128b5b9..8dbdf3fba69e 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -128,7 +128,6 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_link.o \
dp/dp_panel.o \
dp/dp_parser.o \
-   dp/dp_power.o \
dp/dp_audio.o
  
  msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 77a8d9366ed7..da29281c575b 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -76,13 +76,16 @@ struct dp_ctrl_private {
struct drm_dp_aux *aux;
struct dp_panel *panel;
struct dp_link *link;
-   struct dp_power *power;
struct dp_parser *parser;
struct dp_catalog *catalog;
  
  	struct completion idle_comp;

struct completion psr_op_comp;
struct completion video_comp;
+
+   bool core_clks_on;
+   bool link_clks_on;
+   bool stream_clks_on;
  };
  
  static int dp_aux_link_configure(struct drm_dp_aux *aux,

@@ -1338,6 +1341,83 @@ static void dp_ctrl_set_clock_rate(struct 
dp_ctrl_private *ctrl,
name, rate);
  }
  
+int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,

+  enum dp_pm_type pm_type, bool enable)
+{
+   struct dp_ctrl_private *ctrl;
+   struct dss_module_power *mp;
+   int ret = 0;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+   if (pm_type != DP_CORE_PM &&
+   pm_type != DP_CTRL_PM &&
+   pm_type != DP_STREAM_PM) {
+   DRM_ERROR("unsupported ctrl module: %s\n",
+ dp_parser_pm_name(pm_type));
+   return -EINVAL;
+   }
+
+   if (enable) {
+   if (pm_type == DP_CORE_PM && ctrl->core_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "core clks already enabled\n");
+   return 0;
+   }
+
+   if (pm_type == DP_CTRL_PM && ctrl->link_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "links clks already enabled\n");
+   return 0;
+   }
+
+   if (pm_type == DP_STREAM_PM && ctrl->stream_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "pixel clks already enabled\n");
+   return 0;
+   }
+
+   if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "Enable core clks before link clks\n");
+   mp = >parser->mp[DP_CORE_PM];
+
+   ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
+   if (ret)
+   return ret;
+
+   ctrl->core_clks_on = true;
+   }
+   }
+
+   mp = >parser->mp[pm_type];
+   if (enable) {
+   ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
+   if (ret)
+   return ret;
+   } else {
+   clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
+   }
+
+   if (pm_type == DP_CORE_PM)
+   ctrl->core_clks_on = enable;
+   else if (pm_type == DP_STREAM_PM)
+   ctrl->stream_clks_on = enable;
+   else
+   ctrl->link_clks_on = enable;
+
+   drm_dbg_dp(ctrl->drm_dev, "%s clocks for %s\n",
+  enable ? "enable" : "disable",
+  dp_parser_pm_name(pm_type));
+   drm_dbg_dp(ctrl->drm_dev,
+  "stream_clks:%s link_clks:%s core_clks:%s\n",
+  ctrl->stream_clks_on ? "on" : "off",
+  ctrl->link_clks_on ? "on" : "off",
+  ctrl->core_clks_on ? "on" : "off");
+
+   return 0;
+}
+
  static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
  {
int ret = 0;
@@ -1354,7 +1434,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct 
dp_ctrl_private *ctrl)
phy_power_on(phy);
  
  	

Re: [PATCH RESEND v3 04/15] drm/msm/dp: inline dp_power_(de)init

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

In preparation to cleanup of the dp_power module, inline dp_power_init()
and dp_power_deinit() functions, which are now just turning the clocks
on and off.

Reviewed-by: Konrad Dybcio 
Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_display.c |  4 ++--
  drivers/gpu/drm/msm/dp/dp_power.c   | 10 --
  drivers/gpu/drm/msm/dp/dp_power.h   | 21 -
  3 files changed, 2 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 67b48f0a6c83..8cd18705740f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -434,7 +434,7 @@ static void dp_display_host_init(struct dp_display_private 
*dp)
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
  
-	dp_power_init(dp->power);

+   dp_power_clk_enable(dp->power, DP_CORE_PM, true);
dp_ctrl_reset_irq_ctrl(dp->ctrl, true);
dp_aux_init(dp->aux);
dp->core_initialized = true;
@@ -448,7 +448,7 @@ static void dp_display_host_deinit(struct 
dp_display_private *dp)
  
  	dp_ctrl_reset_irq_ctrl(dp->ctrl, false);

dp_aux_deinit(dp->aux);
-   dp_power_deinit(dp->power);
+   dp_power_clk_enable(dp->power, DP_CORE_PM, false);
dp->core_initialized = false;
  }
  
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c

index b095a5b47c8b..f49e3aede308 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -152,16 +152,6 @@ int dp_power_client_init(struct dp_power *dp_power)
return dp_power_clk_init(power);
  }
  
-int dp_power_init(struct dp_power *dp_power)

-{
-   return dp_power_clk_enable(dp_power, DP_CORE_PM, true);
-}
-
-int dp_power_deinit(struct dp_power *dp_power)
-{
-   return dp_power_clk_enable(dp_power, DP_CORE_PM, false);
-}
-
  struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
  {
struct dp_power_private *power;
diff --git a/drivers/gpu/drm/msm/dp/dp_power.h 
b/drivers/gpu/drm/msm/dp/dp_power.h
index 55ada51edb57..eb836b5aa24a 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.h
+++ b/drivers/gpu/drm/msm/dp/dp_power.h
@@ -22,27 +22,6 @@ struct dp_power {
bool stream_clks_on;
  };
  
-/**

- * dp_power_init() - enable power supplies for display controller
- *
- * @power: instance of power module
- * return: 0 if success or error if failure.
- *
- * This API will turn on the regulators and configures gpio's
- * aux/hpd.
- */
-int dp_power_init(struct dp_power *power);
-
-/**
- * dp_power_deinit() - turn off regulators and gpios.
- *
- * @power: instance of power module
- * return: 0 for success
- *
- * This API turns off power and regulators.
- */
-int dp_power_deinit(struct dp_power *power);
-
  /**
   * dp_power_clk_status() - display controller clocks status
   *



Re: [PATCH RESEND v3 03/15] drm/msm/dp: parse DT from dp_parser_get

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

It makes little sense to split the submodule get and actual DT parsing.
Call dp_parser_parse() directly from dp_parser_get(), so that the parser
data is fully initialised once it is returned to the caller.

Reviewed-by: Konrad Dybcio 
Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_display.c | 6 --
  drivers/gpu/drm/msm/dp/dp_parser.c  | 8 +++-
  drivers/gpu/drm/msm/dp/dp_parser.h  | 3 ---
  3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index d37d599aec27..67b48f0a6c83 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1266,12 +1266,6 @@ static int dp_display_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
  
-	rc = dp->parser->parse(dp->parser);

-   if (rc) {
-   DRM_ERROR("device tree parsing failed\n");
-   goto err;
-   }
-
rc = dp_power_client_init(dp->power);
if (rc) {
DRM_ERROR("Power client create failed\n");
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c 
b/drivers/gpu/drm/msm/dp/dp_parser.c
index 7032dcc8842b..2d9d126c119b 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -315,13 +315,19 @@ static int dp_parser_parse(struct dp_parser *parser)
  struct dp_parser *dp_parser_get(struct platform_device *pdev)
  {
struct dp_parser *parser;
+   int ret;
  
  	parser = devm_kzalloc(>dev, sizeof(*parser), GFP_KERNEL);

if (!parser)
return ERR_PTR(-ENOMEM);
  
-	parser->parse = dp_parser_parse;

parser->pdev = pdev;
  
+	ret = dp_parser_parse(parser);

+   if (ret) {
+   dev_err(>dev, "device tree parsing failed\n");
+   return ERR_PTR(ret);
+   }
+
return parser;
  }
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 90a2cdbbe344..4ccc432b4142 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -67,7 +67,6 @@ struct dss_module_power {
   *
   * @pdev: platform data of the client
   * @mp: gpio, regulator and clock related data
- * @parse: function to be called by client to parse device tree.
   */
  struct dp_parser {
struct platform_device *pdev;
@@ -76,8 +75,6 @@ struct dp_parser {
u32 max_dp_lanes;
u32 max_dp_link_rate;
struct drm_bridge *next_bridge;
-
-   int (*parse)(struct dp_parser *parser);
  };
  
  /**




Re: [PATCH RESEND v3 02/15] drm/msm/dp: drop unused fields from dp_power_private

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Drop unused and obsolete fields from struct dp_power_private.

Reviewed-by: Konrad Dybcio 
Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_power.c | 3 ---
  1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_power.c 
b/drivers/gpu/drm/msm/dp/dp_power.c
index c4843dd69f47..b095a5b47c8b 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -16,9 +16,6 @@ struct dp_power_private {
struct dp_parser *parser;
struct device *dev;
struct drm_device *drm_dev;
-   struct clk *link_clk_src;
-   struct clk *pixel_provider;
-   struct clk *link_provider;
  
  	struct dp_power dp_power;

  };



Re: [PATCH RESEND v3 01/15] drm/msm/dp: drop unused parser definitions

2024-01-26 Thread Kuogee Hsieh



On 1/26/2024 10:26 AM, Dmitry Baryshkov wrote:

Drop several unused and obsolete definitions from the dp_parser module.

Signed-off-by: Dmitry Baryshkov 

Tested-by: Kuogee Hsieh 
Reviewed-by: Kuogee Hsieh 

---
  drivers/gpu/drm/msm/dp/dp_parser.h | 46 --
  1 file changed, 46 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 1f068626d445..90a2cdbbe344 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -12,7 +12,6 @@
  
  #include "msm_drv.h"
  
-#define DP_LABEL "MDSS DP DISPLAY"

  #define DP_MAX_PIXEL_CLK_KHZ  675000
  #define DP_MAX_NUM_DP_LANES   4
  #define DP_LINK_RATE_HBR2 54 /* kbytes */
@@ -21,7 +20,6 @@ enum dp_pm_type {
DP_CORE_PM,
DP_CTRL_PM,
DP_STREAM_PM,
-   DP_PHY_PM,
DP_MAX_PM
  };
  
@@ -43,28 +41,10 @@ static inline const char *dp_parser_pm_name(enum dp_pm_type module)

case DP_CORE_PM:return "DP_CORE_PM";
case DP_CTRL_PM:return "DP_CTRL_PM";
case DP_STREAM_PM:  return "DP_STREAM_PM";
-   case DP_PHY_PM: return "DP_PHY_PM";
default:return "???";
}
  }
  
-/**

- * struct dp_display_data  - display related device tree data.
- *
- * @ctrl_node: referece to controller device
- * @phy_node:  reference to phy device
- * @is_active: is the controller currently active
- * @name: name of the display
- * @display_type: type of the display
- */
-struct dp_display_data {
-   struct device_node *ctrl_node;
-   struct device_node *phy_node;
-   bool is_active;
-   const char *name;
-   const char *display_type;
-};
-
  /**
   * struct dp_ctrl_resource - controller's IO related data
   *
@@ -77,28 +57,6 @@ struct dp_io {
union phy_configure_opts phy_opts;
  };
  
-/**

- * struct dp_pinctrl - DP's pin control
- *
- * @pin: pin-controller's instance
- * @state_active: active state pin control
- * @state_hpd_active: hpd active state pin control
- * @state_suspend: suspend state pin control
- */
-struct dp_pinctrl {
-   struct pinctrl *pin;
-   struct pinctrl_state *state_active;
-   struct pinctrl_state *state_hpd_active;
-   struct pinctrl_state *state_suspend;
-};
-
-/* Regulators for DP devices */
-struct dp_reg_entry {
-   char name[32];
-   int enable_load;
-   int disable_load;
-};
-
  struct dss_module_power {
unsigned int num_clk;
struct clk_bulk_data *clocks;
@@ -109,16 +67,12 @@ struct dss_module_power {
   *
   * @pdev: platform data of the client
   * @mp: gpio, regulator and clock related data
- * @pinctrl: pin-control related data
- * @disp_data: controller's display related data
   * @parse: function to be called by client to parse device tree.
   */
  struct dp_parser {
struct platform_device *pdev;
struct dss_module_power mp[DP_MAX_PM];
-   struct dp_pinctrl pinctrl;
struct dp_io io;
-   struct dp_display_data disp_data;
u32 max_dp_lanes;
u32 max_dp_link_rate;
struct drm_bridge *next_bridge;



Re: Re: [PATCH 3/5] drm/ttm: replace busy placement with flags v6

2024-01-26 Thread Lucas De Marchi

On Thu, Jan 18, 2024 at 05:38:16PM +0100, Thomas Hellström wrote:


On 1/17/24 13:27, Thomas Hellström wrote:


On 1/17/24 11:47, Thomas Hellström wrote:

Hi, Christian

Xe changes look good. Will send the series to xe ci to check for 
regressions.


Hmm, there are some checkpatch warnings about author / SOB email 
mismatch,


With those fixed, this patch is

Reviewed-by: Thomas Hellström 



it actually broke drm-tip now that this is merged:

../drivers/gpu/drm/xe/xe_bo.c:41:10: error: ‘struct ttm_placement’ has no 
member named ‘num_busy_placement’; did you mean ‘num_placement’
   41 | .num_busy_placement = 1,
  |  ^~
  |  num_placement
../drivers/gpu/drm/xe/xe_bo.c:41:31: error: excess elements in struct 
initializer [-Werror]
   41 | .num_busy_placement = 1,
  |   ^


Apparently a conflict with another patch that got applied a few days
ago: a201c6ee37d6 ("drm/xe/bo: Evict VRAM to TT rather than to system")

Lucas De Marchi






But worserthere are some regressions in the dma-buf ktest (it tests 
evicting of a dynamic dma-buf),


https://patchwork.freedesktop.org/series/128873/

I'll take a look later today or tomorrow.


These are from the next patch. Will continue the discussion there.

/Thomas




/Thomas





/Thomas


On 1/12/24 13:51, Christian König wrote:

From: Somalapuram Amaranath 

Instead of a list of separate busy placement add flags which indicate
that a placement should only be used when there is room or if we 
need to

evict.

v2: add missing TTM_PL_FLAG_IDLE for i915
v3: fix auto build test ERROR on drm-tip/drm-tip
v4: fix some typos pointed out by checkpatch
v5: cleanup some rebase problems with VMWGFX
v6: implement some missing VMWGFX functionality pointed out by Zack,
 rename the flags as suggested by Michel, rebase on drm-tip and
 adjust XE as well

Signed-off-by: Christian König 
Signed-off-by: Somalapuram Amaranath 
---
  drivers/gpu/drm/amd/amdgpu/amdgpu_object.c |  6 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c    | 11 +---
  drivers/gpu/drm/drm_gem_vram_helper.c  |  2 -
  drivers/gpu/drm/i915/gem/i915_gem_ttm.c    | 37 +--
  drivers/gpu/drm/loongson/lsdc_ttm.c    |  2 -
  drivers/gpu/drm/nouveau/nouveau_bo.c   | 59 +++--
  drivers/gpu/drm/nouveau/nouveau_bo.h   |  1 -
  drivers/gpu/drm/qxl/qxl_object.c   |  2 -
  drivers/gpu/drm/qxl/qxl_ttm.c  |  2 -
  drivers/gpu/drm/radeon/radeon_object.c |  2 -
  drivers/gpu/drm/radeon/radeon_ttm.c    |  8 +--
  drivers/gpu/drm/radeon/radeon_uvd.c    |  1 -
  drivers/gpu/drm/ttm/ttm_bo.c   | 21 ---
  drivers/gpu/drm/ttm/ttm_resource.c | 73 
+-

  drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 33 +++---
  drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c |  4 --
  drivers/gpu/drm/xe/xe_bo.c | 33 +-
  include/drm/ttm/ttm_placement.h    | 10 +--
  include/drm/ttm/ttm_resource.h |  8 +--
  19 files changed, 118 insertions(+), 197 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c

index 425cebcc5cbf..b671b0665492 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -220,9 +220,6 @@ void amdgpu_bo_placement_from_domain(struct 
amdgpu_bo *abo, u32 domain)

    placement->num_placement = c;
  placement->placement = places;
-
-    placement->num_busy_placement = c;
-    placement->busy_placement = places;
  }
    /**
@@ -1397,8 +1394,7 @@ vm_fault_t 
amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)

  AMDGPU_GEM_DOMAIN_GTT);
    /* Avoid costly evictions; only set GTT as a busy placement */
-    abo->placement.num_busy_placement = 1;
-    abo->placement.busy_placement = >placements[1];
+    abo->placements[0].flags |= TTM_PL_FLAG_DESIRED;
    r = ttm_bo_validate(bo, >placement, );
  if (unlikely(r == -EBUSY || r == -ERESTARTSYS))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c

index 75c9fd2c6c2a..8722beba494e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -102,23 +102,19 @@ static void amdgpu_evict_flags(struct 
ttm_buffer_object *bo,

  /* Don't handle scatter gather BOs */
  if (bo->type == ttm_bo_type_sg) {
  placement->num_placement = 0;
-    placement->num_busy_placement = 0;
  return;
  }
    /* Object isn't an AMDGPU object so ignore */
  if (!amdgpu_bo_is_amdgpu_bo(bo)) {
  placement->placement = 
-    placement->busy_placement = 
  placement->num_placement = 1;
-    placement->num_busy_placement = 1;
  return;
  }
    abo = ttm_to_amdgpu_bo(bo);
  if (abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) {
  placement->num_placement = 0;
- 

Re: [git pull] drm fixes for 6.8-rc2

2024-01-26 Thread pr-tracker-bot
The pull request you sent on Sat, 27 Jan 2024 04:56:27 +1000:

> git://anongit.freedesktop.org/drm/drm tags/drm-fixes-2024-01-27

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/168174d78157bba1315d5f8e1c66548b92c84ae9

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


Re: [PATCH v3 4/4] arm64: dts: rockchip: Add devicetree for Pine64 PineTab2

2024-01-26 Thread Manuel Traut
Hello Ondřej,

On Fri, Jan 05, 2024 at 05:48:46PM +0100, Ondřej Jirman wrote:
> On Fri, Jan 05, 2024 at 05:11:03PM +0100, Manuel Traut wrote:
> > On Wed, Jan 03, 2024 at 10:42:54AM +0100, Ondřej Jirman wrote:
> > > Hello Manuel,
> > > 
> > > a few more things I noticed:
> > > 
> > > On Tue, Jan 02, 2024 at 05:15:47PM +0100, Manuel Traut wrote:
> > > > From: Alexander Warnecke 
> > > > 
> > > > +   leds {
> > > > +   compatible = "gpio-leds";
> > > > +
> > > > +   pinctrl-names = "default";
> > > > +   pinctrl-0 = <_led_en_h>;
> > > > +
> > > > +   led-0 {
> > > > +   gpios = < RK_PA5 GPIO_ACTIVE_HIGH>;
> > > > +   color = ;
> > > > +   function = LED_FUNCTION_FLASH;
> > > > +   };
> > > 
> > > This LED is supplied by VCC5V_MIDU, so maybe this should be a 
> > > regulator-led
> > > supplied by gpio (FLASH_LED_EN_H) controlled regulator-fixed named f_led 
> > > which
> > > is in turn supplied by VCC5V_MIDU.
> > > 
> > > https://megous.com/dl/tmp/9bf0d85d78946b5e.png
> > 
> > regulator-leds are controlled by turning on or off the regulator. However
> > VCC5V_MIDU is also used by other devices (USB, HDMI, ..) so I guess this is
> > not what we want. I would keep it as is.
> 
> It's used by the LED. gpio-leds will not ensure it's on when you enable the 
> LED.
> 
> In practice this may only come up if someone tries to save power by unloading
> dwc3 USB driver, when using PT2 outside of the keyboard case. Otherwise
> VCC5V_MIDU will be enabled by DWC3 driver's use of PHY API.
> 
> In any case, I'm not saying you should use VCC5V_MIDU directly in 
> regulator-led,
> but as a vin-supply to a new regulator-fixed node (which would be describing
> this "fixed voltage regulator" https://megous.com/dl/tmp/cc65ec81ab9af163.png 
> ).

Sorry for the late response, I was busy with other things in the last weeks.

I changed it to be a regulator led and will post a v4 soon.


Re: [PATCH RESEND v3 00/15] drm/msm/dp: clear power and parser submodules away

2024-01-26 Thread Dmitry Baryshkov
On Fri, 26 Jan 2024 at 20:26, Dmitry Baryshkov
 wrote:
>
> Reshuffle code in the DP driver, cleaning up clocks and DT parsing and
> dropping the dp_power and dp_parser submodules.
>
> Initially I started by looking onto stream_pixel clock handling only to
> find several wrapping layers around a single clocks. After inlining
> and/or dropping them (and thus dp_power submodule), it was more or less
> natural to continue cleaning up the dp_parser until it got removed
> completely.

I see. I have resent v3 because b4 for some reason didn't pick up R-b
tags  from v2. I didn't notice that `b4 send --resend` doesn't pick up
changes and just resends the previous version.
So I must beg your pardon for the spam. I'll push R-B tags via response emails.


-- 
With best wishes
Dmitry


RE: Making drm_gpuvm work across gpu devices

2024-01-26 Thread Zeng, Oak


> -Original Message-
> From: Christian König 
> Sent: Friday, January 26, 2024 5:10 AM
> To: Zeng, Oak ; David Airlie 
> Cc: Ghimiray, Himal Prasad ;
> thomas.hellst...@linux.intel.com; Winiarski, Michal
> ; Felix Kuehling ; Welty,
> Brian ; Shah, Ankur N ; dri-
> de...@lists.freedesktop.org; intel...@lists.freedesktop.org; Gupta, saurabhg
> ; Danilo Krummrich ; Daniel
> Vetter ; Brost, Matthew ; Bommu,
> Krishnaiah ; Vishwanathapura, Niranjana
> 
> Subject: Re: Making drm_gpuvm work across gpu devices
> 
> Hi Oak,
> 
> you can still use SVM, but it should not be a design criteria for the
> kernel UAPI. In other words the UAPI should be designed in such a way
> that the GPU virtual address can be equal to the CPU virtual address of
> a buffer, but can also be different to support use cases where this
> isn't the case.

Terminology:
SVM: any technology which can achieve a shared virtual address space b/t cpu 
and devices. The virtual address space can be managed by user space or kernel 
space. Intel implemented a SVM, based on the BO-centric gpu driver (gem-create, 
vm-bind) where virtual address space is managed by UMD.
System allocator: another way of implement SVM. User just use malloc'ed memory 
for gpu submission. Virtual address space is managed by Linux core mm. In 
practice, we leverage HMM to implement system allocator.
This article described details of all those different model: 
https://developer.nvidia.com/blog/simplifying-gpu-application-development-with-heterogeneous-memory-management/

Our programming model allows a mixture use of system allocator (even though 
system allocator is ) and traditional vm_bind (where cpu address can != gpu 
address). Let me re-post the pseudo codes:

1. Fd0 = open(/"dev/dri/render0")
2. Fd1 = open("/dev/dri/render1")
3. Fd3 = open("/dev/dri/xe-svm")
4. Gpu_Vm0 =xe_vm_create(fd0) 
5. Gpu_Vm1 = xe_vm_create(fd1) 
6. Queue0 = xe_exec_queue_create(fd0, gpu_vm0)
7. Queue1 = xe_exec_queue_create(fd1, gpu_vm1)
8. ptr = malloc()
9. bo = xe_bo_create(fd0)
10. Vm_bind(bo, gpu_vm0, va)//va is from UMD, cpu can access bo with 
same or different va. It is UMD's responsibility that va doesn't conflict with 
malloc'ed PTRs.
11. Xe_exec(queue0, ptr)//submit gpu job which use ptr, on card0
12. Xe_exec(queue1, ptr)//submit gpu job which use ptr, on card1
13. Xe_exec(queue0, va)//submit gpu job which use va, on card0

In above codes, the va used in vm_bind (line 10, Intel's API to bind an object 
to a va for GPU access) can be different from the CPU address when cpu access 
the same object. But whenever user use malloc'ed ptr for GPU submission (line 
11, 12, so called system allocator), it implies CPU and GPUs use the same ptr 
to access.

In above vm_bind, it is user/UMD's responsibility to guarantee that vm_bind va 
doesn't conflict with malloc'ed ptr. Otherwise it is treated as programming 
error.

I think this design still meets your design restrictions. 


> 
> Additionally to what Dave wrote I can summarize a few things I have
> learned while working on the AMD GPU drivers in the last decade or so:
> 
> 1. Userspace requirements are *not* relevant for UAPI or even more
> general kernel driver design.
> 
> 2. What should be done is to look at the hardware capabilities and try
> to expose those in a save manner to userspace.
> 
> 3. The userspace requirements are then used to validate the kernel
> driver and especially the UAPI design to ensure that nothing was missed.
> 
> The consequence of this is that nobody should ever use things like Cuda,
> Vulkan, OpenCL, OpenGL etc.. as argument to propose a certain UAPI design.
> 
> What should be done instead is to say: My hardware works in this and
> that way -> we want to expose it like this -> because that enables us to
> implement the high level API in this and that way.
> 
> Only this gives then a complete picture of how things interact together
> and allows the kernel community to influence and validate the design.

What you described above is mainly bottom up. I know other people do top down, 
or whole system vertical HW-SW co-design. I don't have strong opinion here.

Regards,
Oak

> 
> This doesn't mean that you need to throw away everything, but it gives a
> clear restriction that designs are not nailed in stone and for example
> you can't use something like a waterfall model.
> 
> Going to answer on your other questions separately.
> 
> Regards,
> Christian.
> 
> Am 25.01.24 um 06:25 schrieb Zeng, Oak:
> > Hi Dave,
> >
> > Let me step back. When I wrote " shared virtual address space b/t cpu and 
> > all
> gpu devices is a hard requirement for our system allocator design", I meant 
> this is
> not only Intel's design requirement. Rather this is a common requirement for
> both Intel, AMD and Nvidia. Take a look at cuda driver API definition of
> cuMemAllocManaged (search this API on 

[PATCH 1/5] drm/vmwgfx: Refactor drm connector probing for display modes

2024-01-26 Thread Zack Rusin
From: Martin Krastev 

Implement drm_connector_helper_funcs.mode_valid and .get_modes,
replacing custom drm_connector_funcs.fill_modes code with
drm_helper_probe_single_connector_modes; for STDU, LDU & SOU
display units.

Signed-off-by: Martin Krastev 
Reviewed-by: Zack Rusin 
Signed-off-by: Zack Rusin 
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c  | 272 +--
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h  |   6 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c  |   5 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c |   5 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c |   4 +-
 5 files changed, 101 insertions(+), 191 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8589a1c3cc36..2398041502c9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -35,6 +35,7 @@
 #include 
 #include 
 #include 
+#include 
 
 void vmw_du_cleanup(struct vmw_display_unit *du)
 {
@@ -2282,107 +2283,6 @@ vmw_du_connector_detect(struct drm_connector 
*connector, bool force)
connector_status_connected : connector_status_disconnected);
 }
 
-static struct drm_display_mode vmw_kms_connector_builtin[] = {
-   /* 640x480@60Hz */
-   { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
-  752, 800, 0, 480, 489, 492, 525, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-   /* 800x600@60Hz */
-   { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 4, 800, 840,
-  968, 1056, 0, 600, 601, 605, 628, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1024x768@60Hz */
-   { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
-  1184, 1344, 0, 768, 771, 777, 806, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-   /* 1152x864@75Hz */
-   { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
-  1344, 1600, 0, 864, 865, 868, 900, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1280x720@60Hz */
-   { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74500, 1280, 1344,
-  1472, 1664, 0, 720, 723, 728, 748, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1280x768@60Hz */
-   { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
-  1472, 1664, 0, 768, 771, 778, 798, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1280x800@60Hz */
-   { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
-  1480, 1680, 0, 800, 803, 809, 831, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-   /* 1280x960@60Hz */
-   { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
-  1488, 1800, 0, 960, 961, 964, 1000, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1280x1024@60Hz */
-   { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
-  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1360x768@60Hz */
-   { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
-  1536, 1792, 0, 768, 771, 777, 795, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1440x1050@60Hz */
-   { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
-  1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1440x900@60Hz */
-   { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
-  1672, 1904, 0, 900, 903, 909, 934, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1600x1200@60Hz */
-   { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
-  1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1680x1050@60Hz */
-   { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
-  1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1792x1344@60Hz */
-   { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
-  2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1853x1392@60Hz */
-   { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
-  2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
-  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-   /* 1920x1080@60Hz */
-   { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 173000, 1920, 2048,
-  2248, 2576, 0, 1080, 1083, 1088, 1120, 0,
-  

[PATCH 5/5] drm/vmwgfx: Fix the lifetime of the bo cursor memory

2024-01-26 Thread Zack Rusin
The cleanup can be dispatched while the atomic update is still active,
which means that the memory acquired in the atomic update needs to
not be invalidated by the cleanup. The buffer objects in vmw_plane_state
instead of using the builtin map_and_cache were trying to handle
the lifetime of the mapped memory themselves, leading to crashes.

Use the map_and_cache instead of trying to manage the lifetime of the
buffer objects held by the vmw_plane_state.

Fixes kernel oops'es in IGT's kms_cursor_legacy forked-bo.

Signed-off-by: Zack Rusin 
Fixes: bb6780aa5a1d ("drm/vmwgfx: Diff cursors when using cmds")
Cc:  # v6.2+
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 13 +
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e2bfaf4522a6..cd4925346ed4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -185,13 +185,12 @@ static u32 vmw_du_cursor_mob_size(u32 w, u32 h)
  */
 static u32 *vmw_du_cursor_plane_acquire_image(struct vmw_plane_state *vps)
 {
-   bool is_iomem;
if (vps->surf) {
if (vps->surf_mapped)
return 
vmw_bo_map_and_cache(vps->surf->res.guest_memory_bo);
return vps->surf->snooper.image;
} else if (vps->bo)
-   return ttm_kmap_obj_virtual(>bo->map, _iomem);
+   return vmw_bo_map_and_cache(vps->bo);
return NULL;
 }
 
@@ -653,22 +652,12 @@ vmw_du_cursor_plane_cleanup_fb(struct drm_plane *plane,
 {
struct vmw_cursor_plane *vcp = vmw_plane_to_vcp(plane);
struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
-   bool is_iomem;
 
if (vps->surf_mapped) {
vmw_bo_unmap(vps->surf->res.guest_memory_bo);
vps->surf_mapped = false;
}
 
-   if (vps->bo && ttm_kmap_obj_virtual(>bo->map, _iomem)) {
-   const int ret = ttm_bo_reserve(>bo->tbo, true, false, 
NULL);
-
-   if (likely(ret == 0)) {
-   ttm_bo_kunmap(>bo->map);
-   ttm_bo_unreserve(>bo->tbo);
-   }
-   }
-
vmw_du_cursor_plane_unmap_cm(vps);
vmw_du_put_cursor_mob(vcp, vps);
 
-- 
2.40.1



[PATCH 2/5] drm/vmwgfx: Make all surfaces shareable

2024-01-26 Thread Zack Rusin
From: Maaz Mombasawala 

There is no real need to have a separate pool for shareable and
non-shareable surfaces. Make all surfaces shareable, regardless of whether
the drm_vmw_surface_flag_shareable has been specified.

Signed-off-by: Maaz Mombasawala 
Reviewed-by: Martin Krastev 
Signed-off-by: Zack Rusin 
---
 drivers/gpu/drm/vmwgfx/ttm_object.c |  6 +++---
 drivers/gpu/drm/vmwgfx/ttm_object.h |  3 +--
 drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 17 ++---
 include/uapi/drm/vmwgfx_drm.h   |  5 +++--
 4 files changed, 13 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.c 
b/drivers/gpu/drm/vmwgfx/ttm_object.c
index ddf8373c1d77..6806c05e57f6 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_object.c
+++ b/drivers/gpu/drm/vmwgfx/ttm_object.c
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 OR MIT */
 /**
  *
- * Copyright (c) 2009-2022 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2009-2023 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -648,7 +648,6 @@ int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
  * @tfile: struct ttm_object_file identifying the caller
  * @size: The size of the dma_bufs we export.
  * @prime: The object to be initialized.
- * @shareable: See ttm_base_object_init
  * @type: See ttm_base_object_init
  * @refcount_release: See ttm_base_object_init
  *
@@ -656,10 +655,11 @@ int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
  * for data sharing between processes and devices.
  */
 int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size,
- struct ttm_prime_object *prime, bool shareable,
+ struct ttm_prime_object *prime,
  enum ttm_object_type type,
  void (*refcount_release) (struct ttm_base_object **))
 {
+   bool shareable = !!(type == VMW_RES_SURFACE);
mutex_init(>mutex);
prime->size = PAGE_ALIGN(size);
prime->real_type = type;
diff --git a/drivers/gpu/drm/vmwgfx/ttm_object.h 
b/drivers/gpu/drm/vmwgfx/ttm_object.h
index e6b77ee33e55..573e038c0fab 100644
--- a/drivers/gpu/drm/vmwgfx/ttm_object.h
+++ b/drivers/gpu/drm/vmwgfx/ttm_object.h
@@ -1,6 +1,6 @@
 /**
  *
- * Copyright (c) 2006-2022 VMware, Inc., Palo Alto, CA., USA
+ * Copyright (c) 2006-2023 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -288,7 +288,6 @@ extern void ttm_object_device_release(struct 
ttm_object_device **p_tdev);
 extern int ttm_prime_object_init(struct ttm_object_file *tfile,
 size_t size,
 struct ttm_prime_object *prime,
-bool shareable,
 enum ttm_object_type type,
 void (*refcount_release)
 (struct ttm_base_object **));
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
index 10498725034c..e7a744dfcecf 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
@@ -832,8 +832,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void 
*data,
srf->snooper.image = NULL;
}
 
-   user_srf->prime.base.shareable = false;
-   user_srf->prime.base.tfile = NULL;
if (drm_is_primary_client(file_priv))
user_srf->master = drm_file_get_master(file_priv);
 
@@ -847,10 +845,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void 
*data,
goto out_unlock;
 
/*
-* A gb-aware client referencing a shared surface will
-* expect a backup buffer to be present.
+* A gb-aware client referencing a surface will expect a backup
+* buffer to be present.
 */
-   if (dev_priv->has_mob && req->shareable) {
+   if (dev_priv->has_mob) {
struct vmw_bo_params params = {
.domain = VMW_BO_DOMAIN_SYS,
.busy_domain = VMW_BO_DOMAIN_SYS,
@@ -869,8 +867,9 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void 
*data,
}
 
tmp = vmw_resource_reference(>res);
-   ret = ttm_prime_object_init(tfile, res->guest_memory_size, 
_srf->prime,
-   req->shareable, VMW_RES_SURFACE,
+   ret = ttm_prime_object_init(tfile, res->guest_memory_size,
+   _srf->prime,
+   VMW_RES_SURFACE,
_user_surface_base_release);
 
if (unlikely(ret != 0)) {
@@ -1549,8 +1548,6 @@ vmw_gb_surface_define_internal(struct 

[PATCH 3/5] drm/vmwgfx: Add SPDX header to vmwgfx_drm.h

2024-01-26 Thread Zack Rusin
From: Maaz Mombasawala 

Update vmwgfx_drm.h with SPDX-License-Identifier:
(GPL-2.0 WITH Linux-syscall-note) OR MIT

Signed-off-by: Maaz Mombasawala 
Reviewed-by: Martin Krastev 
Signed-off-by: Zack Rusin 
---
 include/uapi/drm/vmwgfx_drm.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h
index 26d96fecb902..7d786a0cc835 100644
--- a/include/uapi/drm/vmwgfx_drm.h
+++ b/include/uapi/drm/vmwgfx_drm.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */
 /**
  *
  * Copyright © 2009-2023 VMware, Inc., Palo Alto, CA., USA
-- 
2.40.1



[PATCH 4/5] drm/vmwgfx: Fix vmw_du_get_cursor_mob fencing of newly-created MOBs

2024-01-26 Thread Zack Rusin
From: Martin Krastev 

The fencing of MOB creation used in vmw_du_get_cursor_mob was incompatible
with register-based device communication employed by this routine. As a
result cursor MOB creation was racy, leading to potentially broken/missing
mouse cursor on desktops using CursorMob device feature.

Fixes: 53bc3f6fb6b3 ("drm/vmwgfx: Clean up cursor mobs")
Signed-off-by: Martin Krastev 
Reviewed-by: Maaz Mombasawala 
Reviewed-by: Zack Rusin 
Signed-off-by: Zack Rusin 
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 2398041502c9..e2bfaf4522a6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -273,6 +273,7 @@ static int vmw_du_get_cursor_mob(struct vmw_cursor_plane 
*vcp,
u32 size = vmw_du_cursor_mob_size(vps->base.crtc_w, vps->base.crtc_h);
u32 i;
u32 cursor_max_dim, mob_max_size;
+   struct vmw_fence_obj *fence = NULL;
int ret;
 
if (!dev_priv->has_mob ||
@@ -314,7 +315,15 @@ static int vmw_du_get_cursor_mob(struct vmw_cursor_plane 
*vcp,
if (ret != 0)
goto teardown;
 
-   vmw_bo_fence_single(>cursor.bo->tbo, NULL);
+   ret = vmw_execbuf_fence_commands(NULL, dev_priv, , NULL);
+   if (ret != 0) {
+   ttm_bo_unreserve(>cursor.bo->tbo);
+   goto teardown;
+   }
+
+   dma_fence_wait(>base, false);
+   dma_fence_put(>base);
+
ttm_bo_unreserve(>cursor.bo->tbo);
return 0;
 
-- 
2.40.1



[PATCH 0/5] drm/vmwgfx: Various kms related fixes

2024-01-26 Thread Zack Rusin
A small backlogged series with various fixes mostly related to kms.

Use the drm internal kms modelist instead of rolling out own version and
fix two issues related to cursor handling.

Maaz's patches were already on dri-devel but patchworks doesn't deal
very well with changes in email address and the patches needed
s/vmware.com/broadcom.com/ so those patches are being resent here to
fix patchworks handling of them.

Maaz Mombasawala (2):
  drm/vmwgfx: Make all surfaces shareable
  drm/vmwgfx: Add SPDX header to vmwgfx_drm.h

Martin Krastev (2):
  drm/vmwgfx: Refactor drm connector probing for display modes
  drm/vmwgfx: Fix vmw_du_get_cursor_mob fencing of newly-created MOBs

Zack Rusin (1):
  drm/vmwgfx: Fix the lifetime of the bo cursor memory

 drivers/gpu/drm/vmwgfx/ttm_object.c |   6 +-
 drivers/gpu/drm/vmwgfx/ttm_object.h |   3 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 296 
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h |   6 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c |   5 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c|   5 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c|   4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_surface.c |  17 +-
 include/uapi/drm/vmwgfx_drm.h   |   6 +-
 9 files changed, 126 insertions(+), 222 deletions(-)

-- 
2.40.1



Re: [RFC PATCH 2/2] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-01-26 Thread Alex Hung




On 2024-01-26 09:28, Melissa Wen wrote:

Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.
Working in progress. There are a couple of cast warnings and it was only
tested with IGT.

Signed-off-by: Melissa Wen 
---
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 63 ++-
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 +--
  .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++
  4 files changed, 51 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 68e71e2ea472..741081d73bb3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3277,12 +3277,12 @@ void amdgpu_dm_update_connector_after_detect(
>dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+   aconnector->edid = drm_edid_alloc(edid, 
(edid->extensions + 1) * EDID_LENGTH);
  
  			if (aconnector->dc_link->aux_mode)

drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   aconnector->edid);
+   
drm_edid_raw(aconnector->edid));
}
  
  		if (!aconnector->timing_requested) {

@@ -3293,13 +3293,13 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
  
-		drm_connector_update_edid_property(connector, aconnector->edid);

+   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -6564,7 +6564,6 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
const struct drm_edid *drm_edid;
-   const struct edid *edid;
  
  	/*

 * Note: drm_get_edid gets edid in the following order:
@@ -6578,11 +6577,12 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
-   edid = drm_edid_raw(drm_edid);
-   aconnector->edid = edid;
-
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
/* Update emulated (virtual) sink's EDID */
if (dc_em_sink && dc_link) {
+   const struct edid *edid = drm_edid_raw(drm_edid);
+
memset(_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
memmove(dc_em_sink->dc_edid.raw_edid, (uint8_t *)edid, 
(edid->extensions + 1) * EDID_LENGTH);
dm_helpers_parse_edid_caps(
@@ -6633,13 +6633,13 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
return;
}
  
-	edid = drm_edid_raw(drm_edid);

-
-   if (drm_detect_hdmi_monitor(edid))
+   if (connector->display_info.is_hdmi)
init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
  
-	aconnector->edid = edid;

+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
  
+	edid = drm_edid_raw(drm_edid);

aconnector->dc_em_sink = dc_link_add_remote_sink(
aconnector->dc_link,
(uint8_t *)edid,
@@ -7322,16 +7322,16 @@ static void amdgpu_set_panel_orientation(struct 
drm_connector *connector)
  }
  
  static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,

- struct edid *edid)
+ const struct drm_edid *drm_edid)
  {
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
  
-	if (edid) {

+   if (drm_edid) {
/* empty probed_modes */
INIT_LIST_HEAD(>probed_modes);

[git pull] drm fixes for 6.8-rc2

2024-01-26 Thread Dave Airlie
Hey Linus,

Lots going on for rc2, ivpu has a bunch of stabilisation and debugging
work, then amdgpu and xe are the main fixes. i915, exynos have a few,
then some misc panel and bridge fixes.

Worth mentioning are 3 regression reverts. One of the nouveau fixes in
6.7 for a serious deadlock had side effects, so I guess we will bring
back the deadlock until I can figure out what should be done properly.
There was a scheduler regression vs amdgpu which was reported in a few
places and is now fixed. There was an i915 vs simpledrm problem
resulting in black screens, that is reverted also.

I'll be working on a proper nouveau fix, it kinda looks like one of
those cases where someone tried to use an atomic where they should
have probably used a lock, but I'll see.

Dave.

drm-fixes-2024-01-27:
drm fixes for 6.8-rc2

fb:
- fix simpledrm/i915 regression by reverting change

scheduler:
- fix regression affecting amdgpu users due to sched draining

nouveau:
- revert 6.7 deadlock fix as it has side effects

dp:
- fix documentation warning

ttm:
- fix dummy page read on some platforms

bridge:
- anx7625 suspend fix
- sii902x: fix probing and audio registration
- parade-ps8640: fix suspend of bridge, aux fixes
- samsung-dsim: avoid using FORCE_STOP_STATE

panel:
- simple add missing bus flags
- fix samsung-s6d7aa0 flags

amdgpu:
- AC/DC power supply tracking fix
- Don't show invalid vram vendor data
- SMU 13.0.x fixes
- GART fix for umr on systems without VRAM
- GFX 10/11 UNORD_DISPATCH fixes
- IPS display fixes (required for S0ix on some platforms)
- Misc fixes

i915:
- DSI sequence revert to fix GitLab #10071 and DP test-pattern fix
- Drop -Wstringop-overflow (broken on GCC11)
- PSR fix for HSW

ivpu:
- fix recovery/reset support
- improve submit ioctl stability
- fix dev open/close races on unbind
- PLL disable reset fix
- deprecate context priority param
- improve debug buffer logging
- disable buffer sharing across VPU contexts
- free buffer sgt on unbind
- fix missing lock around shmem vmap
- add better boot diagnostics
- add more debug prints around mapping
- dump MMU events in case of timeout

v3d:
- NULL ptr dereference fix

exynos:
- fix stack usage
- fix incorrect type
- fix dt typo
- fix gsc runtime resume

xe:
- Make an ops struct static
- Fix an implicit 0 to NULL conversion
- A couple of 32-bit fixes
- A migration coherency fix for Lunar Lake.
- An error path vm id leak fix
- Remove PVC references in kunit tests
The following changes since commit 6613476e225e090cc9aad49be7fa504e290dd33d:

  Linux 6.8-rc1 (2024-01-21 14:11:32 -0800)

are available in the Git repository at:

  git://anongit.freedesktop.org/drm/drm tags/drm-fixes-2024-01-27

for you to fetch changes up to 987940f05735a960dd143214f7cc2d699885b625:

  Merge tag 'drm-misc-fixes-for-v6.8-rc2' of
git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into
drm-fixes (2024-01-27 04:12:21 +1000)


drm fixes for 6.8-rc2

fb:
- fix simpledrm/i915 regression by reverting change

scheduler:
- fix regression affecting amdgpu users due to sched draining

nouveau:
- revert 6.7 deadlock fix as it has side effects

dp:
- fix documentation warning

ttm:
- fix dummy page read on some platforms

bridge:
- anx7625 suspend fix
- sii902x: fix probing and audio registration
- parade-ps8640: fix suspend of bridge, aux fixes
- samsung-dsim: avoid using FORCE_STOP_STATE

panel:
- simple add missing bus flags
- fix samsung-s6d7aa0 flags

amdgpu:
- AC/DC power supply tracking fix
- Don't show invalid vram vendor data
- SMU 13.0.x fixes
- GART fix for umr on systems without VRAM
- GFX 10/11 UNORD_DISPATCH fixes
- IPS display fixes (required for S0ix on some platforms)
- Misc fixes

i915:
- DSI sequence revert to fix GitLab #10071 and DP test-pattern fix
- Drop -Wstringop-overflow (broken on GCC11)

ivpu:
- fix recovery/reset support
- improve submit ioctl stability
- fix dev open/close races on unbind
- PLL disable reset fix
- deprecate context priority param
- improve debug buffer logging
- disable buffer sharing across VPU contexts
- free buffer sgt on unbind
- fix missing lock around shmem vmap
- add better boot diagnostics
- add more debug prints around mapping
- dump MMU events in case of timeout

v3d:
- NULL ptr dereference fix

exynos:
- fix stack usage
- fix incorrect type
- fix dt typo
- fix gsc runtime resume

xe:
- Make an ops struct static
- Fix an implicit 0 to NULL conversion
- A couple of 32-bit fixes
- A migration coherency fix for Lunar Lake.
- An error path vm id leak fix
- Remove PVC references in kunit tests


Alex Deucher (2):
  drm/amdgpu/gfx10: set UNORD_DISPATCH in compute MQDs
  drm/amdgpu/gfx11: set UNORD_DISPATCH in compute MQDs

Alvin Lee (1):
  drm/amd/display: Add Replay IPS register for DMUB command table

Arnd Bergmann (2):
  drm/panel/raydium-rm692e5: select CONFIG_DRM_DISPLAY_DP_HELPER

[PATCH 2/2] drm/amd: Fetch the EDID from _DDC if available for eDP

2024-01-26 Thread Mario Limonciello
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.

Attempt to fetch this EDID if it exists and prefer it over the EDID
that is provided by the panel.

Signed-off-by: Mario Limonciello 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  2 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c  | 30 +++
 .../gpu/drm/amd/amdgpu/amdgpu_connectors.c|  5 
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  8 -
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  7 +++--
 5 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index c5f3859fd682..99abe12567a4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1520,6 +1520,7 @@ int amdgpu_acpi_get_mem_info(struct amdgpu_device *adev, 
int xcc_id,
 
 void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
 bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev);
+void *amdgpu_acpi_edid(struct amdgpu_device *adev, struct drm_connector 
*connector);
 void amdgpu_acpi_detect(void);
 void amdgpu_acpi_release(void);
 #else
@@ -1537,6 +1538,7 @@ static inline int amdgpu_acpi_get_mem_info(struct 
amdgpu_device *adev,
 }
 static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { }
 static inline bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev) { 
return false; }
+static inline void *amdgpu_acpi_edid(struct amdgpu_device *adev, struct 
drm_connector *connector) { return NULL; }
 static inline void amdgpu_acpi_detect(void) { }
 static inline void amdgpu_acpi_release(void) { }
 static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return 
false; }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index e550067e5c5d..c106335f1f22 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1380,6 +1380,36 @@ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device 
*adev)
 #endif
 }
 
+/**
+ * amdgpu_acpi_edid
+ * @adev: amdgpu_device pointer
+ * @connector: drm_connector pointer
+ *
+ * Returns the EDID used for the internal panel if present, NULL otherwise.
+ */
+void *
+amdgpu_acpi_edid(struct amdgpu_device *adev, struct drm_connector *connector)
+{
+   struct drm_device *ddev = adev_to_drm(adev);
+   struct acpi_device *acpidev = ACPI_COMPANION(ddev->dev);
+   void *edid;
+   int r;
+
+   if (!acpidev)
+   return NULL;
+
+   if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+   return NULL;
+
+   r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, );
+   if (r < 0) {
+   DRM_DEBUG_DRIVER("Failed to get EDID from ACPI: %d\n", r);
+   return NULL;
+   }
+
+   return kmemdup(edid, r, GFP_KERNEL);
+}
+
 /*
  * amdgpu_acpi_detect - detect ACPI ATIF/ATCS methods
  *
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index 9caba10315a8..c7e1563a46d3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -278,6 +278,11 @@ static void amdgpu_connector_get_edid(struct drm_connector 
*connector)
struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(connector);
 
+   if (amdgpu_connector->edid)
+   return;
+
+   /* if the BIOS specifies the EDID via _DDC, prefer this */
+   amdgpu_connector->edid = amdgpu_acpi_edid(adev, connector);
if (amdgpu_connector->edid)
return;
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index cd98b3565178..1faa21f542bd 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6562,17 +6562,23 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
 {
struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
struct amdgpu_connector *amdgpu_connector = 
to_amdgpu_connector(connector);
+   struct amdgpu_device *adev = drm_to_adev(connector->dev);
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
struct edid *edid;
 
+   /* prefer ACPI over panel for eDP */
+   edid = amdgpu_acpi_edid(adev, connector);
+
/*
 * Note: drm_get_edid gets edid in the following order:
 * 1) override EDID if set via edid_override debugfs,
 * 2) firmware EDID if set via edid_firmware module parameter
 * 3) regular DDC read.
 */
-   edid = drm_get_edid(connector, _connector->ddc_bus->aux.ddc);
+   if (!edid)
+   edid = drm_get_edid(connector, 

[PATCH 1/2] ACPI: video: Handle fetching EDID that is longer than 256 bytes

2024-01-26 Thread Mario Limonciello
The ACPI specification allows for an EDID to be up to 512 bytes but
the _DDC EDID fetching code will only try up to 256 bytes.

Modify the code to instead start at 512 bytes and work it's way
down instead.

Link: 
https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/Apx_B_Video_Extensions/output-device-specific-methods.html#ddc-return-the-edid-for-this-device
Signed-off-by: Mario Limonciello 
---
 drivers/acpi/acpi_video.c | 23 ---
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 62f4364e4460..b3b15dd4755d 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -624,6 +624,10 @@ acpi_video_device_EDID(struct acpi_video_device *device,
arg0.integer.value = 1;
else if (length == 256)
arg0.integer.value = 2;
+   else if (length == 384)
+   arg0.integer.value = 3;
+   else if (length == 512)
+   arg0.integer.value = 4;
else
return -EINVAL;
 
@@ -1443,7 +1447,7 @@ int acpi_video_get_edid(struct acpi_device *device, int 
type, int device_id,
 
for (i = 0; i < video->attached_count; i++) {
video_device = video->attached_array[i].bind_info;
-   length = 256;
+   length = 512;
 
if (!video_device)
continue;
@@ -1478,13 +1482,18 @@ int acpi_video_get_edid(struct acpi_device *device, int 
type, int device_id,
 
if (ACPI_FAILURE(status) || !buffer ||
buffer->type != ACPI_TYPE_BUFFER) {
-   length = 128;
-   status = acpi_video_device_EDID(video_device, ,
-   length);
-   if (ACPI_FAILURE(status) || !buffer ||
-   buffer->type != ACPI_TYPE_BUFFER) {
-   continue;
+   while (length) {
+   length -= 128;
+   status = acpi_video_device_EDID(video_device, 
,
+   length);
+   if (ACPI_FAILURE(status) || !buffer ||
+   buffer->type != ACPI_TYPE_BUFFER) {
+   continue;
+   }
+   break;
}
+   if (!length)
+   continue;
}
 
*edid = buffer->buffer.pointer;
-- 
2.34.1



[PATCH 0/2] Fetch EDID from ACPI _DDC method if available

2024-01-26 Thread Mario Limonciello
Some laptops ship an EDID in the BIOS encoded in the _DDC method that
differs than the EDID directly on the laptop panel for $REASONS.

This is the EDID that is used by the AMD Windows driver, and so sometimes
different results are found in different operating systems.

This series changes it so that when an eDP panel is found the BIOS
is checked first for an EDID and that used as a preference if found.

Mario Limonciello (2):
  ACPI: video: Handle fetching EDID that is longer than 256 bytes
  drm/amd: Fetch the EDID from _DDC if available for eDP

 drivers/acpi/acpi_video.c | 23 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu.h   |  2 ++
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c  | 30 +++
 .../gpu/drm/amd/amdgpu/amdgpu_connectors.c|  5 
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  8 -
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  7 +++--
 6 files changed, 65 insertions(+), 10 deletions(-)

-- 
2.34.1



Re: [PATCH] drm: bridge: samsung-dsim: Don't use FORCE_STOP_STATE

2024-01-26 Thread Dave Airlie
Just FYI this conflictted pretty heavily with drm-misc-next changes in
the same area, someone should check drm-tip has the correct
resolution, I'm not really sure what is definitely should be.

Dave.

On Fri, 19 Jan 2024 at 16:37, Inki Dae  wrote:
>
> Really sorry for late. Will pick it up.
>
> Thanks,
> Inki Dae
>
> 2024년 1월 9일 (화) 오후 9:50, Daniel Vetter 님이 작성:
>>
>> On Tue, Jan 09, 2024 at 09:47:20AM +0100, Michael Walle wrote:
>> > Hi,
>> >
>> > > > Inki, are you picking this up? Or if not, who will?
>> > >
>> > > I can pick it up but it would be better to go to the drm-misc tree. If
>> > > nobody cares about it then I will pick it up. :)
>> > >
>> > > acked-by : Inki Dae 
>> >
>> > Who is going to pick this up? Who has access to the drm-misc tree?
>>
>> Inki has, so I'm assuming since he acked he'll also merge.
>> -Sima
>> --
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> http://blog.ffwll.ch


[PATCH RESEND v3 13/15] drm/msm/dp: move link property handling to dp_panel

2024-01-26 Thread Dmitry Baryshkov
Instead of passing link properties through the separate struct, parse
them directly in the dp_panel.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 -
 drivers/gpu/drm/msm/dp/dp_display.h |  1 -
 drivers/gpu/drm/msm/dp/dp_panel.c   | 66 +
 drivers/gpu/drm/msm/dp/dp_parser.c  | 54 --
 drivers/gpu/drm/msm/dp/dp_parser.h  |  4 ---
 5 files changed, 66 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 5ad96989c5f2..f19cb8c7e8cb 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -356,12 +356,6 @@ static int dp_display_process_hpd_high(struct 
dp_display_private *dp)
int rc = 0;
struct edid *edid;
 
-   dp->panel->max_dp_lanes = dp->parser->max_dp_lanes;
-   dp->panel->max_dp_link_rate = dp->parser->max_dp_link_rate;
-
-   drm_dbg_dp(dp->drm_dev, "max_lanes=%d max_link_rate=%d\n",
-   dp->panel->max_dp_lanes, dp->panel->max_dp_link_rate);
-
rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
goto end;
@@ -381,8 +375,6 @@ static int dp_display_process_hpd_high(struct 
dp_display_private *dp)
dp->audio_supported = drm_detect_monitor_audio(edid);
dp_panel_handle_sink_request(dp->panel);
 
-   dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes;
-
/*
 * set sink to normal operation mode -- D0
 * before dpcd read
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h 
b/drivers/gpu/drm/msm/dp/dp_display.h
index 102f3507d824..70759dd1bfd0 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -28,7 +28,6 @@ struct msm_dp {
 
bool wide_bus_en;
 
-   u32 max_dp_lanes;
struct dp_audio *dp_audio;
bool psr_supported;
 };
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c 
b/drivers/gpu/drm/msm/dp/dp_panel.c
index 127f6af995cd..8242541a81b9 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -7,8 +7,12 @@
 
 #include 
 #include 
+#include 
 #include 
 
+#define DP_MAX_NUM_DP_LANES4
+#define DP_LINK_RATE_HBR2  54 /* kbytes */
+
 struct dp_panel_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -138,6 +142,9 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
 
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
+   drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n",
+   dp_panel->max_dp_lanes, dp_panel->max_dp_link_rate);
+
rc = dp_panel_read_dpcd(dp_panel);
if (rc) {
DRM_ERROR("read dpcd failed %d\n", rc);
@@ -386,10 +393,65 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel)
return 0;
 }
 
+static u32 dp_panel_link_frequencies(struct device_node *of_node)
+{
+   struct device_node *endpoint;
+   u64 frequency = 0;
+   int cnt;
+
+   endpoint = of_graph_get_endpoint_by_regs(of_node, 1, 0); /* port@1 */
+   if (!endpoint)
+   return 0;
+
+   cnt = of_property_count_u64_elems(endpoint, "link-frequencies");
+
+   if (cnt > 0)
+   of_property_read_u64_index(endpoint, "link-frequencies",
+   cnt - 1, );
+   of_node_put(endpoint);
+
+   do_div(frequency,
+   10 * /* from symbol rate to link rate */
+   1000); /* kbytes */
+
+   return frequency;
+}
+
+static int dp_panel_parse_dt(struct dp_panel *dp_panel)
+{
+   struct dp_panel_private *panel;
+   struct device_node *of_node;
+   int cnt;
+
+   panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+   of_node = panel->dev->of_node;
+
+   /*
+* data-lanes is the property of dp_out endpoint
+*/
+   cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, 
DP_MAX_NUM_DP_LANES);
+   if (cnt < 0) {
+   /* legacy code, data-lanes is the property of mdss_dp node */
+   cnt = drm_of_get_data_lanes_count(of_node, 1, 
DP_MAX_NUM_DP_LANES);
+   }
+
+   if (cnt > 0)
+   dp_panel->max_dp_lanes = cnt;
+   else
+   dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */
+
+   dp_panel->max_dp_link_rate = dp_panel_link_frequencies(of_node);
+   if (!dp_panel->max_dp_link_rate)
+   dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2;
+
+   return 0;
+}
+
 struct dp_panel *dp_panel_get(struct dp_panel_in *in)
 {
struct dp_panel_private *panel;
struct dp_panel *dp_panel;
+   int ret;
 
if (!in->dev || !in->catalog || !in->aux || !in->link) {
DRM_ERROR("invalid input\n");
@@ -408,6 +470,10 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
dp_panel = >dp_panel;

[PATCH RESEND v3 05/15] drm/msm/dp: fold dp_power into dp_ctrl module

2024-01-26 Thread Dmitry Baryshkov
The dp_power submodule is limited to handling the clocks only following
previous cleanups. Fold it into the dp_ctrl submodule, removing one
unnecessary level of indirection.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/Makefile|   1 -
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 150 +++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   6 +-
 drivers/gpu/drm/msm/dp/dp_display.c |  24 +
 drivers/gpu/drm/msm/dp/dp_power.c   | 170 
 drivers/gpu/drm/msm/dp/dp_power.h   |  74 
 6 files changed, 142 insertions(+), 283 deletions(-)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b1173128b5b9..8dbdf3fba69e 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -128,7 +128,6 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_link.o \
dp/dp_panel.o \
dp/dp_parser.o \
-   dp/dp_power.o \
dp/dp_audio.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 77a8d9366ed7..da29281c575b 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -76,13 +76,16 @@ struct dp_ctrl_private {
struct drm_dp_aux *aux;
struct dp_panel *panel;
struct dp_link *link;
-   struct dp_power *power;
struct dp_parser *parser;
struct dp_catalog *catalog;
 
struct completion idle_comp;
struct completion psr_op_comp;
struct completion video_comp;
+
+   bool core_clks_on;
+   bool link_clks_on;
+   bool stream_clks_on;
 };
 
 static int dp_aux_link_configure(struct drm_dp_aux *aux,
@@ -1338,6 +1341,83 @@ static void dp_ctrl_set_clock_rate(struct 
dp_ctrl_private *ctrl,
name, rate);
 }
 
+int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
+  enum dp_pm_type pm_type, bool enable)
+{
+   struct dp_ctrl_private *ctrl;
+   struct dss_module_power *mp;
+   int ret = 0;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+   if (pm_type != DP_CORE_PM &&
+   pm_type != DP_CTRL_PM &&
+   pm_type != DP_STREAM_PM) {
+   DRM_ERROR("unsupported ctrl module: %s\n",
+ dp_parser_pm_name(pm_type));
+   return -EINVAL;
+   }
+
+   if (enable) {
+   if (pm_type == DP_CORE_PM && ctrl->core_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "core clks already enabled\n");
+   return 0;
+   }
+
+   if (pm_type == DP_CTRL_PM && ctrl->link_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "links clks already enabled\n");
+   return 0;
+   }
+
+   if (pm_type == DP_STREAM_PM && ctrl->stream_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "pixel clks already enabled\n");
+   return 0;
+   }
+
+   if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
+   drm_dbg_dp(ctrl->drm_dev,
+  "Enable core clks before link clks\n");
+   mp = >parser->mp[DP_CORE_PM];
+
+   ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
+   if (ret)
+   return ret;
+
+   ctrl->core_clks_on = true;
+   }
+   }
+
+   mp = >parser->mp[pm_type];
+   if (enable) {
+   ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
+   if (ret)
+   return ret;
+   } else {
+   clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
+   }
+
+   if (pm_type == DP_CORE_PM)
+   ctrl->core_clks_on = enable;
+   else if (pm_type == DP_STREAM_PM)
+   ctrl->stream_clks_on = enable;
+   else
+   ctrl->link_clks_on = enable;
+
+   drm_dbg_dp(ctrl->drm_dev, "%s clocks for %s\n",
+  enable ? "enable" : "disable",
+  dp_parser_pm_name(pm_type));
+   drm_dbg_dp(ctrl->drm_dev,
+  "stream_clks:%s link_clks:%s core_clks:%s\n",
+  ctrl->stream_clks_on ? "on" : "off",
+  ctrl->link_clks_on ? "on" : "off",
+  ctrl->core_clks_on ? "on" : "off");
+
+   return 0;
+}
+
 static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
 {
int ret = 0;
@@ -1354,7 +1434,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct 
dp_ctrl_private *ctrl)
phy_power_on(phy);
 
dev_pm_opp_set_rate(ctrl->dev, ctrl->link->link_params.rate * 1000);
-   ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, true);
+

[PATCH RESEND v3 14/15] drm/msm/dp: move next_bridge handling to dp_display

2024-01-26 Thread Dmitry Baryshkov
Remove two levels of indirection and fetch next bridge directly in
dp_display_probe_tail().

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 43 -
 drivers/gpu/drm/msm/dp/dp_parser.c  | 14 
 drivers/gpu/drm/msm/dp/dp_parser.h  | 14 
 3 files changed, 14 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index f19cb8c7e8cb..de1306a88748 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1195,16 +1195,25 @@ static const struct msm_dp_desc 
*dp_display_get_desc(struct platform_device *pde
return NULL;
 }
 
-static int dp_display_get_next_bridge(struct msm_dp *dp);
-
 static int dp_display_probe_tail(struct device *dev)
 {
struct msm_dp *dp = dev_get_drvdata(dev);
int ret;
 
-   ret = dp_display_get_next_bridge(dp);
-   if (ret)
-   return ret;
+   /*
+* External bridges are mandatory for eDP interfaces: one has to
+* provide at least an eDP panel (which gets wrapped into panel-bridge).
+*
+* For DisplayPort interfaces external bridges are optional, so
+* silently ignore an error if one is not present (-ENODEV).
+*/
+   dp->next_bridge = devm_drm_of_get_bridge(>pdev->dev, 
dp->pdev->dev.of_node, 1, 0);
+   if (IS_ERR(dp->next_bridge)) {
+   ret = PTR_ERR(dp->next_bridge);
+   dp->next_bridge = NULL;
+   if (dp->is_edp || ret != -ENODEV)
+   return ret;
+   }
 
ret = component_add(dev, _display_comp_ops);
if (ret)
@@ -1397,30 +1406,6 @@ void dp_display_debugfs_init(struct msm_dp *dp_display, 
struct dentry *root, boo
}
 }
 
-static int dp_display_get_next_bridge(struct msm_dp *dp)
-{
-   int rc;
-   struct dp_display_private *dp_priv;
-
-   dp_priv = container_of(dp, struct dp_display_private, dp_display);
-
-   /*
-* External bridges are mandatory for eDP interfaces: one has to
-* provide at least an eDP panel (which gets wrapped into panel-bridge).
-*
-* For DisplayPort interfaces external bridges are optional, so
-* silently ignore an error if one is not present (-ENODEV).
-*/
-   rc = devm_dp_parser_find_next_bridge(>pdev->dev, dp_priv->parser);
-   if (!dp->is_edp && rc == -ENODEV)
-   return 0;
-
-   if (!rc)
-   dp->next_bridge = dp_priv->parser->next_bridge;
-
-   return rc;
-}
-
 int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
 {
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c 
b/drivers/gpu/drm/msm/dp/dp_parser.c
index aa135d5cedbd..f95ab3c5c72c 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -24,20 +24,6 @@ static int dp_parser_ctrl_res(struct dp_parser *parser)
return 0;
 }
 
-int devm_dp_parser_find_next_bridge(struct device *dev, struct dp_parser 
*parser)
-{
-   struct platform_device *pdev = parser->pdev;
-   struct drm_bridge *bridge;
-
-   bridge = devm_drm_of_get_bridge(dev, pdev->dev.of_node, 1, 0);
-   if (IS_ERR(bridge))
-   return PTR_ERR(bridge);
-
-   parser->next_bridge = bridge;
-
-   return 0;
-}
-
 static int dp_parser_parse(struct dp_parser *parser)
 {
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 21a66932e35e..38fd335d5950 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -21,7 +21,6 @@
 struct dp_parser {
struct platform_device *pdev;
struct phy *phy;
-   struct drm_bridge *next_bridge;
 };
 
 /**
@@ -37,17 +36,4 @@ struct dp_parser {
  */
 struct dp_parser *dp_parser_get(struct platform_device *pdev);
 
-/**
- * devm_dp_parser_find_next_bridge() - find an additional bridge to DP
- *
- * @dev: device to tie bridge lifetime to
- * @parser: dp_parser data from client
- *
- * This function is used to find any additional bridge attached to
- * the DP controller. The eDP interface requires a panel bridge.
- *
- * Return: 0 if able to get the bridge, otherwise negative errno for failure.
- */
-int devm_dp_parser_find_next_bridge(struct device *dev, struct dp_parser 
*parser);
-
 #endif

-- 
2.39.2



[PATCH RESEND v3 15/15] drm/msm/dp: drop dp_parser

2024-01-26 Thread Dmitry Baryshkov
Finally drop separate "parsing" submodule. There is no need in it
anymore. All submodules handle DT properties directly rather than
passing them via the separate structure pointer.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/Makefile|  1 -
 drivers/gpu/drm/msm/dp/dp_aux.h |  1 +
 drivers/gpu/drm/msm/dp/dp_catalog.h |  1 -
 drivers/gpu/drm/msm/dp/dp_ctrl.h|  3 +-
 drivers/gpu/drm/msm/dp/dp_debug.c   |  1 -
 drivers/gpu/drm/msm/dp/dp_display.c | 18 +--
 drivers/gpu/drm/msm/dp/dp_display.h |  2 ++
 drivers/gpu/drm/msm/dp/dp_parser.c  | 61 -
 drivers/gpu/drm/msm/dp/dp_parser.h  | 39 
 9 files changed, 12 insertions(+), 115 deletions(-)

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 8dbdf3fba69e..543e04fa72e3 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -127,7 +127,6 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
dp/dp_drm.o \
dp/dp_link.o \
dp/dp_panel.o \
-   dp/dp_parser.o \
dp/dp_audio.o
 
 msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index 16d9b1758748..f47d591c1f54 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -16,6 +16,7 @@ void dp_aux_init(struct drm_dp_aux *dp_aux);
 void dp_aux_deinit(struct drm_dp_aux *dp_aux);
 void dp_aux_reconfig(struct drm_dp_aux *dp_aux);
 
+struct phy;
 struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
  struct phy *phy,
  bool is_edp);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 989e4c4fd6fa..a724a986b6ee 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -8,7 +8,6 @@
 
 #include 
 
-#include "dp_parser.h"
 #include "disp/msm_disp_snapshot.h"
 
 /* interrupts */
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 6e9f375b856a..fa014cee7e21 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -9,7 +9,6 @@
 #include "dp_aux.h"
 #include "dp_panel.h"
 #include "dp_link.h"
-#include "dp_parser.h"
 #include "dp_catalog.h"
 
 struct dp_ctrl {
@@ -17,6 +16,8 @@ struct dp_ctrl {
bool wide_bus_en;
 };
 
+struct phy;
+
 int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
 int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train);
 void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c 
b/drivers/gpu/drm/msm/dp/dp_debug.c
index 6c281dc095b9..ac68554801a4 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -9,7 +9,6 @@
 #include 
 #include 
 
-#include "dp_parser.h"
 #include "dp_catalog.h"
 #include "dp_aux.h"
 #include "dp_ctrl.h"
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index de1306a88748..67956e34436d 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -9,12 +9,12 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
 #include "msm_drv.h"
 #include "msm_kms.h"
-#include "dp_parser.h"
 #include "dp_ctrl.h"
 #include "dp_catalog.h"
 #include "dp_aux.h"
@@ -87,7 +87,6 @@ struct dp_display_private {
struct drm_device *drm_dev;
struct dentry *root;
 
-   struct dp_parser  *parser;
struct dp_catalog *catalog;
struct drm_dp_aux *aux;
struct dp_link*link;
@@ -704,14 +703,11 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
struct dp_panel_in panel_in = {
.dev = dev,
};
+   struct phy *phy;
 
-   dp->parser = dp_parser_get(dp->dp_display.pdev);
-   if (IS_ERR(dp->parser)) {
-   rc = PTR_ERR(dp->parser);
-   DRM_ERROR("failed to initialize parser, rc = %d\n", rc);
-   dp->parser = NULL;
-   goto error;
-   }
+   phy = devm_phy_get(dev, "dp");
+   if (IS_ERR(phy))
+   return PTR_ERR(phy);
 
dp->catalog = dp_catalog_get(dev);
if (IS_ERR(dp->catalog)) {
@@ -722,7 +718,7 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
}
 
dp->aux = dp_aux_get(dev, dp->catalog,
-dp->parser->phy,
+phy,
 dp->dp_display.is_edp);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
@@ -753,7 +749,7 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
 
dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,
   dp->catalog,
-  dp->parser->phy);
+  phy);
if (IS_ERR(dp->ctrl)) {
rc = PTR_ERR(dp->ctrl);
   

[PATCH RESEND v3 08/15] drm/msm/dp: split dp_ctrl_clk_enable into four functuions

2024-01-26 Thread Dmitry Baryshkov
Split the dp_ctrl_clk_enable() beast into four functions, each of them
doing just a single item: enabling or disabling core or link clocks.
This allows us to cleanup the dss_module_power structure and makes
several dp_ctrl functions return void.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 220 +---
 drivers/gpu/drm/msm/dp/dp_ctrl.h|  16 +--
 drivers/gpu/drm/msm/dp/dp_display.c |   4 +-
 3 files changed, 108 insertions(+), 132 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index cfcf6136ffa6..e367eb8e5bea 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -69,11 +69,6 @@ struct dp_vc_tu_mapping_table {
u8 tu_size_minus1;
 };
 
-struct dss_module_power {
-   unsigned int num_clk;
-   struct clk_bulk_data *clocks;
-};
-
 struct dp_ctrl_private {
struct dp_ctrl dp_ctrl;
struct drm_device *drm_dev;
@@ -84,7 +79,12 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
 
-   struct dss_module_power mp[DP_MAX_PM];
+   unsigned int num_core_clks;
+   struct clk_bulk_data *core_clks;
+
+   unsigned int num_link_clks;
+   struct clk_bulk_data *link_clks;
+
struct clk *pixel_clk;
 
struct completion idle_comp;
@@ -96,15 +96,6 @@ struct dp_ctrl_private {
bool stream_clks_on;
 };
 
-static inline const char *dp_pm_name(enum dp_pm_type module)
-{
-   switch (module) {
-   case DP_CORE_PM:return "DP_CORE_PM";
-   case DP_CTRL_PM:return "DP_CTRL_PM";
-   default:return "???";
-   }
-}
-
 static int dp_aux_link_configure(struct drm_dp_aux *aux,
struct dp_link_info *link)
 {
@@ -1337,67 +1328,76 @@ static int dp_ctrl_setup_main_link(struct 
dp_ctrl_private *ctrl,
return ret;
 }
 
-int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
-  enum dp_pm_type pm_type, bool enable)
+int dp_ctrl_core_clk_enable(struct dp_ctrl *dp_ctrl)
 {
struct dp_ctrl_private *ctrl;
-   struct dss_module_power *mp;
int ret = 0;
 
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-   if (pm_type != DP_CORE_PM &&
-   pm_type != DP_CTRL_PM) {
-   DRM_ERROR("unsupported ctrl module: %s\n",
- dp_pm_name(pm_type));
-   return -EINVAL;
+   if (ctrl->core_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev, "core clks already enabled\n");
+   return 0;
}
 
-   if (enable) {
-   if (pm_type == DP_CORE_PM && ctrl->core_clks_on) {
-   drm_dbg_dp(ctrl->drm_dev,
-  "core clks already enabled\n");
-   return 0;
-   }
+   ret = clk_bulk_prepare_enable(ctrl->num_core_clks, ctrl->core_clks);
+   if (ret)
+   return ret;
 
-   if (pm_type == DP_CTRL_PM && ctrl->link_clks_on) {
-   drm_dbg_dp(ctrl->drm_dev,
-  "links clks already enabled\n");
-   return 0;
-   }
+   ctrl->core_clks_on = true;
 
-   if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
-   drm_dbg_dp(ctrl->drm_dev,
-  "Enable core clks before link clks\n");
-   mp = >mp[DP_CORE_PM];
+   drm_dbg_dp(ctrl->drm_dev, "enable core clocks \n");
+   drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
+  ctrl->stream_clks_on ? "on" : "off",
+  ctrl->link_clks_on ? "on" : "off",
+  ctrl->core_clks_on ? "on" : "off");
 
-   ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
-   if (ret)
-   return ret;
+   return 0;
+}
 
-   ctrl->core_clks_on = true;
-   }
+void dp_ctrl_core_clk_disable(struct dp_ctrl *dp_ctrl)
+{
+   struct dp_ctrl_private *ctrl;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+   clk_bulk_disable_unprepare(ctrl->num_core_clks, ctrl->core_clks);
+
+   ctrl->core_clks_on = false;
+
+   drm_dbg_dp(ctrl->drm_dev, "disable core clocks \n");
+   drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
+  ctrl->stream_clks_on ? "on" : "off",
+  ctrl->link_clks_on ? "on" : "off",
+  ctrl->core_clks_on ? "on" : "off");
+}
+
+static int dp_ctrl_link_clk_enable(struct dp_ctrl *dp_ctrl)
+{
+   struct dp_ctrl_private *ctrl;
+   int ret = 0;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+
+   if (ctrl->link_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev, "links clks 

[PATCH RESEND v3 09/15] drm/msm/dp: move phy_configure_opts to dp_ctrl

2024-01-26 Thread Dmitry Baryshkov
There is little point in sharing phy configuration structure between
several modules. Move it to dp_ctrl, which becomes the only submodule
re-configuring the PHY.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 19 -
 drivers/gpu/drm/msm/dp/dp_catalog.h |  2 --
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 41 -
 drivers/gpu/drm/msm/dp/dp_parser.h  |  3 ---
 4 files changed, 27 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5142aeb705a4..e07651768805 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -765,25 +765,6 @@ void dp_catalog_ctrl_phy_reset(struct dp_catalog 
*dp_catalog)
dp_write_ahb(catalog, REG_DP_PHY_CTRL, 0x0);
 }
 
-int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog,
-   u8 v_level, u8 p_level)
-{
-   struct dp_catalog_private *catalog = container_of(dp_catalog,
-   struct dp_catalog_private, dp_catalog);
-   struct dp_io *dp_io = catalog->io;
-   struct phy *phy = dp_io->phy;
-   struct phy_configure_opts_dp *opts_dp = _io->phy_opts.dp;
-
-   /* TODO: Update for all lanes instead of just first one */
-   opts_dp->voltage[0] = v_level;
-   opts_dp->pre[0] = p_level;
-   opts_dp->set_voltages = 1;
-   phy_configure(phy, _io->phy_opts);
-   opts_dp->set_voltages = 0;
-
-   return 0;
-}
-
 void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
u32 pattern)
 {
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 38786e855b51..ba7c62ba7ca3 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -111,8 +111,6 @@ void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, 
bool enter);
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog);
 u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
-int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8 v_level,
-   u8 p_level);
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog);
 u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_update_transfer_unit(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 e367eb8e5bea..4aea72a2b8e8 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -87,6 +87,8 @@ struct dp_ctrl_private {
 
struct clk *pixel_clk;
 
+   union phy_configure_opts phy_opts;
+
struct completion idle_comp;
struct completion psr_op_comp;
struct completion video_comp;
@@ -1017,6 +1019,21 @@ static int dp_ctrl_wait4video_ready(struct 
dp_ctrl_private *ctrl)
return ret;
 }
 
+static int dp_ctrl_set_vx_px(struct dp_ctrl_private *ctrl,
+u8 v_level, u8 p_level)
+{
+   union phy_configure_opts *phy_opts = >phy_opts;
+
+   /* TODO: Update for all lanes instead of just first one */
+   phy_opts->dp.voltage[0] = v_level;
+   phy_opts->dp.pre[0] = p_level;
+   phy_opts->dp.set_voltages = 1;
+   phy_configure(ctrl->parser->io.phy, phy_opts);
+   phy_opts->dp.set_voltages = 0;
+
+   return 0;
+}
+
 static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
 {
struct dp_link *link = ctrl->link;
@@ -1029,7 +1046,7 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private 
*ctrl)
drm_dbg_dp(ctrl->drm_dev,
"voltage level: %d emphasis level: %d\n",
voltage_swing_level, pre_emphasis_level);
-   ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
+   ret = dp_ctrl_set_vx_px(ctrl,
voltage_swing_level, pre_emphasis_level);
 
if (ret)
@@ -1425,16 +1442,14 @@ static void dp_ctrl_link_clk_disable(struct dp_ctrl 
*dp_ctrl)
 static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
 {
int ret = 0;
-   struct dp_io *dp_io = >parser->io;
-   struct phy *phy = dp_io->phy;
-   struct phy_configure_opts_dp *opts_dp = _io->phy_opts.dp;
+   struct phy *phy = ctrl->parser->io.phy;
const u8 *dpcd = ctrl->panel->dpcd;
 
-   opts_dp->lanes = ctrl->link->link_params.num_lanes;
-   opts_dp->link_rate = ctrl->link->link_params.rate / 100;
-   opts_dp->ssc = drm_dp_max_downspread(dpcd);
+   ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
+   ctrl->phy_opts.dp.link_rate = ctrl->link->link_params.rate / 100;
+   ctrl->phy_opts.dp.ssc = drm_dp_max_downspread(dpcd);
 
-   phy_configure(phy, _io->phy_opts);
+   phy_configure(phy, >phy_opts);
phy_power_on(phy);
 
dev_pm_opp_set_rate(ctrl->dev, 

[PATCH RESEND v3 11/15] drm/msm/dp: handle PHY directly in dp_ctrl

2024-01-26 Thread Dmitry Baryshkov
There is little point in going trough dp_parser->io indirection each
time the driver needs to access the PHY. Store the pointer directly in
dp_ctrl_private.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 37 +
 drivers/gpu/drm/msm/dp/dp_ctrl.h|  2 +-
 drivers/gpu/drm/msm/dp/dp_display.c |  3 ++-
 3 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 4aea72a2b8e8..fc7ce315ae41 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -76,9 +76,10 @@ struct dp_ctrl_private {
struct drm_dp_aux *aux;
struct dp_panel *panel;
struct dp_link *link;
-   struct dp_parser *parser;
struct dp_catalog *catalog;
 
+   struct phy *phy;
+
unsigned int num_core_clks;
struct clk_bulk_data *core_clks;
 
@@ -1028,7 +1029,7 @@ static int dp_ctrl_set_vx_px(struct dp_ctrl_private *ctrl,
phy_opts->dp.voltage[0] = v_level;
phy_opts->dp.pre[0] = p_level;
phy_opts->dp.set_voltages = 1;
-   phy_configure(ctrl->parser->io.phy, phy_opts);
+   phy_configure(ctrl->phy, phy_opts);
phy_opts->dp.set_voltages = 0;
 
return 0;
@@ -1442,7 +1443,7 @@ static void dp_ctrl_link_clk_disable(struct dp_ctrl 
*dp_ctrl)
 static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
 {
int ret = 0;
-   struct phy *phy = ctrl->parser->io.phy;
+   struct phy *phy = ctrl->phy;
const u8 *dpcd = ctrl->panel->dpcd;
 
ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
@@ -1540,12 +1541,10 @@ void dp_ctrl_set_psr(struct dp_ctrl *dp_ctrl, bool 
enter)
 void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
 {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
 
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
 
dp_catalog_ctrl_phy_reset(ctrl->catalog);
phy_init(phy);
@@ -1557,12 +1556,10 @@ void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
 void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl)
 {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
 
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
 
dp_catalog_ctrl_phy_reset(ctrl->catalog);
phy_exit(phy);
@@ -1587,7 +1584,7 @@ static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private 
*ctrl)
 
 static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
 {
-   struct phy *phy = ctrl->parser->io.phy;
+   struct phy *phy = ctrl->phy;
int ret = 0;
 
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
@@ -1617,11 +1614,9 @@ static int dp_ctrl_reinitialize_mainlink(struct 
dp_ctrl_private *ctrl)
 
 static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
 {
-   struct dp_io *dp_io;
struct phy *phy;
 
-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
 
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
 
@@ -2047,12 +2042,10 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
 void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
 {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
 
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
 
/* set dongle to D3 (power off) mode */
dp_link_psm_config(ctrl->link, >panel->link_info, true);
@@ -2080,12 +2073,10 @@ void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
 void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl)
 {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
 
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
 
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
 
@@ -2103,12 +2094,10 @@ void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl)
 void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
 {
struct dp_ctrl_private *ctrl;
-   struct dp_io *dp_io;
struct phy *phy;
 
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-   dp_io = >parser->io;
-   phy = dp_io->phy;
+   phy = ctrl->phy;
 
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
 
@@ -2225,7 +2214,7 @@ static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl)
 struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link,
struct dp_panel *panel, struct drm_dp_aux *aux,
struct dp_catalog *catalog,
-   struct dp_parser *parser)
+

[PATCH RESEND v3 10/15] drm/msm/dp: remove PHY handling from dp_catalog.c

2024-01-26 Thread Dmitry Baryshkov
Inline dp_catalog_aux_update_cfg() and call phy_calibrate() from dp_aux
functions directly.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_aux.c |  9 +++--
 drivers/gpu/drm/msm/dp/dp_aux.h |  1 +
 drivers/gpu/drm/msm/dp/dp_catalog.c | 12 
 drivers/gpu/drm/msm/dp/dp_catalog.h |  1 -
 drivers/gpu/drm/msm/dp/dp_display.c |  4 +++-
 5 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 03f4951c49f4..adbd5a367395 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -4,6 +4,7 @@
  */
 
 #include 
+#include 
 #include 
 
 #include "dp_reg.h"
@@ -23,6 +24,8 @@ struct dp_aux_private {
struct device *dev;
struct dp_catalog *catalog;
 
+   struct phy *phy;
+
struct mutex mutex;
struct completion comp;
 
@@ -336,7 +339,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
if (aux->native) {
aux->retry_cnt++;
if (!(aux->retry_cnt % MAX_AUX_RETRIES))
-   dp_catalog_aux_update_cfg(aux->catalog);
+   phy_calibrate(aux->phy);
}
/* reset aux if link is in connected state */
if (dp_catalog_link_is_connected(aux->catalog))
@@ -439,7 +442,7 @@ void dp_aux_reconfig(struct drm_dp_aux *dp_aux)
 
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
 
-   dp_catalog_aux_update_cfg(aux->catalog);
+   phy_calibrate(aux->phy);
dp_catalog_aux_reset(aux->catalog);
 }
 
@@ -517,6 +520,7 @@ static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux,
 }
 
 struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+ struct phy *phy,
  bool is_edp)
 {
struct dp_aux_private *aux;
@@ -537,6 +541,7 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct 
dp_catalog *catalog,
 
aux->dev = dev;
aux->catalog = catalog;
+   aux->phy = phy;
aux->retry_cnt = 0;
 
/*
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index 511305da4f66..16d9b1758748 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -17,6 +17,7 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux);
 void dp_aux_reconfig(struct drm_dp_aux *dp_aux);
 
 struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+ struct phy *phy,
  bool is_edp);
 void dp_aux_put(struct drm_dp_aux *aux);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index e07651768805..4c6207797c99 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -7,8 +7,6 @@
 
 #include 
 #include 
-#include 
-#include 
 #include 
 #include 
 #include 
@@ -243,16 +241,6 @@ void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, 
bool enable)
dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl);
 }
 
-void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog)
-{
-   struct dp_catalog_private *catalog = container_of(dp_catalog,
-   struct dp_catalog_private, dp_catalog);
-   struct dp_io *dp_io = catalog->io;
-   struct phy *phy = dp_io->phy;
-
-   phy_calibrate(phy);
-}
-
 int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog)
 {
u32 state;
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index ba7c62ba7ca3..1f3f58d4b8de 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -84,7 +84,6 @@ int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, 
bool read);
 int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog);
 void dp_catalog_aux_reset(struct dp_catalog *dp_catalog);
 void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable);
-void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog);
 int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog);
 u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 6fbbd0f93d13..c1a51c498e01 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -729,7 +729,9 @@ static int dp_init_sub_modules(struct dp_display_private 
*dp)
goto error;
}
 
-   dp->aux = dp_aux_get(dev, dp->catalog, dp->dp_display.is_edp);
+   dp->aux = dp_aux_get(dev, dp->catalog,
+dp->parser->io.phy,
+dp->dp_display.is_edp);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
DRM_ERROR("failed to initialize aux, rc = %d\n", rc);


[PATCH RESEND v3 04/15] drm/msm/dp: inline dp_power_(de)init

2024-01-26 Thread Dmitry Baryshkov
In preparation to cleanup of the dp_power module, inline dp_power_init()
and dp_power_deinit() functions, which are now just turning the clocks
on and off.

Reviewed-by: Konrad Dybcio 
Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  4 ++--
 drivers/gpu/drm/msm/dp/dp_power.c   | 10 --
 drivers/gpu/drm/msm/dp/dp_power.h   | 21 -
 3 files changed, 2 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 67b48f0a6c83..8cd18705740f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -434,7 +434,7 @@ static void dp_display_host_init(struct dp_display_private 
*dp)
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
 
-   dp_power_init(dp->power);
+   dp_power_clk_enable(dp->power, DP_CORE_PM, true);
dp_ctrl_reset_irq_ctrl(dp->ctrl, true);
dp_aux_init(dp->aux);
dp->core_initialized = true;
@@ -448,7 +448,7 @@ static void dp_display_host_deinit(struct 
dp_display_private *dp)
 
dp_ctrl_reset_irq_ctrl(dp->ctrl, false);
dp_aux_deinit(dp->aux);
-   dp_power_deinit(dp->power);
+   dp_power_clk_enable(dp->power, DP_CORE_PM, false);
dp->core_initialized = false;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c 
b/drivers/gpu/drm/msm/dp/dp_power.c
index b095a5b47c8b..f49e3aede308 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -152,16 +152,6 @@ int dp_power_client_init(struct dp_power *dp_power)
return dp_power_clk_init(power);
 }
 
-int dp_power_init(struct dp_power *dp_power)
-{
-   return dp_power_clk_enable(dp_power, DP_CORE_PM, true);
-}
-
-int dp_power_deinit(struct dp_power *dp_power)
-{
-   return dp_power_clk_enable(dp_power, DP_CORE_PM, false);
-}
-
 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
 {
struct dp_power_private *power;
diff --git a/drivers/gpu/drm/msm/dp/dp_power.h 
b/drivers/gpu/drm/msm/dp/dp_power.h
index 55ada51edb57..eb836b5aa24a 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.h
+++ b/drivers/gpu/drm/msm/dp/dp_power.h
@@ -22,27 +22,6 @@ struct dp_power {
bool stream_clks_on;
 };
 
-/**
- * dp_power_init() - enable power supplies for display controller
- *
- * @power: instance of power module
- * return: 0 if success or error if failure.
- *
- * This API will turn on the regulators and configures gpio's
- * aux/hpd.
- */
-int dp_power_init(struct dp_power *power);
-
-/**
- * dp_power_deinit() - turn off regulators and gpios.
- *
- * @power: instance of power module
- * return: 0 for success
- *
- * This API turns off power and regulators.
- */
-int dp_power_deinit(struct dp_power *power);
-
 /**
  * dp_power_clk_status() - display controller clocks status
  *

-- 
2.39.2



[PATCH RESEND v3 12/15] drm/msm/dp: move all IO handling to dp_catalog

2024-01-26 Thread Dmitry Baryshkov
Rather than parsing the I/O addresses from dp_parser and then passing
them via a struct pointer to dp_catalog, handle I/O region parsing in
dp_catalog and drop it from dp_parser.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c | 125 ++--
 drivers/gpu/drm/msm/dp/dp_catalog.h |   2 +-
 drivers/gpu/drm/msm/dp/dp_display.c |   6 +-
 drivers/gpu/drm/msm/dp/dp_parser.c  |  73 +
 drivers/gpu/drm/msm/dp/dp_parser.h  |  26 +---
 5 files changed, 114 insertions(+), 118 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 4c6207797c99..541aac2cb246 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -7,6 +7,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -53,10 +54,31 @@
(PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
 
+#define DP_DEFAULT_AHB_OFFSET  0x
+#define DP_DEFAULT_AHB_SIZE0x0200
+#define DP_DEFAULT_AUX_OFFSET  0x0200
+#define DP_DEFAULT_AUX_SIZE0x0200
+#define DP_DEFAULT_LINK_OFFSET 0x0400
+#define DP_DEFAULT_LINK_SIZE   0x0C00
+#define DP_DEFAULT_P0_OFFSET   0x1000
+#define DP_DEFAULT_P0_SIZE 0x0400
+
+struct dss_io_region {
+   size_t len;
+   void __iomem *base;
+};
+
+struct dss_io_data {
+   struct dss_io_region ahb;
+   struct dss_io_region aux;
+   struct dss_io_region link;
+   struct dss_io_region p0;
+};
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
-   struct dp_io *io;
+   struct dss_io_data io;
u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
struct dp_catalog dp_catalog;
u8 aux_lut_cfg_index[PHY_AUX_CFG_MAX];
@@ -66,7 +88,7 @@ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, 
struct msm_disp_state *d
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
-   struct dss_io_data *dss = >io->dp_controller;
+   struct dss_io_data *dss = >io;
 
msm_disp_snapshot_add_block(disp_state, dss->ahb.len, dss->ahb.base, 
"dp_ahb");
msm_disp_snapshot_add_block(disp_state, dss->aux.len, dss->aux.base, 
"dp_aux");
@@ -76,7 +98,7 @@ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, 
struct msm_disp_state *d
 
 static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32 offset)
 {
-   return readl_relaxed(catalog->io->dp_controller.aux.base + offset);
+   return readl_relaxed(catalog->io.aux.base + offset);
 }
 
 static inline void dp_write_aux(struct dp_catalog_private *catalog,
@@ -86,12 +108,12 @@ static inline void dp_write_aux(struct dp_catalog_private 
*catalog,
 * To make sure aux reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   writel(data, catalog->io->dp_controller.aux.base + offset);
+   writel(data, catalog->io.aux.base + offset);
 }
 
 static inline u32 dp_read_ahb(const struct dp_catalog_private *catalog, u32 
offset)
 {
-   return readl_relaxed(catalog->io->dp_controller.ahb.base + offset);
+   return readl_relaxed(catalog->io.ahb.base + offset);
 }
 
 static inline void dp_write_ahb(struct dp_catalog_private *catalog,
@@ -101,7 +123,7 @@ static inline void dp_write_ahb(struct dp_catalog_private 
*catalog,
 * To make sure phy reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   writel(data, catalog->io->dp_controller.ahb.base + offset);
+   writel(data, catalog->io.ahb.base + offset);
 }
 
 static inline void dp_write_p0(struct dp_catalog_private *catalog,
@@ -111,7 +133,7 @@ static inline void dp_write_p0(struct dp_catalog_private 
*catalog,
 * To make sure interface reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   writel(data, catalog->io->dp_controller.p0.base + offset);
+   writel(data, catalog->io.p0.base + offset);
 }
 
 static inline u32 dp_read_p0(struct dp_catalog_private *catalog,
@@ -121,12 +143,12 @@ static inline u32 dp_read_p0(struct dp_catalog_private 
*catalog,
 * To make sure interface reg writes happens before any other operation,
 * this function uses writel() instread of writel_relaxed()
 */
-   return readl_relaxed(catalog->io->dp_controller.p0.base + offset);
+   return readl_relaxed(catalog->io.p0.base + offset);
 }
 
 static inline u32 dp_read_link(struct dp_catalog_private *catalog, u32 offset)
 {
-   return readl_relaxed(catalog->io->dp_controller.link.base + offset);
+   return readl_relaxed(catalog->io.link.base + offset);
 }
 
 static inline void dp_write_link(struct dp_catalog_private *catalog,
@@ -136,7 +158,7 @@ 

[PATCH RESEND v3 06/15] drm/msm/dp: simplify stream clocks handling

2024-01-26 Thread Dmitry Baryshkov
There is only a single DP_STREAM_PM clock, stream_pixel. Instead of
using a separate dss_module_power instance for this single clock, handle
this clock directly. This allows us to drop several wrapping functions.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c   | 91 --
 drivers/gpu/drm/msm/dp/dp_parser.c | 41 -
 drivers/gpu/drm/msm/dp/dp_parser.h |  2 -
 3 files changed, 47 insertions(+), 87 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index da29281c575b..56a424a82a1b 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -79,6 +79,8 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
 
+   struct clk *pixel_clk;
+
struct completion idle_comp;
struct completion psr_op_comp;
struct completion video_comp;
@@ -1320,27 +1322,6 @@ static int dp_ctrl_setup_main_link(struct 
dp_ctrl_private *ctrl,
return ret;
 }
 
-static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
-   enum dp_pm_type module, char *name, unsigned long rate)
-{
-   u32 num = ctrl->parser->mp[module].num_clk;
-   struct clk_bulk_data *cfg = ctrl->parser->mp[module].clocks;
-
-   while (num && strcmp(cfg->id, name)) {
-   num--;
-   cfg++;
-   }
-
-   drm_dbg_dp(ctrl->drm_dev, "setting rate=%lu on clk=%s\n",
-   rate, name);
-
-   if (num)
-   clk_set_rate(cfg->clk, rate);
-   else
-   DRM_ERROR("%s clock doesn't exit to set rate %lu\n",
-   name, rate);
-}
-
 int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
   enum dp_pm_type pm_type, bool enable)
 {
@@ -1351,8 +1332,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
if (pm_type != DP_CORE_PM &&
-   pm_type != DP_CTRL_PM &&
-   pm_type != DP_STREAM_PM) {
+   pm_type != DP_CTRL_PM) {
DRM_ERROR("unsupported ctrl module: %s\n",
  dp_parser_pm_name(pm_type));
return -EINVAL;
@@ -1371,12 +1351,6 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
return 0;
}
 
-   if (pm_type == DP_STREAM_PM && ctrl->stream_clks_on) {
-   drm_dbg_dp(ctrl->drm_dev,
-  "pixel clks already enabled\n");
-   return 0;
-   }
-
if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
drm_dbg_dp(ctrl->drm_dev,
   "Enable core clks before link clks\n");
@@ -1401,8 +1375,6 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
 
if (pm_type == DP_CORE_PM)
ctrl->core_clks_on = enable;
-   else if (pm_type == DP_STREAM_PM)
-   ctrl->stream_clks_on = enable;
else
ctrl->link_clks_on = enable;
 
@@ -1734,14 +1706,23 @@ static int dp_ctrl_process_phy_test_request(struct 
dp_ctrl_private *ctrl)
}
 
pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
-   dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 
1000);
-
-   ret = dp_ctrl_clk_enable(>dp_ctrl, DP_STREAM_PM, true);
+   ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
-   DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
+   DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
return ret;
}
 
+   if (ctrl->stream_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
+   } else {
+   ret = clk_prepare_enable(ctrl->pixel_clk);
+   if (ret) {
+   DRM_ERROR("Failed to start pixel clocks. ret=%d\n", 
ret);
+   return ret;
+   }
+   ctrl->stream_clks_on = true;
+   }
+
dp_ctrl_send_phy_test_pattern(ctrl);
 
return 0;
@@ -1977,14 +1958,23 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool 
force_link_train)
}
}
 
-   dp_ctrl_set_clock_rate(ctrl, DP_STREAM_PM, "stream_pixel", pixel_rate * 
1000);
-
-   ret = dp_ctrl_clk_enable(>dp_ctrl, DP_STREAM_PM, true);
+   ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
-   DRM_ERROR("Unable to start pixel clocks. ret=%d\n", ret);
+   DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
goto end;
}
 
+   if (ctrl->stream_clks_on) {
+   drm_dbg_dp(ctrl->drm_dev, "pixel clks already enabled\n");
+   } else {
+   ret = clk_prepare_enable(ctrl->pixel_clk);
+

[PATCH RESEND v3 07/15] drm/msm/dp: stop parsing clock names from DT

2024-01-26 Thread Dmitry Baryshkov
All supported platforms use the same clocks configuration. Instead of
parsing names from DT in a pretty complex manner, use the static
configuration. If at some point newer (or older) platforms have
different clock configuration, this clock config can be moved to the
device data.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  73 ++--
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_parser.c | 112 -
 drivers/gpu/drm/msm/dp/dp_parser.h |  22 
 4 files changed, 63 insertions(+), 150 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 56a424a82a1b..cfcf6136ffa6 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -69,6 +69,11 @@ struct dp_vc_tu_mapping_table {
u8 tu_size_minus1;
 };
 
+struct dss_module_power {
+   unsigned int num_clk;
+   struct clk_bulk_data *clocks;
+};
+
 struct dp_ctrl_private {
struct dp_ctrl dp_ctrl;
struct drm_device *drm_dev;
@@ -79,6 +84,7 @@ struct dp_ctrl_private {
struct dp_parser *parser;
struct dp_catalog *catalog;
 
+   struct dss_module_power mp[DP_MAX_PM];
struct clk *pixel_clk;
 
struct completion idle_comp;
@@ -90,6 +96,15 @@ struct dp_ctrl_private {
bool stream_clks_on;
 };
 
+static inline const char *dp_pm_name(enum dp_pm_type module)
+{
+   switch (module) {
+   case DP_CORE_PM:return "DP_CORE_PM";
+   case DP_CTRL_PM:return "DP_CTRL_PM";
+   default:return "???";
+   }
+}
+
 static int dp_aux_link_configure(struct drm_dp_aux *aux,
struct dp_link_info *link)
 {
@@ -1334,7 +1349,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
if (pm_type != DP_CORE_PM &&
pm_type != DP_CTRL_PM) {
DRM_ERROR("unsupported ctrl module: %s\n",
- dp_parser_pm_name(pm_type));
+ dp_pm_name(pm_type));
return -EINVAL;
}
 
@@ -1354,7 +1369,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
if ((pm_type == DP_CTRL_PM) && (!ctrl->core_clks_on)) {
drm_dbg_dp(ctrl->drm_dev,
   "Enable core clks before link clks\n");
-   mp = >parser->mp[DP_CORE_PM];
+   mp = >mp[DP_CORE_PM];
 
ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (ret)
@@ -1364,7 +1379,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
}
}
 
-   mp = >parser->mp[pm_type];
+   mp = >mp[pm_type];
if (enable) {
ret = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
if (ret)
@@ -1380,7 +1395,7 @@ int dp_ctrl_clk_enable(struct dp_ctrl *dp_ctrl,
 
drm_dbg_dp(ctrl->drm_dev, "%s clocks for %s\n",
   enable ? "enable" : "disable",
-  dp_parser_pm_name(pm_type));
+  dp_pm_name(pm_type));
drm_dbg_dp(ctrl->drm_dev,
   "stream_clks:%s link_clks:%s core_clks:%s\n",
   ctrl->stream_clks_on ? "on" : "off",
@@ -2158,30 +2173,56 @@ irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
return ret;
 }
 
+static const char *core_clks[] = {
+   "core_iface",
+   "core_aux",
+};
+
+static const char *ctrl_clks[] = {
+   "ctrl_link",
+   "ctrl_link_iface",
+};
+
 static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl)
 {
-   struct dp_ctrl_private *ctrl_private;
-   int rc = 0;
-   struct dss_module_power *core, *ctrl;
+   struct dp_ctrl_private *ctrl;
+   struct dss_module_power *core, *link;
struct device *dev;
+   int i, rc;
+
+   ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+   dev = ctrl->dev;
 
-   ctrl_private = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-   dev = ctrl_private->dev;
+   core = >mp[DP_CORE_PM];
+   link = >mp[DP_CTRL_PM];
 
-   core = _private->parser->mp[DP_CORE_PM];
-   ctrl = _private->parser->mp[DP_CTRL_PM];
+   core->num_clk = ARRAY_SIZE(core_clks);
+   core->clocks = devm_kcalloc(dev, core->num_clk, sizeof(*core->clocks), 
GFP_KERNEL);
+   if (!core->clocks)
+   return -ENOMEM;
+
+   for (i = 0; i < core->num_clk; i++)
+   core->clocks[i].id = core_clks[i];
 
rc = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
if (rc)
return rc;
 
-   rc = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
+   link->num_clk = ARRAY_SIZE(ctrl_clks);
+   link->clocks = devm_kcalloc(dev, link->num_clk, sizeof(*link->clocks), 
GFP_KERNEL);
+   if (!link->clocks)
+   return -ENOMEM;
+
+   for (i = 0; i < link->num_clk; i++)
+

[PATCH RESEND v3 03/15] drm/msm/dp: parse DT from dp_parser_get

2024-01-26 Thread Dmitry Baryshkov
It makes little sense to split the submodule get and actual DT parsing.
Call dp_parser_parse() directly from dp_parser_get(), so that the parser
data is fully initialised once it is returned to the caller.

Reviewed-by: Konrad Dybcio 
Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 6 --
 drivers/gpu/drm/msm/dp/dp_parser.c  | 8 +++-
 drivers/gpu/drm/msm/dp/dp_parser.h  | 3 ---
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index d37d599aec27..67b48f0a6c83 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1266,12 +1266,6 @@ static int dp_display_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
 
-   rc = dp->parser->parse(dp->parser);
-   if (rc) {
-   DRM_ERROR("device tree parsing failed\n");
-   goto err;
-   }
-
rc = dp_power_client_init(dp->power);
if (rc) {
DRM_ERROR("Power client create failed\n");
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c 
b/drivers/gpu/drm/msm/dp/dp_parser.c
index 7032dcc8842b..2d9d126c119b 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -315,13 +315,19 @@ static int dp_parser_parse(struct dp_parser *parser)
 struct dp_parser *dp_parser_get(struct platform_device *pdev)
 {
struct dp_parser *parser;
+   int ret;
 
parser = devm_kzalloc(>dev, sizeof(*parser), GFP_KERNEL);
if (!parser)
return ERR_PTR(-ENOMEM);
 
-   parser->parse = dp_parser_parse;
parser->pdev = pdev;
 
+   ret = dp_parser_parse(parser);
+   if (ret) {
+   dev_err(>dev, "device tree parsing failed\n");
+   return ERR_PTR(ret);
+   }
+
return parser;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 90a2cdbbe344..4ccc432b4142 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -67,7 +67,6 @@ struct dss_module_power {
  *
  * @pdev: platform data of the client
  * @mp: gpio, regulator and clock related data
- * @parse: function to be called by client to parse device tree.
  */
 struct dp_parser {
struct platform_device *pdev;
@@ -76,8 +75,6 @@ struct dp_parser {
u32 max_dp_lanes;
u32 max_dp_link_rate;
struct drm_bridge *next_bridge;
-
-   int (*parse)(struct dp_parser *parser);
 };
 
 /**

-- 
2.39.2



[PATCH RESEND v3 02/15] drm/msm/dp: drop unused fields from dp_power_private

2024-01-26 Thread Dmitry Baryshkov
Drop unused and obsolete fields from struct dp_power_private.

Reviewed-by: Konrad Dybcio 
Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_power.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_power.c 
b/drivers/gpu/drm/msm/dp/dp_power.c
index c4843dd69f47..b095a5b47c8b 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -16,9 +16,6 @@ struct dp_power_private {
struct dp_parser *parser;
struct device *dev;
struct drm_device *drm_dev;
-   struct clk *link_clk_src;
-   struct clk *pixel_provider;
-   struct clk *link_provider;
 
struct dp_power dp_power;
 };

-- 
2.39.2



[PATCH RESEND v3 00/15] drm/msm/dp: clear power and parser submodules away

2024-01-26 Thread Dmitry Baryshkov
Reshuffle code in the DP driver, cleaning up clocks and DT parsing and
dropping the dp_power and dp_parser submodules.

Initially I started by looking onto stream_pixel clock handling only to
find several wrapping layers around a single clocks. After inlining
and/or dropping them (and thus dp_power submodule), it was more or less
natural to continue cleaning up the dp_parser until it got removed
completely.

---
Changes in v3:
- Fixed crash in the DP when there is no next bridge (Kuogee)
- Removed excess documentation for the removed dp_parser::io field
- Link to v2: 
https://lore.kernel.org/r/20231231-dp-power-parser-cleanup-v2-0-fc3e902a6...@linaro.org

Changes in v2:
- Fixed unrelated power->ctrl change in comment (Konrad)
- Made sure that all functions use reverse-Christmas-tree flow (Konrad)
- Fixed indents in several moved functions
- Added a patch splitting dp_ctlr_clk_enable
- Link to v1: 
https://lore.kernel.org/r/20231229225650.912751-1-dmitry.barysh...@linaro.org

---
Dmitry Baryshkov (15):
  drm/msm/dp: drop unused parser definitions
  drm/msm/dp: drop unused fields from dp_power_private
  drm/msm/dp: parse DT from dp_parser_get
  drm/msm/dp: inline dp_power_(de)init
  drm/msm/dp: fold dp_power into dp_ctrl module
  drm/msm/dp: simplify stream clocks handling
  drm/msm/dp: stop parsing clock names from DT
  drm/msm/dp: split dp_ctrl_clk_enable into four functuions
  drm/msm/dp: move phy_configure_opts to dp_ctrl
  drm/msm/dp: remove PHY handling from dp_catalog.c
  drm/msm/dp: handle PHY directly in dp_ctrl
  drm/msm/dp: move all IO handling to dp_catalog
  drm/msm/dp: move link property handling to dp_panel
  drm/msm/dp: move next_bridge handling to dp_display
  drm/msm/dp: drop dp_parser

 drivers/gpu/drm/msm/Makefile|   2 -
 drivers/gpu/drm/msm/dp/dp_aux.c |   9 +-
 drivers/gpu/drm/msm/dp/dp_aux.h |   2 +
 drivers/gpu/drm/msm/dp/dp_catalog.c | 156 +++-
 drivers/gpu/drm/msm/dp/dp_catalog.h |   6 +-
 drivers/gpu/drm/msm/dp/dp_ctrl.c| 358 
 drivers/gpu/drm/msm/dp/dp_ctrl.h|  17 +-
 drivers/gpu/drm/msm/dp/dp_debug.c   |   1 -
 drivers/gpu/drm/msm/dp/dp_display.c | 102 +++---
 drivers/gpu/drm/msm/dp/dp_display.h |   3 +-
 drivers/gpu/drm/msm/dp/dp_panel.c   |  66 +++
 drivers/gpu/drm/msm/dp/dp_parser.c  | 327 
 drivers/gpu/drm/msm/dp/dp_parser.h  | 155 
 drivers/gpu/drm/msm/dp/dp_power.c   | 183 --
 drivers/gpu/drm/msm/dp/dp_power.h   |  95 --
 15 files changed, 465 insertions(+), 1017 deletions(-)
---
base-commit: 39676dfe52331dba909c617f213fdb21015c8d10
change-id: 20231231-dp-power-parser-cleanup-9e3a5f9a6821

Best regards,
-- 
Dmitry Baryshkov 



[PATCH RESEND v3 01/15] drm/msm/dp: drop unused parser definitions

2024-01-26 Thread Dmitry Baryshkov
Drop several unused and obsolete definitions from the dp_parser module.

Signed-off-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_parser.h | 46 --
 1 file changed, 46 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h 
b/drivers/gpu/drm/msm/dp/dp_parser.h
index 1f068626d445..90a2cdbbe344 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -12,7 +12,6 @@
 
 #include "msm_drv.h"
 
-#define DP_LABEL "MDSS DP DISPLAY"
 #define DP_MAX_PIXEL_CLK_KHZ   675000
 #define DP_MAX_NUM_DP_LANES4
 #define DP_LINK_RATE_HBR2  54 /* kbytes */
@@ -21,7 +20,6 @@ enum dp_pm_type {
DP_CORE_PM,
DP_CTRL_PM,
DP_STREAM_PM,
-   DP_PHY_PM,
DP_MAX_PM
 };
 
@@ -43,28 +41,10 @@ static inline const char *dp_parser_pm_name(enum dp_pm_type 
module)
case DP_CORE_PM:return "DP_CORE_PM";
case DP_CTRL_PM:return "DP_CTRL_PM";
case DP_STREAM_PM:  return "DP_STREAM_PM";
-   case DP_PHY_PM: return "DP_PHY_PM";
default:return "???";
}
 }
 
-/**
- * struct dp_display_data  - display related device tree data.
- *
- * @ctrl_node: referece to controller device
- * @phy_node:  reference to phy device
- * @is_active: is the controller currently active
- * @name: name of the display
- * @display_type: type of the display
- */
-struct dp_display_data {
-   struct device_node *ctrl_node;
-   struct device_node *phy_node;
-   bool is_active;
-   const char *name;
-   const char *display_type;
-};
-
 /**
  * struct dp_ctrl_resource - controller's IO related data
  *
@@ -77,28 +57,6 @@ struct dp_io {
union phy_configure_opts phy_opts;
 };
 
-/**
- * struct dp_pinctrl - DP's pin control
- *
- * @pin: pin-controller's instance
- * @state_active: active state pin control
- * @state_hpd_active: hpd active state pin control
- * @state_suspend: suspend state pin control
- */
-struct dp_pinctrl {
-   struct pinctrl *pin;
-   struct pinctrl_state *state_active;
-   struct pinctrl_state *state_hpd_active;
-   struct pinctrl_state *state_suspend;
-};
-
-/* Regulators for DP devices */
-struct dp_reg_entry {
-   char name[32];
-   int enable_load;
-   int disable_load;
-};
-
 struct dss_module_power {
unsigned int num_clk;
struct clk_bulk_data *clocks;
@@ -109,16 +67,12 @@ struct dss_module_power {
  *
  * @pdev: platform data of the client
  * @mp: gpio, regulator and clock related data
- * @pinctrl: pin-control related data
- * @disp_data: controller's display related data
  * @parse: function to be called by client to parse device tree.
  */
 struct dp_parser {
struct platform_device *pdev;
struct dss_module_power mp[DP_MAX_PM];
-   struct dp_pinctrl pinctrl;
struct dp_io io;
-   struct dp_display_data disp_data;
u32 max_dp_lanes;
u32 max_dp_link_rate;
struct drm_bridge *next_bridge;

-- 
2.39.2



Re: [PATCH 7/7] accel/ivpu: Add job status for jobs aborted by the driver

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:28 AM, Jacek Lawrynowicz wrote:

From: Grzegorz Trzebiatowski 

Add DRM_IVPU_JOB_STATUS_ABORTED to indicate that the job was aborted
by the driver due to e.g. TDR or user context MMU faults.

This will help UMD and tests distinguish if job was aborted by the FW
or the driver.

Signed-off-by: Grzegorz Trzebiatowski 
Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH 6/7] accel/ivpu/40xx: Stop passing SKU boot parameters to FW

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:28 AM, Jacek Lawrynowicz wrote:

From: Krystian Pradzynski 

This parameter was never used by the 40xx FW.

Signed-off-by: Krystian Pradzynski 
Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH 5/7] accel/ivpu/40xx: Enable D0i3 message

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:28 AM, Jacek Lawrynowicz wrote:

From: Krystian Pradzynski 

All recent 40xx firmware already supports D0i3 entry message and this
WA is no longer needed.


Can I assume that the workaround only applies to pre-production firmware?


Re: [PATCH 4/7] accel/ivpu: Gracefully shutdown NPU before reset

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:28 AM, Jacek Lawrynowicz wrote:

From: "Wachowski, Karol" 

Replace forceful disable of power domains with requests to disable
TOP NOC CPU_CTRL and HOSTIF_L2CACHE through QREQN.

In case of failure retry multiple times following HAS sequence of
checking both QACCEPN and QDENYN registers.

This fixes VPU hangs with PCODE released in January 2024 onwards.

Fixes: 3f7c0634926d ("accel/ivpu/37xx: Fix hangs related to MMIO reset")
Signed-off-by: Wachowski, Karol 
Signed-off-by: Jacek Lawrynowicz 
---
  drivers/accel/ivpu/ivpu_hw_37xx.c | 122 +++---
  1 file changed, 60 insertions(+), 62 deletions(-)

diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c 
b/drivers/accel/ivpu/ivpu_hw_37xx.c
index 77accd029c4a..b1a3a19c8986 100644
--- a/drivers/accel/ivpu/ivpu_hw_37xx.c
+++ b/drivers/accel/ivpu/ivpu_hw_37xx.c
@@ -332,28 +332,6 @@ static int ivpu_boot_top_noc_qrenqn_check(struct 
ivpu_device *vdev, u32 exp_val)
return 0;
  }
  
-static int ivpu_boot_top_noc_qacceptn_check(struct ivpu_device *vdev, u32 exp_val)

-{
-   u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QACCEPTN);
-
-   if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QACCEPTN, CPU_CTRL, exp_val, 
val) ||
-   !REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QACCEPTN, HOSTIF_L2CACHE, 
exp_val, val))
-   return -EIO;
-
-   return 0;
-}
-
-static int ivpu_boot_top_noc_qdeny_check(struct ivpu_device *vdev, u32 exp_val)
-{
-   u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QDENY);
-
-   if (!REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QDENY, CPU_CTRL, exp_val, val) ||
-   !REG_TEST_FLD_NUM(VPU_37XX_TOP_NOC_QDENY, HOSTIF_L2CACHE, exp_val, 
val))
-   return -EIO;
-
-   return 0;
-}
-
  static int ivpu_boot_host_ss_configure(struct ivpu_device *vdev)
  {
ivpu_boot_host_ss_rst_clr_assert(vdev);
@@ -396,37 +374,68 @@ static int ivpu_boot_host_ss_axi_enable(struct 
ivpu_device *vdev)
return ivpu_boot_host_ss_axi_drive(vdev, true);
  }
  
-static int ivpu_boot_host_ss_top_noc_drive(struct ivpu_device *vdev, bool enable)

+static int ivpu_boot_host_ss_top_noc_qacceptn_check(struct ivpu_device *vdev, 
bool enable, u32 mask)
+{
+   u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QACCEPTN) & mask;
+
+   if (enable && val == mask)
+   return 0;
+
+   if (!enable && val == 0)
+   return 0;
+
+   ivpu_dbg(vdev, PM, "Failed qacceptn check 0x%x (mask 0x%x enable 
%d)\n", val, mask, enable);
+   return -EIO;
+}
+
+static int ivpu_boot_host_ss_top_noc_qdeny_check(struct ivpu_device *vdev, u32 
mask)
+{
+   u32 val = REGV_RD32(VPU_37XX_TOP_NOC_QDENY) & mask;
+
+   if (val) {
+   ivpu_dbg(vdev, PM, "Failed qdeny check 0x%x (mask 0x%x)\n", 
val, mask);
+   return -EIO;
+   }
+
+   return 0;
+}
+
+static int ivpu_boot_host_ss_top_noc_drive(struct ivpu_device *vdev, bool 
enable, u32 mask)
  {
-   int ret;
u32 val;
  
  	val = REGV_RD32(VPU_37XX_TOP_NOC_QREQN);

-   if (enable) {
-   val = REG_SET_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val);
-   val = REG_SET_FLD(VPU_37XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
-   } else {
-   val = REG_CLR_FLD(VPU_37XX_TOP_NOC_QREQN, CPU_CTRL, val);
-   val = REG_CLR_FLD(VPU_37XX_TOP_NOC_QREQN, HOSTIF_L2CACHE, val);
-   }
-   REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val);
+   if (enable)
+   REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val | mask);
+   else
+   REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val & ~mask);
  
-	ret = ivpu_boot_top_noc_qacceptn_check(vdev, enable ? 0x1 : 0x0);

-   if (ret) {
-   ivpu_err(vdev, "Failed qacceptn check: %d\n", ret);
-   return ret;
-   }
+   if (!ivpu_boot_host_ss_top_noc_qacceptn_check(vdev, enable, mask))
+   return 0;
  
-	ret = ivpu_boot_top_noc_qdeny_check(vdev, 0x0);

-   if (ret)
-   ivpu_err(vdev, "Failed qdeny check: %d\n", ret);
+   if (!enable && ivpu_boot_host_ss_top_noc_qdeny_check(vdev, mask))
+   REGV_WR32(VPU_37XX_TOP_NOC_QREQN, val | mask);
  
-	return ret;

+   return -EIO;
  }
  
  static int ivpu_boot_host_ss_top_noc_enable(struct ivpu_device *vdev)

  {
-   return ivpu_boot_host_ss_top_noc_drive(vdev, true);
+   return ivpu_boot_host_ss_top_noc_drive(vdev, true,
+  
VPU_37XX_TOP_NOC_QREQN_CPU_CTRL_MASK |
+  
VPU_37XX_TOP_NOC_QREQN_HOSTIF_L2CACHE_MASK);
+}
+
+static int ivpu_boot_host_ss_top_noc_cpu_ctrl_disable(struct ivpu_device *vdev)
+{
+   return ivpu_boot_host_ss_top_noc_drive(vdev, false,
+  
VPU_37XX_TOP_NOC_QREQN_CPU_CTRL_MASK);
+}
+
+static int ivpu_boot_host_ss_top_noc_hostif_l2cache_disable(struct ivpu_device 
*vdev)
+{
+   return ivpu_boot_host_ss_top_noc_drive(vdev, false,
+  

Re: [RFC PATCH 0/2] drm/amd/display: switch amdgpu_dm_connector to

2024-01-26 Thread Mario Limonciello

On 1/26/2024 10:28, Melissa Wen wrote:

Hi,

I'm debugging a null-pointer dereference when running
igt@kms_connector_force_edid and the way I found to solve the bug is to
stop using raw edid handler in amdgpu_connector_funcs_force and
create_eml_sink in favor of managing resouces via sruct drm_edid helpers
(Patch 1). The proper solution seems to be switch amdgpu_dm_connector
from struct edid to struct drm_edid and avoid the usage of different
approaches in the driver (Patch 2). However, doing it implies a good
amount of work and validation, therefore I decided to send this RFC
first to collect opinions and check if there is any parallel work on
this side. It's a working in progress.

The null-pointer error trigger by the igt@kms_connector_force_edid test
was introduced by:
- e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")

You can check the error trace in the first patch.

This series was tested with kms_hdmi_inject and kms_force_connector. No
null-pointer error, kms_hdmi_inject is successul and kms_force_connector
is sucessful after the second execution - the force-edid subtest
still fails in the first run (I'm still investigating).

There is also a couple of cast warnings to be addressed - I'm looking
for the best replacement.

I appreciate any feedback and testing.


So I'm actually a little bit worried by hardcoding EDID_LENGTH in this 
series.


I have some other patches that I'm posting later on that let you get the 
EDID from _DDC BIOS method too.  My observation was that the EDID can be 
anywhere up to 512 bytes according to the ACPI spec.


An earlier version of my patch was using EDID_LENGTH when fetching it 
and the EDID checksum failed.


I'll CC you on the post, we probably want to get your changes and mine 
merged together.




Melissa

Melissa Wen (2):
   drm/amd/display: fix null-pointer dereference on edid reading
   drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 78 ++-
  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
  .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 ++-
  .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++---
  4 files changed, 60 insertions(+), 54 deletions(-)





Re: [PATCH 3/7] accel/ivpu: Disable d3hot_delay on all NPU generations

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:28 AM, Jacek Lawrynowicz wrote:

NPU does not require this delay regardless of the generation.
All generations are integrated into the SOC.

Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH 2/7] accel/ivpu: Correct MMU queue size checking functions

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:27 AM, Jacek Lawrynowicz wrote:

From: "Wachowski, Karol" 

Do not use kernel CIRC_SPACE and CIRC_CNT that
incorrectly return space of a queue when wrap bit was set.
Use correct implementation that compares producer, consumer and
wrap bit values.

Without this fix it was possible to lose events in case when event
queue was full.

Signed-off-by: Wachowski, Karol 
Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH 1/7] accel/ivpu: Force snooping for MMU writes

2024-01-26 Thread Jeffrey Hugo

On 1/26/2024 5:27 AM, Jacek Lawrynowicz wrote:

From: "Wachowski, Karol" 

Set AW_SNOOP_OVERRIDE bit in VPU_37/40XX_HOST_IF_TCU_PTW_OVERRIDES
to force snooping for MMU write accesses (setting event queue events).

MMU event queue buffer is the only buffer written by MMU and
mapped as write-back which break cache coherency. Force write
transactions to be snooped solving the problem.

Signed-off-by: Wachowski, Karol 
Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH v19 22/30] drm/shmem-helper: Add common memory shrinker

2024-01-26 Thread Boris Brezillon
On Fri, 26 Jan 2024 19:27:49 +0300
Dmitry Osipenko  wrote:

> On 1/26/24 12:55, Boris Brezillon wrote:
> > On Fri, 26 Jan 2024 00:56:47 +0300
> > Dmitry Osipenko  wrote:
> >   
> >> On 1/25/24 13:19, Boris Brezillon wrote:  
> >>> On Fri,  5 Jan 2024 21:46:16 +0300
> >>> Dmitry Osipenko  wrote:
> >>> 
>  +static bool drm_gem_shmem_is_evictable(struct drm_gem_shmem_object 
>  *shmem)
>  +{
>  +return (shmem->madv >= 0) && shmem->base.funcs->evict &&
>  +refcount_read(>pages_use_count) &&
>  +!refcount_read(>pages_pin_count) &&
>  +!shmem->base.dma_buf && !shmem->base.import_attach &&
>  +!shmem->evicted;
> >>>
> >>> Are we missing
> >>>
> >>> && dma_resv_test_signaled(shmem->base.resv,
> >>> DMA_RESV_USAGE_BOOKKEEP)
> >>>
> >>> to make sure the GPU is done using the BO?
> >>> The same applies to drm_gem_shmem_is_purgeable() BTW.
> >>>
> >>> If you don't want to do this test here, we need a way to let drivers
> >>> provide a custom is_{evictable,purgeable}() test.
> >>>
> >>> I guess we should also expose drm_gem_shmem_shrinker_update_lru_locked()
> >>> to let drivers move the GEMs that were used most recently (those
> >>> referenced by a GPU job) at the end of the evictable LRU.
> >>
> >> We have the signaled-check in the common drm_gem_evict() helper:
> >>
> >> https://elixir.bootlin.com/linux/v6.8-rc1/source/drivers/gpu/drm/drm_gem.c#L1496
> >>   
> > 
> > Ah, indeed. I'll need DMA_RESV_USAGE_BOOKKEEP instead of
> > DMA_RESV_USAGE_READ in panthor, but I can add it in the driver specific  
> > ->evict() hook (though that means calling dma_resv_test_signaled()  
> > twice, which is not great, oh well).  
> 
> Maybe we should change drm_gem_evict() to use BOOKKEEP. The
> test_signaled(BOOKKEEP) should be a "stronger" check than
> test_signaled(READ)?

It is, just wondering if some users have a good reason to want
READ here.

> 
> > The problem about the evictable LRU remains though: we need a way to let
> > drivers put their BOs at the end of the list when the BO has been used
> > by the GPU, don't we?  
> 
> If BO is use, then it won't be evicted, while idling BOs will be
> evicted. Hence, the used BOs will be naturally moved down the LRU list
> each time shrinker is invoked.
> 

That only do the trick if the BOs being used most often are busy when
the shrinker kicks in though. Let's take this scenario:


BO 1BO 2
shinker

busy
idle (first-pos-in-evictable-LRU)

busy
idle (second-pos-in-evictable-LRU)

busy
idle

busy
idle

busy
idle


find a BO to evict

pick BO 2

busy (swapin)
idle

If the LRU had been updated at each busy event, BO 1 should have
been picked for eviction. But we evicted the BO that was first
recorded idle instead of the one that was least recently
recorded busy.



Re: [PATCH 3/3] accel/ivpu: Improve recovery and reset support

2024-01-26 Thread Jeffrey Hugo

On 1/22/2024 5:09 AM, Jacek Lawrynowicz wrote:

   - Synchronize job submission with reset/recovery using reset_lock
   - Always print recovery reason and call diagnose_failure()
   - Don't allow for autosupend during recovery
   - Prevent immediate autosuspend after reset/recovery
   - Prevent force_recovery for issuing TDR when device is suspended
   - Reset VPU instead triggering recovery after changing debugfs params


This change appears to be doing 6 different things.  While they are all 
reset related, it seems like this should be 6 individual changes.  Is 
there some dependency in the code that I am missing where having these 
all combined is the better technical solution?


Re: [PATCH 2/3] accel/ivpu: Improve stability of ivpu_submit_ioctl()

2024-01-26 Thread Jeffrey Hugo

On 1/22/2024 5:09 AM, Jacek Lawrynowicz wrote:

- Wake up the device as late as possible


Can you amend with why this is a good idea?


- Remove job reference counting in order to simplify the code
- Don't put jobs that are not fully submitted on submitted_jobs_xa in
   order to avoid potential races with reset/recovery

Signed-off-by: Jacek Lawrynowicz 
---
  drivers/accel/ivpu/ivpu_job.c | 139 +++---
  drivers/accel/ivpu/ivpu_job.h |   1 -
  2 files changed, 62 insertions(+), 78 deletions(-)

diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
index 4fed0c05e051..d9b47a04b35f 100644
--- a/drivers/accel/ivpu/ivpu_job.c
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -125,7 +125,7 @@ void ivpu_cmdq_release_all_locked(struct ivpu_file_priv 
*file_priv)
  /*
   * Mark the doorbell as unregistered and reset job queue pointers.
   * This function needs to be called when the VPU hardware is restarted
- * and FW looses job queue state. The next time job queue is used it
+ * and FW loses job queue state. The next time job queue is used it
   * will be registered again.
   */
  static void ivpu_cmdq_reset_locked(struct ivpu_file_priv *file_priv, u16 
engine)
@@ -239,60 +239,32 @@ static struct dma_fence *ivpu_fence_create(struct 
ivpu_device *vdev)
return >base;
  }
  
-static void job_get(struct ivpu_job *job, struct ivpu_job **link)

+static void ivpu_job_destroy(struct ivpu_job *job)
  {
struct ivpu_device *vdev = job->vdev;
-
-   kref_get(>ref);
-   *link = job;
-
-   ivpu_dbg(vdev, KREF, "Job get: id %u refcount %u\n", job->job_id, 
kref_read(>ref));
-}
-
-static void job_release(struct kref *ref)
-{
-   struct ivpu_job *job = container_of(ref, struct ivpu_job, ref);
-   struct ivpu_device *vdev = job->vdev;
u32 i;
  
+	ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d",

+job->job_id, job->file_priv->ctx.id, job->engine_idx);
+
for (i = 0; i < job->bo_count; i++)
if (job->bos[i])
drm_gem_object_put(>bos[i]->base.base);
  
  	dma_fence_put(job->done_fence);

ivpu_file_priv_put(>file_priv);
-
-   ivpu_dbg(vdev, KREF, "Job released: id %u\n", job->job_id);
kfree(job);
-
-   /* Allow the VPU to get suspended, must be called after 
ivpu_file_priv_put() */
-   ivpu_rpm_put(vdev);
-}
-
-static void job_put(struct ivpu_job *job)
-{
-   struct ivpu_device *vdev = job->vdev;
-
-   ivpu_dbg(vdev, KREF, "Job put: id %u refcount %u\n", job->job_id, 
kref_read(>ref));
-   kref_put(>ref, job_release);
  }
  
  static struct ivpu_job *

-ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
+ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count)
  {
struct ivpu_device *vdev = file_priv->vdev;
struct ivpu_job *job;
-   int ret;
-
-   ret = ivpu_rpm_get(vdev);
-   if (ret < 0)
-   return NULL;
  
  	job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL);

if (!job)
-   goto err_rpm_put;
-
-   kref_init(>ref);
+   return NULL;
  
  	job->vdev = vdev;

job->engine_idx = engine_idx;
@@ -306,17 +278,14 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 
engine_idx, u32 bo_count)
job->file_priv = ivpu_file_priv_get(file_priv);
  
  	ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx);

-
return job;
  
  err_free_job:

kfree(job);
-err_rpm_put:
-   ivpu_rpm_put(vdev);
return NULL;
  }
  
-static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)

+static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, 
u32 job_status)
  {
struct ivpu_job *job;
  
@@ -333,9 +302,10 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status)

ivpu_dbg(vdev, JOB, "Job complete:  id %3u ctx %2d engine %d status 
0x%x\n",
 job->job_id, job->file_priv->ctx.id, job->engine_idx, 
job_status);
  
+	ivpu_job_destroy(job);

ivpu_stop_job_timeout_detection(vdev);
  
-	job_put(job);

+   ivpu_rpm_put(vdev);


Since this put() corresponds to a get() that is not in this function, I 
suggest adding a comment that points to where the corresponding get() is.


Reviewed-by: Jeffrey Hugo 


Re: [PATCH 1/3] accel/ivpu: Fix dev open/close races with unbind

2024-01-26 Thread Jeffrey Hugo

On 1/22/2024 5:09 AM, Jacek Lawrynowicz wrote:

   - Add context_list_lock to synchronize user context addition/removal
   - Use drm_dev_enter() to prevent unbinding the device during ivpu_open()
 and vpu address allocation

Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH 2/3] udmabuf: Sync buffer mappings for attached devices

2024-01-26 Thread Andrew Davis

On 1/26/24 1:25 AM, Kasireddy, Vivek wrote:

Currently this driver creates a SGT table using the CPU as the
target device, then performs the dma_sync operations against
that SGT. This is backwards to how DMA-BUFs are supposed to behave.
This may have worked for the case where these buffers were given
only back to the same CPU that produced them as in the QEMU case.
And only then because the original author had the dma_sync
operations also backwards, syncing for the "device" on begin_cpu.
This was noticed and "fixed" in this patch[0].

That then meant we were sync'ing from the CPU to the CPU using
a pseudo-device "miscdevice". Which then caused another issue
due to the miscdevice not having a proper DMA mask (and why should
it, the CPU is not a DMA device). The fix for that was an even
more egregious hack[1] that declares the CPU is coherent with
itself and can access its own memory space..

Unwind all this and perform the correct action by doing the dma_sync
operations for each device currently attached to the backing buffer.

Makes sense.



[0] commit 1ffe09590121 ("udmabuf: fix dma-buf cpu access")
[1] commit 9e9fa6a9198b ("udmabuf: Set the DMA mask for the udmabuf
device (v2)")

Signed-off-by: Andrew Davis 
---
   drivers/dma-buf/udmabuf.c | 41 +++
   1 file changed, 16 insertions(+), 25 deletions(-)

diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 3a23f0a7d112a..ab6764322523c 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -26,8 +26,6 @@ MODULE_PARM_DESC(size_limit_mb, "Max size of a
dmabuf, in megabytes. Default is
   struct udmabuf {
pgoff_t pagecount;
struct page **pages;
-   struct sg_table *sg;
-   struct miscdevice *device;
struct list_head attachments;
struct mutex lock;
   };
@@ -169,12 +167,8 @@ static void unmap_udmabuf(struct
dma_buf_attachment *at,
   static void release_udmabuf(struct dma_buf *buf)
   {
struct udmabuf *ubuf = buf->priv;
-   struct device *dev = ubuf->device->this_device;
pgoff_t pg;

-   if (ubuf->sg)
-   put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);

What happens if the last importer maps the dmabuf but erroneously
closes it immediately? Would unmap somehow get called in this case?



Good question, had to scan the framework code a bit here. I thought
closing a DMABUF handle would automatically unwind any current
attachments/mappings, but it seems nothing in the framework does that.

Looks like that is up to the importing drivers[0]:


Once a driver is done with a shared buffer it needs to call
dma_buf_detach() (after cleaning up any mappings) and then
release the reference acquired with dma_buf_get() by
calling dma_buf_put().


So closing a DMABUF after mapping without first unmapping it would
be a bug in the importer, it is not the exporters problem to check

It may be a bug in the importer but wouldn't the memory associated
with the sg table and attachment get leaked if unmap doesn't get called
in this scenario?



Yes the attachment data would be leaked if unattach was not called,
but that is true for all DMABUF exporters. The .release() callback
is meant to be the mirror of the export function and it only cleans
up that. Same for attach/unattach, map/unmap, etc.. If these calls
are not balanced then yes they can leak memory.

Since balance is guaranteed by the API, checking the balance should
be done at that level, not in each and every exporter. If your
comment is that we should add those checks into the DMABUF framework
layer then I would agree.

Andrew


Thanks,
Vivek


for (although some more warnings in the framework checking for that
might not be a bad idea..).

Andrew

[0] https://www.kernel.org/doc/html/v6.7/driver-api/dma-buf.html


Thanks,
Vivek


-
for (pg = 0; pg < ubuf->pagecount; pg++)
put_page(ubuf->pages[pg]);
kfree(ubuf->pages);
@@ -185,33 +179,31 @@ static int begin_cpu_udmabuf(struct dma_buf
*buf,
 enum dma_data_direction direction)
   {
struct udmabuf *ubuf = buf->priv;
-   struct device *dev = ubuf->device->this_device;
-   int ret = 0;
-
-   if (!ubuf->sg) {
-   ubuf->sg = get_sg_table(dev, buf, direction);
-   if (IS_ERR(ubuf->sg)) {
-   ret = PTR_ERR(ubuf->sg);
-   ubuf->sg = NULL;
-   }
-   } else {
-   dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents,
-   direction);
-   }
+   struct udmabuf_attachment *a;

-   return ret;
+   mutex_lock(>lock);
+
+   list_for_each_entry(a, >attachments, list)
+   dma_sync_sgtable_for_cpu(a->dev, a->table, direction);
+
+   mutex_unlock(>lock);
+
+   return 0;
   }

   static int end_cpu_udmabuf(struct dma_buf *buf,
   enum dma_data_direction direction)
   {
struct 

Re: [PATCH v11 14/26] locking/lockdep, cpu/hotplus: Use a weaker annotation in AP thread

2024-01-26 Thread Thomas Gleixner
On Wed, Jan 24 2024 at 20:59, Byungchul Park wrote:

Why is lockdep in the subsystem prefix here? You are changing the CPU
hotplug (not hotplus) code, right?

> cb92173d1f0 ("locking/lockdep, cpu/hotplug: Annotate AP thread") was
> introduced to make lockdep_assert_cpus_held() work in AP thread.
>
> However, the annotation is too strong for that purpose. We don't have to
> use more than try lock annotation for that.

This lacks a proper explanation why this is too strong.

> Furthermore, now that Dept was introduced, false positive alarms was
> reported by that. Replaced it with try lock annotation.

I still have zero idea what this is about.

Thanks,

tglx


Re: [PATCH v5 040/111] pwm: Provide devm_pwmchip_alloc() function

2024-01-26 Thread Uwe Kleine-König
Hello Alex,

On Fri, Jan 26, 2024 at 08:56:33AM -0600, Alex Elder wrote:
> On 1/25/24 6:09 AM, Uwe Kleine-König wrote:
> > This function allocates a struct pwm_chip and driver data. Compared to
> > the status quo the split into pwm_chip and driver data is new, otherwise
> > it doesn't change anything relevant (yet).
> > 
> > The intention is that after all drivers are switched to use this
> > allocation function, its possible to add a struct device to struct
> > pwm_chip to properly track the latter's lifetime without touching all
> > drivers again. Proper lifetime tracking is a necessary precondition to
> > introduce character device support for PWMs (that implements atomic
> > setting and doesn't suffer from the sysfs overhead of the /sys/class/pwm
> > userspace support).
> > 
> > The new function pwmchip_priv() (obviously?) only works for chips
> > allocated with devm_pwmchip_alloc().
> 
> I think this looks good.  Two questions:
> - Should you explicitly align the private data?  Or do you believe
>   the default alignment (currently pointer size aligned) is adequate?

I'm not aware of a requirement for a higher order alignment (but I might
well miss something). I did my tests on arm, nothing exploded there.
Maybe the conservative approach of asserting the same alignment as
kmalloc would be a good idea. I'll think and research about that.

iio uses ARCH_DMA_MINALIGN, net uses 32 (NETDEV_ALIGN).

> - Is there a non-devres version of the allocation function?

Patch #109 introduces a non-devres variant. As it's not used it's a
static function though. Can easily be changed is a use case pops up.

Best regards
Uwe

-- 
Pengutronix e.K.   | Uwe Kleine-König|
Industrial Linux Solutions | https://www.pengutronix.de/ |


signature.asc
Description: PGP signature


Re: [PATCH v2 9/9] accel/ivpu: Deprecate DRM_IVPU_PARAM_CONTEXT_PRIORITY param

2024-01-26 Thread Jeffrey Hugo

On 1/15/2024 6:44 AM, Jacek Lawrynowicz wrote:

From: "Wachowski, Karol" 

DRM_IVPU_PARAM_CONTEXT_PRIORITY has been deprecated because it
has been replaced with DRM_IVPU_JOB_PRIORITY levels set with
submit IOCTL and was unused anyway.

Signed-off-by: Wachowski, Karol 
Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [Linaro-mm-sig] [PATCH 2/3] udmabuf: Sync buffer mappings for attached devices

2024-01-26 Thread Andrew Davis

On 1/25/24 2:30 PM, Daniel Vetter wrote:

On Tue, Jan 23, 2024 at 04:12:26PM -0600, Andrew Davis wrote:

Currently this driver creates a SGT table using the CPU as the
target device, then performs the dma_sync operations against
that SGT. This is backwards to how DMA-BUFs are supposed to behave.
This may have worked for the case where these buffers were given
only back to the same CPU that produced them as in the QEMU case.
And only then because the original author had the dma_sync
operations also backwards, syncing for the "device" on begin_cpu.
This was noticed and "fixed" in this patch[0].

That then meant we were sync'ing from the CPU to the CPU using
a pseudo-device "miscdevice". Which then caused another issue
due to the miscdevice not having a proper DMA mask (and why should
it, the CPU is not a DMA device). The fix for that was an even
more egregious hack[1] that declares the CPU is coherent with
itself and can access its own memory space..

Unwind all this and perform the correct action by doing the dma_sync
operations for each device currently attached to the backing buffer.

[0] commit 1ffe09590121 ("udmabuf: fix dma-buf cpu access")
[1] commit 9e9fa6a9198b ("udmabuf: Set the DMA mask for the udmabuf device 
(v2)")

Signed-off-by: Andrew Davis 


So yeah the above hacks are terrible, but I don't think this is better.
What you're doing now is that you're potentially doing the flushing
multiple times, so if you have a lot of importers with life mappings this
is a performance regression.


I'd take lower performing but correct than fast and broken. :)

Syncing for CPU/device is about making sure the CPU/device can see
the data produced by the other. Some devices might be dma-coherent
and syncing for them would be a NOP, but we cant know that here
in this driver. Let's say we have two attached devices, one that
is cache coherent and one that isn't. If we only sync for first
attached device then that is converted to a NOP and we never flush
like the second device needed.

Same is true for devices behind IOMMU or with an L3 cache when
syncing in the other direction for CPU. So we have to sync for all
attached devices to ensure we get even the lowest common denominator
device sync'd. It is up to the DMA-API layer to decide which syncs
need to actually do something. If all attached devices are coherent
then all syncs will be NOPs and we have no performance penalty.



It's probably time to bite the bullet and teach the dma-api about flushing
for multiple devices. Or some way we can figure out which is the one
device we need to pick which gives us the right amount of flushing.



Seems like a constraint solving micro-optimization. The DMA-API layer
would have to track which buffers have already been flushed from CPU
cache and also track that nothing has been written into those caches
since that point, only then could it skip the flush. But that is already
the point of the dirty bit in the caches themselves, cleaning already
clean cache lines is essentially free in hardware. And so is invalidating
lines, it is just flipping a bit.

Andrew


Cheers, Sima


---
  drivers/dma-buf/udmabuf.c | 41 +++
  1 file changed, 16 insertions(+), 25 deletions(-)

diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
index 3a23f0a7d112a..ab6764322523c 100644
--- a/drivers/dma-buf/udmabuf.c
+++ b/drivers/dma-buf/udmabuf.c
@@ -26,8 +26,6 @@ MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in 
megabytes. Default is
  struct udmabuf {
pgoff_t pagecount;
struct page **pages;
-   struct sg_table *sg;
-   struct miscdevice *device;
struct list_head attachments;
struct mutex lock;
  };
@@ -169,12 +167,8 @@ static void unmap_udmabuf(struct dma_buf_attachment *at,
  static void release_udmabuf(struct dma_buf *buf)
  {
struct udmabuf *ubuf = buf->priv;
-   struct device *dev = ubuf->device->this_device;
pgoff_t pg;
  
-	if (ubuf->sg)

-   put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);
-
for (pg = 0; pg < ubuf->pagecount; pg++)
put_page(ubuf->pages[pg]);
kfree(ubuf->pages);
@@ -185,33 +179,31 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
 enum dma_data_direction direction)
  {
struct udmabuf *ubuf = buf->priv;
-   struct device *dev = ubuf->device->this_device;
-   int ret = 0;
-
-   if (!ubuf->sg) {
-   ubuf->sg = get_sg_table(dev, buf, direction);
-   if (IS_ERR(ubuf->sg)) {
-   ret = PTR_ERR(ubuf->sg);
-   ubuf->sg = NULL;
-   }
-   } else {
-   dma_sync_sg_for_cpu(dev, ubuf->sg->sgl, ubuf->sg->nents,
-   direction);
-   }
+   struct udmabuf_attachment *a;
  
-	return ret;

+   mutex_lock(>lock);
+
+   list_for_each_entry(a, >attachments, list)
+   

Re: [PATCH v3 1/2] pm: runtime: Simplify pm_runtime_get_if_active() usage

2024-01-26 Thread Sakari Ailus
Hi Alex,

On Fri, Jan 26, 2024 at 09:12:02AM -0600, Alex Elder wrote:
> On 1/22/24 5:41 AM, Sakari Ailus wrote:
> > There are two ways to opportunistically increment a device's runtime PM
> > usage count, calling either pm_runtime_get_if_active() or
> > pm_runtime_get_if_in_use(). The former has an argument to tell whether to
> > ignore the usage count or not, and the latter simply calls the former with
> > ign_usage_count set to false. The other users that want to ignore the
> > usage_count will have to explitly set that argument to true which is a bit
> > cumbersome.
> > 
> > To make this function more practical to use, remove the ign_usage_count
> > argument from the function. The main implementation is renamed as
> > pm_runtime_get_conditional().
> > 
> > Signed-off-by: Sakari Ailus 
> > Reviewed-by: Alex Elder  # drivers/net/ipa/ipa_smp2p.c
> 
> I actually intended my "Reviewed-by" to cover the entire patch.  I
> checked every caller and they all looked good to me.

Thanks, I'll drop the file name. AFAIR it was just below that file, so I
added it, but I could be wrong, too.

v5 will also squash the 2nd patch of v4 into this one
https://lore.kernel.org/linux-pm/ZbBAWROxRKE8Y8VU@kekkonen.localdomain/T/#m76d34e679e12d8536a20eb29af6e826e2a85a24b>,
I hope that's fine.

-- 
Kind regards,

Sakari Ailus


Re: [PATCH v2 8/9] accel/ivpu: Improve buffer object debug logs

2024-01-26 Thread Jeffrey Hugo

On 1/15/2024 6:44 AM, Jacek Lawrynowicz wrote:

Make debug logs more readable and consistent:
   - don't print handle as it is not always available for all buffers
   - use hashed ivpu_bo ptr as main buffer identifier
   - remove unused fields from ivpu_bo_print_info()

Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH v2 7/9] accel/ivpu: Disable buffer sharing among VPU contexts

2024-01-26 Thread Jeffrey Hugo

On 1/15/2024 6:44 AM, Jacek Lawrynowicz wrote:

This was not supported properly. A buffer was imported to another VPU
context as a separate buffer object with duplicated sgt.
Both exported and imported buffers could be DMA mapped causing a double
mapping on the same device.

Buffers imported from another VPU context will now just increase
reference count, leaving only a single sgt, fixing the problem above.
Buffers still can't be shared among VPU contexts because each has its
own MMU mapping and ivpu_bo only supports single MMU mappings.

The solution would be to use a mapping list as in panfrost or etnaviv
drivers and it will be implemented in future if required.

Signed-off-by: Jacek Lawrynowicz 


Reviewed-by: Jeffrey Hugo 


Re: [PATCH RFC for upstream 2/4] drm/panel: simple: Add EDT ETML1010G3DRA panel

2024-01-26 Thread Jessica Zhang




On 1/26/2024 12:57 AM, Yannic Moog wrote:

From: Primoz Fiser 

Add support for the EDT ETML1010G3DRA 10.1" 1280x800 LVDS panel.
Datasheet can be found at [1].

[1] 
https://www.glynshop.com/erp/owweb/Daten/DSS/EDT/Products/Specifications/Active%20Displays/ETML1010G3DRA%20Ver.3-RoHS.pdf

Signed-off-by: Primoz Fiser 
Signed-off-by: Yannic Moog 


Hi Yannic,

Reviewed-by: Jessica Zhang 

Thanks,

Jessica Zhang


---
  drivers/gpu/drm/panel/panel-simple.c | 30 ++
  1 file changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c 
b/drivers/gpu/drm/panel/panel-simple.c
index 9367a4572dcf..662cf8d10a8a 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1920,6 +1920,33 @@ static const struct panel_desc edt_etml0700y5dha = {
.connector_type = DRM_MODE_CONNECTOR_LVDS,
  };
  
+static const struct display_timing edt_etml1010g3dra_timing = {

+   .pixelclock = { 6630, 7240, 7890 },
+   .hactive = { 1280, 1280, 1280 },
+   .hfront_porch = { 12, 72, 132 },
+   .hback_porch = { 86, 86, 86 },
+   .hsync_len = { 2, 2, 2 },
+   .vactive = { 800, 800, 800 },
+   .vfront_porch = { 1, 15, 49 },
+   .vback_porch = { 21, 21, 21 },
+   .vsync_len = { 2, 2, 2 },
+   .flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW |
+DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc edt_etml1010g3dra = {
+   .timings = _etml1010g3dra_timing,
+   .num_timings = 1,
+   .bpc = 8,
+   .size = {
+   .width = 216,
+   .height = 135,
+   },
+   .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+   .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+   .connector_type = DRM_MODE_CONNECTOR_LVDS,
+};
+
  static const struct drm_display_mode edt_etmv570g2dhu_mode = {
.clock = 25175,
.hdisplay = 640,
@@ -4328,6 +4355,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "edt,etml0700y5dha",
.data = _etml0700y5dha,
+   }, {
+   .compatible = "edt,etml1010g3dra",
+   .data = _etml1010g3dra,
}, {
.compatible = "edt,etmv570g2dhu",
.data = _etmv570g2dhu,

--
2.34.1



[RFC PATCH 0/2] drm/amd/display: switch amdgpu_dm_connector to

2024-01-26 Thread Melissa Wen
Hi,

I'm debugging a null-pointer dereference when running
igt@kms_connector_force_edid and the way I found to solve the bug is to
stop using raw edid handler in amdgpu_connector_funcs_force and
create_eml_sink in favor of managing resouces via sruct drm_edid helpers
(Patch 1). The proper solution seems to be switch amdgpu_dm_connector
from struct edid to struct drm_edid and avoid the usage of different
approaches in the driver (Patch 2). However, doing it implies a good
amount of work and validation, therefore I decided to send this RFC
first to collect opinions and check if there is any parallel work on
this side. It's a working in progress.

The null-pointer error trigger by the igt@kms_connector_force_edid test
was introduced by:
- e54ed41620f ("drm/amd/display: Remove unwanted drm edid references")

You can check the error trace in the first patch.

This series was tested with kms_hdmi_inject and kms_force_connector. No
null-pointer error, kms_hdmi_inject is successul and kms_force_connector
is sucessful after the second execution - the force-edid subtest
still fails in the first run (I'm still investigating).

There is also a couple of cast warnings to be addressed - I'm looking
for the best replacement. 

I appreciate any feedback and testing.

Melissa

Melissa Wen (2):
  drm/amd/display: fix null-pointer dereference on edid reading
  drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 78 ++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 ++-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++---
 4 files changed, 60 insertions(+), 54 deletions(-)

-- 
2.43.0



[RFC PATCH 2/2] drm/amd/display: switch amdgpu_dm_connector to use struct drm_edid

2024-01-26 Thread Melissa Wen
Replace raw edid handling (struct edid) with the opaque EDID type
(struct drm_edid) on amdgpu_dm_connector for consistency. It may also
prevent mismatch of approaches in different parts of the driver code.
Working in progress. There are a couple of cast warnings and it was only
tested with IGT.

Signed-off-by: Melissa Wen 
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 63 ++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  9 +--
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 23 +++
 4 files changed, 51 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 68e71e2ea472..741081d73bb3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3277,12 +3277,12 @@ void amdgpu_dm_update_connector_after_detect(
>dm_dp_aux.aux);
}
} else {
-   aconnector->edid =
-   (struct edid *)sink->dc_edid.raw_edid;
+   const struct edid *edid = (const struct edid 
*)sink->dc_edid.raw_edid;
+   aconnector->edid = drm_edid_alloc(edid, 
(edid->extensions + 1) * EDID_LENGTH);
 
if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(>dm_dp_aux.aux,
-   aconnector->edid);
+   
drm_edid_raw(aconnector->edid));
}
 
if (!aconnector->timing_requested) {
@@ -3293,13 +3293,13 @@ void amdgpu_dm_update_connector_after_detect(
"failed to create 
aconnector->requested_timing\n");
}
 
-   drm_connector_update_edid_property(connector, aconnector->edid);
+   drm_edid_connector_update(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
drm_dp_cec_unset_edid(>dm_dp_aux.aux);
amdgpu_dm_update_freesync_caps(connector, NULL);
-   drm_connector_update_edid_property(connector, NULL);
+   drm_edid_connector_update(connector, NULL);
aconnector->num_modes = 0;
dc_sink_release(aconnector->dc_sink);
aconnector->dc_sink = NULL;
@@ -6564,7 +6564,6 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
struct dc_link *dc_link = aconnector->dc_link;
struct dc_sink *dc_em_sink = aconnector->dc_em_sink;
const struct drm_edid *drm_edid;
-   const struct edid *edid;
 
/*
 * Note: drm_get_edid gets edid in the following order:
@@ -6578,11 +6577,12 @@ static void amdgpu_dm_connector_funcs_force(struct 
drm_connector *connector)
DRM_ERROR("No EDID found on connector: %s.\n", connector->name);
return;
}
-   edid = drm_edid_raw(drm_edid);
-   aconnector->edid = edid;
-
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
/* Update emulated (virtual) sink's EDID */
if (dc_em_sink && dc_link) {
+   const struct edid *edid = drm_edid_raw(drm_edid);
+
memset(_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps));
memmove(dc_em_sink->dc_edid.raw_edid, (uint8_t *)edid, 
(edid->extensions + 1) * EDID_LENGTH);
dm_helpers_parse_edid_caps(
@@ -6633,13 +6633,13 @@ static void create_eml_sink(struct amdgpu_dm_connector 
*aconnector)
return;
}
 
-   edid = drm_edid_raw(drm_edid);
-
-   if (drm_detect_hdmi_monitor(edid))
+   if (connector->display_info.is_hdmi)
init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A;
 
-   aconnector->edid = edid;
+   aconnector->edid = drm_edid;
+   drm_edid_connector_update(connector, drm_edid);
 
+   edid = drm_edid_raw(drm_edid);
aconnector->dc_em_sink = dc_link_add_remote_sink(
aconnector->dc_link,
(uint8_t *)edid,
@@ -7322,16 +7322,16 @@ static void amdgpu_set_panel_orientation(struct 
drm_connector *connector)
 }
 
 static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
- struct edid *edid)
+ const struct drm_edid *drm_edid)
 {
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
 
-   if (edid) {
+   if (drm_edid) {
/* empty probed_modes */
INIT_LIST_HEAD(>probed_modes);

[RFC PATCH 1/2] drm/amd/display: fix null-pointer dereference on edid reading

2024-01-26 Thread Melissa Wen
Use drm_edid helpers to fix a null-pointer derefence that happens when
running igt@kms_force_connector_basic in a system with DCN2.1 and HDMI
connector detected as below:

[  +0.178146] BUG: kernel NULL pointer dereference, address: 04c0
[  +0.10] #PF: supervisor read access in kernel mode
[  +0.05] #PF: error_code(0x) - not-present page
[  +0.04] PGD 0 P4D 0
[  +0.06] Oops:  [#1] PREEMPT SMP NOPTI
[  +0.06] CPU: 15 PID: 2368 Comm: kms_force_conne Not tainted 6.5.0-asdn+ 
#152
[  +0.05] Hardware name: HP HP ENVY x360 Convertible 13-ay1xxx/8929, BIOS 
F.01 07/14/2021
[  +0.04] RIP: 0010:i2c_transfer+0xd/0x100
[  +0.11] Code: ea fc ff ff 66 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 
90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 41 54 55 53 <48> 8b 47 10 
48 89 fb 48 83 38 00 0f 84 b3 00 00 00 83 3d 2f 80 16
[  +0.04] RSP: 0018:9c4f89c0fad0 EFLAGS: 00010246
[  +0.05] RAX:  RBX: 0005 RCX: 0080
[  +0.03] RDX: 0002 RSI: 9c4f89c0fb20 RDI: 04b0
[  +0.03] RBP: 9c4f89c0fb80 R08: 0080 R09: 8d8e0b15b980
[  +0.03] R10: 000380e0 R11:  R12: 0080
[  +0.02] R13: 0002 R14: 9c4f89c0fb0e R15: 9c4f89c0fb0f
[  +0.04] FS:  7f9ad2176c40() GS:8d90fe9c() 
knlGS:
[  +0.03] CS:  0010 DS:  ES:  CR0: 80050033
[  +0.04] CR2: 04c0 CR3: 000121bc4000 CR4: 00750ee0
[  +0.03] PKRU: 5554
[  +0.03] Call Trace:
[  +0.06]  
[  +0.06]  ? __die+0x23/0x70
[  +0.11]  ? page_fault_oops+0x17d/0x4c0
[  +0.08]  ? preempt_count_add+0x6e/0xa0
[  +0.08]  ? srso_alias_return_thunk+0x5/0x7f
[  +0.11]  ? exc_page_fault+0x7f/0x180
[  +0.09]  ? asm_exc_page_fault+0x26/0x30
[  +0.13]  ? i2c_transfer+0xd/0x100
[  +0.10]  drm_do_probe_ddc_edid+0xc2/0x140 [drm]
[  +0.67]  ? srso_alias_return_thunk+0x5/0x7f
[  +0.06]  ? _drm_do_get_edid+0x97/0x3c0 [drm]
[  +0.43]  ? __pfx_drm_do_probe_ddc_edid+0x10/0x10 [drm]
[  +0.42]  edid_block_read+0x3b/0xd0 [drm]
[  +0.43]  _drm_do_get_edid+0xb6/0x3c0 [drm]
[  +0.41]  ? __pfx_drm_do_probe_ddc_edid+0x10/0x10 [drm]
[  +0.43]  drm_edid_read_custom+0x37/0xd0 [drm]
[  +0.44]  amdgpu_dm_connector_mode_valid+0x129/0x1d0 [amdgpu]
[  +0.000153]  drm_connector_mode_valid+0x3b/0x60 [drm_kms_helper]
[  +0.00]  __drm_helper_update_and_validate+0xfe/0x3c0 [drm_kms_helper]
[  +0.00]  ? amdgpu_dm_connector_get_modes+0xb6/0x520 [amdgpu]
[  +0.00]  ? srso_alias_return_thunk+0x5/0x7f
[  +0.00]  drm_helper_probe_single_connector_modes+0x2ab/0x540 
[drm_kms_helper]
[  +0.00]  status_store+0xb2/0x1f0 [drm]
[  +0.00]  kernfs_fop_write_iter+0x136/0x1d0
[  +0.00]  vfs_write+0x24d/0x440
[  +0.00]  ksys_write+0x6f/0xf0
[  +0.00]  do_syscall_64+0x60/0xc0
[  +0.00]  ? srso_alias_return_thunk+0x5/0x7f
[  +0.00]  ? syscall_exit_to_user_mode+0x2b/0x40
[  +0.00]  ? srso_alias_return_thunk+0x5/0x7f
[  +0.00]  ? do_syscall_64+0x6c/0xc0
[  +0.00]  ? do_syscall_64+0x6c/0xc0
[  +0.00]  entry_SYSCALL_64_after_hwframe+0x6e/0xd8
[  +0.00] RIP: 0033:0x7f9ad46b4b00
[  +0.00] Code: 40 00 48 8b 15 19 b3 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff 
ff eb b7 0f 1f 00 80 3d e1 3a 0e 00 00 74 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 
ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 28 48 89
[  +0.00] RSP: 002b:7ffcbd3bd6d8 EFLAGS: 0202 ORIG_RAX: 
0001
[  +0.00] RAX: ffda RBX:  RCX: 7f9ad46b4b00
[  +0.00] RDX: 0002 RSI: 7f9ad48a7417 RDI: 0009
[  +0.00] RBP: 0002 R08: 0064 R09: 
[  +0.00] R10:  R11: 0202 R12: 7f9ad48a7417
[  +0.00] R13: 0009 R14: 7ffcbd3bd760 R15: 0001
[  +0.00]  
[  +0.00] Modules linked in: ctr ccm rfcomm snd_seq_dummy snd_hrtimer 
snd_seq snd_seq_device cmac algif_hash algif_skcipher af_alg bnep btusb btrtl 
btbcm btintel btmtk bluetooth uvcvideo videobuf2_vmalloc sha3_generic 
videobuf2_memops uvc jitterentropy_rng videobuf2_v4l2 videodev drbg 
videobuf2_common ansi_cprng mc ecdh_generic ecc qrtr binfmt_misc 
hid_sensor_accel_3d hid_sensor_magn_3d hid_sensor_gyro_3d hid_sensor_trigger 
industrialio_triggered_buffer kfifo_buf industrialio snd_ctl_led joydev 
hid_sensor_iio_common rtw89_8852ae rtw89_8852a rtw89_pci snd_hda_codec_realtek 
rtw89_core snd_hda_codec_generic intel_rapl_msr ledtrig_audio intel_rapl_common 
snd_hda_codec_hdmi mac80211 snd_hda_intel snd_intel_dspcfg kvm_amd 
snd_hda_codec snd_soc_dmic snd_acp3x_rn snd_acp3x_pdm_dma libarc4 snd_hwdep 
snd_soc_core kvm snd_hda_core cfg80211 snd_pci_acp6x snd_pcm nls_ascii 
snd_timer hp_wmi snd_pci_acp5x nls_cp437 snd_rn_pci_acp3x ucsi_acpi 

[PATCH] drm/etnaviv: fix DMA direction handling for cached read/write buffers

2024-01-26 Thread Lucas Stach
The dma sync operation needs to be done with DMA_BIDIRECTIONAL when
the BO is prepared for both read and write operations. With the
current inverted if ladder it would only be synced for DMA_FROM_DEVICE.

Fixes: a8c21a5451d8 ("drm/etnaviv: add initial etnaviv DRM driver")
Signed-off-by: Lucas Stach 
---
 drivers/gpu/drm/etnaviv/etnaviv_gem.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c 
b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index b5f73502e3dd..d788a27aacb8 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -356,12 +356,14 @@ static void *etnaviv_gem_vmap_impl(struct 
etnaviv_gem_object *obj)
 
 static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op)
 {
-   if (op & ETNA_PREP_READ)
+   if (op & (ETNA_PREP_READ | ETNA_PREP_WRITE))
+   return DMA_BIDIRECTIONAL;
+   else if (op & ETNA_PREP_READ)
return DMA_FROM_DEVICE;
else if (op & ETNA_PREP_WRITE)
return DMA_TO_DEVICE;
-   else
-   return DMA_BIDIRECTIONAL;
+
+   return DMA_NONE;
 }
 
 int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
-- 
2.39.2



[PATCH] drm/etnaviv: switch devcoredump allocations to GFP_NOWAIT

2024-01-26 Thread Lucas Stach
The etnaviv devcoredump is created in the GPU reset path, which
must make forward progress to avoid stalling memory reclaim on
unsignalled dma fences. The currently used __GFP_NORETRY does not
prohibit sleeping on direct reclaim, breaking the forward progress
guarantee. Switch to GFP_NOWAIT, which allows background reclaim
to be triggered, but avoids any stalls waiting for direct reclaim.

Signed-off-by: Lucas Stach 
---
 drivers/gpu/drm/etnaviv/etnaviv_dump.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c 
b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
index 898f84a0fc30c..42c5028872d54 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -159,8 +159,7 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit)
file_size += sizeof(*iter.hdr) * n_obj;
 
/* Allocate the file in vmalloc memory, it's likely to be big */
-   iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
-   __GFP_NORETRY);
+   iter.start = __vmalloc(file_size, GFP_NOWAIT | __GFP_NOWARN);
if (!iter.start) {
mutex_unlock(>mmu_context->lock);
dev_warn(gpu->dev, "failed to allocate devcoredump file\n");
@@ -230,5 +229,6 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit)
 
etnaviv_core_dump_header(, ETDUMP_BUF_END, iter.data);
 
-   dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL);
+   dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start,
+ GFP_NOWAIT | __GFP_NOWARN);
 }
-- 
2.41.0



Re: [PATCH v19 09/30] drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages()

2024-01-26 Thread Dmitry Osipenko
On 1/26/24 13:18, Boris Brezillon wrote:
> On Thu, 25 Jan 2024 18:24:04 +0100
> Daniel Vetter  wrote:
> 
>> On Fri, Jan 05, 2024 at 09:46:03PM +0300, Dmitry Osipenko wrote:
>>> Add lockless drm_gem_shmem_get_pages() helper that skips taking reservation
>>> lock if pages_use_count is non-zero, leveraging from atomicity of the
>>> refcount_t. Make drm_gem_shmem_mmap() to utilize the new helper.
>>>
>>> Acked-by: Maxime Ripard 
>>> Reviewed-by: Boris Brezillon 
>>> Suggested-by: Boris Brezillon 
>>> Signed-off-by: Dmitry Osipenko 
>>> ---
>>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 19 +++
>>>  1 file changed, 15 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c 
>>> b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>> index cacf0f8c42e2..1c032513abf1 100644
>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>> @@ -226,6 +226,20 @@ void drm_gem_shmem_put_pages_locked(struct 
>>> drm_gem_shmem_object *shmem)
>>>  }
>>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked);
>>>  
>>> +static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
>>> +{
>>> +   int ret;  
>>
>> Just random drive-by comment: a might_lock annotation here might be good,
>> or people could hit some really interesting bugs that are rather hard to
>> reproduce ...
> 
> Actually, being able to acquire a ref in a dma-signalling path on an
> object we know for sure already has refcount >= 1 (because we previously
> acquired a ref in a path where dma_resv_lock() was allowed), was the
> primary reason I suggested moving to this atomic-refcount approach.
> 
> In the meantime, drm_gpuvm has evolved in a way that allows me to not
> take the ref in the dma-signalling path (the gpuvm_bo object now holds
> the ref, and it's acquired/released outside the dma-signalling path).
> 
> Not saying we shouldn't add this might_lock(), but others might have
> good reasons to have this function called in a path where locking
> is not allowed.

For Panthor the might_lock indeed won't be a appropriate, thanks for
reminding about it. I'll add explanatory comment to the code.

-- 
Best regards,
Dmitry



Re: [Linaro-mm-sig] [PATCH v5 1/6] dma-buf: Add dma_buf_{begin,end}_access()

2024-01-26 Thread Christian König

Am 25.01.24 um 19:01 schrieb Daniel Vetter:

On Thu, Jan 25, 2024 at 04:00:16PM +0100, Christian König wrote:

Am 24.01.24 um 11:58 schrieb Paul Cercueil:

[SNIP]

The problem was then that dma_buf_unmap_attachment cannot be called
before the dma_fence is signaled, and calling it after is already
too
late (because the fence would be signaled before the data is
sync'd).

   Well what sync are you talking about? CPU sync? In DMA-buf that is
handled differently.
   For importers it's mandatory that they can be coherent with the
exporter. That usually means they can snoop the CPU cache if the
exporter can snoop the CPU cache.

I seem to have such a system where one device can snoop the CPU cache
and the other cannot. Therefore if I want to support it properly, I do
need cache flush/sync. I don't actually try to access the data using
the CPU (and when I do, I call the sync start/end ioctls).

Usually that isn't a problem as long as you don't access the data with the
CPU.

[SNIP]


(and I *think* there is a way to force coherency in the
Ultrascale's
interconnect - we're investigating it)

   What you can do is that instead of using udmabuf or dma-heaps is
that the device which can't provide coherency act as exporters of the
buffers.
   The exporter is allowed to call sync_for_cpu/sync_for_device on it's
own buffers and also gets begin/end CPU access notfications. So you
can then handle coherency between the exporter and the CPU.

But again that would only work if the importers would call
begin_cpu_access() / end_cpu_access(), which they don't, because they
don't actually access the data using the CPU.

Wow, that is a completely new use case then.

Neither DMA-buf nor the DMA subsystem in Linux actually supports this as far
as I can see.


Unless you mean that the exporter can call sync_for_cpu/sync_for_device
before/after every single DMA transfer so that the data appears
coherent to the importers, without them having to call
begin_cpu_access() / end_cpu_access().

Yeah, I mean the importers don't have to call begin_cpu_access() /
end_cpu_access() if they don't do CPU access :)

What you can still do as exporter is to call sync_for_device() and
sync_for_cpu() before and after each operation on your non-coherent device.
Paired with the fence signaling that should still work fine then.

But taking a step back, this use case is not something even the low level
DMA subsystem supports. That sync_for_cpu() does the right thing is
coincident and not proper engineering.

What you need is a sync_device_to_device() which does the appropriate
actions depending on which devices are involved.


In which case - this would still demultiply the complexity; my USB-
functionfs interface here (and IIO interface in the separate patchset)
are not device-specific, so I'd rather keep them importers.

   If you really don't have coherency between devices then that would
be a really new use case and we would need much more agreement on how
to do this.

[snip]

Agreed. Desiging a good generic solution would be better.

With that said...

Let's keep it out of this USB-functionfs interface for now. The
interface does work perfectly fine on platforms that don't have
coherency problems. The coherency issue in itself really is a
tangential issue.

Yeah, completely agree.


So I will send a v6 where I don't try to force the cache coherency -
and instead assume that the attached devices are coherent between
themselves.

But it would be even better to have a way to detect non-coherency and
return an error on attach.

Take a look into the DMA subsystem. I'm pretty sure we already have
something like this in there.

If nothing else helps you could take a look if the coherent memory access
mask is non zero or something like that.

Jumping in way late and apolgies to everyone since yes I indeed suggested
this entire mess to Paul in some private thread.

And worse, I think we need it, it's just that we got away without it thus
far.

So way back at the og dma-buf kick-off dma coherency was discussed, and a
few things where noted:
- the dma api only supports device<->cpu coherency
- getting the full coherency model off the ground right away is probably
   too hard, so we made the decision that where it matters, relevant
   flushing needs to be done in dma_buf_map/unmap.

If you look at the earliest patches for dma-buf we had pretty clear
language that all dma-operations should be bracketed with map/unmap. Of
course that didn't work out for drm at all, and we had to first get
dma_resv_lock and dma_fence landed and then your dynamic exporter/importer
support in just to get the buffer migration functionality working, which
was only one of the things discussed that braketing everything with
map/unmap was supposed to take care of.

The other was coherency management. But looking through archives I think
this was already agreed to be postponed for later in the original kick-off
meeting and never further discussed on the mailing list.

This worked for a 

Re: [PATCH] drm/sched: Drain all entities in DRM sched run job worker

2024-01-26 Thread Matthew Brost
On Fri, Jan 26, 2024 at 11:32:57AM +0100, Christian König wrote:
> Am 25.01.24 um 18:30 schrieb Matthew Brost:
> > On Thu, Jan 25, 2024 at 04:12:58PM +0100, Christian König wrote:
> > > 
> > > Am 24.01.24 um 22:08 schrieb Matthew Brost:
> > > > All entities must be drained in the DRM scheduler run job worker to
> > > > avoid the following case. An entity found that is ready, no job found
> > > > ready on entity, and run job worker goes idle with other entities + jobs
> > > > ready. Draining all ready entities (i.e. loop over all ready entities)
> > > > in the run job worker ensures all job that are ready will be scheduled.
> > > That doesn't make sense. drm_sched_select_entity() only returns entities
> > > which are "ready", e.g. have a job to run.
> > > 
> > That is what I thought too, hence my original design but it is not
> > exactly true. Let me explain.
> > 
> > drm_sched_select_entity() returns an entity with a non-empty spsc queue
> > (job in queue) and no *current* waiting dependecies [1]. Dependecies for
> > an entity can be added when drm_sched_entity_pop_job() is called [2][3]
> > returning a NULL job. Thus we can get into a scenario where 2 entities
> > A and B both have jobs and no current dependecies. A's job is waiting
> > B's job, entity A gets selected first, a dependecy gets installed in
> > drm_sched_entity_pop_job(), run work goes idle, and now we deadlock.
> 
> And here is the real problem. run work doesn't goes idle in that moment.
> 
> drm_sched_run_job_work() should restarts itself until there is either no
> more space in the ring buffer or it can't find a ready entity any more.
> 
> At least that was the original design when that was all still driven by a
> kthread.
> 
> It can perfectly be that we messed this up when switching from kthread to a
> work item.
> 

Right, that what this patch does - the run worker does not go idle until
no ready entities are found. That was incorrect in the original patch
and fixed here. Do you have any issues with this fix? It has been tested
3x times and clearly fixes the issue. 

Matt

> Regards,
> Christian.
> 
> > 
> > The proper solution is to loop over all ready entities until one with a
> > job is found via drm_sched_entity_pop_job() and then requeue the run
> > job worker. Or loop over all entities until drm_sched_select_entity()
> > returns NULL and then let the run job worker go idle. This is what the
> > old threaded design did too [4]. Hope this clears everything up.
> > 
> > Matt
> > 
> > [1] 
> > https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/scheduler/sched_entity.c#L144
> > [2] 
> > https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/scheduler/sched_entity.c#L464
> > [3] 
> > https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/scheduler/sched_entity.c#L397
> > [4] 
> > https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/scheduler/sched_main.c#L1011
> > 
> > > If that's not the case any more then you have broken something else.
> > > 
> > > Regards,
> > > Christian.
> > > 
> > > > Cc: Thorsten Leemhuis 
> > > > Reported-by: Mikhail Gavrilov 
> > > > Closes: 
> > > > https://lore.kernel.org/all/CABXGCsM2VLs489CH-vF-1539-s3in37=bwuowtoeee+q26z...@mail.gmail.com/
> > > > Reported-and-tested-by: Mario Limonciello 
> > > > Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3124
> > > > Link: 
> > > > https://lore.kernel.org/all/20240123021155.2775-1-mario.limoncie...@amd.com/
> > > > Reported-by: Vlastimil Babka 
> > > > Closes: 
> > > > https://lore.kernel.org/dri-devel/05ddb2da-b182-4791-8ef7-82179fd15...@amd.com/T/#m0c31d4d1b9ae9995bb880974c4f1dbaddc33a48a
> > > > Signed-off-by: Matthew Brost 
> > > > ---
> > > >drivers/gpu/drm/scheduler/sched_main.c | 15 +++
> > > >1 file changed, 7 insertions(+), 8 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/scheduler/sched_main.c 
> > > > b/drivers/gpu/drm/scheduler/sched_main.c
> > > > index 550492a7a031..85f082396d42 100644
> > > > --- a/drivers/gpu/drm/scheduler/sched_main.c
> > > > +++ b/drivers/gpu/drm/scheduler/sched_main.c
> > > > @@ -1178,21 +1178,20 @@ static void drm_sched_run_job_work(struct 
> > > > work_struct *w)
> > > > struct drm_sched_entity *entity;
> > > > struct dma_fence *fence;
> > > > struct drm_sched_fence *s_fence;
> > > > -   struct drm_sched_job *sched_job;
> > > > +   struct drm_sched_job *sched_job = NULL;
> > > > int r;
> > > > if (READ_ONCE(sched->pause_submit))
> > > > return;
> > > > -   entity = drm_sched_select_entity(sched);
> > > > +   /* Find entity with a ready job */
> > > > +   while (!sched_job && (entity = drm_sched_select_entity(sched))) 
> > > > {
> > > > +   sched_job = drm_sched_entity_pop_job(entity);
> > > > +   if (!sched_job)
> > > > +   complete_all(>entity_idle);
> > > > +   }
> > > > if (!entity)
> > > > -   return;
> 

Re: [PATCH v19 22/30] drm/shmem-helper: Add common memory shrinker

2024-01-26 Thread Dmitry Osipenko
On 1/26/24 12:55, Boris Brezillon wrote:
> On Fri, 26 Jan 2024 00:56:47 +0300
> Dmitry Osipenko  wrote:
> 
>> On 1/25/24 13:19, Boris Brezillon wrote:
>>> On Fri,  5 Jan 2024 21:46:16 +0300
>>> Dmitry Osipenko  wrote:
>>>   
 +static bool drm_gem_shmem_is_evictable(struct drm_gem_shmem_object *shmem)
 +{
 +  return (shmem->madv >= 0) && shmem->base.funcs->evict &&
 +  refcount_read(>pages_use_count) &&
 +  !refcount_read(>pages_pin_count) &&
 +  !shmem->base.dma_buf && !shmem->base.import_attach &&
 +  !shmem->evicted;  
>>>
>>> Are we missing
>>>
>>> && dma_resv_test_signaled(shmem->base.resv,
>>>   DMA_RESV_USAGE_BOOKKEEP)
>>>
>>> to make sure the GPU is done using the BO?
>>> The same applies to drm_gem_shmem_is_purgeable() BTW.
>>>
>>> If you don't want to do this test here, we need a way to let drivers
>>> provide a custom is_{evictable,purgeable}() test.
>>>
>>> I guess we should also expose drm_gem_shmem_shrinker_update_lru_locked()
>>> to let drivers move the GEMs that were used most recently (those
>>> referenced by a GPU job) at the end of the evictable LRU.  
>>
>> We have the signaled-check in the common drm_gem_evict() helper:
>>
>> https://elixir.bootlin.com/linux/v6.8-rc1/source/drivers/gpu/drm/drm_gem.c#L1496
> 
> Ah, indeed. I'll need DMA_RESV_USAGE_BOOKKEEP instead of
> DMA_RESV_USAGE_READ in panthor, but I can add it in the driver specific
> ->evict() hook (though that means calling dma_resv_test_signaled()
> twice, which is not great, oh well).

Maybe we should change drm_gem_evict() to use BOOKKEEP. The
test_signaled(BOOKKEEP) should be a "stronger" check than
test_signaled(READ)?

> The problem about the evictable LRU remains though: we need a way to let
> drivers put their BOs at the end of the list when the BO has been used
> by the GPU, don't we?

If BO is use, then it won't be evicted, while idling BOs will be
evicted. Hence, the used BOs will be naturally moved down the LRU list
each time shrinker is invoked.

-- 
Best regards,
Dmitry




Re: [PATCH RFC for upstream 1/4] dt-bindings: display: panel-simple: add ETML1010G3DRA

2024-01-26 Thread Conor Dooley
Hey,

On Fri, Jan 26, 2024 at 09:57:23AM +0100, Yannic Moog wrote:
> Add Emerging Display Technology Corp. etml1010g3dra 10.1" LCD-TFT LVDS
> panel compatible string.
> 
> Signed-off-by: Yannic Moog 

> [PATCH RFC for upstream 1/4]

The "for upstream" here is not really relevant, what else would the
patch be for?

Acked-by: Conor Dooley 

Thanks,
Conor.


> ---
>  Documentation/devicetree/bindings/display/panel/panel-simple.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git 
> a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml 
> b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> index 11422af3477e..b6bbdb3dd2b2 100644
> --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> @@ -139,6 +139,8 @@ properties:
>- edt,etm0700g0edh6
>  # Emerging Display Technology Corp. LVDS WSVGA TFT Display with 
> capacitive touch
>- edt,etml0700y5dha
> +# Emerging Display Technology Corp. 10.1" LVDS WXGA TFT Display with 
> capacitive touch
> +  - edt,etml1010g3dra
>  # Emerging Display Technology Corp. 5.7" VGA TFT LCD panel with
>  # capacitive touch
>- edt,etmv570g2dhu
> 
> -- 
> 2.34.1
> 


signature.asc
Description: PGP signature


[PATCH v4 6/8] drm/amd/display: Introduce KUnit tests for dcn20_fpu

2024-01-26 Thread Rodrigo Siqueira
From: Magali Lemes 

This commit adds unit tests to the functions dcn20_cap_soc_clocks and
dcn21_update_bw_bounding_box from dcn20/dcn20_fpu.

Signed-off-by: Magali Lemes 
Signed-off-by: Maíra Canal 
---
 drivers/gpu/drm/amd/display/tests/Makefile|   3 +-
 .../tests/dc/dml/dcn20/dcn20_fpu_test.c   | 561 ++
 2 files changed, 563 insertions(+), 1 deletion(-)
 create mode 100644 
drivers/gpu/drm/amd/display/tests/dc/dml/dcn20/dcn20_fpu_test.c

diff --git a/drivers/gpu/drm/amd/display/tests/Makefile 
b/drivers/gpu/drm/amd/display/tests/Makefile
index cc1e9edd38c3..a34677808e48 100644
--- a/drivers/gpu/drm/amd/display/tests/Makefile
+++ b/drivers/gpu/drm/amd/display/tests/Makefile
@@ -9,7 +9,8 @@ endif
 
 ifdef CONFIG_DML_KUNIT_TEST
CFLAGS_$(AMDDALPATH)/tests/dc/dml/display_mode_vba_test.o := 
$(dml_ccflags)
-   DC_TESTS += dc/dml/display_mode_vba_test.o
+   CFLAGS_$(AMDDALPATH)/tests/dc/dml/dcn20/dcn20_fpu_test.o := 
$(dml_ccflags)
+   DC_TESTS += dc/dml/display_mode_vba_test.o dc/dml/dcn20/dcn20_fpu_test.o
 endif
 
 AMD_DAL_DC_TESTS = $(addprefix $(AMDDALPATH)/tests/,$(DC_TESTS))
diff --git a/drivers/gpu/drm/amd/display/tests/dc/dml/dcn20/dcn20_fpu_test.c 
b/drivers/gpu/drm/amd/display/tests/dc/dml/dcn20/dcn20_fpu_test.c
new file mode 100644
index ..6b7ebb78fec9
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/tests/dc/dml/dcn20/dcn20_fpu_test.c
@@ -0,0 +1,561 @@
+// SPDX-License-Identifier: MIT
+/*
+ * KUnit tests for dml/dcn20/dcn20_fpu.h
+ *
+ * Copyright (C) 2022, Magali Lemes 
+ */
+
+#include 
+
+#include "dc/inc/resource.h"
+#include "dc/inc/hw/clk_mgr.h"
+#include "dc/dcn21/dcn21_resource.h"
+
+#include "dml/dcn20/dcn20_fpu.h"
+
+/**
+ * DOC: Unit tests for AMDGPU DML dcn20/dcn20_fpu.h
+ */
+
+struct dcn20_cap_soc_clocks_test_case {
+   const char *desc;
+   struct _vcs_dpi_soc_bounding_box_st bb;
+   struct pp_smu_nv_clock_table max_clocks;
+   const int clock_states;
+   const struct _vcs_dpi_voltage_scaling_st 
expected_clock_limits[DC__VOLTAGE_STATES];
+};
+
+struct dcn21_update_bw_bounding_box_test_case {
+   const char *desc;
+   struct dc dc;
+   struct clk_bw_params bw_params;
+   const int clocks_to_compare;
+   const struct _vcs_dpi_voltage_scaling_st 
expected_clock_limits[DC__VOLTAGE_STATES];
+};
+
+struct dcn20_cap_soc_clocks_test_case dcn20_cap_soc_clocks_test_cases[] = {
+   {
+   .desc = "4-state bounding box clock limits ",
+   .bb = {
+   .clock_limits = {
+   {
+   .dcfclk_mhz = 506.0,
+   .fabricclk_mhz = 506.0,
+   .dispclk_mhz = 1284.0,
+   .dppclk_mhz = 400.0,
+   .phyclk_mhz = 810.0,
+   .socclk_mhz = 506.0,
+   .dscclk_mhz = 428.0,
+   .dram_speed_mts = 1600.0,
+   },
+   {
+   .dcfclk_mhz = 540.0,
+   .fabricclk_mhz = 540.0,
+   .dispclk_mhz = 1284.0,
+   .dppclk_mhz = 1284.0,
+   .phyclk_mhz = 810.0,
+   .socclk_mhz = 540.0,
+   .dscclk_mhz = 428.0,
+   .dram_speed_mts = 8000.0,
+   },
+   {
+   .dcfclk_mhz = 675.0,
+   .fabricclk_mhz = 675.0,
+   .dispclk_mhz = 1284.0,
+   .dppclk_mhz = 1284.0,
+   .phyclk_mhz = 810.0,
+   .socclk_mhz = 675.0,
+   .dscclk_mhz = 428.0,
+   .dram_speed_mts = 1.0,
+   },
+   {
+   .dcfclk_mhz = 1265.0,
+   .fabricclk_mhz = 1266.0,
+   .dispclk_mhz = 1284.0,
+   .dppclk_mhz = 1284.0,
+   .phyclk_mhz = 810.0,
+   .socclk_mhz = 1266.0,
+   .dscclk_mhz = 428.0,
+   .dram_speed_mts = 15000.0,
+   },
+   },
+   .num_states = 4,
+   },
+   .max_clocks = {
+   .dcfClockInKhz 

[PATCH v4 8/8] Documentation/gpu: Add Display Core Unit Test documentation

2024-01-26 Thread Rodrigo Siqueira
From: Maíra Canal 

Explain how to run the KUnit tests present in the AMDGPU's Display
Core and clarify which architectures and tools can be used to run
the tests. Moreover, explains how to add new tests to the existing
tests.

Signed-off-by: Maíra Canal 
---
 .../gpu/amdgpu/display/display-test.rst   | 88 +++
 Documentation/gpu/amdgpu/display/index.rst|  1 +
 2 files changed, 89 insertions(+)
 create mode 100644 Documentation/gpu/amdgpu/display/display-test.rst

diff --git a/Documentation/gpu/amdgpu/display/display-test.rst 
b/Documentation/gpu/amdgpu/display/display-test.rst
new file mode 100644
index ..a8c136ce87b7
--- /dev/null
+++ b/Documentation/gpu/amdgpu/display/display-test.rst
@@ -0,0 +1,88 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+
+Display Core Unit Tests
+
+
+Display core provides a set of unit tests, currently focused on the Display 
Mode
+Library. The unit tests use KUnit (Kernel Unit Testing Framework), a common
+framework for unit tests within the Linux Kernel.
+
+This section covers the specifics of the tests for the AMDGPU driver. For 
general
+information about KUnit, please refer to 
Documentation/dev-tools/kunit/start.rst.
+
+How to run the tests?
+=
+
+In order to facilitate running the test suite, a configuration file is present
+in ``drivers/gpu/drm/amd/display/tests/dc/.kunitconfig``. This configuration 
file
+can be used to run the kunit_tool, a Python script 
(``tools/testing/kunit/kunit.py``)
+used to configure, build, exec, parse and run tests.
+
+.. code-block:: bash
+
+   $ ./tools/testing/kunit/kunit.py run --arch=x86_64 \
+   --kunitconfig=drivers/gpu/drm/amd/display/tests
+
+Currently, the Display Core Unit Tests are only supported on x86_64.
+
+Moreover, the tests can also be run on real hardware or in other emulation
+environments. To include the Display Core Unit Tests on a deployable kernel,
+you might add the following config options to your ``.config``:
+
+.. code-block:: none
+
+   CONFIG_KUNIT=y
+   CONFIG_AMDGPU=m
+   CONFIG_AMD_DC_BASICS_KUNIT_TEST=y
+   CONFIG_AMD_DC_KUNIT_TEST=y
+   CONFIG_DCE_KUNIT_TEST=y
+   CONFIG_DML_KUNIT_TEST=y
+
+Once the kernel is built and installed, you can load the ``amdgpu`` module
+to run all tests available.
+
+Also, the tests can be added to the kernel as built-in modules, by adding the
+following config options to your ``.config``:
+
+.. code-block:: none
+
+   CONFIG_KUNIT=y
+   CONFIG_AMDGPU=y
+   CONFIG_AMD_DC_BASICS_KUNIT_TEST=y
+   CONFIG_AMD_DC_KUNIT_TEST=y
+   CONFIG_DCE_KUNIT_TEST=y
+   CONFIG_DML_KUNIT_TEST=y
+
+In order to run specific tests, you can check the filter options from KUnit on
+Documentation/dev-tools/kunit/kunit-tool.rst.
+
+How to add new tests?
+=
+
+Tests covering different parts of the Display Core are always welcomed. Adding
+a new test is a simple procedure, that consists in creating a unit test file
+and adding the following guard to the end of the tested file when you are
+testing static functions:
+
+.. code-block:: c
+
+   #ifdef CONFIG_MY_KUNIT_TEST
+   #include "my_kunit_test.c"
+   #endif
+
+If you are not testing static functions, you should use the Makefile placed on
+``display/tests``. In order to add a test to the Makefile, you can just add
+the following entry to the Makefile:
+
+.. code-block:: make
+
+   ifdef CONFIG_MY_KUNIT_TEST
+   DC_TESTS += my_kunit_test.o
+   endif
+
+The ``display/tests`` folder replicates the folder hierarchy of the ``display``
+folder, so this must be considered while adding new tests.
+
+More information on how to write unit tests with the KUnit API can be provided
+on Documentation/dev-tools/kunit/api/test.rst.
diff --git a/Documentation/gpu/amdgpu/display/index.rst 
b/Documentation/gpu/amdgpu/display/index.rst
index f8a4f53d70d8..9b13f0f3524f 100644
--- a/Documentation/gpu/amdgpu/display/index.rst
+++ b/Documentation/gpu/amdgpu/display/index.rst
@@ -29,4 +29,5 @@ table of content:
dc-debug.rst
dcn-overview.rst
mpo-overview.rst
+   display-test.rst
dc-glossary.rst
-- 
2.43.0



[PATCH v4 7/8] drm/amd/display: Introduce KUnit tests to dc_dmub_srv library

2024-01-26 Thread Rodrigo Siqueira
From: Maíra Canal 

Add a unit test to the SubVP feature in order to avoid possible
regressions and ensure code robustness. In particular, this new test
validates the expected parameters when using 4k144 and 4k240 displays.

Signed-off-by: Maíra Canal 
Signed-off-by: Rodrigo Siqueira 
Reported-by: kernel test robot 
---
 drivers/gpu/drm/amd/display/Kconfig   |  13 ++
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c  |   4 +
 .../amd/display/tests/dc/dc_dmub_srv_test.c   | 159 ++
 3 files changed, 176 insertions(+)
 create mode 100644 drivers/gpu/drm/amd/display/tests/dc/dc_dmub_srv_test.c

diff --git a/drivers/gpu/drm/amd/display/Kconfig 
b/drivers/gpu/drm/amd/display/Kconfig
index 877ba3be6aed..9724162d7509 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -90,4 +90,17 @@ config AMD_DC_BASICS_KUNIT_TEST
 
If unsure, say N.
 
+config AMD_DC_KUNIT_TEST
+   bool "Enable KUnit tests for the 'utils' sub-component of DAL" if 
!KUNIT_ALL_TESTS
+   depends on DRM_AMD_DC && KUNIT
+   default KUNIT_ALL_TESTS
+   help
+   Enables unit tests for the basics folder of Display Core. Only 
useful for
+   kernel devs running KUnit.
+
+   For more information on KUnit and unit tests in general please 
refer to
+   the KUnit documentation in Documentation/dev-tools/kunit/.
+
+   If unsure, say N.
+
 endmenu
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c 
b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index 2b79a0e5638e..181d1bcabb0f 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1415,3 +1415,7 @@ bool dc_wake_and_execute_gpint(const struct dc_context 
*ctx, enum dmub_gpint_com
 
return result;
 }
+
+#if IS_ENABLED(CONFIG_AMD_DC_KUNIT_TEST)
+#include "../tests/dc/dc_dmub_srv_test.c"
+#endif
diff --git a/drivers/gpu/drm/amd/display/tests/dc/dc_dmub_srv_test.c 
b/drivers/gpu/drm/amd/display/tests/dc/dc_dmub_srv_test.c
new file mode 100644
index ..d12c4e3816b5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/tests/dc/dc_dmub_srv_test.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: MIT
+/*
+ * KUnit tests for dc_dmub_srv.c
+ *
+ * Copyright (C) 2022, Maíra Canal 
+ */
+
+#include 
+#include "dc_dmub_srv.h"
+
+/**
+ * DOC: overview
+ *
+ * The file dc_dumb_srv.c has many functions that work as an interface to
+ * generate some of the DMUB parameters. To offload some of the complexity from
+ * the DMUB, the 'dc_dmub_srv.c' file provides functions that perform
+ * mathematical calculations to generate the parameter that will be passed to
+ * the DMUB to enable specific configurations.
+ */
+
+/**
+ * struct populate_subvp_cmd_drr_info_test_case - Fields for subvp validation
+ *
+ * The function populate_subvp_cmd_drr_info() performs calculations based on
+ * different pipe context timing values. This struct maintains those fields
+ * required to be passed to the populate_subvp_cmd_drr_info.
+ */
+struct populate_subvp_cmd_drr_info_test_case {
+   const char *desc;
+   /**
+   * @dc: In the specific context of populate_subvp_cmd_drr_info() test,
+   * we only care about the DC capabilities.
+   */
+   struct dc *dc;
+
+   /**
+* @subvp_pipe: This parameter plays an essential role in the
+* populate_subvp_cmd_drr_info validation because it will be used to
+* derive some of the parameters for the max VTotal, but it is also
+* employed in a pointer validation that extracts the phantom timing
+* from the context.
+*/
+   struct pipe_ctx *subvp_pipe;
+
+   /**
+* @vblank_pipe: This field keeps the DRR timing values used in the Max
+* and Min VTotal calculation.
+*/
+   struct pipe_ctx *vblank_pipe;
+
+   /**
+* @context: In the context of populate_subvp_cmd_drr_info(), this
+* field it is only necessary to fulfill the requirements for
+* dc_state_get_paired_subvp_stream() helper.
+*/
+   struct dc_state *context;
+};
+
+const struct dc_stream_status mock_dc_stream_state_returned_from_get_paired = {
+   .mall_stream_config =  (struct mall_stream_config) {
+   .paired_stream = &(struct dc_stream_state) {
+   .timing = {
+   .v_total = 216,
+   .h_total = 4000,
+   .v_addressable = 149,
+   .pix_clk_100hz = 5332500,
+   .v_front_porch = 1,
+   },
+   }
+   }
+};
+
+struct pipe_ctx mock_vblank_pipe_parameter = {
+   .stream = &(struct dc_stream_state) {
+   .timing = {
+   .v_total = 2250,
+   .h_total = 4400,
+   .v_addressable = 2160,
+   

  1   2   >