Re: [Freedreno] [RFC 4/4] drm/msm/mdp5: writeback support

2018-02-26 Thread Sean Paul
On Fri, Feb 23, 2018 at 01:15:54PM -0500, Rob Clark wrote:
> On Fri, Feb 23, 2018 at 11:30 AM, Sean Paul  wrote:
> > On Fri, Feb 23, 2018 at 08:17:54AM -0500, Rob Clark wrote:
> >> In a way, based on the original writeback patch from Jilai Wang, but a
> >> lot has shifted around since then.
> >>
> >> Signed-off-by: Rob Clark 
> >> ---
> >>  drivers/gpu/drm/msm/Makefile  |   1 +
> >>  drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c |  23 +-
> >>  drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c  |  38 +++-
> >>  drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h  |   7 +-
> >>  drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c   | 367 
> >> ++
> >>  drivers/gpu/drm/msm/dsi/dsi_host.c|   4 +-
> >>  6 files changed, 431 insertions(+), 9 deletions(-)
> >>  create mode 100644 drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c
> >>
> >> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> >> index cd40c050b2d7..c9f50adef2db 100644
> >> --- a/drivers/gpu/drm/msm/Makefile
> >> +++ b/drivers/gpu/drm/msm/Makefile
> >> @@ -45,6 +45,7 @@ msm-y := \
> >>   disp/mdp5/mdp5_mixer.o \
> >>   disp/mdp5/mdp5_plane.o \
> >>   disp/mdp5/mdp5_smp.o \
> >> + disp/mdp5/mdp5_wb.o \
> >>   msm_atomic.o \
> >>   msm_debugfs.o \
> >>   msm_drv.o \
> >> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c 
> >> b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
> >> index 9893e43ba6c5..b00ca88b741d 100644
> >> --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
> >> +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
> >> @@ -484,7 +484,11 @@ static void mdp5_crtc_atomic_enable(struct drm_crtc 
> >> *crtc,
> >>   }
> >>
> >>   /* Restore vblank irq handling after power is enabled */
> >> - drm_crtc_vblank_on(crtc);
> >> +// TODO we can't ->get_scanout_pos() for wb (since virtual intf)..
> >> +// perhaps drm core should be clever enough not to 
> >> drm_reset_vblank_timestamp()
> >> +// for virtual encoders / writeback?
> >> + if (mdp5_cstate->pipeline.intf->type != INTF_WB)
> >> + drm_crtc_vblank_on(crtc);
> >>
> >>   mdp5_crtc_mode_set_nofb(crtc);
> >>
> >> @@ -518,7 +522,11 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
> >>   u32 caps;
> >>   int ret;
> >>
> >> - caps = MDP_LM_CAP_DISPLAY;
> >> + if (pipeline->intf->type == INTF_WB)
> >> + caps = MDP_LM_CAP_WB;
> >> + else
> >> + caps = MDP_LM_CAP_DISPLAY;
> >> +
> >>   if (need_right_mixer)
> >>   caps |= MDP_LM_CAP_PAIR;
> >>
> >> @@ -545,6 +553,7 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
> >>   mdp5_cstate->err_irqmask = intf2err(intf->num);
> >>   mdp5_cstate->vblank_irqmask = intf2vblank(pipeline->mixer, intf);
> >>
> >> +// XXX should we be treating WB as cmd_mode??
> >>   if ((intf->type == INTF_DSI) &&
> >>   (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
> >>   mdp5_cstate->pp_done_irqmask = lm2ppdone(pipeline->mixer);
> >> @@ -639,8 +648,12 @@ static int mdp5_crtc_atomic_check(struct drm_crtc 
> >> *crtc,
> >>   }
> >>
> >>   /* bail out early if there aren't any planes */
> >> - if (!cnt)
> >> - return 0;
> >> + if (!cnt) {
> >> + if (!state->active)
> >> + return 0;
> >> + dev_err(dev->dev, "%s has no planes!\n", crtc->name);
> >> + return -EINVAL;
> >> + }
> >
> > This seems unrelated?
> >
> 
> hmm, yeah, kinda.  It was a case that I hit before working out all the
> bugs in my kmscube writeback mode, but I guess isn't directly related
> to wb.
> 
> >>
> >>   hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
> >>
> >> @@ -1160,7 +1173,7 @@ void mdp5_crtc_wait_for_commit_done(struct drm_crtc 
> >> *crtc)
> >>
> >>   if (mdp5_cstate->cmd_mode)
> >>   mdp5_crtc_wait_for_pp_done(crtc);
> >> - else
> >> + else if (mdp5_cstate->pipeline.intf->type != INTF_WB)
> >>   mdp5_crtc_wait_for_flush_done(crtc);
> >>  }
> >>
> >> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c 
> >> b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
> >> index 1f44d8f15ce1..239010905637 100644
> >> --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
> >> +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
> >> @@ -427,7 +427,8 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
> >>* the MDP5 interfaces) than the number of layer mixers present in 
> >> HW,
> >>* but let's be safe here anyway
> >>*/
> >> - num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers);
> >> + num_crtcs = min(priv->num_encoders + hw_cfg->wb.count,
> >> + mdp5_kms->num_hwmixers);
> >>
> >>   /*
> >>* Construct planes equaling the number of hw pipes, and CRTCs for 
> >> the
> >> @@ -482,6 +483,33 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
> >> 

Re: [Freedreno] [RFC 4/4] drm/msm/mdp5: writeback support

2018-02-23 Thread Rob Clark
On Fri, Feb 23, 2018 at 11:30 AM, Sean Paul  wrote:
> On Fri, Feb 23, 2018 at 08:17:54AM -0500, Rob Clark wrote:
>> In a way, based on the original writeback patch from Jilai Wang, but a
>> lot has shifted around since then.
>>
>> Signed-off-by: Rob Clark 
>> ---
>>  drivers/gpu/drm/msm/Makefile  |   1 +
>>  drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c |  23 +-
>>  drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c  |  38 +++-
>>  drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h  |   7 +-
>>  drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c   | 367 
>> ++
>>  drivers/gpu/drm/msm/dsi/dsi_host.c|   4 +-
>>  6 files changed, 431 insertions(+), 9 deletions(-)
>>  create mode 100644 drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c
>>
>> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
>> index cd40c050b2d7..c9f50adef2db 100644
>> --- a/drivers/gpu/drm/msm/Makefile
>> +++ b/drivers/gpu/drm/msm/Makefile
>> @@ -45,6 +45,7 @@ msm-y := \
>>   disp/mdp5/mdp5_mixer.o \
>>   disp/mdp5/mdp5_plane.o \
>>   disp/mdp5/mdp5_smp.o \
>> + disp/mdp5/mdp5_wb.o \
>>   msm_atomic.o \
>>   msm_debugfs.o \
>>   msm_drv.o \
>> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c 
>> b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
>> index 9893e43ba6c5..b00ca88b741d 100644
>> --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
>> +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
>> @@ -484,7 +484,11 @@ static void mdp5_crtc_atomic_enable(struct drm_crtc 
>> *crtc,
>>   }
>>
>>   /* Restore vblank irq handling after power is enabled */
>> - drm_crtc_vblank_on(crtc);
>> +// TODO we can't ->get_scanout_pos() for wb (since virtual intf)..
>> +// perhaps drm core should be clever enough not to 
>> drm_reset_vblank_timestamp()
>> +// for virtual encoders / writeback?
>> + if (mdp5_cstate->pipeline.intf->type != INTF_WB)
>> + drm_crtc_vblank_on(crtc);
>>
>>   mdp5_crtc_mode_set_nofb(crtc);
>>
>> @@ -518,7 +522,11 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
>>   u32 caps;
>>   int ret;
>>
>> - caps = MDP_LM_CAP_DISPLAY;
>> + if (pipeline->intf->type == INTF_WB)
>> + caps = MDP_LM_CAP_WB;
>> + else
>> + caps = MDP_LM_CAP_DISPLAY;
>> +
>>   if (need_right_mixer)
>>   caps |= MDP_LM_CAP_PAIR;
>>
>> @@ -545,6 +553,7 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
>>   mdp5_cstate->err_irqmask = intf2err(intf->num);
>>   mdp5_cstate->vblank_irqmask = intf2vblank(pipeline->mixer, intf);
>>
>> +// XXX should we be treating WB as cmd_mode??
>>   if ((intf->type == INTF_DSI) &&
>>   (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
>>   mdp5_cstate->pp_done_irqmask = lm2ppdone(pipeline->mixer);
>> @@ -639,8 +648,12 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
>>   }
>>
>>   /* bail out early if there aren't any planes */
>> - if (!cnt)
>> - return 0;
>> + if (!cnt) {
>> + if (!state->active)
>> + return 0;
>> + dev_err(dev->dev, "%s has no planes!\n", crtc->name);
>> + return -EINVAL;
>> + }
>
> This seems unrelated?
>

hmm, yeah, kinda.  It was a case that I hit before working out all the
bugs in my kmscube writeback mode, but I guess isn't directly related
to wb.

>>
>>   hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
>>
>> @@ -1160,7 +1173,7 @@ void mdp5_crtc_wait_for_commit_done(struct drm_crtc 
>> *crtc)
>>
>>   if (mdp5_cstate->cmd_mode)
>>   mdp5_crtc_wait_for_pp_done(crtc);
>> - else
>> + else if (mdp5_cstate->pipeline.intf->type != INTF_WB)
>>   mdp5_crtc_wait_for_flush_done(crtc);
>>  }
>>
>> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c 
>> b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
>> index 1f44d8f15ce1..239010905637 100644
>> --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
>> +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
>> @@ -427,7 +427,8 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>>* the MDP5 interfaces) than the number of layer mixers present in HW,
>>* but let's be safe here anyway
>>*/
>> - num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers);
>> + num_crtcs = min(priv->num_encoders + hw_cfg->wb.count,
>> + mdp5_kms->num_hwmixers);
>>
>>   /*
>>* Construct planes equaling the number of hw pipes, and CRTCs for the
>> @@ -482,6 +483,33 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>>   encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
>>   }
>>
>> + /*
>> +  * Lastly, construct writeback connectors.
>> +  */
>> + for (i = 0; i < hw_cfg->wb.count; i++) {
>> + struct drm_writeback_connector *wb_conn;
>> + struct mdp5_ctl *ctl;
>> +
>> +  

Re: [Freedreno] [RFC 4/4] drm/msm/mdp5: writeback support

2018-02-23 Thread Sean Paul
On Fri, Feb 23, 2018 at 08:17:54AM -0500, Rob Clark wrote:
> In a way, based on the original writeback patch from Jilai Wang, but a
> lot has shifted around since then.
> 
> Signed-off-by: Rob Clark 
> ---
>  drivers/gpu/drm/msm/Makefile  |   1 +
>  drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c |  23 +-
>  drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c  |  38 +++-
>  drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h  |   7 +-
>  drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c   | 367 
> ++
>  drivers/gpu/drm/msm/dsi/dsi_host.c|   4 +-
>  6 files changed, 431 insertions(+), 9 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index cd40c050b2d7..c9f50adef2db 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -45,6 +45,7 @@ msm-y := \
>   disp/mdp5/mdp5_mixer.o \
>   disp/mdp5/mdp5_plane.o \
>   disp/mdp5/mdp5_smp.o \
> + disp/mdp5/mdp5_wb.o \
>   msm_atomic.o \
>   msm_debugfs.o \
>   msm_drv.o \
> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c 
> b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
> index 9893e43ba6c5..b00ca88b741d 100644
> --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
> @@ -484,7 +484,11 @@ static void mdp5_crtc_atomic_enable(struct drm_crtc 
> *crtc,
>   }
>  
>   /* Restore vblank irq handling after power is enabled */
> - drm_crtc_vblank_on(crtc);
> +// TODO we can't ->get_scanout_pos() for wb (since virtual intf)..
> +// perhaps drm core should be clever enough not to 
> drm_reset_vblank_timestamp()
> +// for virtual encoders / writeback?
> + if (mdp5_cstate->pipeline.intf->type != INTF_WB)
> + drm_crtc_vblank_on(crtc);
>  
>   mdp5_crtc_mode_set_nofb(crtc);
>  
> @@ -518,7 +522,11 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
>   u32 caps;
>   int ret;
>  
> - caps = MDP_LM_CAP_DISPLAY;
> + if (pipeline->intf->type == INTF_WB)
> + caps = MDP_LM_CAP_WB;
> + else
> + caps = MDP_LM_CAP_DISPLAY;
> +
>   if (need_right_mixer)
>   caps |= MDP_LM_CAP_PAIR;
>  
> @@ -545,6 +553,7 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
>   mdp5_cstate->err_irqmask = intf2err(intf->num);
>   mdp5_cstate->vblank_irqmask = intf2vblank(pipeline->mixer, intf);
>  
> +// XXX should we be treating WB as cmd_mode??
>   if ((intf->type == INTF_DSI) &&
>   (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
>   mdp5_cstate->pp_done_irqmask = lm2ppdone(pipeline->mixer);
> @@ -639,8 +648,12 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
>   }
>  
>   /* bail out early if there aren't any planes */
> - if (!cnt)
> - return 0;
> + if (!cnt) {
> + if (!state->active)
> + return 0;
> + dev_err(dev->dev, "%s has no planes!\n", crtc->name);
> + return -EINVAL;
> + }

This seems unrelated?

>  
>   hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
>  
> @@ -1160,7 +1173,7 @@ void mdp5_crtc_wait_for_commit_done(struct drm_crtc 
> *crtc)
>  
>   if (mdp5_cstate->cmd_mode)
>   mdp5_crtc_wait_for_pp_done(crtc);
> - else
> + else if (mdp5_cstate->pipeline.intf->type != INTF_WB)
>   mdp5_crtc_wait_for_flush_done(crtc);
>  }
>  
> diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c 
> b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
> index 1f44d8f15ce1..239010905637 100644
> --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
> +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
> @@ -427,7 +427,8 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>* the MDP5 interfaces) than the number of layer mixers present in HW,
>* but let's be safe here anyway
>*/
> - num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers);
> + num_crtcs = min(priv->num_encoders + hw_cfg->wb.count,
> + mdp5_kms->num_hwmixers);
>  
>   /*
>* Construct planes equaling the number of hw pipes, and CRTCs for the
> @@ -482,6 +483,33 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>   encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
>   }
>  
> + /*
> +  * Lastly, construct writeback connectors.
> +  */
> + for (i = 0; i < hw_cfg->wb.count; i++) {
> + struct drm_writeback_connector *wb_conn;
> + struct mdp5_ctl *ctl;
> +
> + ctl = mdp5_ctlm_request(mdp5_kms->ctlm, -1);
> + if (!ctl) {
> + dev_err(dev->dev,
> + "failed to allocate ctl for writeback %d\n", i);
> + continue;
> + }
> +
> + wb_conn = mdp5_wb_connector_init(dev, ctl,

[Freedreno] [RFC 4/4] drm/msm/mdp5: writeback support

2018-02-23 Thread Rob Clark
In a way, based on the original writeback patch from Jilai Wang, but a
lot has shifted around since then.

Signed-off-by: Rob Clark 
---
 drivers/gpu/drm/msm/Makefile  |   1 +
 drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c |  23 +-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c  |  38 +++-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.h  |   7 +-
 drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c   | 367 ++
 drivers/gpu/drm/msm/dsi/dsi_host.c|   4 +-
 6 files changed, 431 insertions(+), 9 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/disp/mdp5/mdp5_wb.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index cd40c050b2d7..c9f50adef2db 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -45,6 +45,7 @@ msm-y := \
disp/mdp5/mdp5_mixer.o \
disp/mdp5/mdp5_plane.o \
disp/mdp5/mdp5_smp.o \
+   disp/mdp5/mdp5_wb.o \
msm_atomic.o \
msm_debugfs.o \
msm_drv.o \
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c 
b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
index 9893e43ba6c5..b00ca88b741d 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
@@ -484,7 +484,11 @@ static void mdp5_crtc_atomic_enable(struct drm_crtc *crtc,
}
 
/* Restore vblank irq handling after power is enabled */
-   drm_crtc_vblank_on(crtc);
+// TODO we can't ->get_scanout_pos() for wb (since virtual intf)..
+// perhaps drm core should be clever enough not to drm_reset_vblank_timestamp()
+// for virtual encoders / writeback?
+   if (mdp5_cstate->pipeline.intf->type != INTF_WB)
+   drm_crtc_vblank_on(crtc);
 
mdp5_crtc_mode_set_nofb(crtc);
 
@@ -518,7 +522,11 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
u32 caps;
int ret;
 
-   caps = MDP_LM_CAP_DISPLAY;
+   if (pipeline->intf->type == INTF_WB)
+   caps = MDP_LM_CAP_WB;
+   else
+   caps = MDP_LM_CAP_DISPLAY;
+
if (need_right_mixer)
caps |= MDP_LM_CAP_PAIR;
 
@@ -545,6 +553,7 @@ int mdp5_crtc_setup_pipeline(struct drm_crtc *crtc,
mdp5_cstate->err_irqmask = intf2err(intf->num);
mdp5_cstate->vblank_irqmask = intf2vblank(pipeline->mixer, intf);
 
+// XXX should we be treating WB as cmd_mode??
if ((intf->type == INTF_DSI) &&
(intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) {
mdp5_cstate->pp_done_irqmask = lm2ppdone(pipeline->mixer);
@@ -639,8 +648,12 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
}
 
/* bail out early if there aren't any planes */
-   if (!cnt)
-   return 0;
+   if (!cnt) {
+   if (!state->active)
+   return 0;
+   dev_err(dev->dev, "%s has no planes!\n", crtc->name);
+   return -EINVAL;
+   }
 
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
 
@@ -1160,7 +1173,7 @@ void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
 
if (mdp5_cstate->cmd_mode)
mdp5_crtc_wait_for_pp_done(crtc);
-   else
+   else if (mdp5_cstate->pipeline.intf->type != INTF_WB)
mdp5_crtc_wait_for_flush_done(crtc);
 }
 
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c 
b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index 1f44d8f15ce1..239010905637 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -427,7 +427,8 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
 * the MDP5 interfaces) than the number of layer mixers present in HW,
 * but let's be safe here anyway
 */
-   num_crtcs = min(priv->num_encoders, mdp5_kms->num_hwmixers);
+   num_crtcs = min(priv->num_encoders + hw_cfg->wb.count,
+   mdp5_kms->num_hwmixers);
 
/*
 * Construct planes equaling the number of hw pipes, and CRTCs for the
@@ -482,6 +483,33 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
}
 
+   /*
+* Lastly, construct writeback connectors.
+*/
+   for (i = 0; i < hw_cfg->wb.count; i++) {
+   struct drm_writeback_connector *wb_conn;
+   struct mdp5_ctl *ctl;
+
+   ctl = mdp5_ctlm_request(mdp5_kms->ctlm, -1);
+   if (!ctl) {
+   dev_err(dev->dev,
+   "failed to allocate ctl for writeback %d\n", i);
+   continue;
+   }
+
+   wb_conn = mdp5_wb_connector_init(dev, ctl,
+   hw_cfg->wb.instances[i].id);
+   if (IS_ERR(wb_conn)) {
+   ret = PTR_ERR(wb_conn);
+   dev_err(dev->dev,
+