From d65bd0e431156f156f43946b6efb524694afb685 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 6 Aug 2014 07:43:12 -0400 Subject: [PATCH] drm/msm/mdp4: fix blend setup with multiple crtcs In particular, blend_setup() should not overwrite the other crtc's mixer settings. Also, the encoder needs to be able to specify the mixer-id explicitly, since both LVDS and DTV use 'INTF_LVDC_DTV', so we cannot guess the mixer-id from the interface. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 21 +++++---- .../gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c | 2 +- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 1 + drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h | 43 +++++++++++++------ drivers/gpu/drm/msm/msm_drv.c | 2 +- 5 files changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 74cebb51e8c2..f9bc0ef8b836 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -273,14 +273,17 @@ static void blend_setup(struct drm_crtc *crtc) }; 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_LOW1(ovlp), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0); - /* TODO single register for all CRTCs, so this won't work properly - * when multiple CRTCs are active.. - */ for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { struct drm_plane *plane = mdp4_crtc->planes[i]; if (plane) { @@ -291,7 +294,8 @@ static void blend_setup(struct drm_crtc *crtc) to_mdp_format(msm_framebuffer_format(plane->fb)); alpha[idx-1] = format->alpha_enable; } - mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]); + mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer, + pipe_id, stages[idx]); } } @@ -320,6 +324,7 @@ static void blend_setup(struct drm_crtc *crtc) mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0); } + mdp4_kms->mixer_cfg = mixer_cfg; mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg); } @@ -670,7 +675,7 @@ void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config) } /* set interface for routing crtc->encoder: */ -void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf) +void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct mdp4_kms *mdp4_kms = get_kms(crtc); @@ -696,15 +701,13 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf) if (intf == INTF_DSI_VIDEO) { intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD; intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO; - mdp4_crtc->mixer = 0; } else if (intf == INTF_DSI_CMD) { intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO; intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD; - mdp4_crtc->mixer = 0; - } else if (intf == INTF_LCDC_DTV){ - mdp4_crtc->mixer = 1; } + mdp4_crtc->mixer = mixer; + blend_setup(crtc); DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c index 067ed03b35fe..c3878420180b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c @@ -233,7 +233,7 @@ static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder) MDP4_DMA_CONFIG_G_BPC(BPC8) | MDP4_DMA_CONFIG_B_BPC(BPC8) | MDP4_DMA_CONFIG_PACK(0x21)); - mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV); + mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1); mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON); } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 733646c0d3f8..af69079082f7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -106,6 +106,7 @@ static int mdp4_hw_init(struct msm_kms *kms) if (mdp4_kms->rev >= 2) mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1); + mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0); /* disable CSC matrix / YUV by default: */ mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index 6a8a94f0cb96..e74146fe2ae6 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -30,6 +30,13 @@ struct mdp4_kms { 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: */ int id; @@ -108,38 +115,50 @@ static inline uint32_t dma2err(enum mdp4_dma dma) } } -static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe, - enum mdp_mixer_stage_id stage) +static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer, + enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage) { - uint32_t mixer_cfg = 0; - switch (pipe) { case VG1: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1); break; case VG2: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1); break; case RGB1: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1); break; case RGB2: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1); break; case RGB3: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1); break; case VG3: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1); break; case VG4: - mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) | + mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK | + MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1); + mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) | COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1); break; default: @@ -188,7 +207,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); -void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf); +void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer); void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane); struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 47ccdbf49fa1..3b05fb4e3d66 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -280,7 +280,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) dev->mode_config.max_height = 2048; dev->mode_config.funcs = &mode_config_funcs; - ret = drm_vblank_init(dev, 1); + ret = drm_vblank_init(dev, priv->num_crtcs); if (ret < 0) { dev_err(dev->dev, "failed to initialize vblank\n"); goto fail;