drm/msm/mdp4: fix mixer setup for multi-crtc + planes
On mdp4 there is a single global LAYERMIXER_IN_CFG register. The previous logic to share that between multiple crtcs didn't actually handle plane-disable very well. Easier just to look at all of the crtcs each time. Signed-off-by: Rob Clark <robdclark@gmail.com>
This commit is contained in:
parent
d6ac4a84e7
commit
4dd14fe6fb
@ -167,35 +167,55 @@ static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* statically (for now) map planes to mixer stage (z-order): */
|
||||||
|
static const int idxs[] = {
|
||||||
|
[VG1] = 1,
|
||||||
|
[VG2] = 2,
|
||||||
|
[RGB1] = 0,
|
||||||
|
[RGB2] = 0,
|
||||||
|
[RGB3] = 0,
|
||||||
|
[VG3] = 3,
|
||||||
|
[VG4] = 4,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* setup mixer config, for which we need to consider all crtc's and
|
||||||
|
* the planes attached to them
|
||||||
|
*
|
||||||
|
* TODO may possibly need some extra locking here
|
||||||
|
*/
|
||||||
|
static void setup_mixer(struct mdp4_kms *mdp4_kms)
|
||||||
|
{
|
||||||
|
struct drm_mode_config *config = &mdp4_kms->dev->mode_config;
|
||||||
|
struct drm_crtc *crtc;
|
||||||
|
uint32_t mixer_cfg = 0;
|
||||||
|
static const enum mdp_mixer_stage_id stages[] = {
|
||||||
|
STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_for_each_entry(crtc, &config->crtc_list, head) {
|
||||||
|
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
|
||||||
|
struct drm_plane *plane;
|
||||||
|
|
||||||
|
for_each_plane_on_crtc(crtc, plane) {
|
||||||
|
enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
|
||||||
|
int idx = idxs[pipe_id];
|
||||||
|
mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
|
||||||
|
pipe_id, stages[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
static void blend_setup(struct drm_crtc *crtc)
|
static void blend_setup(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
|
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
|
||||||
struct mdp4_kms *mdp4_kms = get_kms(crtc);
|
struct mdp4_kms *mdp4_kms = get_kms(crtc);
|
||||||
struct drm_plane *plane;
|
struct drm_plane *plane;
|
||||||
int i, ovlp = mdp4_crtc->ovlp;
|
int i, ovlp = mdp4_crtc->ovlp;
|
||||||
uint32_t mixer_cfg = 0;
|
|
||||||
static const enum mdp_mixer_stage_id stages[] = {
|
|
||||||
STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
|
|
||||||
};
|
|
||||||
/* statically (for now) map planes to mixer stage (z-order): */
|
|
||||||
static const int idxs[] = {
|
|
||||||
[VG1] = 1,
|
|
||||||
[VG2] = 2,
|
|
||||||
[RGB1] = 0,
|
|
||||||
[RGB2] = 0,
|
|
||||||
[RGB3] = 0,
|
|
||||||
[VG3] = 3,
|
|
||||||
[VG4] = 4,
|
|
||||||
|
|
||||||
};
|
|
||||||
bool alpha[4]= { false, false, false, false };
|
bool alpha[4]= { false, false, false, false };
|
||||||
|
|
||||||
/* Don't rely on value read back from hw, but instead use our
|
|
||||||
* own shadowed value. Possibly disable/reenable looses the
|
|
||||||
* previous value and goes back to power-on default?
|
|
||||||
*/
|
|
||||||
mixer_cfg = mdp4_kms->mixer_cfg;
|
|
||||||
|
|
||||||
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
|
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
|
||||||
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
|
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
|
||||||
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
|
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
|
||||||
@ -209,13 +229,8 @@ static void blend_setup(struct drm_crtc *crtc)
|
|||||||
to_mdp_format(msm_framebuffer_format(plane->fb));
|
to_mdp_format(msm_framebuffer_format(plane->fb));
|
||||||
alpha[idx-1] = format->alpha_enable;
|
alpha[idx-1] = format->alpha_enable;
|
||||||
}
|
}
|
||||||
mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
|
|
||||||
pipe_id, stages[idx]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this shouldn't happen.. and seems to cause underflow: */
|
|
||||||
WARN_ON(!mixer_cfg);
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
uint32_t op;
|
uint32_t op;
|
||||||
|
|
||||||
@ -238,8 +253,7 @@ static void blend_setup(struct drm_crtc *crtc)
|
|||||||
mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
|
mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
mdp4_kms->mixer_cfg = mixer_cfg;
|
setup_mixer(mdp4_kms);
|
||||||
mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||||
|
@ -32,13 +32,6 @@ struct mdp4_kms {
|
|||||||
|
|
||||||
int rev;
|
int rev;
|
||||||
|
|
||||||
/* Shadow value for MDP4_LAYERMIXER_IN_CFG.. since setup for all
|
|
||||||
* crtcs/encoders is in one shared register, we need to update it
|
|
||||||
* via read/modify/write. But to avoid getting confused by power-
|
|
||||||
* on-default values after resume, use this shadow value instead:
|
|
||||||
*/
|
|
||||||
uint32_t mixer_cfg;
|
|
||||||
|
|
||||||
/* mapper-id used to request GEM buffer mapped for scanout: */
|
/* mapper-id used to request GEM buffer mapped for scanout: */
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user