diff mbox

[1/5] drm/msm/mdp5: introduce mdp5_hw_pipe

Message ID 1478363161-29293-2-git-send-email-robdclark@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Rob Clark Nov. 5, 2016, 4:25 p.m. UTC
Split out the hardware pipe specifics from mdp5_plane.  To start, the hw
pipes are statically assigned to planes, but next step is to assign the
hw pipes during plane->atomic_check() based on requested caps (scaling,
YUV, etc).  And then hw pipe re-assignment if required if required SMP
blocks changes.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 drivers/gpu/drm/msm/Makefile              |   1 +
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c   | 126 +++++++++++++++++++-----------
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h   |   7 +-
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c  |  43 ++++++++++
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h  |  39 +++++++++
 drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c |  66 +++++++---------
 6 files changed, 197 insertions(+), 85 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
 create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h

Comments

Archit Taneja Nov. 7, 2016, 10:38 a.m. UTC | #1
On 11/05/2016 09:55 PM, Rob Clark wrote:
> Split out the hardware pipe specifics from mdp5_plane.  To start, the hw
> pipes are statically assigned to planes, but next step is to assign the
> hw pipes during plane->atomic_check() based on requested caps (scaling,
> YUV, etc).  And then hw pipe re-assignment if required if required SMP
> blocks changes.
>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  drivers/gpu/drm/msm/Makefile              |   1 +
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c   | 126 +++++++++++++++++++-----------
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h   |   7 +-
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c  |  43 ++++++++++
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h  |  39 +++++++++
>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c |  66 +++++++---------
>  6 files changed, 197 insertions(+), 85 deletions(-)
>  create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
>  create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
>
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index fb5be3e..90f66c4 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -37,6 +37,7 @@ msm-y := \
>  	mdp/mdp5/mdp5_irq.o \
>  	mdp/mdp5/mdp5_mdss.o \
>  	mdp/mdp5/mdp5_kms.o \
> +	mdp/mdp5/mdp5_pipe.o \
>  	mdp/mdp5/mdp5_plane.o \
>  	mdp/mdp5/mdp5_smp.o \
>  	msm_atomic.o \
> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> index f1288c7..d3d45ed 100644
> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
> @@ -119,6 +119,10 @@ static void mdp5_kms_destroy(struct msm_kms *kms)
>  {
>  	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
>  	struct msm_gem_address_space *aspace = mdp5_kms->aspace;
> +	int i;
> +
> +	for (i = 0; i < mdp5_kms->num_hwpipes; i++)
> +		mdp5_pipe_destroy(mdp5_kms->hwpipes[i]);
>
>  	if (aspace) {
>  		aspace->mmu->funcs->detach(aspace->mmu,
> @@ -323,15 +327,6 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
>
>  static int modeset_init(struct mdp5_kms *mdp5_kms)
>  {
> -	static const enum mdp5_pipe rgb_planes[] = {
> -			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
> -	};
> -	static const enum mdp5_pipe vig_planes[] = {
> -			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
> -	};
> -	static const enum mdp5_pipe dma_planes[] = {
> -			SSPP_DMA0, SSPP_DMA1,
> -	};
>  	struct drm_device *dev = mdp5_kms->dev;
>  	struct msm_drm_private *priv = dev->dev_private;
>  	const struct mdp5_cfg_hw *hw_cfg;
> @@ -339,58 +334,34 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>
>  	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
>
> -	/* construct CRTCs and their private planes: */
> -	for (i = 0; i < hw_cfg->pipe_rgb.count; i++) {
> +	/* Construct planes equaling the number of hw pipes, and CRTCs
> +	 * for the N layer-mixers (LM).  The first N planes become primary
> +	 * planes for the CRTCs, with the remainder as overlay planes:
> +	 */

Jfyi, we might need to change this a bit in the future. It'll be better to
get the max number of displays connected on our platform via parsing DT,
etc, and calculate CRTCs based on that, and not number of layermixers. Maybe
add a couple for writeback too. This way, we get the right number of
CRTCs, and we don't rely on #LMs, since we can have 2 per crtc
in the future.

Reviewed-by: Archit Taneja <architt@codeaurora.org>
Rob Clark Nov. 7, 2016, 2:48 p.m. UTC | #2
On Mon, Nov 7, 2016 at 5:38 AM, Archit Taneja <architt@codeaurora.org> wrote:
>
>
> On 11/05/2016 09:55 PM, Rob Clark wrote:
>>
>> Split out the hardware pipe specifics from mdp5_plane.  To start, the hw
>> pipes are statically assigned to planes, but next step is to assign the
>> hw pipes during plane->atomic_check() based on requested caps (scaling,
>> YUV, etc).  And then hw pipe re-assignment if required if required SMP
>> blocks changes.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  drivers/gpu/drm/msm/Makefile              |   1 +
>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c   | 126
>> +++++++++++++++++++-----------
>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h   |   7 +-
>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c  |  43 ++++++++++
>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h  |  39 +++++++++
>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c |  66 +++++++---------
>>  6 files changed, 197 insertions(+), 85 deletions(-)
>>  create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
>>  create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
>>
>> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
>> index fb5be3e..90f66c4 100644
>> --- a/drivers/gpu/drm/msm/Makefile
>> +++ b/drivers/gpu/drm/msm/Makefile
>> @@ -37,6 +37,7 @@ msm-y := \
>>         mdp/mdp5/mdp5_irq.o \
>>         mdp/mdp5/mdp5_mdss.o \
>>         mdp/mdp5/mdp5_kms.o \
>> +       mdp/mdp5/mdp5_pipe.o \
>>         mdp/mdp5/mdp5_plane.o \
>>         mdp/mdp5/mdp5_smp.o \
>>         msm_atomic.o \
>> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> index f1288c7..d3d45ed 100644
>> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>> @@ -119,6 +119,10 @@ static void mdp5_kms_destroy(struct msm_kms *kms)
>>  {
>>         struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
>>         struct msm_gem_address_space *aspace = mdp5_kms->aspace;
>> +       int i;
>> +
>> +       for (i = 0; i < mdp5_kms->num_hwpipes; i++)
>> +               mdp5_pipe_destroy(mdp5_kms->hwpipes[i]);
>>
>>         if (aspace) {
>>                 aspace->mmu->funcs->detach(aspace->mmu,
>> @@ -323,15 +327,6 @@ static int modeset_init_intf(struct mdp5_kms
>> *mdp5_kms, int intf_num)
>>
>>  static int modeset_init(struct mdp5_kms *mdp5_kms)
>>  {
>> -       static const enum mdp5_pipe rgb_planes[] = {
>> -                       SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
>> -       };
>> -       static const enum mdp5_pipe vig_planes[] = {
>> -                       SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
>> -       };
>> -       static const enum mdp5_pipe dma_planes[] = {
>> -                       SSPP_DMA0, SSPP_DMA1,
>> -       };
>>         struct drm_device *dev = mdp5_kms->dev;
>>         struct msm_drm_private *priv = dev->dev_private;
>>         const struct mdp5_cfg_hw *hw_cfg;
>> @@ -339,58 +334,34 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>>
>>         hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
>>
>> -       /* construct CRTCs and their private planes: */
>> -       for (i = 0; i < hw_cfg->pipe_rgb.count; i++) {
>> +       /* Construct planes equaling the number of hw pipes, and CRTCs
>> +        * for the N layer-mixers (LM).  The first N planes become primary
>> +        * planes for the CRTCs, with the remainder as overlay planes:
>> +        */
>
>
> Jfyi, we might need to change this a bit in the future. It'll be better to
> get the max number of displays connected on our platform via parsing DT,
> etc, and calculate CRTCs based on that, and not number of layermixers. Maybe
> add a couple for writeback too. This way, we get the right number of
> CRTCs, and we don't rely on #LMs, since we can have 2 per crtc
> in the future.

I *guess* when we get to that stage, we'll dynamically assign LM's
too, in a similar way as hwpipe.  And I suppose we could also put a
cap on # of crtc's based on # of encoders?

BR,
-R

> Reviewed-by: Archit Taneja <architt@codeaurora.org>
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project
Archit Taneja Nov. 7, 2016, 3:39 p.m. UTC | #3
On 11/7/2016 8:18 PM, Rob Clark wrote:
> On Mon, Nov 7, 2016 at 5:38 AM, Archit Taneja <architt@codeaurora.org> wrote:
>>
>>
>> On 11/05/2016 09:55 PM, Rob Clark wrote:
>>>
>>> Split out the hardware pipe specifics from mdp5_plane.  To start, the hw
>>> pipes are statically assigned to planes, but next step is to assign the
>>> hw pipes during plane->atomic_check() based on requested caps (scaling,
>>> YUV, etc).  And then hw pipe re-assignment if required if required SMP
>>> blocks changes.
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>>  drivers/gpu/drm/msm/Makefile              |   1 +
>>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c   | 126
>>> +++++++++++++++++++-----------
>>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h   |   7 +-
>>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c  |  43 ++++++++++
>>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h  |  39 +++++++++
>>>  drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c |  66 +++++++---------
>>>  6 files changed, 197 insertions(+), 85 deletions(-)
>>>  create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
>>>  create mode 100644 drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
>>>
>>> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
>>> index fb5be3e..90f66c4 100644
>>> --- a/drivers/gpu/drm/msm/Makefile
>>> +++ b/drivers/gpu/drm/msm/Makefile
>>> @@ -37,6 +37,7 @@ msm-y := \
>>>         mdp/mdp5/mdp5_irq.o \
>>>         mdp/mdp5/mdp5_mdss.o \
>>>         mdp/mdp5/mdp5_kms.o \
>>> +       mdp/mdp5/mdp5_pipe.o \
>>>         mdp/mdp5/mdp5_plane.o \
>>>         mdp/mdp5/mdp5_smp.o \
>>>         msm_atomic.o \
>>> diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>>> b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>>> index f1288c7..d3d45ed 100644
>>> --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>>> +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
>>> @@ -119,6 +119,10 @@ static void mdp5_kms_destroy(struct msm_kms *kms)
>>>  {
>>>         struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
>>>         struct msm_gem_address_space *aspace = mdp5_kms->aspace;
>>> +       int i;
>>> +
>>> +       for (i = 0; i < mdp5_kms->num_hwpipes; i++)
>>> +               mdp5_pipe_destroy(mdp5_kms->hwpipes[i]);
>>>
>>>         if (aspace) {
>>>                 aspace->mmu->funcs->detach(aspace->mmu,
>>> @@ -323,15 +327,6 @@ static int modeset_init_intf(struct mdp5_kms
>>> *mdp5_kms, int intf_num)
>>>
>>>  static int modeset_init(struct mdp5_kms *mdp5_kms)
>>>  {
>>> -       static const enum mdp5_pipe rgb_planes[] = {
>>> -                       SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
>>> -       };
>>> -       static const enum mdp5_pipe vig_planes[] = {
>>> -                       SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
>>> -       };
>>> -       static const enum mdp5_pipe dma_planes[] = {
>>> -                       SSPP_DMA0, SSPP_DMA1,
>>> -       };
>>>         struct drm_device *dev = mdp5_kms->dev;
>>>         struct msm_drm_private *priv = dev->dev_private;
>>>         const struct mdp5_cfg_hw *hw_cfg;
>>> @@ -339,58 +334,34 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
>>>
>>>         hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
>>>
>>> -       /* construct CRTCs and their private planes: */
>>> -       for (i = 0; i < hw_cfg->pipe_rgb.count; i++) {
>>> +       /* Construct planes equaling the number of hw pipes, and CRTCs
>>> +        * for the N layer-mixers (LM).  The first N planes become primary
>>> +        * planes for the CRTCs, with the remainder as overlay planes:
>>> +        */
>>
>>
>> Jfyi, we might need to change this a bit in the future. It'll be better to
>> get the max number of displays connected on our platform via parsing DT,
>> etc, and calculate CRTCs based on that, and not number of layermixers. Maybe
>> add a couple for writeback too. This way, we get the right number of
>> CRTCs, and we don't rely on #LMs, since we can have 2 per crtc
>> in the future.
>
> I *guess* when we get to that stage, we'll dynamically assign LM's
> too, in a similar way as hwpipe.  And I suppose we could also put a
> cap on # of crtc's based on # of encoders?

Yeah. Currently, we end up creating 2 encoders for each DSI instance,
i.e, 1 for command mode, and another for video mode. Only one can be
used at a time. If we adjust for that, then I guess # of crtcs should
equal to # of encoders.

Archit

>
> BR,
> -R
>
>> Reviewed-by: Archit Taneja <architt@codeaurora.org>
>>
>> --
>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>> a Linux Foundation Collaborative Project
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index fb5be3e..90f66c4 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -37,6 +37,7 @@  msm-y := \
 	mdp/mdp5/mdp5_irq.o \
 	mdp/mdp5/mdp5_mdss.o \
 	mdp/mdp5/mdp5_kms.o \
+	mdp/mdp5/mdp5_pipe.o \
 	mdp/mdp5/mdp5_plane.o \
 	mdp/mdp5/mdp5_smp.o \
 	msm_atomic.o \
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index f1288c7..d3d45ed 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -119,6 +119,10 @@  static void mdp5_kms_destroy(struct msm_kms *kms)
 {
 	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
 	struct msm_gem_address_space *aspace = mdp5_kms->aspace;
+	int i;
+
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++)
+		mdp5_pipe_destroy(mdp5_kms->hwpipes[i]);
 
 	if (aspace) {
 		aspace->mmu->funcs->detach(aspace->mmu,
@@ -323,15 +327,6 @@  static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
 
 static int modeset_init(struct mdp5_kms *mdp5_kms)
 {
-	static const enum mdp5_pipe rgb_planes[] = {
-			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
-	};
-	static const enum mdp5_pipe vig_planes[] = {
-			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
-	};
-	static const enum mdp5_pipe dma_planes[] = {
-			SSPP_DMA0, SSPP_DMA1,
-	};
 	struct drm_device *dev = mdp5_kms->dev;
 	struct msm_drm_private *priv = dev->dev_private;
 	const struct mdp5_cfg_hw *hw_cfg;
@@ -339,58 +334,34 @@  static int modeset_init(struct mdp5_kms *mdp5_kms)
 
 	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
 
-	/* construct CRTCs and their private planes: */
-	for (i = 0; i < hw_cfg->pipe_rgb.count; i++) {
+	/* Construct planes equaling the number of hw pipes, and CRTCs
+	 * for the N layer-mixers (LM).  The first N planes become primary
+	 * planes for the CRTCs, with the remainder as overlay planes:
+	 */
+	for (i = 0; i < mdp5_kms->num_hwpipes; i++) {
+		bool primary = i < mdp5_cfg->lm.count;
 		struct drm_plane *plane;
 		struct drm_crtc *crtc;
 
-		plane = mdp5_plane_init(dev, rgb_planes[i], true,
-			hw_cfg->pipe_rgb.base[i], hw_cfg->pipe_rgb.caps);
+		plane = mdp5_plane_init(dev, mdp5_kms->hwpipes[i], primary);
 		if (IS_ERR(plane)) {
 			ret = PTR_ERR(plane);
-			dev_err(dev->dev, "failed to construct plane for %s (%d)\n",
-					pipe2name(rgb_planes[i]), ret);
+			dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
 			goto fail;
 		}
 
+		if (!primary)
+			continue;
+
 		crtc  = mdp5_crtc_init(dev, plane, i);
 		if (IS_ERR(crtc)) {
 			ret = PTR_ERR(crtc);
-			dev_err(dev->dev, "failed to construct crtc for %s (%d)\n",
-					pipe2name(rgb_planes[i]), ret);
+			dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
 			goto fail;
 		}
 		priv->crtcs[priv->num_crtcs++] = crtc;
 	}
 
-	/* Construct video planes: */
-	for (i = 0; i < hw_cfg->pipe_vig.count; i++) {
-		struct drm_plane *plane;
-
-		plane = mdp5_plane_init(dev, vig_planes[i], false,
-			hw_cfg->pipe_vig.base[i], hw_cfg->pipe_vig.caps);
-		if (IS_ERR(plane)) {
-			ret = PTR_ERR(plane);
-			dev_err(dev->dev, "failed to construct %s plane: %d\n",
-					pipe2name(vig_planes[i]), ret);
-			goto fail;
-		}
-	}
-
-	/* DMA planes */
-	for (i = 0; i < hw_cfg->pipe_dma.count; i++) {
-		struct drm_plane *plane;
-
-		plane = mdp5_plane_init(dev, dma_planes[i], false,
-				hw_cfg->pipe_dma.base[i], hw_cfg->pipe_dma.caps);
-		if (IS_ERR(plane)) {
-			ret = PTR_ERR(plane);
-			dev_err(dev->dev, "failed to construct %s plane: %d\n",
-					pipe2name(dma_planes[i]), ret);
-			goto fail;
-		}
-	}
-
 	/* Construct encoders and modeset initialize connector devices
 	 * for each external display interface.
 	 */
@@ -676,6 +647,67 @@  static void mdp5_destroy(struct platform_device *pdev)
 		pm_runtime_disable(&pdev->dev);
 }
 
+static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt,
+		const enum mdp5_pipe *pipes, const uint32_t *offsets,
+		uint32_t caps)
+{
+	struct drm_device *dev = mdp5_kms->dev;
+	int i, ret;
+
+	for (i = 0; i < cnt; i++) {
+		struct mdp5_hw_pipe *hwpipe;
+
+		hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps);
+		if (IS_ERR(hwpipe)) {
+			ret = PTR_ERR(hwpipe);
+			dev_err(dev->dev, "failed to construct pipe for %s (%d)\n",
+					pipe2name(pipes[i]), ret);
+			return ret;
+		}
+		hwpipe->idx = mdp5_kms->num_hwpipes;
+		mdp5_kms->hwpipes[mdp5_kms->num_hwpipes++] = hwpipe;
+	}
+
+	return 0;
+}
+
+static int hwpipe_init(struct mdp5_kms *mdp5_kms)
+{
+	static const enum mdp5_pipe rgb_planes[] = {
+			SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, SSPP_RGB3,
+	};
+	static const enum mdp5_pipe vig_planes[] = {
+			SSPP_VIG0, SSPP_VIG1, SSPP_VIG2, SSPP_VIG3,
+	};
+	static const enum mdp5_pipe dma_planes[] = {
+			SSPP_DMA0, SSPP_DMA1,
+	};
+	const struct mdp5_cfg_hw *hw_cfg;
+	int ret;
+
+	hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
+
+	/* Construct RGB pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_rgb.count, rgb_planes,
+			hw_cfg->pipe_rgb.base, hw_cfg->pipe_rgb.caps);
+	if (ret)
+		return ret;
+
+	/* Construct video (VIG) pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_vig.count, vig_planes,
+			hw_cfg->pipe_vig.base, hw_cfg->pipe_vig.caps);
+	if (ret)
+		return ret;
+
+	/* Construct DMA pipes: */
+	ret = construct_pipes(mdp5_kms, hw_cfg->pipe_dma.count, dma_planes,
+			hw_cfg->pipe_dma.base, hw_cfg->pipe_dma.caps);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
 {
 	struct msm_drm_private *priv = dev->dev_private;
@@ -765,6 +797,10 @@  static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
 		goto fail;
 	}
 
+	ret = hwpipe_init(mdp5_kms);
+	if (ret)
+		goto fail;
+
 	/* set uninit-ed kms */
 	priv->kms = &mdp5_kms->base.base;
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index d5e40af..88120c5 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -24,6 +24,7 @@ 
 #include "mdp5_cfg.h"	/* must be included before mdp5.xml.h */
 #include "mdp5.xml.h"
 #include "mdp5_ctl.h"
+#include "mdp5_pipe.h"
 #include "mdp5_smp.h"
 
 struct mdp5_kms {
@@ -33,6 +34,9 @@  struct mdp5_kms {
 
 	struct platform_device *pdev;
 
+	unsigned num_hwpipes;
+	struct mdp5_hw_pipe *hwpipes[16];
+
 	struct mdp5_cfg_handler *cfg;
 	uint32_t caps;	/* MDP capabilities (MDP_CAP_XXX bits) */
 
@@ -207,8 +211,7 @@  void mdp5_plane_complete_commit(struct drm_plane *plane,
 	struct drm_plane_state *state);
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-		enum mdp5_pipe pipe, bool private_plane,
-		uint32_t reg_offset, uint32_t caps);
+		struct mdp5_hw_pipe *hwpipe, bool primary);
 
 uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
 
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
new file mode 100644
index 0000000..7f3e8e50
--- /dev/null
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
@@ -0,0 +1,43 @@ 
+/*
+ * Copyright (C) 2016 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mdp5_kms.h"
+
+void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe)
+{
+	kfree(hwpipe);
+}
+
+struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
+		uint32_t reg_offset, uint32_t caps)
+{
+	struct mdp5_hw_pipe *hwpipe;
+
+	hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL);
+	if (!hwpipe)
+		return ERR_PTR(-ENOMEM);
+
+	hwpipe->name = pipe2name(pipe);
+	hwpipe->pipe = pipe;
+	hwpipe->reg_offset = reg_offset;
+	hwpipe->caps = caps;
+	hwpipe->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
+
+	spin_lock_init(&hwpipe->pipe_lock);
+
+	return hwpipe;
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
new file mode 100644
index 0000000..dcfa0e0
--- /dev/null
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.h
@@ -0,0 +1,39 @@ 
+/*
+ * Copyright (C) 2016 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MDP5_PIPE_H__
+#define __MDP5_PIPE_H__
+
+/* represents a hw pipe, which is dynamically assigned to a plane */
+struct mdp5_hw_pipe {
+	int idx;
+
+	const char *name;
+	enum mdp5_pipe pipe;
+
+	spinlock_t pipe_lock;     /* protect REG_MDP5_PIPE_* registers */
+	uint32_t reg_offset;
+	uint32_t caps;
+
+	uint32_t flush_mask;      /* used to commit pipe registers */
+};
+
+struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
+		uint32_t reg_offset, uint32_t caps);
+void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe);
+
+#endif /* __MDP5_PIPE_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 7b46cfb..e4ecfeb 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -22,13 +22,7 @@ 
 struct mdp5_plane {
 	struct drm_plane base;
 
-	enum mdp5_pipe pipe;
-
-	spinlock_t pipe_lock;	/* protect REG_MDP5_PIPE_* registers */
-	uint32_t reg_offset;
-	uint32_t caps;
-
-	uint32_t flush_mask;	/* used to commit pipe registers */
+	struct mdp5_hw_pipe *hwpipe;
 
 	uint32_t nformats;
 	uint32_t formats[32];
@@ -71,8 +65,8 @@  static void mdp5_plane_install_rotation_property(struct drm_device *dev,
 {
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 
-	if (!(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP) &&
-		!(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP))
+	if (!(mdp5_plane->hwpipe->caps & MDP_PIPE_CAP_HFLIP) &&
+		!(mdp5_plane->hwpipe->caps & MDP_PIPE_CAP_VFLIP))
 		return;
 
 	drm_plane_create_rotation_property(plane,
@@ -304,13 +298,13 @@  static int mdp5_plane_atomic_check(struct drm_plane *plane,
 
 		format = to_mdp_format(msm_framebuffer_format(state->fb));
 		if (MDP_FORMAT_IS_YUV(format) &&
-			!pipe_supports_yuv(mdp5_plane->caps)) {
+			!pipe_supports_yuv(mdp5_plane->hwpipe->caps)) {
 			DBG("Pipe doesn't support YUV\n");
 
 			return -EINVAL;
 		}
 
-		if (!(mdp5_plane->caps & MDP_PIPE_CAP_SCALE) &&
+		if (!(mdp5_plane->hwpipe->caps & MDP_PIPE_CAP_SCALE) &&
 			(((state->src_w >> 16) != state->crtc_w) ||
 			((state->src_h >> 16) != state->crtc_h))) {
 			DBG("Pipe doesn't support scaling (%dx%d -> %dx%d)\n",
@@ -324,11 +318,12 @@  static int mdp5_plane_atomic_check(struct drm_plane *plane,
 						 DRM_ROTATE_0 |
 						 DRM_REFLECT_X |
 						 DRM_REFLECT_Y);
+
 		hflip = !!(rotation & DRM_REFLECT_X);
 		vflip = !!(rotation & DRM_REFLECT_Y);
 
-		if ((vflip && !(mdp5_plane->caps & MDP_PIPE_CAP_VFLIP)) ||
-			(hflip && !(mdp5_plane->caps & MDP_PIPE_CAP_HFLIP))) {
+		if ((vflip && !(mdp5_plane->hwpipe->caps & MDP_PIPE_CAP_VFLIP)) ||
+			(hflip && !(mdp5_plane->hwpipe->caps & MDP_PIPE_CAP_HFLIP))) {
 			DBG("Pipe doesn't support flip\n");
 
 			return -EINVAL;
@@ -396,7 +391,7 @@  static void set_scanout_locked(struct drm_plane *plane,
 {
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	enum mdp5_pipe pipe = mdp5_plane->pipe;
+	enum mdp5_pipe pipe = mdp5_plane->hwpipe->pipe;
 
 	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
 			MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
@@ -678,12 +673,13 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 {
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 	struct drm_plane_state *pstate = plane->state;
+	struct mdp5_hw_pipe *hwpipe = mdp5_plane->hwpipe;
 	struct mdp5_kms *mdp5_kms = get_kms(plane);
-	enum mdp5_pipe pipe = mdp5_plane->pipe;
+	enum mdp5_pipe pipe = hwpipe->pipe;
 	const struct mdp_format *format;
 	uint32_t nplanes, config = 0;
 	uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,};
-	bool pe = mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT;
+	bool pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT;
 	int pe_left[COMP_MAX], pe_right[COMP_MAX];
 	int pe_top[COMP_MAX], pe_bottom[COMP_MAX];
 	uint32_t hdecm = 0, vdecm = 0;
@@ -714,8 +710,8 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 
 	/* Request some memory from the SMP: */
 	if (mdp5_kms->smp) {
-		ret = mdp5_smp_request(mdp5_kms->smp,
-				mdp5_plane->pipe, format, src_w, false);
+		ret = mdp5_smp_request(mdp5_kms->smp, pipe,
+				format, src_w, false);
 		if (ret)
 			return ret;
 	}
@@ -737,7 +733,7 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 	if (ret)
 		return ret;
 
-	if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
+	if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
 		calc_pixel_ext(format, src_w, crtc_w, phasex_step,
 					 pe_left, pe_right, true);
 		calc_pixel_ext(format, src_h, crtc_h, phasey_step,
@@ -758,7 +754,7 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 	hflip = !!(rotation & DRM_REFLECT_X);
 	vflip = !!(rotation & DRM_REFLECT_Y);
 
-	spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
+	spin_lock_irqsave(&hwpipe->pipe_lock, flags);
 
 	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
 			MDP5_PIPE_SRC_IMG_SIZE_WIDTH(min(fb->width, src_w)) |
@@ -807,12 +803,12 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 	/* not using secure mode: */
 	mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
 
-	if (mdp5_plane->caps & MDP_PIPE_CAP_SW_PIX_EXT)
+	if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT)
 		mdp5_write_pixel_ext(mdp5_kms, pipe, format,
 				src_w, pe_left, pe_right,
 				src_h, pe_top, pe_bottom);
 
-	if (mdp5_plane->caps & MDP_PIPE_CAP_SCALE) {
+	if (hwpipe->caps & MDP_PIPE_CAP_SCALE) {
 		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
 				phasex_step[COMP_0]);
 		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
@@ -827,7 +823,7 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 		mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
 	}
 
-	if (mdp5_plane->caps & MDP_PIPE_CAP_CSC) {
+	if (hwpipe->caps & MDP_PIPE_CAP_CSC) {
 		if (MDP_FORMAT_IS_YUV(format))
 			csc_enable(mdp5_kms, pipe,
 					mdp_get_default_csc_cfg(CSC_YUV2RGB));
@@ -837,7 +833,7 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 
 	set_scanout_locked(plane, fb);
 
-	spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
+	spin_unlock_irqrestore(&hwpipe->pipe_lock, flags);
 
 	return ret;
 }
@@ -845,14 +841,14 @@  static int mdp5_plane_mode_set(struct drm_plane *plane,
 enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
 {
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-	return mdp5_plane->pipe;
+	return mdp5_plane->hwpipe->pipe;
 }
 
 uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
 {
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
 
-	return mdp5_plane->flush_mask;
+	return mdp5_plane->hwpipe->flush_mask;
 }
 
 /* called after vsync in thread context */
@@ -861,7 +857,7 @@  void mdp5_plane_complete_commit(struct drm_plane *plane,
 {
 	struct mdp5_kms *mdp5_kms = get_kms(plane);
 	struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
-	enum mdp5_pipe pipe = mdp5_plane->pipe;
+	enum mdp5_pipe pipe = mdp5_plane->hwpipe->pipe;
 
 	if (mdp5_kms->smp) {
 		if (plane_enabled(plane->state)) {
@@ -878,8 +874,7 @@  void mdp5_plane_complete_commit(struct drm_plane *plane,
 
 /* initialize plane */
 struct drm_plane *mdp5_plane_init(struct drm_device *dev,
-		enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset,
-		uint32_t caps)
+		struct mdp5_hw_pipe *hwpipe, bool primary)
 {
 	struct drm_plane *plane = NULL;
 	struct mdp5_plane *mdp5_plane;
@@ -894,21 +889,16 @@  struct drm_plane *mdp5_plane_init(struct drm_device *dev,
 
 	plane = &mdp5_plane->base;
 
-	mdp5_plane->pipe = pipe;
-	mdp5_plane->caps = caps;
+	mdp5_plane->hwpipe = hwpipe;
 
 	mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
 		ARRAY_SIZE(mdp5_plane->formats),
-		!pipe_supports_yuv(mdp5_plane->caps));
-
-	mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
-	mdp5_plane->reg_offset = reg_offset;
-	spin_lock_init(&mdp5_plane->pipe_lock);
+		!pipe_supports_yuv(hwpipe->caps));
 
-	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 	ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
 				 mdp5_plane->formats, mdp5_plane->nformats,
-				 type, "%s", pipe2name(pipe));
+				 type, "%s", hwpipe->name);
 	if (ret)
 		goto fail;