aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/mdp/mdp5
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/mdp/mdp5')
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h48
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c10
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h3
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c135
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c73
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c14
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h4
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c77
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c123
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h45
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c8
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c183
12 files changed, 476 insertions, 247 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
index 27d5371acee0..e6dfc518d4db 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
@@ -8,19 +8,11 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2015-05-20 20:03:14)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-02-10 17:07:21)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-05-20 20:03:14)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2015-09-18 12:07:28)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 36965 bytes, from 2016-11-26 23:01:08)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 27887 bytes, from 2015-10-22 16:34:52)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 602 bytes, from 2015-10-22 16:35:02)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2015-05-20 20:03:14)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2015-05-20 20:03:07)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 41472 bytes, from 2016-01-22 18:18:18)
-- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-20 20:03:14)
-
-Copyright (C) 2013-2016 by the following authors:
+- /local/mnt/workspace/source_trees/envytools/rnndb/../rnndb/mdp/mdp5.xml ( 37411 bytes, from 2017-01-11 05:19:19)
+- /local/mnt/workspace/source_trees/envytools/rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-05-09 06:32:54)
+- /local/mnt/workspace/source_trees/envytools/rnndb/mdp/mdp_common.xml ( 2849 bytes, from 2016-01-07 08:45:55)
+
+Copyright (C) 2013-2017 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
@@ -65,16 +57,19 @@ enum mdp5_intfnum {
};
enum mdp5_pipe {
- SSPP_VIG0 = 0,
- SSPP_VIG1 = 1,
- SSPP_VIG2 = 2,
- SSPP_RGB0 = 3,
- SSPP_RGB1 = 4,
- SSPP_RGB2 = 5,
- SSPP_DMA0 = 6,
- SSPP_DMA1 = 7,
- SSPP_VIG3 = 8,
- SSPP_RGB3 = 9,
+ SSPP_NONE = 0,
+ SSPP_VIG0 = 1,
+ SSPP_VIG1 = 2,
+ SSPP_VIG2 = 3,
+ SSPP_RGB0 = 4,
+ SSPP_RGB1 = 5,
+ SSPP_RGB2 = 6,
+ SSPP_DMA0 = 7,
+ SSPP_DMA1 = 8,
+ SSPP_VIG3 = 9,
+ SSPP_RGB3 = 10,
+ SSPP_CURSOR0 = 11,
+ SSPP_CURSOR1 = 12,
};
enum mdp5_ctl_mode {
@@ -532,6 +527,7 @@ static inline uint32_t MDP5_CTL_LAYER_EXT_REG_CURSOR1(enum mdp_mixer_stage_id va
static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
{
switch (idx) {
+ case SSPP_NONE: return (INVALID_IDX(idx));
case SSPP_VIG0: return (mdp5_cfg->pipe_vig.base[0]);
case SSPP_VIG1: return (mdp5_cfg->pipe_vig.base[1]);
case SSPP_VIG2: return (mdp5_cfg->pipe_vig.base[2]);
@@ -542,6 +538,8 @@ static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
case SSPP_DMA1: return (mdp5_cfg->pipe_dma.base[1]);
case SSPP_VIG3: return (mdp5_cfg->pipe_vig.base[3]);
case SSPP_RGB3: return (mdp5_cfg->pipe_rgb.base[3]);
+ case SSPP_CURSOR0: return (mdp5_cfg->pipe_cursor.base[0]);
+ case SSPP_CURSOR1: return (mdp5_cfg->pipe_cursor.base[1]);
default: return INVALID_IDX(idx);
}
}
@@ -1073,6 +1071,10 @@ static inline uint32_t REG_MDP5_LM_BLEND_COLOR_OUT(uint32_t i0) { return 0x00000
#define MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA 0x00000004
#define MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA 0x00000008
#define MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA 0x00000010
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE4_FG_ALPHA 0x00000020
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE5_FG_ALPHA 0x00000040
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE6_FG_ALPHA 0x00000080
+#define MDP5_LM_BLEND_COLOR_OUT_SPLIT_LEFT_RIGHT 0x80000000
static inline uint32_t REG_MDP5_LM_OUT_SIZE(uint32_t i0) { return 0x00000004 + __offset_LM(i0); }
#define MDP5_LM_OUT_SIZE_HEIGHT__MASK 0xffff0000
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
index 618b2ffed9b4..34ab553f6897 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c
@@ -421,6 +421,16 @@ const struct mdp5_cfg_hw msm8x96_config = {
MDP_PIPE_CAP_SW_PIX_EXT |
0,
},
+ .pipe_cursor = {
+ .count = 2,
+ .base = { 0x34000, 0x36000 },
+ .caps = MDP_PIPE_CAP_HFLIP |
+ MDP_PIPE_CAP_VFLIP |
+ MDP_PIPE_CAP_SW_PIX_EXT |
+ MDP_PIPE_CAP_CURSOR |
+ 0,
+ },
+
.lm = {
.count = 6,
.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
index 050e1618c836..b1c7daaede86 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h
@@ -32,7 +32,7 @@ extern const struct mdp5_cfg_hw *mdp5_cfg;
typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS);
#define MDP5_SUB_BLOCK_DEFINITION \
- int count; \
+ unsigned int count; \
uint32_t base[MAX_BASES]
struct mdp5_sub_block {
@@ -85,6 +85,7 @@ struct mdp5_cfg_hw {
struct mdp5_pipe_block pipe_vig;
struct mdp5_pipe_block pipe_rgb;
struct mdp5_pipe_block pipe_dma;
+ struct mdp5_pipe_block pipe_cursor;
struct mdp5_lm_block lm;
struct mdp5_sub_block dspp;
struct mdp5_sub_block ad;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
index c627ab6d0061..df1c8adec3f3 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
@@ -16,16 +16,6 @@
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
-struct mdp5_cmd_encoder {
- struct drm_encoder base;
- struct mdp5_interface intf;
- bool enabled;
- uint32_t bsc;
-
- struct mdp5_ctl *ctl;
-};
-#define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
-
static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
{
struct msm_drm_private *priv = encoder->dev->dev_private;
@@ -36,47 +26,8 @@ static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
#include <mach/board.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
- { \
- .src = MSM_BUS_MASTER_MDP_PORT0, \
- .dst = MSM_BUS_SLAVE_EBI_CH0, \
- .ab = (ab_val), \
- .ib = (ib_val), \
- }
-
-static struct msm_bus_vectors mdp_bus_vectors[] = {
- MDP_BUS_VECTOR_ENTRY(0, 0),
- MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
-};
-static struct msm_bus_paths mdp_bus_usecases[] = { {
- .num_paths = 1,
- .vectors = &mdp_bus_vectors[0],
-}, {
- .num_paths = 1,
- .vectors = &mdp_bus_vectors[1],
-} };
-static struct msm_bus_scale_pdata mdp_bus_scale_table = {
- .usecase = mdp_bus_usecases,
- .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
- .name = "mdss_mdp",
-};
-
-static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc)
-{
- mdp5_cmd_enc->bsc = msm_bus_scale_register_client(
- &mdp_bus_scale_table);
- DBG("bus scale client: %08x", mdp5_cmd_enc->bsc);
-}
-
-static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc)
-{
- if (mdp5_cmd_enc->bsc) {
- msm_bus_scale_unregister_client(mdp5_cmd_enc->bsc);
- mdp5_cmd_enc->bsc = 0;
- }
-}
-static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx)
+static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx)
{
if (mdp5_cmd_enc->bsc) {
DBG("set bus scaling: %d", idx);
@@ -89,14 +40,12 @@ static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx)
}
}
#else
-static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
-static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
-static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx) {}
+static void bs_set(struct mdp5_encoder *mdp5_cmd_enc, int idx) {}
#endif
#define VSYNC_CLK_RATE 19200000
static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
- struct drm_display_mode *mode)
+ struct drm_display_mode *mode)
{
struct mdp5_kms *mdp5_kms = get_kms(encoder);
struct device *dev = encoder->dev->dev;
@@ -176,23 +125,11 @@ static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
clk_disable_unprepare(mdp5_kms->vsync_clk);
}
-static void mdp5_cmd_encoder_destroy(struct drm_encoder *encoder)
-{
- struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
- bs_fini(mdp5_cmd_enc);
- drm_encoder_cleanup(encoder);
- kfree(mdp5_cmd_enc);
-}
-
-static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
- .destroy = mdp5_cmd_encoder_destroy,
-};
-
-static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+ struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
mode = adjusted_mode;
@@ -209,9 +146,9 @@ static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
mdp5_cmd_enc->ctl);
}
-static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
+void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
{
- struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+ struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
@@ -228,9 +165,9 @@ static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
mdp5_cmd_enc->enabled = false;
}
-static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
+void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
{
- struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+ struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
struct mdp5_ctl *ctl = mdp5_cmd_enc->ctl;
struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
@@ -248,16 +185,10 @@ static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
mdp5_cmd_enc->enabled = true;
}
-static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = {
- .mode_set = mdp5_cmd_encoder_mode_set,
- .disable = mdp5_cmd_encoder_disable,
- .enable = mdp5_cmd_encoder_enable,
-};
-
int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
- struct drm_encoder *slave_encoder)
+ struct drm_encoder *slave_encoder)
{
- struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
+ struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms;
int intf_num;
u32 data = 0;
@@ -292,43 +223,3 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
return 0;
}
-
-/* initialize command mode encoder */
-struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
- struct mdp5_interface *intf, struct mdp5_ctl *ctl)
-{
- struct drm_encoder *encoder = NULL;
- struct mdp5_cmd_encoder *mdp5_cmd_enc;
- int ret;
-
- if (WARN_ON((intf->type != INTF_DSI) &&
- (intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) {
- ret = -EINVAL;
- goto fail;
- }
-
- mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL);
- if (!mdp5_cmd_enc) {
- ret = -ENOMEM;
- goto fail;
- }
-
- memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
- encoder = &mdp5_cmd_enc->base;
- mdp5_cmd_enc->ctl = ctl;
-
- drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
- DRM_MODE_ENCODER_DSI, NULL);
-
- drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
-
- bs_init(mdp5_cmd_enc);
-
- return encoder;
-
-fail:
- if (encoder)
- mdp5_cmd_encoder_destroy(encoder);
-
- return ERR_PTR(ret);
-}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 1ce8a01a5a28..d0c8b38b96ce 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -177,6 +177,21 @@ static void mdp5_crtc_destroy(struct drm_crtc *crtc)
kfree(mdp5_crtc);
}
+static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage)
+{
+ switch (stage) {
+ case STAGE0: return MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA;
+ case STAGE1: return MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA;
+ case STAGE2: return MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA;
+ case STAGE3: return MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA;
+ case STAGE4: return MDP5_LM_BLEND_COLOR_OUT_STAGE4_FG_ALPHA;
+ case STAGE5: return MDP5_LM_BLEND_COLOR_OUT_STAGE5_FG_ALPHA;
+ case STAGE6: return MDP5_LM_BLEND_COLOR_OUT_STAGE6_FG_ALPHA;
+ default:
+ return 0;
+ }
+}
+
/*
* blend_setup() - blend all the planes of a CRTC
*
@@ -195,8 +210,10 @@ static void blend_setup(struct drm_crtc *crtc)
uint32_t lm = mdp5_crtc->lm;
uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
unsigned long flags;
- uint8_t stage[STAGE_MAX + 1];
+ enum mdp5_pipe stage[STAGE_MAX + 1] = { SSPP_NONE };
int i, plane_cnt = 0;
+ bool bg_alpha_enabled = false;
+ u32 mixer_op_mode = 0;
#define blender(stage) ((stage) - STAGE0)
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
@@ -218,6 +235,11 @@ static void blend_setup(struct drm_crtc *crtc)
if (!pstates[STAGE_BASE]) {
ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
DBG("Border Color is enabled");
+ } else if (plane_cnt) {
+ format = to_mdp_format(msm_framebuffer_format(pstates[STAGE_BASE]->base.fb));
+
+ if (format->alpha_enable)
+ bg_alpha_enabled = true;
}
/* The reset for blending */
@@ -232,6 +254,12 @@ static void blend_setup(struct drm_crtc *crtc)
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST);
fg_alpha = pstates[i]->alpha;
bg_alpha = 0xFF - pstates[i]->alpha;
+
+ if (!format->alpha_enable && bg_alpha_enabled)
+ mixer_op_mode = 0;
+ else
+ mixer_op_mode |= mdp5_lm_use_fg_alpha_mask(i);
+
DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha);
if (format->alpha_enable && pstates[i]->premultiplied) {
@@ -268,6 +296,8 @@ static void blend_setup(struct drm_crtc *crtc)
blender(i)), bg_alpha);
}
+ mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm), mixer_op_mode);
+
mdp5_ctl_blend(mdp5_crtc->ctl, stage, plane_cnt, ctl_blend_flags);
out:
@@ -370,6 +400,7 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
struct plane_state pstates[STAGE_MAX + 1];
const struct mdp5_cfg_hw *hw_cfg;
const struct drm_plane_state *pstate;
+ bool cursor_plane = false;
int cnt = 0, base = 0, i;
DBG("%s: check", crtc->name);
@@ -379,6 +410,9 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
pstates[cnt].state = to_mdp5_plane_state(pstate);
cnt++;
+
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
+ cursor_plane = true;
}
/* assign a stage based on sorted zpos property */
@@ -390,6 +424,10 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
if ((cnt > 0) && !is_fullscreen(state, &pstates[0].state->base))
base++;
+ /* trigger a warning if cursor isn't the highest zorder */
+ WARN_ON(cursor_plane &&
+ (pstates[cnt - 1].plane->type != DRM_PLANE_TYPE_CURSOR));
+
/* verify that there are not too many planes attached to crtc
* and that we don't have conflicting mixer stages:
*/
@@ -401,7 +439,10 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
}
for (i = 0; i < cnt; i++) {
- pstates[i].state->stage = STAGE_BASE + i + base;
+ if (cursor_plane && (i == (cnt - 1)))
+ pstates[i].state->stage = hw_cfg->lm.nb_stages;
+ else
+ pstates[i].state->stage = STAGE_BASE + i + base;
DBG("%s: assign pipe %s on stage=%d", crtc->name,
pstates[i].plane->name,
pstates[i].state->stage);
@@ -612,6 +653,16 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
.cursor_move = mdp5_crtc_cursor_move,
};
+static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = mdp5_crtc_destroy,
+ .page_flip = drm_atomic_helper_page_flip,
+ .set_property = drm_atomic_helper_crtc_set_property,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
.mode_set_nofb = mdp5_crtc_mode_set_nofb,
.disable = mdp5_crtc_disable,
@@ -727,6 +778,13 @@ void mdp5_crtc_set_pipeline(struct drm_crtc *crtc,
mdp5_ctl_set_pipeline(ctl, intf, lm);
}
+struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
+{
+ struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+ return mdp5_crtc->ctl;
+}
+
int mdp5_crtc_get_lm(struct drm_crtc *crtc)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
@@ -745,7 +803,8 @@ void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc)
/* initialize crtc */
struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
- struct drm_plane *plane, int id)
+ struct drm_plane *plane,
+ struct drm_plane *cursor_plane, int id)
{
struct drm_crtc *crtc = NULL;
struct mdp5_crtc *mdp5_crtc;
@@ -766,8 +825,12 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
mdp5_crtc->err.irq = mdp5_crtc_err_irq;
- drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs,
- NULL);
+ if (cursor_plane)
+ drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane,
+ &mdp5_crtc_no_lm_cursor_funcs, NULL);
+ else
+ drm_crtc_init_with_planes(dev, crtc, plane, NULL,
+ &mdp5_crtc_funcs, NULL);
drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
"unref cursor", unref_cursor_worker);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
index d021edc3b307..8b93f7e13200 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
@@ -326,6 +326,8 @@ static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
case SSPP_DMA1: return MDP5_CTL_LAYER_REG_DMA1(stage);
case SSPP_VIG3: return MDP5_CTL_LAYER_REG_VIG3(stage);
case SSPP_RGB3: return MDP5_CTL_LAYER_REG_RGB3(stage);
+ case SSPP_CURSOR0:
+ case SSPP_CURSOR1:
default: return 0;
}
}
@@ -333,7 +335,7 @@ static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
enum mdp_mixer_stage_id stage)
{
- if (stage < STAGE6)
+ if (stage < STAGE6 && (pipe != SSPP_CURSOR0 && pipe != SSPP_CURSOR1))
return 0;
switch (pipe) {
@@ -347,12 +349,14 @@ static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
case SSPP_DMA1: return MDP5_CTL_LAYER_EXT_REG_DMA1_BIT3;
case SSPP_VIG3: return MDP5_CTL_LAYER_EXT_REG_VIG3_BIT3;
case SSPP_RGB3: return MDP5_CTL_LAYER_EXT_REG_RGB3_BIT3;
+ case SSPP_CURSOR0: return MDP5_CTL_LAYER_EXT_REG_CURSOR0(stage);
+ case SSPP_CURSOR1: return MDP5_CTL_LAYER_EXT_REG_CURSOR1(stage);
default: return 0;
}
}
-int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
- u32 ctl_blend_op_flags)
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, enum mdp5_pipe *stage, u32 stage_cnt,
+ u32 ctl_blend_op_flags)
{
unsigned long flags;
u32 blend_cfg = 0, blend_ext_cfg = 0;
@@ -365,7 +369,7 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
start_stage = STAGE_BASE;
}
- for (i = start_stage; i < start_stage + stage_cnt; i++) {
+ for (i = start_stage; stage_cnt && i <= STAGE_MAX; i++) {
blend_cfg |= mdp_ctl_blend_mask(stage[i], i);
blend_ext_cfg |= mdp_ctl_blend_ext_mask(stage[i], i);
}
@@ -422,6 +426,8 @@ u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
+ case SSPP_CURSOR0: return MDP5_CTL_FLUSH_CURSOR_0;
+ case SSPP_CURSOR1: return MDP5_CTL_FLUSH_CURSOR_1;
default: return 0;
}
}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
index 96148c6f863c..fda00d33e4db 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
@@ -56,8 +56,8 @@ int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
* (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
*/
#define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT BIT(0)
-int mdp5_ctl_blend(struct mdp5_ctl *ctl, u8 *stage, u32 stage_cnt,
- u32 ctl_blend_op_flags);
+int mdp5_ctl_blend(struct mdp5_ctl *ctl, enum mdp5_pipe *stage, u32 stage_cnt,
+ u32 ctl_blend_op_flags);
/**
* mdp_ctl_flush_mask...() - Register FLUSH masks
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
index fe0c22230883..80fa482ae8ed 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
@@ -21,17 +21,6 @@
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
-struct mdp5_encoder {
- struct drm_encoder base;
- struct mdp5_interface intf;
- spinlock_t intf_lock; /* protect REG_MDP5_INTF_* registers */
- bool enabled;
- uint32_t bsc;
-
- struct mdp5_ctl *ctl;
-};
-#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
-
static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
{
struct msm_drm_private *priv = encoder->dev->dev_private;
@@ -112,9 +101,9 @@ static const struct drm_encoder_funcs mdp5_encoder_funcs = {
.destroy = mdp5_encoder_destroy,
};
-static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
@@ -221,7 +210,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
mdp5_encoder->ctl);
}
-static void mdp5_encoder_disable(struct drm_encoder *encoder)
+static void mdp5_vid_encoder_disable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
@@ -256,7 +245,7 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder)
mdp5_encoder->enabled = false;
}
-static void mdp5_encoder_enable(struct drm_encoder *encoder)
+static void mdp5_vid_encoder_enable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
@@ -279,6 +268,41 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
mdp5_encoder->enabled = true;
}
+static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_interface *intf = &mdp5_encoder->intf;
+
+ if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+ mdp5_cmd_encoder_mode_set(encoder, mode, adjusted_mode);
+ else
+ mdp5_vid_encoder_mode_set(encoder, mode, adjusted_mode);
+}
+
+static void mdp5_encoder_disable(struct drm_encoder *encoder)
+{
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_interface *intf = &mdp5_encoder->intf;
+
+ if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+ mdp5_cmd_encoder_disable(encoder);
+ else
+ mdp5_vid_encoder_disable(encoder);
+}
+
+static void mdp5_encoder_enable(struct drm_encoder *encoder)
+{
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_interface *intf = &mdp5_encoder->intf;
+
+ if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
+ mdp5_cmd_encoder_disable(encoder);
+ else
+ mdp5_vid_encoder_enable(encoder);
+}
+
static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
.mode_set = mdp5_encoder_mode_set,
.disable = mdp5_encoder_disable,
@@ -303,8 +327,8 @@ u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder)
return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
}
-int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
- struct drm_encoder *slave_encoder)
+int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
+ struct drm_encoder *slave_encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
@@ -342,6 +366,23 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
return 0;
}
+void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode)
+{
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_interface *intf = &mdp5_encoder->intf;
+
+ /* TODO: Expand this to set writeback modes too */
+ if (cmd_mode) {
+ WARN_ON(intf->type != INTF_DSI);
+ intf->mode = MDP5_INTF_DSI_MODE_COMMAND;
+ } else {
+ if (intf->type == INTF_DSI)
+ intf->mode = MDP5_INTF_DSI_MODE_VIDEO;
+ else
+ intf->mode = MDP5_INTF_MODE_NONE;
+ }
+}
+
/* initialize encoder */
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf, struct mdp5_ctl *ctl)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index c396d459a9d0..3eb0749223d9 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -148,7 +148,15 @@ static int mdp5_set_split_display(struct msm_kms *kms,
return mdp5_cmd_encoder_set_split_display(encoder,
slave_encoder);
else
- return mdp5_encoder_set_split_display(encoder, slave_encoder);
+ return mdp5_vid_encoder_set_split_display(encoder,
+ slave_encoder);
+}
+
+static void mdp5_set_encoder_mode(struct msm_kms *kms,
+ struct drm_encoder *encoder,
+ bool cmd_mode)
+{
+ mdp5_encoder_set_intf_mode(encoder, cmd_mode);
}
static void mdp5_kms_destroy(struct msm_kms *kms)
@@ -230,6 +238,7 @@ static const struct mdp_kms_funcs kms_funcs = {
.get_format = mdp_get_format,
.round_pixclk = mdp5_round_pixclk,
.set_split_display = mdp5_set_split_display,
+ .set_encoder_mode = mdp5_set_encoder_mode,
.destroy = mdp5_kms_destroy,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = mdp5_kms_debugfs_init,
@@ -267,7 +276,7 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
enum mdp5_intf_type intf_type, int intf_num,
- enum mdp5_intf_mode intf_mode, struct mdp5_ctl *ctl)
+ struct mdp5_ctl *ctl)
{
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
@@ -275,21 +284,15 @@ static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
struct mdp5_interface intf = {
.num = intf_num,
.type = intf_type,
- .mode = intf_mode,
+ .mode = MDP5_INTF_MODE_NONE,
};
- if ((intf_type == INTF_DSI) &&
- (intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
- encoder = mdp5_cmd_encoder_init(dev, &intf, ctl);
- else
- encoder = mdp5_encoder_init(dev, &intf, ctl);
-
+ encoder = mdp5_encoder_init(dev, &intf, ctl);
if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct encoder\n");
return encoder;
}
- encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
priv->encoders[priv->num_encoders++] = encoder;
return encoder;
@@ -338,8 +341,7 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
break;
}
- encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
- MDP5_INTF_MODE_NONE, ctl);
+ encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
@@ -357,8 +359,7 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
break;
}
- encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
- MDP5_INTF_MODE_NONE, ctl);
+ encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num, ctl);
if (IS_ERR(encoder)) {
ret = PTR_ERR(encoder);
break;
@@ -369,9 +370,6 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
case INTF_DSI:
{
int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num);
- struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
- enum mdp5_intf_mode mode;
- int i;
if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
dev_err(dev->dev, "failed to find dsi from intf %d\n",
@@ -389,19 +387,13 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
break;
}
- for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
- mode = (i == MSM_DSI_CMD_ENCODER_ID) ?
- MDP5_INTF_DSI_MODE_COMMAND :
- MDP5_INTF_DSI_MODE_VIDEO;
- dsi_encs[i] = construct_encoder(mdp5_kms, INTF_DSI,
- intf_num, mode, ctl);
- if (IS_ERR(dsi_encs[i])) {
- ret = PTR_ERR(dsi_encs[i]);
- break;
- }
+ encoder = construct_encoder(mdp5_kms, INTF_DSI, intf_num, ctl);
+ if (IS_ERR(encoder)) {
+ ret = PTR_ERR(encoder);
+ break;
}
- ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
+ ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, encoder);
break;
}
default:
@@ -418,20 +410,48 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
struct drm_device *dev = mdp5_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
const struct mdp5_cfg_hw *hw_cfg;
- int i, ret;
+ unsigned int num_crtcs;
+ int i, ret, pi = 0, ci = 0;
+ struct drm_plane *primary[MAX_BASES] = { NULL };
+ struct drm_plane *cursor[MAX_BASES] = { NULL };
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
- /* Construct planes equaling the number of hw pipes, and CRTCs
- * for the N layer-mixers (LM). The first N planes become primary
+ /*
+ * Construct encoders and modeset initialize connector devices
+ * for each external display interface.
+ */
+ for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
+ ret = modeset_init_intf(mdp5_kms, i);
+ if (ret)
+ goto fail;
+ }
+
+ /*
+ * We should ideally have less number of encoders (set up by parsing
+ * 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_cfg->lm.count);
+
+ /*
+ * Construct planes equaling the number of hw pipes, and CRTCs for the
+ * N encoders set up by the driver. 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 mdp5_hw_pipe *hwpipe = mdp5_kms->hwpipes[i];
struct drm_plane *plane;
- struct drm_crtc *crtc;
+ enum drm_plane_type type;
- plane = mdp5_plane_init(dev, primary);
+ if (i < num_crtcs)
+ type = DRM_PLANE_TYPE_PRIMARY;
+ else if (hwpipe->caps & MDP_PIPE_CAP_CURSOR)
+ type = DRM_PLANE_TYPE_CURSOR;
+ else
+ type = DRM_PLANE_TYPE_OVERLAY;
+
+ plane = mdp5_plane_init(dev, type);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
dev_err(dev->dev, "failed to construct plane %d (%d)\n", i, ret);
@@ -439,10 +459,16 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
}
priv->planes[priv->num_planes++] = plane;
- if (!primary)
- continue;
+ if (type == DRM_PLANE_TYPE_PRIMARY)
+ primary[pi++] = plane;
+ if (type == DRM_PLANE_TYPE_CURSOR)
+ cursor[ci++] = plane;
+ }
+
+ for (i = 0; i < num_crtcs; i++) {
+ struct drm_crtc *crtc;
- crtc = mdp5_crtc_init(dev, plane, i);
+ crtc = mdp5_crtc_init(dev, primary[i], cursor[i], i);
if (IS_ERR(crtc)) {
ret = PTR_ERR(crtc);
dev_err(dev->dev, "failed to construct crtc %d (%d)\n", i, ret);
@@ -451,13 +477,14 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
priv->crtcs[priv->num_crtcs++] = crtc;
}
- /* Construct encoders and modeset initialize connector devices
- * for each external display interface.
+ /*
+ * Now that we know the number of crtcs we've created, set the possible
+ * crtcs for the encoders
*/
- for (i = 0; i < ARRAY_SIZE(hw_cfg->intf.connect); i++) {
- ret = modeset_init_intf(mdp5_kms, i);
- if (ret)
- goto fail;
+ for (i = 0; i < priv->num_encoders; i++) {
+ struct drm_encoder *encoder = priv->encoders[i];
+
+ encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
}
return 0;
@@ -773,6 +800,9 @@ static int hwpipe_init(struct mdp5_kms *mdp5_kms)
static const enum mdp5_pipe dma_planes[] = {
SSPP_DMA0, SSPP_DMA1,
};
+ static const enum mdp5_pipe cursor_planes[] = {
+ SSPP_CURSOR0, SSPP_CURSOR1,
+ };
const struct mdp5_cfg_hw *hw_cfg;
int ret;
@@ -796,6 +826,13 @@ static int hwpipe_init(struct mdp5_kms *mdp5_kms)
if (ret)
return ret;
+ /* Construct cursor pipes: */
+ ret = construct_pipes(mdp5_kms, hw_cfg->pipe_cursor.count,
+ cursor_planes, hw_cfg->pipe_cursor.base,
+ hw_cfg->pipe_cursor.caps);
+ if (ret)
+ return ret;
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index cdfc63d90c7b..9de471191eba 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -126,6 +126,17 @@ struct mdp5_interface {
enum mdp5_intf_mode mode;
};
+struct mdp5_encoder {
+ struct drm_encoder base;
+ struct mdp5_interface intf;
+ spinlock_t intf_lock; /* protect REG_MDP5_INTF_* registers */
+ bool enabled;
+ uint32_t bsc;
+
+ struct mdp5_ctl *ctl;
+};
+#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
+
static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
{
msm_writel(data, mdp5_kms->mmio + reg);
@@ -156,6 +167,7 @@ static inline const char *pipe2name(enum mdp5_pipe pipe)
NAME(RGB0), NAME(RGB1), NAME(RGB2),
NAME(DMA0), NAME(DMA1),
NAME(VIG3), NAME(RGB3),
+ NAME(CURSOR0), NAME(CURSOR1),
#undef NAME
};
return names[pipe];
@@ -231,8 +243,10 @@ void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
-struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary);
+struct drm_plane *mdp5_plane_init(struct drm_device *dev,
+ enum drm_plane_type type);
+struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc);
uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
int mdp5_crtc_get_lm(struct drm_crtc *crtc);
@@ -240,25 +254,36 @@ void mdp5_crtc_set_pipeline(struct drm_crtc *crtc,
struct mdp5_interface *intf, struct mdp5_ctl *ctl);
void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc);
struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
- struct drm_plane *plane, int id);
+ struct drm_plane *plane,
+ struct drm_plane *cursor_plane, int id);
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf, struct mdp5_ctl *ctl);
-int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
- struct drm_encoder *slave_encoder);
+int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
+ struct drm_encoder *slave_encoder);
+void mdp5_encoder_set_intf_mode(struct drm_encoder *encoder, bool cmd_mode);
int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
#ifdef CONFIG_DRM_MSM_DSI
-struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
- struct mdp5_interface *intf, struct mdp5_ctl *ctl);
+void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+void mdp5_cmd_encoder_disable(struct drm_encoder *encoder);
+void mdp5_cmd_encoder_enable(struct drm_encoder *encoder);
int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
- struct drm_encoder *slave_encoder);
+ struct drm_encoder *slave_encoder);
#else
-static inline struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
- struct mdp5_interface *intf, struct mdp5_ctl *ctl)
+static inline void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+static inline void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
+{
+}
+static inline void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
{
- return ERR_PTR(-EINVAL);
}
static inline int mdp5_cmd_encoder_set_split_display(
struct drm_encoder *encoder, struct drm_encoder *slave_encoder)
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
index 1ae9dc8d260d..35c4dabb0c0c 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_pipe.c
@@ -53,6 +53,14 @@ struct mdp5_hw_pipe *mdp5_pipe_assign(struct drm_atomic_state *s,
if (caps & ~cur->caps)
continue;
+ /*
+ * don't assign a cursor pipe to a plane that isn't going to
+ * be used as a cursor
+ */
+ if (cur->caps & MDP_PIPE_CAP_CURSOR &&
+ plane->type != DRM_PLANE_TYPE_CURSOR)
+ continue;
+
/* possible candidate, take the one with the
* fewest unneeded caps bits set:
*/
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 25d9d0a97156..0ffb8affef35 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -29,6 +29,11 @@ struct mdp5_plane {
static int mdp5_plane_mode_set(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ struct drm_rect *src, struct drm_rect *dest);
+
+static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
@@ -45,7 +50,7 @@ static struct mdp5_kms *get_kms(struct drm_plane *plane)
static bool plane_enabled(struct drm_plane_state *state)
{
- return state->fb && state->crtc;
+ return state->visible;
}
static void mdp5_plane_destroy(struct drm_plane *plane)
@@ -246,6 +251,19 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
.atomic_print_state = mdp5_plane_atomic_print_state,
};
+static const struct drm_plane_funcs mdp5_cursor_plane_funcs = {
+ .update_plane = mdp5_update_cursor_plane_legacy,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = mdp5_plane_destroy,
+ .set_property = drm_atomic_helper_plane_set_property,
+ .atomic_set_property = mdp5_plane_atomic_set_property,
+ .atomic_get_property = mdp5_plane_atomic_get_property,
+ .reset = mdp5_plane_reset,
+ .atomic_duplicate_state = mdp5_plane_duplicate_state,
+ .atomic_destroy_state = mdp5_plane_destroy_state,
+ .atomic_print_state = mdp5_plane_atomic_print_state,
+};
+
static int mdp5_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *new_state)
{
@@ -272,15 +290,20 @@ static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
msm_framebuffer_cleanup(fb, mdp5_kms->id);
}
-static int mdp5_plane_atomic_check(struct drm_plane *plane,
- struct drm_plane_state *state)
+#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
+static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
+ struct drm_plane_state *state)
{
struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
+ struct drm_plane *plane = state->plane;
struct drm_plane_state *old_state = plane->state;
struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg);
bool new_hwpipe = false;
uint32_t max_width, max_height;
uint32_t caps = 0;
+ struct drm_rect clip;
+ int min_scale, max_scale;
+ int ret;
DBG("%s: check (%d -> %d)", plane->name,
plane_enabled(old_state), plane_enabled(state));
@@ -296,6 +319,18 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
return -ERANGE;
}
+ clip.x1 = 0;
+ clip.y1 = 0;
+ clip.x2 = crtc_state->adjusted_mode.hdisplay;
+ clip.y2 = crtc_state->adjusted_mode.vdisplay;
+ min_scale = FRAC_16_16(1, 8);
+ max_scale = FRAC_16_16(8, 1);
+
+ ret = drm_plane_helper_check_state(state, &clip, min_scale,
+ max_scale, true, true);
+ if (ret)
+ return ret;
+
if (plane_enabled(state)) {
unsigned int rotation;
const struct mdp_format *format;
@@ -321,6 +356,9 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
if (rotation & DRM_REFLECT_Y)
caps |= MDP_PIPE_CAP_VFLIP;
+ if (plane->type == DRM_PLANE_TYPE_CURSOR)
+ caps |= MDP_PIPE_CAP_CURSOR;
+
/* (re)allocate hw pipe if we don't have one or caps-mismatch: */
if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
new_hwpipe = true;
@@ -356,6 +394,23 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
return 0;
}
+static int mdp5_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+
+ crtc = state->crtc ? state->crtc : plane->state->crtc;
+ if (!crtc)
+ return 0;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
+
+ return mdp5_plane_atomic_check_with_state(crtc_state, state);
+}
+
static void mdp5_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -368,10 +423,7 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane,
ret = mdp5_plane_mode_set(plane,
state->crtc, state->fb,
- state->crtc_x, state->crtc_y,
- state->crtc_w, state->crtc_h,
- state->src_x, state->src_y,
- state->src_w, state->src_h);
+ &state->src, &state->dst);
/* atomic_check should have ensured that this doesn't fail */
WARN_ON(ret < 0);
}
@@ -664,10 +716,7 @@ static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
static int mdp5_plane_mode_set(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
- int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h)
+ struct drm_rect *src, struct drm_rect *dest)
{
struct drm_plane_state *pstate = plane->state;
struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe;
@@ -683,10 +732,14 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
uint32_t pix_format;
unsigned int rotation;
bool vflip, hflip;
+ int crtc_x, crtc_y;
+ unsigned int crtc_w, crtc_h;
+ uint32_t src_x, src_y;
+ uint32_t src_w, src_h;
unsigned long flags;
int ret;
- nplanes = drm_format_num_planes(fb->pixel_format);
+ nplanes = fb->format->num_planes;
/* bad formats should already be rejected: */
if (WARN_ON(nplanes > pipe2nclients(pipe)))
@@ -695,6 +748,16 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
format = to_mdp_format(msm_framebuffer_format(fb));
pix_format = format->base.pixel_format;
+ src_x = src->x1;
+ src_y = src->y1;
+ src_w = drm_rect_width(src);
+ src_h = drm_rect_height(src);
+
+ crtc_x = dest->x1;
+ crtc_y = dest->y1;
+ crtc_w = drm_rect_width(dest);
+ crtc_h = drm_rect_height(dest);
+
/* src values are in Q16 fixed point, convert to integer: */
src_x = src_x >> 16;
src_y = src_y >> 16;
@@ -818,12 +881,88 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
return ret;
}
+static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane,
+ struct drm_crtc *crtc, struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h)
+{
+ struct drm_plane_state *plane_state, *new_plane_state;
+ struct mdp5_plane_state *mdp5_pstate;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ int ret;
+
+ if (!crtc_state->active || drm_atomic_crtc_needs_modeset(crtc_state))
+ goto slow;
+
+ plane_state = plane->state;
+ mdp5_pstate = to_mdp5_plane_state(plane_state);
+
+ /* don't use fast path if we don't have a hwpipe allocated yet */
+ if (!mdp5_pstate->hwpipe)
+ goto slow;
+
+ /* only allow changing of position(crtc x/y or src x/y) in fast path */
+ if (plane_state->crtc != crtc ||
+ plane_state->src_w != src_w ||
+ plane_state->src_h != src_h ||
+ plane_state->crtc_w != crtc_w ||
+ plane_state->crtc_h != crtc_h ||
+ !plane_state->fb ||
+ plane_state->fb != fb)
+ goto slow;
+
+ new_plane_state = mdp5_plane_duplicate_state(plane);
+ if (!new_plane_state)
+ return -ENOMEM;
+
+ new_plane_state->src_x = src_x;
+ new_plane_state->src_y = src_y;
+ new_plane_state->src_w = src_w;
+ new_plane_state->src_h = src_h;
+ new_plane_state->crtc_x = crtc_x;
+ new_plane_state->crtc_y = crtc_y;
+ new_plane_state->crtc_w = crtc_w;
+ new_plane_state->crtc_h = crtc_h;
+
+ ret = mdp5_plane_atomic_check_with_state(crtc_state, new_plane_state);
+ if (ret)
+ goto slow_free;
+
+ if (new_plane_state->visible) {
+ struct mdp5_ctl *ctl;
+
+ ret = mdp5_plane_mode_set(plane, crtc, fb,
+ &new_plane_state->src,
+ &new_plane_state->dst);
+ WARN_ON(ret < 0);
+
+ ctl = mdp5_crtc_get_ctl(crtc);
+
+ mdp5_ctl_commit(ctl, mdp5_plane_get_flush(plane));
+ }
+
+ *to_mdp5_plane_state(plane_state) =
+ *to_mdp5_plane_state(new_plane_state);
+
+ mdp5_plane_destroy_state(plane, new_plane_state);
+
+ return 0;
+slow_free:
+ mdp5_plane_destroy_state(plane, new_plane_state);
+slow:
+ return drm_atomic_helper_update_plane(plane, crtc, fb,
+ crtc_x, crtc_y, crtc_w, crtc_h,
+ src_x, src_y, src_w, src_h);
+}
+
enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
{
struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
if (WARN_ON(!pstate->hwpipe))
- return 0;
+ return SSPP_NONE;
return pstate->hwpipe->pipe;
}
@@ -839,12 +978,12 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
}
/* initialize plane */
-struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary)
+struct drm_plane *mdp5_plane_init(struct drm_device *dev,
+ enum drm_plane_type type)
{
struct drm_plane *plane = NULL;
struct mdp5_plane *mdp5_plane;
int ret;
- enum drm_plane_type type;
mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
if (!mdp5_plane) {
@@ -857,10 +996,16 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary)
mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
ARRAY_SIZE(mdp5_plane->formats), false);
- 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, NULL);
+ if (type == DRM_PLANE_TYPE_CURSOR)
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &mdp5_cursor_plane_funcs,
+ mdp5_plane->formats, mdp5_plane->nformats,
+ type, NULL);
+ else
+ ret = drm_universal_plane_init(dev, plane, 0xff,
+ &mdp5_plane_funcs,
+ mdp5_plane->formats, mdp5_plane->nformats,
+ type, NULL);
if (ret)
goto fail;