[PATCH v4 08/13] drm/msm/dpu: add support for virtual planes

Dmitry Baryshkov dmitry.baryshkov at linaro.org
Fri Jun 7 22:26:29 UTC 2024


On Sat, 8 Jun 2024 at 00:39, Abhinav Kumar <quic_abhinavk at quicinc.com> wrote:
>
>
>
> On 6/7/2024 2:10 PM, Dmitry Baryshkov wrote:
> > On Fri, Jun 07, 2024 at 12:22:16PM -0700, Abhinav Kumar wrote:
> >>
> >>
> >> On 6/7/2024 12:16 AM, Dmitry Baryshkov wrote:
> >>> On Thu, Jun 06, 2024 at 03:21:11PM -0700, Abhinav Kumar wrote:
> >>>> On 3/13/2024 5:02 PM, Dmitry Baryshkov wrote:
> >>>>> Only several SSPP blocks support such features as YUV output or scaling,
> >>>>> thus different DRM planes have different features.  Properly utilizing
> >>>>> all planes requires the attention of the compositor, who should
> >>>>> prefer simpler planes to YUV-supporting ones. Otherwise it is very easy
> >>>>> to end up in a situation when all featureful planes are already
> >>>>> allocated for simple windows, leaving no spare plane for YUV playback.
> >>>>>
> >>>>> To solve this problem make all planes virtual. Each plane is registered
> >>>>> as if it supports all possible features, but then at the runtime during
> >>>>> the atomic_check phase the driver selects backing SSPP block for each
> >>>>> plane.
> >>>>>
> >>>>> Note, this does not provide support for using two different SSPP blocks
> >>>>> for a single plane or using two rectangles of an SSPP to drive two
> >>>>> planes. Each plane still gets its own SSPP and can utilize either a solo
> >>>>> rectangle or both multirect rectangles depending on the resolution.
> >>>>>
> >>>>> Note #2: By default support for virtual planes is turned off and the
> >>>>> driver still uses old code path with preallocated SSPP block for each
> >>>>> plane. To enable virtual planes, pass 'msm.dpu_use_virtual_planes=1'
> >>>>> kernel parameter.
> >>>>>
> >>>>
> >>>> I like the overall approach in this patch. Some comments below.
> >>>>
> >>>>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at linaro.org>
> >>>>> ---
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c  |  50 +++++
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c   |  10 +-
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h   |   4 +
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 230 +++++++++++++++++++---
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h |  19 ++
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c    |  77 ++++++++
> >>>>>     drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h    |  28 +++
> >>>>>     7 files changed, 390 insertions(+), 28 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>> index 88c2e51ab166..794c5643584f 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> >>>>> @@ -1168,6 +1168,49 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state *cstate)
> >>>>>           return false;
> >>>>>     }
> >>>>> +static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
> >>>>> +{
> >>>>> + int total_planes = crtc->dev->mode_config.num_total_plane;
> >>>>> + struct drm_atomic_state *state = crtc_state->state;
> >>>>> + struct dpu_global_state *global_state;
> >>>>> + struct drm_plane_state **states;
> >>>>> + struct drm_plane *plane;
> >>>>> + int ret;
> >>>>> +
> >>>>> + global_state = dpu_kms_get_global_state(crtc_state->state);
> >>>>> + if (IS_ERR(global_state))
> >>>>> +         return PTR_ERR(global_state);
> >>>>> +
> >>>>> + dpu_rm_release_all_sspp(global_state, crtc);
> >>>>> +
> >>>>
> >>>> Do we need to call dpu_rm_release_all_sspp() even in the
> >>>> _dpu_plane_atomic_disable()?
> >>>
> >>> It allows the driver to optimize the usage of the SSPP rectangles.
> >>>
> >>
> >> No, what I meant was that we should call dpu_rm_release_all_sspp() in
> >> dpu_plane_atomic_update() as well because in the atomic_check() path where
> >> its called today, its being called only for zpos_changed and planes_changed
> >> but during disable we must call this for sure.
> >
> > No. the dpu_rm_release_all_sspp() should only be called during check.
> > When dpu_plane_atomic_update() is called, the state should already be
> > finalised. The atomic_check() callback is called when a plane is going
> > to be disabled.
> >
>
> atomic_check() will be called when plane is disabled but
> dpu_rm_release_all_sspp() may not be called as it is protected by
> zpos_changed and planes_changed. OR you need to add a !visible check
> here to call dpu_rm_release_all_sspp() that time. Thats whay I wrote
> previously.

Unless I miss something, if a plane gets disabled, then obviously
planes_changed is true.

[trimmed]

>
> >>>>> @@ -1486,7 +1593,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>           supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> >>>>> - if (pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION))
> >>>>> + if (inline_rotation)
> >>>>>                   supported_rotations |= DRM_MODE_ROTATE_MASK;
> >>>>>           drm_plane_create_rotation_property(plane,
> >>>>> @@ -1494,10 +1601,81 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>           drm_plane_enable_fb_damage_clips(plane);
> >>>>> - /* success! finalize initialization */
> >>>>> + DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> >>>>> +                                 pipe, plane->base.id);
> >>>>> + return plane;
> >>>>> +}
> >>>>> +
> >>>>> +struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>> +                          uint32_t pipe, enum drm_plane_type type,
> >>>>> +                          unsigned long possible_crtcs)
> >>>>> +{
> >>>>> + struct drm_plane *plane = NULL;
> >>>>> + struct msm_drm_private *priv = dev->dev_private;
> >>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> >>>>> + struct dpu_hw_sspp *pipe_hw;
> >>>>> +
> >>>>> + /* initialize underlying h/w driver */
> >>>>> + pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe);
> >>>>> + if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) {
> >>>>> +         DPU_ERROR("[%u]SSPP is invalid\n", pipe);
> >>>>> +         return ERR_PTR(-EINVAL);
> >>>>> + }
> >>>>> +
> >>>>> +
> >>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> >>>>> +                               pipe_hw->cap->features & BIT(DPU_SSPP_INLINE_ROTATION),
> >>>>> +                               pipe_hw->cap->sblk->format_list,
> >>>>> +                               pipe_hw->cap->sblk->num_formats,
> >>>>> +                               pipe);
> >>>>> + if (IS_ERR(plane))
> >>>>> +         return plane;
> >>>>> +
> >>>>>           drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
> >>>>>           DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name,
> >>>>>                                           pipe, plane->base.id);
> >>>>> +
> >>>>> + return plane;
> >>>>> +}
> >>>>> +
> >>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> >>>>> +                                  enum drm_plane_type type,
> >>>>> +                                  unsigned long possible_crtcs)
> >>>>> +{
> >>>>> + struct drm_plane *plane = NULL;
> >>>>> + struct msm_drm_private *priv = dev->dev_private;
> >>>>> + struct dpu_kms *kms = to_dpu_kms(priv->kms);
> >>>>> + bool has_inline_rotation = false;
> >>>>> + const u32 *format_list = NULL;
> >>>>> + u32 num_formats = 0;
> >>>>> + int i;
> >>>>> +
> >>>>> + /* Determine the largest configuration that we can implement */
> >>>>> + for (i = 0; i < kms->catalog->sspp_count; i++) {
> >>>>> +         const struct dpu_sspp_cfg *cfg = &kms->catalog->sspp[i];
> >>>>> +
> >>>>> +         if (test_bit(DPU_SSPP_INLINE_ROTATION, &cfg->features))
> >>>>> +                 has_inline_rotation = true;
> >>>>> +
> >>>>> +         if (!format_list ||
> >>>>> +             cfg->sblk->csc_blk.len) {
> >>>>
> >>>> But format_list is being assigned to NULL just a few lines above. Why is
> >>>> this check needed?
> >>>
> >>> It was assigned before the loop.
> >>>
> >>
> >> Yes, I got this part but missed on why we needed the loop at all.
> >
> > Which set of formats should the virtual plane use?
> >
> >>>>
> >>>> I dont get why this part can also goto dpu_plane_init_common() as it looks
> >>>> identical to me.
> >>>
> >>> And it is not. For the non-virtual case there is no loop around formats
> >>> list assignment.
> >>>
> >>
> >> Ah okay, I misunderstood the logic. After reading the comment above the loop
> >> I get what you are trying to do here.
> >>
> >> But I dont get why you really need to do that?
> >>
> >> 1) In this patch the relationship between virtual plane and SSPP is still
> >> 1:1 so what is wrong to retain the sspp's actual format for the plane rather
> >> than picking the best format (you are targetting Vig SSPP)
> >
> > No. With this patch there is no 1:1 relationship. The RM will select the
> > SSPP that suits the requirements (YUV, scaling, rotation, etc).
> >
>
> Yes but there is always only one SSPP for one plane is what I meant.
> That does not change till the next patch.
>
> In that sense, I dont see why you need to expose the superset of formats.

Let me please repeat my question: what set of formats should be used
for plane init?

>
> >> In fact, that will reduce atomic_check() failures with this patch because
> >> compositor will still work the same way as it used to work before by not
> >> trying an unsupported format on a plane.
> >
> > The virtual plane should support any of the formats that the backing
> > hardware can support. If (for example) we only had RGB-only and YUV-only
> > hardware blocks, the driver would have to construct a _superset_ of
> > those formats. Fortunately this is not the case and VIG supports a
> > strict superset of what DMA (or RGB) SSPP supports.
> >
>
> Yes, thats why I said plane_formats_yuv is enough in my next point below
> because Vig is super set of DMA or IOW Vig is the most feature rich plane.

QCM2290 doesn't have YUV support if I'm not mistaken.

>
> >> If one plane maps to two SSPPs, then yes we can go with the superset of
> >> formats but that comes in a later patch right?
> >>
> >> 2) So even if we want to do it this way from this patch itself, I think all
> >> you are looking for is whether there is a Vig SSPP and if so use
> >> plane_formats_yuv. There is no need for this loop IMO.
> >>
> >> 3) I noticed that virt_format_list is still present in the driver. If you
> >> are planning to not use that perhaps drop it with this series.
> >
> > Ack
> >
> >>
> >>>>
> >>>>
> >>>>> +                 format_list = cfg->sblk->format_list;
> >>>>> +                 num_formats = cfg->sblk->num_formats;
> >>>>> +         }
> >>>>> + }
> >>>>> +
> >>>>> + plane = dpu_plane_init_common(dev, type, possible_crtcs,
> >>>>> +                               has_inline_rotation,
> >>>>> +                               format_list,
> >>>>> +                               num_formats,
> >>>>> +                               SSPP_NONE);
> >>>>
> >>>> Ok, here is the part which we were discussing in
> >>>>
> >>>> https://patchwork.freedesktop.org/patch/582820/?series=131109&rev=1#comment_1087370
> >>>>
> >>>> So yes, that part belongs to this patch.
> >>>
> >>> I'll check it while preparing the next iteration.
> >>>
> >>>>
> >>>>> + if (IS_ERR(plane))
> >>>>> +         return plane;
> >>>>> +
> >>>>> + drm_plane_helper_add(plane, &dpu_plane_virtual_helper_funcs);
> >>>>> +
> >>>>> + DPU_DEBUG("%s created virtual id:%u\n", plane->name, plane->base.id);
> >>>>> +
> >>>>>           return plane;
> >>>>>     }
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>> index a3ae45dc95d0..15f7d60d8b85 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h
> >>>>> @@ -30,6 +30,7 @@
> >>>>>      * @plane_fetch_bw: calculated BW per plane
> >>>>>      * @plane_clk: calculated clk per plane
> >>>>>      * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed
> >>>>> + * @saved_fmt: format used by the plane's FB, saved for for virtual plane support
> >>>>>      */
> >>>>>     struct dpu_plane_state {
> >>>>>           struct drm_plane_state base;
> >>>>> @@ -46,6 +47,8 @@ struct dpu_plane_state {
> >>>>>           u64 plane_clk;
> >>>>>           bool needs_dirtyfb;
> >>>>> +
> >>>>> + const struct dpu_format *saved_fmt;
> >>>>>     };
> >>>>
> >>>> Why is saved_fmt needed?
> >>>>
> >>>> The use-case which comes to my mind is lets say if we have a RGB format and
> >>>> we need to switch to a YUV format, basically switch from DMA to ViG SSPP,
> >>>> then yes we have to mark planes_changed as we need to switch the underlying
> >>>> SSPP that time, but why cant we simply check that by means of a check to see
> >>>> if the fmt is YUV and whether CSC block is present in the SSPP.
> >>>
> >>> Yes, correct. And vice versa, going from YUV to RGB might free the VIG
> >>> SSPP.
> >>>
> >>>>
> >>>> This will lead to dpu_crtc_reassign_planes() getting called for format
> >>>> changes even when the new format might be available in the same SSPP.
> >>>
> >>> So use 'needs_vig' instead of storing the format? Sounds good to me.
> >>>
> >>
> >> Yes thats the idea. Basically "needs_reassignment". You could even go from
> >> Vig to DMA if the use-case can just use DMA to save up Vig.
> >>
> >> Also, do we really need to cache anything in the plane state to track this?
> >>
> >> If we have a function called dpu_crtc_needs_plane_reassignment() will go
> >> through the current plane state and the current SSPP from the global state
> >> and see if needs reassignment.
> >
> > No, looking at the global state won't be possible here. I'd have to lock
> > the private object before consulting it, which might cause EDEADLOCK
> > later on during resource reallocation. So all necessary information
> > should be stored in the dpu_plane_state.
> >
>
> But you are already calling dpu_kms_get_global_state() in
> dpu_crtc_reassign_planes().

It happens at a different point. And I'm not sure how modeset locking
will react to an attempt to lock the private object twice.

>
> >>
> >>>>
> >>>>>     #define to_dpu_plane_state(x) \
> >>>>> @@ -75,6 +78,16 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
> >>>>>                   uint32_t pipe, enum drm_plane_type type,
> >>>>>                   unsigned long possible_crtcs);
> >>>>> +/**
> >>>>> + * dpu_plane_init_virtual - create new dpu virtualized plane
> >>>>> + * @dev:   Pointer to DRM device
> >>>>> + * @type:  Plane type - PRIMARY/OVERLAY/CURSOR
> >>>>> + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe
> >>>>> + */
> >>>>> +struct drm_plane *dpu_plane_init_virtual(struct drm_device *dev,
> >>>>> +                                  enum drm_plane_type type,
> >>>>> +                                  unsigned long possible_crtcs);
> >>>>> +
> >>>>>     /**
> >>>>>      * dpu_plane_color_fill - enables color fill on plane
> >>>>>      * @plane:  Pointer to DRM plane object
> >>>>> @@ -91,4 +104,10 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable);
> >>>>>     static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {}
> >>>>>     #endif
> >>>>> +int dpu_assign_plane_resources(struct dpu_global_state *global_state,
> >>>>> +                        struct drm_atomic_state *state,
> >>>>> +                        struct drm_crtc *crtc,
> >>>>> +                        struct drm_plane_state **states,
> >>>>> +                        unsigned int num_planes);
> >>>>> +
> >>>>>     #endif /* _DPU_PLANE_H_ */
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>> index 44938ba7a2b7..7264a4d44a14 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
> >>>>> @@ -694,6 +694,83 @@ int dpu_rm_reserve(
> >>>>>           return ret;
> >>>>>     }
> >>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> >>>>> +                                 struct dpu_global_state *global_state,
> >>>>> +                                 struct drm_crtc *crtc,
> >>>>> +                                 struct dpu_rm_sspp_requirements *reqs)
> >>>>> +{
> >>>>> + uint32_t crtc_id = crtc->base.id;
> >>>>> + unsigned int weight, best_weght = UINT_MAX;
> >>>>
> >>>> best_weight?
> >>>
> >>> Yes
> >>>
> >>>>
> >>>>> + struct dpu_hw_sspp *hw_sspp;
> >>>>> + unsigned long mask = 0;
> >>>>> + int i, best_idx = -1;
> >>>>> +
> >>>>> + /*
> >>>>> +  * Don't take cursor feature into consideration until there is proper support for SSPP_CURSORn.
> >>>>> +  */
> >>>>> + mask |= BIT(DPU_SSPP_CURSOR);
> >>>>> +
> >>>>> + if (reqs->scale)
> >>>>> +         mask |= BIT(DPU_SSPP_SCALER_RGB) |
> >>>>> +                 BIT(DPU_SSPP_SCALER_QSEED2) |
> >>>>> +                 BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE);
> >>>>> +
> >>>>> + if (reqs->yuv)
> >>>>> +         mask |= BIT(DPU_SSPP_CSC) |
> >>>>> +                 BIT(DPU_SSPP_CSC_10BIT);
> >>>>> +
> >>>>> + if (reqs->rot90)
> >>>>> +         mask |= BIT(DPU_SSPP_INLINE_ROTATION);
> >>>>> +
> >>>>> + for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) {
> >>>>> +         if (!rm->hw_sspp[i])
> >>>>> +                 continue;
> >>>>> +
> >>>>> +         if (global_state->sspp_to_crtc_id[i])
> >>>>> +                 continue;
> >>>>> +
> >>>>> +         hw_sspp = rm->hw_sspp[i];
> >>>>> +
> >>>>> +         /* skip incompatible planes */
> >>>>> +         if (reqs->scale && !hw_sspp->cap->sblk->scaler_blk.len)
> >>>>> +                 continue;
> >>>>> +
> >>>>> +         if (reqs->yuv && !hw_sspp->cap->sblk->csc_blk.len)
> >>>>> +                 continue;
> >>>>> +
> >>>>> +         if (reqs->rot90 && !(hw_sspp->cap->features & DPU_SSPP_INLINE_ROTATION))
> >>>>> +                 continue;
> >>>>> +
> >>>>> +         /*
> >>>>> +          * For non-yuv, non-scaled planes prefer simple (DMA or RGB)
> >>>>> +          * plane, falling back to VIG only if there are no such planes.
> >>>>> +          *
> >>>>> +          * This way we'd leave VIG sspps to be later used for YUV formats.
> >>>>> +          */
> >>>>> +         weight = hweight64(hw_sspp->cap->features & ~mask);
> >>>>
> >>>> This approach is assuming that ViG feature masks are more than DMA.
> >>>> Hence the hweight of DMA SSPP's features is less than hweight of ViG SSPPs.
> >>>>
> >>>> Is this really true? Because there are other bits such as DMA_SDM845_MASK
> >>>> which might increase the hweight of DMA SSPPs
> >>>
> >>> Which bits are present in the DMA mask, which are not present in the VIG
> >>> mask? Also for the older platforms there are three kinds of planes: VIG,
> >>> DMA and RGB. The selection algorithm should not require significant
> >>> changes to support that case.
> >>>
> >>
> >> DMA_SDM845_MASK has DPU_SSPP_QOS_8LVL which is not there in VIG_MSM8998_MASK
> >> afaict. But we really cannot be counting the number of feature bits and
> >> going by that.
> >
> > MSM8998 uses DMA_MSM8998_MASK, not DMA_SDM845_MASK.
> >
> >> Hence, inherently, going by hweight is not right because whenever we add a
> >> catalog change to add a new feature bit to SSPP, we have to come back here
> >> and make sure this logic will not break.
> >>>>
> >>>> I would rather make it simpler.
> >>>>
> >>>> 1) if we need scaling || yuv, then we have to get only a Vig
> >>>> 2) else, first try to get a DMA SSPP
> >>>
> >>> How would you distinguish between VIG and DMA?
> >>>
> >>
> >> the type SSPP_TYPE_VIG OR SSPP_TYPE_DMA. We also have a SSPP_TYPE_RGB so
> >> that should address your concern about the third type of plane (Vig, DMA,
> >> RGB).
> >
> > I don't particularly like the idea of using type. We still need to
> > evaluate plane's features. Consider QCM2290, where VIG planes do not
> > support scaling.
> >
> > I will evaluate if I can rework this part to use type, while still
> > checking for the feature bit. BTW: should we prefer RGB or DMA plane if
> > all other conditions are met?
> >
>
> Ok, qcm2290 really seems like an odd case but point taken.
>
> I am fine if it needs to be a combination of type and feature bit but
> certainly not hweight of feature bit. If you want to use type along with
> presence of scaler blk feature bit thats fine.
>
> I need to check if there is any feature loss in RGB Vs DMA. Let me check
> and get back. This needs some history digging.

Sure.

>
> >>
> >>
> >>>> 3) if (2) fails, we have to try to get a ViG SSPP.
> >>>>
> >>>> Lets be more explicit about the SSPP type here rather than using hweight.
> >>>>
> >>>>
> >>>>> +         if (weight < best_weght) {
> >>>>> +                 best_weght = weight;
> >>>>> +                 best_idx = i;
> >>>>> +         }
> >>>>> + }
> >>>>> +
> >>>>> + if (best_idx < 0)
> >>>>> +         return NULL;
> >>>>> +
> >>>>> + global_state->sspp_to_crtc_id[best_idx] = crtc_id;
> >>>>> +
> >>>>> + return rm->hw_sspp[best_idx];
> >>>>> +}
> >>>>> +
> >>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> >>>>> +                      struct drm_crtc *crtc)
> >>>>> +{
> >>>>> + uint32_t crtc_id = crtc->base.id;
> >>>>> +
> >>>>> + _dpu_rm_clear_mapping(global_state->sspp_to_crtc_id,
> >>>>> +         ARRAY_SIZE(global_state->sspp_to_crtc_id), crtc_id);
> >>>>> +}
> >>>>> +
> >>>>>     int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
> >>>>>           struct dpu_global_state *global_state, uint32_t enc_id,
> >>>>>           enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size)
> >>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> >>>>> index e63db8ace6b9..bf9110547385 100644
> >>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> >>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
> >>>>> @@ -37,6 +37,12 @@ struct dpu_rm {
> >>>>>           struct dpu_hw_blk *cdm_blk;
> >>>>>     };
> >>>>> +struct dpu_rm_sspp_requirements {
> >>>>> + bool yuv;
> >>>>> + bool scale;
> >>>>> + bool rot90;
> >>>>> +};
> >>>>> +
> >>>>>     /**
> >>>>>      * dpu_rm_init - Read hardware catalog and create reservation tracking objects
> >>>>>      *    for all HW blocks.
> >>>>> @@ -82,6 +88,28 @@ int dpu_rm_reserve(struct dpu_rm *rm,
> >>>>>     void dpu_rm_release(struct dpu_global_state *global_state,
> >>>>>                   struct drm_encoder *enc);
> >>>>> +/**
> >>>>> + * dpu_rm_reserve_sspp - Reserve the required SSPP for the provided CRTC
> >>>>> + * @rm: DPU Resource Manager handle
> >>>>> + * @global_state: private global state
> >>>>> + * @crtc: DRM CRTC handle
> >>>>> + * @reqs: SSPP required features
> >>>>> + */
> >>>>> +struct dpu_hw_sspp *dpu_rm_reserve_sspp(struct dpu_rm *rm,
> >>>>> +                                 struct dpu_global_state *global_state,
> >>>>> +                                 struct drm_crtc *crtc,
> >>>>> +                                 struct dpu_rm_sspp_requirements *reqs);
> >>>>> +
> >>>>> +/**
> >>>>> + * dpu_rm_release_all_sspp - Given the CRTC, release all SSPP
> >>>>> + *       blocks previously reserved for that use case.
> >>>>> + * @rm: DPU Resource Manager handle
> >>>>> + * @crtc: DRM CRTC handle
> >>>>> + * @Return: 0 on Success otherwise -ERROR
> >>>>> + */
> >>>>
> >>>> This is void so does not return anything?
> >
> > Yes
> >
> >>>>
> >>>>> +void dpu_rm_release_all_sspp(struct dpu_global_state *global_state,
> >>>>> +                      struct drm_crtc *crtc);
> >>>>> +
> >>>>>     /**
> >>>>>      * Get hw resources of the given type that are assigned to this encoder.
> >>>>>      */
> >>>
> >



-- 
With best wishes
Dmitry


More information about the Freedreno mailing list