Re: [v1 2/2] drm/msm/disp/dpu1: enable crtc color management based on encoder topology

From: Rob Clark
Date: Wed Jul 20 2022 - 16:26:50 EST


On Mon, Jun 27, 2022 at 4:56 AM Kalyan Thota <kalyant@xxxxxxxxxxxxxxxx> wrote:
>
> Thanks for the comments, Dmitry. I haven't noticed mode->hdisplay being used. My idea was to run thru the topology and tie up the encoders with dspp to the CRTCs.
> Since mode is available only in the commit, we cannot use the dpu_encoder_get_topology during initialization sequence.
>
> The requirement here is that when we initialize the crtc, we need to enable drm_crtc_enable_color_mgmt only for the crtcs that support it. As I understand from Rob, chrome framework will check for the enablement in order to exercise the feature.
>
> Do you have any ideas on how to handle this requirement ? Since we will reserve the dspp's only when a commit is issued, I guess it will be too late to enable color management by then.
>
> @robdclark@xxxxxxxxx
> Is it okay, if we disable color management for all the crtcs during initialization and enable it when we have dspps available during modeset. Can we framework code query for the property before issuing a commit for the frame after modeset ?
>

So, I suppose it would work out, because the splashscreen/frecon is
doing the first modeset before chrome even starts. But that seems a
bit... delicate.

BR,
-R

> Thanks,
> Kalyan
>
> > -----Original Message-----
> > From: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx>
> > Sent: Tuesday, June 21, 2022 4:43 PM
> > To: Kalyan Thota (QUIC) <quic_kalyant@xxxxxxxxxxx>
> > Cc: y@xxxxxxxxxxxx; dri-devel@xxxxxxxxxxxxxxxxxxxxx; linux-arm-
> > msm@xxxxxxxxxxxxxxx; freedreno@xxxxxxxxxxxxxxxxxxxxx;
> > devicetree@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx;
> > robdclark@xxxxxxxxx; dianders@xxxxxxxxxxxx; swboyd@xxxxxxxxxxxx;
> > Vinod Polimera (QUIC) <quic_vpolimer@xxxxxxxxxxx>; Abhinav Kumar (QUIC)
> > <quic_abhinavk@xxxxxxxxxxx>
> > Subject: Re: [v1 2/2] drm/msm/disp/dpu1: enable crtc color management based
> > on encoder topology
> >
> > WARNING: This email originated from outside of Qualcomm. Please be wary of
> > any links or attachments, and do not enable macros.
> >
> > Generic comment: y@xxxxxxxxxxxx address bounces. Please remove it from
> > the cc list. If you need to send a patch for the internal reasons, please use Bcc.
> >
> > On Tue, 21 Jun 2022 at 12:06, Kalyan Thota <quic_kalyant@xxxxxxxxxxx> wrote:
> > >
> > > Crtc color management needs to be registered only for the crtc which
> > > has the capability to handle it. Since topology decides which encoder
> > > will get the dspp hw block, tie up the crtc and the encoder together
> > > (encoder->possible_crtcs)
> > >
> > > Change-Id: If5a0f33547b6f527ca4b8fbb78424b141dbbd711
> >
> > No change-id's please. This is not the gerrit.
> >
> > > Signed-off-by: Kalyan Thota <quic_kalyant@xxxxxxxxxxx>
> > > ---
> > > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 8 ++++++--
> > > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 +-
> > > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 20 ++++++++++++++++----
> > > drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 5 +++++
> > > drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 22 ++++++++++++++++++----
> > > 5 files changed, 46 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > index 7763558..2913acb 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > > @@ -1511,7 +1511,7 @@ static const struct drm_crtc_helper_funcs
> > > dpu_crtc_helper_funcs = {
> > >
> > > /* initialize crtc */
> > > struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane
> > *plane,
> > > - struct drm_plane *cursor)
> > > + struct drm_plane *cursor, unsigned int
> > > + enc_mask)
> > > {
> > > struct drm_crtc *crtc = NULL;
> > > struct dpu_crtc *dpu_crtc = NULL; @@ -1544,7 +1544,11 @@
> > > struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct
> > > drm_plane *plane,
> > >
> > > drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs);
> > >
> > > - drm_crtc_enable_color_mgmt(crtc, 0, true, 0);
> > > + /* Register crtc color management if the encoder has dspp, use the
> > > + * crtc to mark it as possible_crtcs for that encoder.
> > > + */
> > > + if(BIT(crtc->index) & enc_mask)
> >
> > So, we are checking CRTC's index against the encoder's mask? This is
> > counterintuitive.
> >
> > > + drm_crtc_enable_color_mgmt(crtc, 0, true, 0);
> > >
> > > /* save user friendly CRTC name for later */
> > > snprintf(dpu_crtc->name, DPU_CRTC_NAME_SIZE, "crtc%u",
> > > crtc->base.id); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > index b8785c3..0a6458e 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
> > > @@ -269,7 +269,7 @@ void dpu_crtc_complete_commit(struct drm_crtc
> > *crtc);
> > > * @Return: new crtc object or error
> > > */
> > > struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane
> > *plane,
> > > - struct drm_plane *cursor);
> > > + struct drm_plane *cursor, unsigned int
> > > + enc_mask);
> > >
> > > /**
> > > * dpu_crtc_register_custom_event - api for enabling/disabling crtc
> > > event diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > > b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > > index f2cb497..893ce68 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > > @@ -13,6 +13,8 @@
> > > #include <drm/drm_crtc.h>
> > > #include <drm/drm_file.h>
> > > #include <drm/drm_probe_helper.h>
> > > +#include <drm/drm_bridge.h>
> > > +#include <drm/drm_bridge_connector.h>
> > >
> > > #include "msm_drv.h"
> > > #include "dpu_kms.h"
> > > @@ -511,13 +513,18 @@ void dpu_encoder_helper_split_config(
> > > }
> > > }
> > >
> > > -static struct msm_display_topology dpu_encoder_get_topology(
> > > - struct dpu_encoder_virt *dpu_enc,
> > > +struct msm_display_topology dpu_encoder_get_topology(
> > > + struct drm_encoder *drm_enc,
> > > struct dpu_kms *dpu_kms,
> > > struct drm_display_mode *mode) {
> > > struct msm_display_topology topology = {0};
> > > + struct dpu_encoder_virt *dpu_enc;
> > > + struct drm_bridge *bridge;
> > > int i, intf_count = 0;
> > > + bool primary_display = false;
> > > +
> > > + dpu_enc = to_dpu_encoder_virt(drm_enc);
> > >
> > > for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++)
> > > if (dpu_enc->phys_encs[i]) @@ -542,7 +549,12 @@ static
> > > struct msm_display_topology dpu_encoder_get_topology(
> > > else
> > > topology.num_lm = (mode->hdisplay >
> > > MAX_HDISPLAY_SPLIT) ? 2 : 1;
> > >
> > > - if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI) {
> > > + drm_for_each_bridge_in_chain(drm_enc, bridge) {
> > > + if (bridge->type != DRM_MODE_CONNECTOR_DisplayPort)
> > > + primary_display = true;
> > > + }
> >
> > I must admit, I never actually liked the original (intf_type == DSI) check. However
> > the new one is even worse. We are checking the whole bridge chain in an
> > attempt to rule out the DP ports for whatever reason. What about the HDMI
> > ports? Should they be also frowned upon?
> > The ugly part is that we are making the decision for the user, which displays are
> > "primary" for him. Can we let the user make this setting?
> >
> > > +
> > > + if (primary_display) {
> > > if (dpu_kms->catalog->dspp &&
> > > (dpu_kms->catalog->dspp_count >= topology.num_lm))
> > > topology.num_dspp = topology.num_lm; @@ -601,7
> > > +613,7 @@ static int dpu_encoder_virt_atomic_check(
> > > }
> > > }
> > >
> > > - topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode);
> > > + topology = dpu_encoder_get_topology(drm_enc, dpu_kms,
> > > + adj_mode);
> >
> > extra whitespace change. Please drop.
> >
> > >
> > > /* Reserve dynamic resources now. */
> > > if (!ret) {
> > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> > > b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> > > index 1f39327..c4daf7c 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
> > > @@ -172,4 +172,9 @@ int dpu_encoder_get_vsync_count(struct
> > drm_encoder
> > > *drm_enc);
> > >
> > > bool dpu_encoder_is_widebus_enabled(const struct drm_encoder
> > > *drm_enc);
> > >
> > > +struct msm_display_topology dpu_encoder_get_topology(
> > > + struct drm_encoder *drm_enc,
> > > + struct dpu_kms *dpu_kms,
> > > + struct drm_display_mode *mode);
> > > +
> > > #endif /* __DPU_ENCODER_H__ */
> > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > index 3a4da0d..486ff9d 100644
> > > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> > > @@ -687,9 +687,12 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms
> > *dpu_kms)
> > > unsigned cursor_idx = 0;
> > > unsigned primary_idx = 0;
> > > bool pin_overlays;
> > > + unsigned int max_dspp_count = 0;
> > > + unsigned int enc_mask = 0;
> > >
> > > struct msm_drm_private *priv;
> > > struct dpu_mdss_cfg *catalog;
> > > + struct msm_display_topology topology = {0};
> > >
> > > int primary_planes_idx = 0, cursor_planes_idx = 0, i, ret;
> > > int max_crtc_count;
> > > @@ -754,10 +757,19 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms
> > *dpu_kms)
> > > }
> > >
> > > max_crtc_count = min(max_crtc_count, primary_planes_idx);
> > > + max_dspp_count = catalog->dspp_count;
> > > +
> > > + drm_for_each_encoder(encoder, dev) {
> > > + topology = dpu_encoder_get_topology(encoder, dpu_kms,
> > > + NULL);
> >
> > This can crash dpu_encoder_get_topology() because it checks mode->hdisplay.
> > And the check anyway is futile here. We do not know if the encoder is going to
> > use 1 or 2 LMs (since we do not know the resolution), so we do not know
> > whether it will use 1 or 2 DSPP blocks.
> >
> > > + if (topology.num_dspp > 0 && (topology.num_dspp <=
> > max_dspp_count)) {
> > > + enc_mask |= BIT(encoder->index);
> > > + max_dspp_count -= topology.num_dspp;
> > > + }
> > > + }
> > >
> > > /* Create one CRTC per encoder */
> > > for (i = 0; i < max_crtc_count; i++) {
> > > - crtc = dpu_crtc_init(dev, primary_planes[i], cursor_planes[i]);
> > > + crtc = dpu_crtc_init(dev, primary_planes[i],
> > > + cursor_planes[i], enc_mask);
> > > if (IS_ERR(crtc)) {
> > > ret = PTR_ERR(crtc);
> > > return ret;
> > > @@ -765,9 +777,11 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms
> > *dpu_kms)
> > > priv->crtcs[priv->num_crtcs++] = crtc;
> > > }
> > >
> > > - /* All CRTCs are compatible with all encoders */
> > > - drm_for_each_encoder(encoder, dev)
> > > - encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
> > > + /* Attach CRTC's to compatiable encoders */
> >
> > compatible
> >
> >
> > > + drm_for_each_encoder(encoder, dev) {
> > > + encoder->possible_crtcs = (enc_mask & BIT(encoder->index)) ?
> > > + BIT(encoder->index) : (((1 << priv->num_crtcs) - 1) &
> > ~enc_mask);
> > > + }
> > >
> > > return 0;
> > > }
> > > --
> > > 2.7.4
> > >
> >
> >
> > --
> > With best wishes
> > Dmitry