Commit b7621b2a authored by Archit Taneja's avatar Archit Taneja Committed by Rob Clark

drm/msm/mdp5: Add optional 'right' Layer Mixer in CRTC state

Add another mdp5_hw_mixer pointer (r_mixer) in mdp5_crtc_state.
This mixer will be used to generate the right half of the scanout.

With Source Split, a SSPP can now be connected to 2 Layer Mixers, but
has to be at the same blend level (stage #) on both Layer Mixers.

A drm_plane that has a lesser width than the max width supported, will
comprise of a single SSPP/hwpipe, staged on both the Layer Mixers at
the same blend level. A plane that is greater than max width will comprise
of 2 SSPPs, with the 'left' SSPP staged on the left LM, and the 'right'
SSPP staged on the right LM at the same blend level.

For now, the drm_plane consists of only one SSPP, therefore, it
needs to be staged on both the LMs in blend_setup() and mdp5_ctl_blend().
We'll extend this logic to support 2 hwpipes per plane later.

The crtc cursor ops (using the LM cursors, not SSPP cursors) simply
return an error if they're called when the right mixer is assigned to
the CRTC state. With source split is enabled, we're expected to only
SSPP cursors.

This commit adds code that configures the right mixer, but the r_mixer
itself isn't assigned at the moment.
Signed-off-by: default avatarArchit Taneja <architt@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 621da7d9
......@@ -105,7 +105,7 @@ static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
static u32 crtc_flush_all(struct drm_crtc *crtc)
{
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct mdp5_hw_mixer *mixer;
struct mdp5_hw_mixer *mixer, *r_mixer;
struct drm_plane *plane;
uint32_t flush_mask = 0;
......@@ -120,6 +120,10 @@ static u32 crtc_flush_all(struct drm_crtc *crtc)
mixer = mdp5_cstate->pipeline.mixer;
flush_mask |= mdp_ctl_flush_mask_lm(mixer->lm);
r_mixer = mdp5_cstate->pipeline.r_mixer;
if (r_mixer)
flush_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
return crtc_flush(crtc, flush_mask);
}
......@@ -145,7 +149,7 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
if (ctl && !crtc->state->enable) {
/* set STAGE_UNUSED for all layers */
mdp5_ctl_blend(ctl, pipeline, NULL, 0, 0);
mdp5_ctl_blend(ctl, pipeline, NULL, NULL, 0, 0);
/* XXX: What to do here? */
/* mdp5_crtc->ctl = NULL; */
}
......@@ -186,6 +190,12 @@ static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage)
}
}
/*
* left/right pipe offsets for the stage array used in blend_setup()
*/
#define PIPE_LEFT 0
#define PIPE_RIGHT 1
/*
* blend_setup() - blend all the planes of a CRTC
*
......@@ -205,10 +215,13 @@ static void blend_setup(struct drm_crtc *crtc)
const struct mdp_format *format;
struct mdp5_hw_mixer *mixer = pipeline->mixer;
uint32_t lm = mixer->lm;
struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
uint32_t r_lm = r_mixer ? r_mixer->lm : 0;
struct mdp5_ctl *ctl = mdp5_cstate->ctl;
uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0;
unsigned long flags;
enum mdp5_pipe stage[STAGE_MAX + 1] = { SSPP_NONE };
enum mdp5_pipe stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { SSPP_NONE };
enum mdp5_pipe r_stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { SSPP_NONE };
int i, plane_cnt = 0;
bool bg_alpha_enabled = false;
u32 mixer_op_mode = 0;
......@@ -227,7 +240,15 @@ static void blend_setup(struct drm_crtc *crtc)
drm_atomic_crtc_for_each_plane(plane, crtc) {
pstate = to_mdp5_plane_state(plane->state);
pstates[pstate->stage] = pstate;
stage[pstate->stage] = mdp5_plane_pipe(plane);
stage[pstate->stage][PIPE_LEFT] = mdp5_plane_pipe(plane);
/*
* if we have a right mixer, stage the same pipe as we
* have on the left mixer
*/
if (r_mixer)
r_stage[pstate->stage][PIPE_LEFT] =
mdp5_plane_pipe(plane);
plane_cnt++;
}
......@@ -293,12 +314,23 @@ static void blend_setup(struct drm_crtc *crtc)
blender(i)), fg_alpha);
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm,
blender(i)), bg_alpha);
if (r_mixer) {
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(r_lm,
blender(i)), blend_op);
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(r_lm,
blender(i)), fg_alpha);
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(r_lm,
blender(i)), bg_alpha);
}
}
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm), mixer_op_mode);
if (r_mixer)
mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm),
mixer_op_mode);
mdp5_ctl_blend(ctl, pipeline, stage, plane_cnt, ctl_blend_flags);
mdp5_ctl_blend(ctl, pipeline, stage, r_stage, plane_cnt,
ctl_blend_flags);
out:
spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
}
......@@ -309,6 +341,7 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
struct mdp5_kms *mdp5_kms = get_kms(crtc);
struct mdp5_hw_mixer *mixer = mdp5_cstate->pipeline.mixer;
struct mdp5_hw_mixer *r_mixer = mdp5_cstate->pipeline.r_mixer;
uint32_t lm = mixer->lm;
unsigned long flags;
struct drm_display_mode *mode;
......@@ -331,6 +364,10 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(lm),
MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
if (r_mixer)
mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(r_mixer->lm),
MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
}
......@@ -612,6 +649,10 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
if (!ctl)
return -EINVAL;
/* don't support LM cursors when we we have source split enabled */
if (mdp5_cstate->pipeline.r_mixer)
return -EINVAL;
if (!handle) {
DBG("Cursor off");
cursor_enable = false;
......@@ -685,6 +726,10 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
uint32_t roi_h;
unsigned long flags;
/* don't support LM cursors when we we have source split enabled */
if (mdp5_cstate->pipeline.r_mixer)
return -EINVAL;
/* In case the CRTC is disabled, just drop the cursor update */
if (unlikely(!crtc->state->enable))
return 0;
......@@ -714,12 +759,17 @@ mdp5_crtc_atomic_print_state(struct drm_printer *p,
{
struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state);
struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
struct mdp5_kms *mdp5_kms = get_kms(state->crtc);
if (WARN_ON(!pipeline))
return;
drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ?
pipeline->mixer->name : "(null)");
if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ?
pipeline->r_mixer->name : "(null)");
}
static void mdp5_crtc_reset(struct drm_crtc *crtc)
......
......@@ -172,9 +172,12 @@ int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline)
struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
struct mdp5_interface *intf = pipeline->intf;
struct mdp5_hw_mixer *mixer = pipeline->mixer;
struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) |
mdp_ctl_flush_mask_encoder(intf);
if (r_mixer)
ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
/* Virtual interfaces need not set a display intf (e.g.: Writeback) */
if (!mdp5_cfg_intf_is_virtual(intf->type))
......@@ -224,8 +227,11 @@ static void refill_start_mask(struct mdp5_ctl *ctl,
{
struct mdp5_interface *intf = pipeline->intf;
struct mdp5_hw_mixer *mixer = pipeline->mixer;
struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm);
if (r_mixer)
ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm);
/*
* Writeback encoder needs to program & flush
......@@ -282,6 +288,11 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
return -EINVAL;
}
if (pipeline->r_mixer) {
dev_err(ctl_mgr->dev->dev, "unsupported configuration");
return -EINVAL;
}
spin_lock_irqsave(&ctl->hw_lock, flags);
blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm));
......@@ -344,24 +355,40 @@ static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe,
}
}
#define PIPE_LEFT 0
#define PIPE_RIGHT 1
int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
enum mdp5_pipe *stage, u32 stage_cnt, u32 ctl_blend_op_flags)
enum mdp5_pipe stage[][MAX_PIPE_STAGE],
enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
u32 stage_cnt, u32 ctl_blend_op_flags)
{
struct mdp5_hw_mixer *mixer = pipeline->mixer;
struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer;
unsigned long flags;
u32 blend_cfg = 0, blend_ext_cfg = 0;
u32 r_blend_cfg = 0, r_blend_ext_cfg = 0;
int i, start_stage;
if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) {
start_stage = STAGE0;
blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
if (r_mixer)
r_blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR;
} else {
start_stage = STAGE_BASE;
}
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);
blend_cfg |=
mdp_ctl_blend_mask(stage[i][PIPE_LEFT], i);
blend_ext_cfg |=
mdp_ctl_blend_ext_mask(stage[i][PIPE_LEFT], i);
if (r_mixer) {
r_blend_cfg |=
mdp_ctl_blend_mask(r_stage[i][PIPE_LEFT], i);
r_blend_ext_cfg |=
mdp_ctl_blend_ext_mask(r_stage[i][PIPE_LEFT], i);
}
}
spin_lock_irqsave(&ctl->hw_lock, flags);
......@@ -371,12 +398,23 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg);
ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, mixer->lm),
blend_ext_cfg);
if (r_mixer) {
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, r_mixer->lm),
r_blend_cfg);
ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, r_mixer->lm),
r_blend_ext_cfg);
}
spin_unlock_irqrestore(&ctl->hw_lock, flags);
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(mixer->lm);
if (r_mixer)
ctl->pending_ctl_trigger |= mdp_ctl_flush_mask_lm(r_mixer->lm);
DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", mixer->lm,
blend_cfg, blend_ext_cfg);
if (r_mixer)
DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x",
r_mixer->lm, r_blend_cfg, r_blend_ext_cfg);
return 0;
}
......
......@@ -46,6 +46,8 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
int cursor_id, bool enable);
int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
#define MAX_PIPE_STAGE 2
/*
* mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
*
......@@ -59,8 +61,9 @@ int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable);
*/
#define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT BIT(0)
int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
enum mdp5_pipe *stage, u32 stage_cnt,
u32 ctl_blend_op_flags);
enum mdp5_pipe stage[][MAX_PIPE_STAGE],
enum mdp5_pipe r_stage[][MAX_PIPE_STAGE],
u32 stage_cnt, u32 ctl_blend_op_flags);
/**
* mdp_ctl_flush_mask...() - Register FLUSH masks
......
......@@ -119,6 +119,7 @@ struct mdp5_plane_state {
struct mdp5_pipeline {
struct mdp5_interface *intf;
struct mdp5_hw_mixer *mixer;
struct mdp5_hw_mixer *r_mixer; /* right mixer */
};
struct mdp5_crtc_state {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment