Re: [Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state

2018-10-12 Thread Jeykumar Sankaran

On 2018-10-09 23:28, Jeykumar Sankaran wrote:

On 2018-10-09 14:06, Sean Paul wrote:

On Mon, Oct 08, 2018 at 09:27:24PM -0700, Jeykumar Sankaran wrote:

DPU maintained reservation lists to cache assigned
HW blocks for the display and a retrieval mechanism for
the individual DRM components to query their respective
HW blocks.

This patch uses the sub-classed CRTC state to store
and track HW blocks assigned for different components
of the display pipeline. It helps the driver:
- to get rid of unwanted store and retrieval RM API's
- to preserve HW resources assigned in atomic_check
  through atomic swap/duplicate.

Separate patch is submitted to remove resource
reservation in atomic_commit path.

Signed-off-by: Jeykumar Sankaran 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   | 65

+++---

 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h   | 14 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 28 +++---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 20 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 58

---

 5 files changed, 72 insertions(+), 113 deletions(-)

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

b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c

index 4960641..0625f56 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -421,69 +421,20 @@ void dpu_crtc_complete_commit(struct drm_crtc

*crtc,

trace_dpu_crtc_complete_commit(DRMID(crtc));
 }

-static void _dpu_crtc_setup_mixer_for_encoder(
-   struct drm_crtc *crtc,
-   struct drm_encoder *enc)
+static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
 {
struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
-   struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
-   struct dpu_rm *rm = _kms->rm;
struct dpu_crtc_mixer *mixer;
-   struct dpu_hw_ctl *last_valid_ctl = NULL;
-   int i;
-   struct dpu_rm_hw_iter lm_iter, ctl_iter;
-
-   dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_LM);
-   dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_CTL);
+   int i, ctl_index;

/* Set up all the mixers and ctls reserved by this encoder */
-   for (i = cstate->num_mixers; i < ARRAY_SIZE(cstate->mixers); i++)

{

+   for (i = 0; i < cstate->num_mixers; i++) {
mixer = >mixers[i];

-   if (!dpu_rm_get_hw(rm, _iter))
-   break;
-   mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw;
-
/* CTL may be <= LMs, if <, multiple LMs controlled by 1

CTL */

-   if (!dpu_rm_get_hw(rm, _iter)) {
-   DPU_DEBUG("no ctl assigned to lm %d, using

previous\n",

-   mixer->hw_lm->idx - LM_0);
-   mixer->lm_ctl = last_valid_ctl;
-   } else {
-   mixer->lm_ctl = (struct dpu_hw_ctl *)ctl_iter.hw;
-   last_valid_ctl = mixer->lm_ctl;
-   }
-
-   /* Shouldn't happen, mixers are always >= ctls */
-   if (!mixer->lm_ctl) {
-   DPU_ERROR("no valid ctls found for lm %d\n",
-   mixer->hw_lm->idx - LM_0);
-   return;
-   }
-
-   cstate->num_mixers++;
-   DPU_DEBUG("setup mixer %d: lm %d\n",
-   i, mixer->hw_lm->idx - LM_0);
-   DPU_DEBUG("setup mixer %d: ctl %d\n",
-   i, mixer->lm_ctl->idx - CTL_0);
-   }
-}
-
-static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
-{
-   struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
-   struct drm_encoder *enc;
-
-   mutex_lock(_crtc->crtc_lock);
-   /* Check for mixers on all encoders attached to this crtc */
-   list_for_each_entry(enc, >dev->mode_config.encoder_list,

head) {

-   if (enc->crtc != crtc)
-   continue;
-
-   _dpu_crtc_setup_mixer_for_encoder(crtc, enc);
+   ctl_index = min(i, cstate->num_ctls - 1);


This is another one of those places I mentioned where we're just 
assuming

a
value is going to be in a certain range. If
num_ctls/num_intfs/num_phys_encs
(all the same value afaict) is 0, we end up in a bad place.
Even though all these variables have the same value, they are 
representing the

sizes of logically seperate components.



At a minimum, there should be a WARN_ON/BUG_ON somewhere ensuring this 
can

never
drop below 0.

Isn't RM guaranteeing that? I can add the WARN_ON checks on these
num_xxx when the HW blocks are allocated.

Thanks,
Jeykumar S.



+   mixer->lm_ctl = cstate->hw_ctls[ctl_index];
}
-
-   mutex_unlock(_crtc->crtc_lock);
 }

 static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc,
@@ -536,10 +487,8 @@ static void dpu_crtc_atomic_begin(struct 

Re: [Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state

2018-10-10 Thread Jeykumar Sankaran

On 2018-10-09 14:06, Sean Paul wrote:

On Mon, Oct 08, 2018 at 09:27:24PM -0700, Jeykumar Sankaran wrote:

DPU maintained reservation lists to cache assigned
HW blocks for the display and a retrieval mechanism for
the individual DRM components to query their respective
HW blocks.

This patch uses the sub-classed CRTC state to store
and track HW blocks assigned for different components
of the display pipeline. It helps the driver:
- to get rid of unwanted store and retrieval RM API's
- to preserve HW resources assigned in atomic_check
  through atomic swap/duplicate.

Separate patch is submitted to remove resource
reservation in atomic_commit path.

Signed-off-by: Jeykumar Sankaran 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   | 65

+++---

 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h   | 14 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 28 +++---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 20 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 58

---

 5 files changed, 72 insertions(+), 113 deletions(-)

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

b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c

index 4960641..0625f56 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -421,69 +421,20 @@ void dpu_crtc_complete_commit(struct drm_crtc

*crtc,

trace_dpu_crtc_complete_commit(DRMID(crtc));
 }

-static void _dpu_crtc_setup_mixer_for_encoder(
-   struct drm_crtc *crtc,
-   struct drm_encoder *enc)
+static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
 {
struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
-   struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
-   struct dpu_rm *rm = _kms->rm;
struct dpu_crtc_mixer *mixer;
-   struct dpu_hw_ctl *last_valid_ctl = NULL;
-   int i;
-   struct dpu_rm_hw_iter lm_iter, ctl_iter;
-
-   dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_LM);
-   dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_CTL);
+   int i, ctl_index;

/* Set up all the mixers and ctls reserved by this encoder */
-   for (i = cstate->num_mixers; i < ARRAY_SIZE(cstate->mixers); i++)

{

+   for (i = 0; i < cstate->num_mixers; i++) {
mixer = >mixers[i];

-   if (!dpu_rm_get_hw(rm, _iter))
-   break;
-   mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw;
-
/* CTL may be <= LMs, if <, multiple LMs controlled by 1

CTL */

-   if (!dpu_rm_get_hw(rm, _iter)) {
-   DPU_DEBUG("no ctl assigned to lm %d, using

previous\n",

-   mixer->hw_lm->idx - LM_0);
-   mixer->lm_ctl = last_valid_ctl;
-   } else {
-   mixer->lm_ctl = (struct dpu_hw_ctl *)ctl_iter.hw;
-   last_valid_ctl = mixer->lm_ctl;
-   }
-
-   /* Shouldn't happen, mixers are always >= ctls */
-   if (!mixer->lm_ctl) {
-   DPU_ERROR("no valid ctls found for lm %d\n",
-   mixer->hw_lm->idx - LM_0);
-   return;
-   }
-
-   cstate->num_mixers++;
-   DPU_DEBUG("setup mixer %d: lm %d\n",
-   i, mixer->hw_lm->idx - LM_0);
-   DPU_DEBUG("setup mixer %d: ctl %d\n",
-   i, mixer->lm_ctl->idx - CTL_0);
-   }
-}
-
-static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
-{
-   struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
-   struct drm_encoder *enc;
-
-   mutex_lock(_crtc->crtc_lock);
-   /* Check for mixers on all encoders attached to this crtc */
-   list_for_each_entry(enc, >dev->mode_config.encoder_list,

head) {

-   if (enc->crtc != crtc)
-   continue;
-
-   _dpu_crtc_setup_mixer_for_encoder(crtc, enc);
+   ctl_index = min(i, cstate->num_ctls - 1);


This is another one of those places I mentioned where we're just 
assuming

a
value is going to be in a certain range. If
num_ctls/num_intfs/num_phys_encs
(all the same value afaict) is 0, we end up in a bad place.
Even though all these variables have the same value, they are 
representing the

sizes of logically seperate components.



At a minimum, there should be a WARN_ON/BUG_ON somewhere ensuring this 
can

never
drop below 0.

Isn't RM guaranteeing that? I can add the WARN_ON checks on these
num_xxx when the HW blocks are allocated.

Thanks,
Jeykumar S.



+   mixer->lm_ctl = cstate->hw_ctls[ctl_index];
}
-
-   mutex_unlock(_crtc->crtc_lock);
 }

 static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc,
@@ -536,10 +487,8 @@ static void dpu_crtc_atomic_begin(struct drm_crtc

*crtc,

dev = crtc->dev;

Re: [Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state

2018-10-09 Thread kbuild test robot
Hi Jeykumar,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robclark/msm-next]
[also build test WARNING on next-20181009]
[cannot apply to v4.19-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Jeykumar-Sankaran/reserve-RM-resources-in-CRTC-state/20181010-031051
base:   git://people.freedesktop.org/~robclark/linux msm-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=7.2.0 make.cross ARCH=arm 

All warnings (new ones prefixed by >>):

   In file included from include/linux/list.h:9:0,
from include/linux/wait.h:7,
from include/linux/wait_bit.h:8,
from include/linux/fs.h:6,
from include/linux/debugfs.h:15,
from drivers/gpu//drm/msm/disp/dpu1/dpu_crtc.c:21:
   drivers/gpu//drm/msm/disp/dpu1/dpu_crtc.c: In function 
'_dpu_crtc_setup_mixers':
   include/linux/kernel.h:845:29: warning: comparison of distinct pointer types 
lacks a cast
  (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
^
   include/linux/kernel.h:859:4: note: in expansion of macro '__typecheck'
  (__typecheck(x, y) && __no_side_effects(x, y))
   ^~~
   include/linux/kernel.h:869:24: note: in expansion of macro '__safe_cmp'
 __builtin_choose_expr(__safe_cmp(x, y), \
   ^~
   include/linux/kernel.h:878:19: note: in expansion of macro '__careful_cmp'
#define min(x, y) __careful_cmp(x, y, <)
  ^
>> drivers/gpu//drm/msm/disp/dpu1/dpu_crtc.c:435:15: note: in expansion of 
>> macro 'min'
  ctl_index = min(i, cstate->num_ctls - 1);
  ^~~

vim +/min +435 drivers/gpu//drm/msm/disp/dpu1/dpu_crtc.c

   423  
   424  static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
   425  {
   426  struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
   427  struct dpu_crtc_mixer *mixer;
   428  int i, ctl_index;
   429  
   430  /* Set up all the mixers and ctls reserved by this encoder */
   431  for (i = 0; i < cstate->num_mixers; i++) {
   432  mixer = >mixers[i];
   433  
   434  /* CTL may be <= LMs, if <, multiple LMs controlled by 
1 CTL */
 > 435  ctl_index = min(i, cstate->num_ctls - 1);
   436  mixer->lm_ctl = cstate->hw_ctls[ctl_index];
   437  }
   438  }
   439  

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation


.config.gz
Description: application/gzip
___
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno


Re: [Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state

2018-10-09 Thread Sean Paul
On Mon, Oct 08, 2018 at 09:27:24PM -0700, Jeykumar Sankaran wrote:
> DPU maintained reservation lists to cache assigned
> HW blocks for the display and a retrieval mechanism for
> the individual DRM components to query their respective
> HW blocks.
> 
> This patch uses the sub-classed CRTC state to store
> and track HW blocks assigned for different components
> of the display pipeline. It helps the driver:
> - to get rid of unwanted store and retrieval RM API's
> - to preserve HW resources assigned in atomic_check
>   through atomic swap/duplicate.
> 
> Separate patch is submitted to remove resource
> reservation in atomic_commit path.
> 
> Signed-off-by: Jeykumar Sankaran 
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   | 65 
> +++---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h   | 14 +
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 28 +++---
>  .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 20 ++-
>  drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 58 ---
>  5 files changed, 72 insertions(+), 113 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 4960641..0625f56 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -421,69 +421,20 @@ void dpu_crtc_complete_commit(struct drm_crtc *crtc,
>   trace_dpu_crtc_complete_commit(DRMID(crtc));
>  }
>  
> -static void _dpu_crtc_setup_mixer_for_encoder(
> - struct drm_crtc *crtc,
> - struct drm_encoder *enc)
> +static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
>  {
>   struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
> - struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
> - struct dpu_rm *rm = _kms->rm;
>   struct dpu_crtc_mixer *mixer;
> - struct dpu_hw_ctl *last_valid_ctl = NULL;
> - int i;
> - struct dpu_rm_hw_iter lm_iter, ctl_iter;
> -
> - dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_LM);
> - dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_CTL);
> + int i, ctl_index;
>  
>   /* Set up all the mixers and ctls reserved by this encoder */
> - for (i = cstate->num_mixers; i < ARRAY_SIZE(cstate->mixers); i++) {
> + for (i = 0; i < cstate->num_mixers; i++) {
>   mixer = >mixers[i];
>  
> - if (!dpu_rm_get_hw(rm, _iter))
> - break;
> - mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw;
> -
>   /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */
> - if (!dpu_rm_get_hw(rm, _iter)) {
> - DPU_DEBUG("no ctl assigned to lm %d, using previous\n",
> - mixer->hw_lm->idx - LM_0);
> - mixer->lm_ctl = last_valid_ctl;
> - } else {
> - mixer->lm_ctl = (struct dpu_hw_ctl *)ctl_iter.hw;
> - last_valid_ctl = mixer->lm_ctl;
> - }
> -
> - /* Shouldn't happen, mixers are always >= ctls */
> - if (!mixer->lm_ctl) {
> - DPU_ERROR("no valid ctls found for lm %d\n",
> - mixer->hw_lm->idx - LM_0);
> - return;
> - }
> -
> - cstate->num_mixers++;
> - DPU_DEBUG("setup mixer %d: lm %d\n",
> - i, mixer->hw_lm->idx - LM_0);
> - DPU_DEBUG("setup mixer %d: ctl %d\n",
> - i, mixer->lm_ctl->idx - CTL_0);
> - }
> -}
> -
> -static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
> -{
> - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
> - struct drm_encoder *enc;
> -
> - mutex_lock(_crtc->crtc_lock);
> - /* Check for mixers on all encoders attached to this crtc */
> - list_for_each_entry(enc, >dev->mode_config.encoder_list, head) {
> - if (enc->crtc != crtc)
> - continue;
> -
> - _dpu_crtc_setup_mixer_for_encoder(crtc, enc);
> + ctl_index = min(i, cstate->num_ctls - 1);

This is another one of those places I mentioned where we're just assuming a
value is going to be in a certain range. If num_ctls/num_intfs/num_phys_encs
(all the same value afaict) is 0, we end up in a bad place.

At a minimum, there should be a WARN_ON/BUG_ON somewhere ensuring this can never
drop below 0.

> + mixer->lm_ctl = cstate->hw_ctls[ctl_index];
>   }
> -
> - mutex_unlock(_crtc->crtc_lock);
>  }
>  
>  static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc,
> @@ -536,10 +487,8 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc,
>   dev = crtc->dev;
>   smmu_state = _crtc->smmu_state;
>  
> - if (!cstate->num_mixers) {
> - _dpu_crtc_setup_mixers(crtc);
> - _dpu_crtc_setup_lm_bounds(crtc, crtc->state);
> - }
> + 

[Freedreno] [PATCH 07/25] drm/msm/dpu: reserve using crtc state

2018-10-08 Thread Jeykumar Sankaran
DPU maintained reservation lists to cache assigned
HW blocks for the display and a retrieval mechanism for
the individual DRM components to query their respective
HW blocks.

This patch uses the sub-classed CRTC state to store
and track HW blocks assigned for different components
of the display pipeline. It helps the driver:
- to get rid of unwanted store and retrieval RM API's
- to preserve HW resources assigned in atomic_check
  through atomic swap/duplicate.

Separate patch is submitted to remove resource
reservation in atomic_commit path.

Signed-off-by: Jeykumar Sankaran 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   | 65 +++---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h   | 14 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c| 28 +++---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 20 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 58 ---
 5 files changed, 72 insertions(+), 113 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 4960641..0625f56 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -421,69 +421,20 @@ void dpu_crtc_complete_commit(struct drm_crtc *crtc,
trace_dpu_crtc_complete_commit(DRMID(crtc));
 }
 
-static void _dpu_crtc_setup_mixer_for_encoder(
-   struct drm_crtc *crtc,
-   struct drm_encoder *enc)
+static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
 {
struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
-   struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc);
-   struct dpu_rm *rm = _kms->rm;
struct dpu_crtc_mixer *mixer;
-   struct dpu_hw_ctl *last_valid_ctl = NULL;
-   int i;
-   struct dpu_rm_hw_iter lm_iter, ctl_iter;
-
-   dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_LM);
-   dpu_rm_init_hw_iter(_iter, enc->base.id, DPU_HW_BLK_CTL);
+   int i, ctl_index;
 
/* Set up all the mixers and ctls reserved by this encoder */
-   for (i = cstate->num_mixers; i < ARRAY_SIZE(cstate->mixers); i++) {
+   for (i = 0; i < cstate->num_mixers; i++) {
mixer = >mixers[i];
 
-   if (!dpu_rm_get_hw(rm, _iter))
-   break;
-   mixer->hw_lm = (struct dpu_hw_mixer *)lm_iter.hw;
-
/* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */
-   if (!dpu_rm_get_hw(rm, _iter)) {
-   DPU_DEBUG("no ctl assigned to lm %d, using previous\n",
-   mixer->hw_lm->idx - LM_0);
-   mixer->lm_ctl = last_valid_ctl;
-   } else {
-   mixer->lm_ctl = (struct dpu_hw_ctl *)ctl_iter.hw;
-   last_valid_ctl = mixer->lm_ctl;
-   }
-
-   /* Shouldn't happen, mixers are always >= ctls */
-   if (!mixer->lm_ctl) {
-   DPU_ERROR("no valid ctls found for lm %d\n",
-   mixer->hw_lm->idx - LM_0);
-   return;
-   }
-
-   cstate->num_mixers++;
-   DPU_DEBUG("setup mixer %d: lm %d\n",
-   i, mixer->hw_lm->idx - LM_0);
-   DPU_DEBUG("setup mixer %d: ctl %d\n",
-   i, mixer->lm_ctl->idx - CTL_0);
-   }
-}
-
-static void _dpu_crtc_setup_mixers(struct drm_crtc *crtc)
-{
-   struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
-   struct drm_encoder *enc;
-
-   mutex_lock(_crtc->crtc_lock);
-   /* Check for mixers on all encoders attached to this crtc */
-   list_for_each_entry(enc, >dev->mode_config.encoder_list, head) {
-   if (enc->crtc != crtc)
-   continue;
-
-   _dpu_crtc_setup_mixer_for_encoder(crtc, enc);
+   ctl_index = min(i, cstate->num_ctls - 1);
+   mixer->lm_ctl = cstate->hw_ctls[ctl_index];
}
-
-   mutex_unlock(_crtc->crtc_lock);
 }
 
 static void _dpu_crtc_setup_lm_bounds(struct drm_crtc *crtc,
@@ -536,10 +487,8 @@ static void dpu_crtc_atomic_begin(struct drm_crtc *crtc,
dev = crtc->dev;
smmu_state = _crtc->smmu_state;
 
-   if (!cstate->num_mixers) {
-   _dpu_crtc_setup_mixers(crtc);
-   _dpu_crtc_setup_lm_bounds(crtc, crtc->state);
-   }
+   _dpu_crtc_setup_mixers(crtc);
+   _dpu_crtc_setup_lm_bounds(crtc, crtc->state);
 
if (dpu_crtc->event) {
WARN_ON(dpu_crtc->event);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
index 75fdd3c..17aaad7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
@@ -84,12 +84,14 @@ struct dpu_crtc_smmu_state_data {
  * struct dpu_crtc_mixer: stores the map for each virtual