mirror of
https://github.com/torvalds/linux.git
synced 2024-12-13 22:53:20 +00:00
drm/msm/mdp5: Add plane blending operation support for MDP5 (v2)
This change is to add properties alpha/zpos/blend_mode to mdp5 plane for alpha blending operation to generate the blended output. v1: Initial change v2: Change "premultilied" property to enum (Rob's comment) Signed-off-by: Jilai Wang <jilaiw@codeaurora.org> [Don't actually expose alpha/premultiplied props to userspace yet pending a chance for discussion and some userspace to exercise it] Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
parent
4ff696eafa
commit
129877819c
@ -160,7 +160,7 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
|
||||
|
||||
if (mdp5_crtc->ctl && !crtc->state->enable) {
|
||||
/* set STAGE_UNUSED for all layers */
|
||||
mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
|
||||
mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, NULL, 0, 0);
|
||||
mdp5_ctl_release(mdp5_crtc->ctl);
|
||||
mdp5_crtc->ctl = NULL;
|
||||
}
|
||||
@ -196,13 +196,9 @@ static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
/*
|
||||
* blend_setup() - blend all the planes of a CRTC
|
||||
*
|
||||
* When border is enabled, the border color will ALWAYS be the base layer.
|
||||
* Therefore, the first plane (private RGB pipe) will start at STAGE0.
|
||||
* If disabled, the first plane starts at STAGE_BASE.
|
||||
*
|
||||
* Note:
|
||||
* Border is not enabled here because the private plane is exactly
|
||||
* the CRTC resolution.
|
||||
* If no base layer is available, border will be enabled as the base layer.
|
||||
* Otherwise all layers will be blended based on their stage calculated
|
||||
* in mdp5_crtc_atomic_check.
|
||||
*/
|
||||
static void blend_setup(struct drm_crtc *crtc)
|
||||
{
|
||||
@ -210,9 +206,14 @@ static void blend_setup(struct drm_crtc *crtc)
|
||||
struct mdp5_kms *mdp5_kms = get_kms(crtc);
|
||||
struct drm_plane *plane;
|
||||
const struct mdp5_cfg_hw *hw_cfg;
|
||||
uint32_t lm = mdp5_crtc->lm, blend_cfg = 0;
|
||||
struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL};
|
||||
const struct mdp_format *format;
|
||||
uint32_t lm = mdp5_crtc->lm;
|
||||
uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
|
||||
unsigned long flags;
|
||||
#define blender(stage) ((stage) - STAGE_BASE)
|
||||
uint8_t stage[STAGE_MAX + 1];
|
||||
int i, plane_cnt = 0;
|
||||
#define blender(stage) ((stage) - STAGE0)
|
||||
|
||||
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
|
||||
|
||||
@ -222,33 +223,73 @@ static void blend_setup(struct drm_crtc *crtc)
|
||||
if (!mdp5_crtc->ctl)
|
||||
goto out;
|
||||
|
||||
/* Collect all plane information */
|
||||
drm_atomic_crtc_for_each_plane(plane, crtc) {
|
||||
enum mdp_mixer_stage_id stage =
|
||||
to_mdp5_plane_state(plane->state)->stage;
|
||||
|
||||
/*
|
||||
* Note: This cannot happen with current implementation but
|
||||
* we need to check this condition once z property is added
|
||||
*/
|
||||
BUG_ON(stage > hw_cfg->lm.nb_stages);
|
||||
|
||||
/* LM */
|
||||
mdp5_write(mdp5_kms,
|
||||
REG_MDP5_LM_BLEND_OP_MODE(lm, blender(stage)),
|
||||
MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST));
|
||||
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
|
||||
blender(stage)), 0xff);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
|
||||
blender(stage)), 0x00);
|
||||
/* CTL */
|
||||
blend_cfg |= mdp_ctl_blend_mask(mdp5_plane_pipe(plane), stage);
|
||||
DBG("%s: blending pipe %s on stage=%d", mdp5_crtc->name,
|
||||
pipe2name(mdp5_plane_pipe(plane)), stage);
|
||||
pstate = to_mdp5_plane_state(plane->state);
|
||||
pstates[pstate->stage] = pstate;
|
||||
stage[pstate->stage] = mdp5_plane_pipe(plane);
|
||||
plane_cnt++;
|
||||
}
|
||||
|
||||
DBG("%s: lm%d: blend config = 0x%08x", mdp5_crtc->name, lm, blend_cfg);
|
||||
mdp5_ctl_blend(mdp5_crtc->ctl, lm, blend_cfg);
|
||||
/*
|
||||
* If there is no base layer, enable border color.
|
||||
* Although it's not possbile in current blend logic,
|
||||
* put it here as a reminder.
|
||||
*/
|
||||
if (!pstates[STAGE_BASE] && plane_cnt) {
|
||||
ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT;
|
||||
DBG("Border Color is enabled");
|
||||
}
|
||||
|
||||
/* The reset for blending */
|
||||
for (i = STAGE0; i <= STAGE_MAX; i++) {
|
||||
if (!pstates[i])
|
||||
continue;
|
||||
|
||||
format = to_mdp_format(
|
||||
msm_framebuffer_format(pstates[i]->base.fb));
|
||||
plane = pstates[i]->base.plane;
|
||||
blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST);
|
||||
fg_alpha = pstates[i]->alpha;
|
||||
bg_alpha = 0xFF - pstates[i]->alpha;
|
||||
DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha);
|
||||
|
||||
if (format->alpha_enable && pstates[i]->premultiplied) {
|
||||
blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
|
||||
if (fg_alpha != 0xff) {
|
||||
bg_alpha = fg_alpha;
|
||||
blend_op |=
|
||||
MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
|
||||
} else {
|
||||
blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
|
||||
}
|
||||
} else if (format->alpha_enable) {
|
||||
blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_PIXEL) |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL);
|
||||
if (fg_alpha != 0xff) {
|
||||
bg_alpha = fg_alpha;
|
||||
blend_op |=
|
||||
MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA |
|
||||
MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA |
|
||||
MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA;
|
||||
} else {
|
||||
blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA;
|
||||
}
|
||||
}
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(lm,
|
||||
blender(i)), blend_op);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm,
|
||||
blender(i)), fg_alpha);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
|
||||
blender(i)), bg_alpha);
|
||||
}
|
||||
|
||||
mdp5_ctl_blend(mdp5_crtc->ctl, lm, stage, plane_cnt, ctl_blend_flags);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
|
||||
@ -339,7 +380,8 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
struct mdp5_kms *mdp5_kms = get_kms(crtc);
|
||||
struct drm_plane *plane;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct plane_state pstates[STAGE3 + 1];
|
||||
struct plane_state pstates[STAGE_MAX + 1];
|
||||
const struct mdp5_cfg_hw *hw_cfg;
|
||||
int cnt = 0, i;
|
||||
|
||||
DBG("%s: check", mdp5_crtc->name);
|
||||
@ -354,10 +396,10 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
/* verify that there are not too many planes attached to crtc
|
||||
* and that we don't have conflicting mixer stages:
|
||||
*/
|
||||
hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg);
|
||||
drm_atomic_crtc_state_for_each_plane(plane, state) {
|
||||
struct drm_plane_state *pstate;
|
||||
|
||||
if (cnt >= ARRAY_SIZE(pstates)) {
|
||||
if (cnt >= (hw_cfg->lm.nb_stages)) {
|
||||
dev_err(dev->dev, "too many planes!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -369,13 +411,13 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
|
||||
*/
|
||||
if (!pstate)
|
||||
pstate = plane->state;
|
||||
|
||||
pstates[cnt].plane = plane;
|
||||
pstates[cnt].state = to_mdp5_plane_state(pstate);
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
/* assign a stage based on sorted zpos property */
|
||||
sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
|
@ -287,30 +287,86 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable)
|
||||
blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
|
||||
|
||||
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
|
||||
ctl->cursor_on = enable;
|
||||
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
|
||||
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
|
||||
ctl->cursor_on = enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
|
||||
static u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
|
||||
enum mdp_mixer_stage_id stage)
|
||||
{
|
||||
switch (pipe) {
|
||||
case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
|
||||
case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
|
||||
case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
|
||||
case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
|
||||
case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
|
||||
case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
|
||||
case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
|
||||
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);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
|
||||
enum mdp_mixer_stage_id stage)
|
||||
{
|
||||
if (stage < STAGE6)
|
||||
return 0;
|
||||
|
||||
switch (pipe) {
|
||||
case SSPP_VIG0: return MDP5_CTL_LAYER_EXT_REG_VIG0_BIT3;
|
||||
case SSPP_VIG1: return MDP5_CTL_LAYER_EXT_REG_VIG1_BIT3;
|
||||
case SSPP_VIG2: return MDP5_CTL_LAYER_EXT_REG_VIG2_BIT3;
|
||||
case SSPP_RGB0: return MDP5_CTL_LAYER_EXT_REG_RGB0_BIT3;
|
||||
case SSPP_RGB1: return MDP5_CTL_LAYER_EXT_REG_RGB1_BIT3;
|
||||
case SSPP_RGB2: return MDP5_CTL_LAYER_EXT_REG_RGB2_BIT3;
|
||||
case SSPP_DMA0: return MDP5_CTL_LAYER_EXT_REG_DMA0_BIT3;
|
||||
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;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u8 *stage, u32 stage_cnt,
|
||||
u32 ctl_blend_op_flags)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 blend_cfg = 0, blend_ext_cfg = 0;
|
||||
int i, start_stage;
|
||||
|
||||
if (ctl->cursor_on)
|
||||
blend_cfg |= MDP5_CTL_LAYER_REG_CURSOR_OUT;
|
||||
else
|
||||
blend_cfg &= ~MDP5_CTL_LAYER_REG_CURSOR_OUT;
|
||||
if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
|
||||
start_stage = STAGE0;
|
||||
blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
|
||||
} else {
|
||||
start_stage = STAGE_BASE;
|
||||
}
|
||||
|
||||
for (i = start_stage; i < start_stage + stage_cnt; i++) {
|
||||
blend_cfg |= mdp_ctl_blend_mask(stage[i], i);
|
||||
blend_ext_cfg |= mdp_ctl_blend_ext_mask(stage[i], i);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ctl->hw_lock, flags);
|
||||
if (ctl->cursor_on)
|
||||
blend_cfg |= MDP5_CTL_LAYER_REG_CURSOR_OUT;
|
||||
|
||||
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
|
||||
ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, lm), blend_ext_cfg);
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
|
||||
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm);
|
||||
|
||||
DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", lm,
|
||||
blend_cfg, blend_ext_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -41,40 +41,20 @@ int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled);
|
||||
|
||||
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable);
|
||||
|
||||
/*
|
||||
* blend_cfg (LM blender config):
|
||||
*
|
||||
* The function below allows the caller of mdp5_ctl_blend() to specify how pipes
|
||||
* are being blended according to their stage (z-order), through @blend_cfg arg.
|
||||
*/
|
||||
static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
|
||||
enum mdp_mixer_stage_id stage)
|
||||
{
|
||||
switch (pipe) {
|
||||
case SSPP_VIG0: return MDP5_CTL_LAYER_REG_VIG0(stage);
|
||||
case SSPP_VIG1: return MDP5_CTL_LAYER_REG_VIG1(stage);
|
||||
case SSPP_VIG2: return MDP5_CTL_LAYER_REG_VIG2(stage);
|
||||
case SSPP_RGB0: return MDP5_CTL_LAYER_REG_RGB0(stage);
|
||||
case SSPP_RGB1: return MDP5_CTL_LAYER_REG_RGB1(stage);
|
||||
case SSPP_RGB2: return MDP5_CTL_LAYER_REG_RGB2(stage);
|
||||
case SSPP_DMA0: return MDP5_CTL_LAYER_REG_DMA0(stage);
|
||||
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);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
|
||||
*
|
||||
* @blend_cfg: see LM blender config definition below
|
||||
* @stage: array to contain the pipe num for each stage
|
||||
* @stage_cnt: valid stage number in stage array
|
||||
* @ctl_blend_op_flags: blender operation mode flags
|
||||
*
|
||||
* Note:
|
||||
* CTL registers need to be flushed after calling this function
|
||||
* (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
|
||||
*/
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
|
||||
#define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT BIT(0)
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u8 *stage, u32 stage_cnt,
|
||||
u32 ctl_blend_op_flags);
|
||||
|
||||
/**
|
||||
* mdp_ctl_flush_mask...() - Register FLUSH masks
|
||||
|
@ -70,18 +70,12 @@ struct mdp5_kms {
|
||||
struct mdp5_plane_state {
|
||||
struct drm_plane_state base;
|
||||
|
||||
/* "virtual" zpos.. we calculate actual mixer-stage at runtime
|
||||
* by sorting the attached planes by zpos and then assigning
|
||||
* mixer stage lowest to highest. Private planes get default
|
||||
* zpos of zero, and public planes a unique value that is
|
||||
* greater than zero. This way, things work out if a naive
|
||||
* userspace assigns planes to a crtc without setting zpos.
|
||||
*/
|
||||
int zpos;
|
||||
/* aligned with property */
|
||||
uint8_t premultiplied;
|
||||
uint8_t zpos;
|
||||
uint8_t alpha;
|
||||
|
||||
/* the actual mixer stage, calculated in crtc->atomic_check()
|
||||
* NOTE: this should move to mdp5_crtc_state, when that exists
|
||||
*/
|
||||
/* assigned by crtc blender */
|
||||
enum mdp_mixer_stage_id stage;
|
||||
|
||||
/* some additional transactional status to help us know in the
|
||||
|
@ -68,14 +68,103 @@ static void mdp5_plane_destroy(struct drm_plane *plane)
|
||||
static void mdp5_plane_install_properties(struct drm_plane *plane,
|
||||
struct drm_mode_object *obj)
|
||||
{
|
||||
// XXX
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct msm_drm_private *dev_priv = dev->dev_private;
|
||||
struct drm_property *prop;
|
||||
|
||||
#define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
|
||||
prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
|
||||
if (!prop) { \
|
||||
prop = drm_property_##fnc(dev, 0, #name, \
|
||||
##__VA_ARGS__); \
|
||||
if (!prop) { \
|
||||
dev_warn(dev->dev, \
|
||||
"Create property %s failed\n", \
|
||||
#name); \
|
||||
return; \
|
||||
} \
|
||||
dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
|
||||
} \
|
||||
drm_object_attach_property(&plane->base, prop, init_val); \
|
||||
} while (0)
|
||||
|
||||
#define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
|
||||
INSTALL_PROPERTY(name, NAME, init_val, \
|
||||
create_range, min, max)
|
||||
|
||||
#define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
|
||||
INSTALL_PROPERTY(name, NAME, init_val, \
|
||||
create_enum, name##_prop_enum_list, \
|
||||
ARRAY_SIZE(name##_prop_enum_list))
|
||||
|
||||
INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
|
||||
|
||||
#undef INSTALL_RANGE_PROPERTY
|
||||
#undef INSTALL_ENUM_PROPERTY
|
||||
#undef INSTALL_PROPERTY
|
||||
}
|
||||
|
||||
int mdp5_plane_set_property(struct drm_plane *plane,
|
||||
static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
|
||||
struct drm_plane_state *state, struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct mdp5_plane_state *pstate;
|
||||
struct msm_drm_private *dev_priv = dev->dev_private;
|
||||
int ret = 0;
|
||||
|
||||
pstate = to_mdp5_plane_state(state);
|
||||
|
||||
#define SET_PROPERTY(name, NAME, type) do { \
|
||||
if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
|
||||
pstate->name = (type)val; \
|
||||
DBG("Set property %s %d", #name, (type)val); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
SET_PROPERTY(zpos, ZPOS, uint8_t);
|
||||
|
||||
dev_err(dev->dev, "Invalid property\n");
|
||||
ret = -EINVAL;
|
||||
done:
|
||||
return ret;
|
||||
#undef SET_PROPERTY
|
||||
}
|
||||
|
||||
static int mdp5_plane_set_property(struct drm_plane *plane,
|
||||
struct drm_property *property, uint64_t val)
|
||||
{
|
||||
// XXX
|
||||
return -EINVAL;
|
||||
return mdp5_plane_atomic_set_property(plane, plane->state, property,
|
||||
val);
|
||||
}
|
||||
|
||||
static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
|
||||
const struct drm_plane_state *state,
|
||||
struct drm_property *property, uint64_t *val)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct mdp5_plane_state *pstate;
|
||||
struct msm_drm_private *dev_priv = dev->dev_private;
|
||||
int ret = 0;
|
||||
|
||||
pstate = to_mdp5_plane_state(state);
|
||||
|
||||
#define GET_PROPERTY(name, NAME, type) do { \
|
||||
if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
|
||||
*val = pstate->name; \
|
||||
DBG("Get property %s %lld", #name, *val); \
|
||||
goto done; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
GET_PROPERTY(zpos, ZPOS, uint8_t);
|
||||
|
||||
dev_err(dev->dev, "Invalid property\n");
|
||||
ret = -EINVAL;
|
||||
done:
|
||||
return ret;
|
||||
#undef SET_PROPERTY
|
||||
}
|
||||
|
||||
static void mdp5_plane_reset(struct drm_plane *plane)
|
||||
@ -88,11 +177,15 @@ static void mdp5_plane_reset(struct drm_plane *plane)
|
||||
kfree(to_mdp5_plane_state(plane->state));
|
||||
mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
|
||||
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
|
||||
mdp5_state->zpos = 0;
|
||||
} else {
|
||||
mdp5_state->zpos = 1 + drm_plane_index(plane);
|
||||
}
|
||||
/* assign default blend parameters */
|
||||
mdp5_state->alpha = 255;
|
||||
mdp5_state->premultiplied = 0;
|
||||
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
mdp5_state->zpos = STAGE_BASE;
|
||||
else
|
||||
mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
|
||||
|
||||
mdp5_state->base.plane = plane;
|
||||
|
||||
plane->state = &mdp5_state->base;
|
||||
@ -132,6 +225,8 @@ static const struct drm_plane_funcs mdp5_plane_funcs = {
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = mdp5_plane_destroy,
|
||||
.set_property = mdp5_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,
|
||||
|
@ -64,6 +64,13 @@ struct msm_file_private {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
enum msm_mdp_plane_property {
|
||||
PLANE_PROP_ZPOS,
|
||||
PLANE_PROP_ALPHA,
|
||||
PLANE_PROP_PREMULTIPLIED,
|
||||
PLANE_PROP_MAX_NUM
|
||||
};
|
||||
|
||||
struct msm_drm_private {
|
||||
|
||||
struct msm_kms *kms;
|
||||
@ -128,6 +135,9 @@ struct msm_drm_private {
|
||||
unsigned int num_connectors;
|
||||
struct drm_connector *connectors[8];
|
||||
|
||||
/* Properties */
|
||||
struct drm_property *plane_property[PLANE_PROP_MAX_NUM];
|
||||
|
||||
/* VRAM carveout, used when no IOMMU: */
|
||||
struct {
|
||||
unsigned long size;
|
||||
|
Loading…
Reference in New Issue
Block a user