Commit d65bd0e4 authored by Rob Clark's avatar Rob Clark

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: default avatarRob Clark <robdclark@gmail.com>
parent f9a1ca5c
...@@ -273,14 +273,17 @@ static void blend_setup(struct drm_crtc *crtc) ...@@ -273,14 +273,17 @@ static void blend_setup(struct drm_crtc *crtc)
}; };
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);
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(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++) { for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
struct drm_plane *plane = mdp4_crtc->planes[i]; struct drm_plane *plane = mdp4_crtc->planes[i];
if (plane) { if (plane) {
...@@ -291,7 +294,8 @@ static void blend_setup(struct drm_crtc *crtc) ...@@ -291,7 +294,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(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) ...@@ -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_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); 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) ...@@ -670,7 +675,7 @@ void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config)
} }
/* set interface for routing crtc->encoder: */ /* 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_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
struct mdp4_kms *mdp4_kms = get_kms(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) ...@@ -696,15 +701,13 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
if (intf == INTF_DSI_VIDEO) { if (intf == INTF_DSI_VIDEO) {
intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD; intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD;
intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO; intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO;
mdp4_crtc->mixer = 0;
} else if (intf == INTF_DSI_CMD) { } else if (intf == INTF_DSI_CMD) {
intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO; intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO;
intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD; 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); blend_setup(crtc);
DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel); DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel);
......
...@@ -233,7 +233,7 @@ static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder) ...@@ -233,7 +233,7 @@ static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder)
MDP4_DMA_CONFIG_G_BPC(BPC8) | MDP4_DMA_CONFIG_G_BPC(BPC8) |
MDP4_DMA_CONFIG_B_BPC(BPC8) | MDP4_DMA_CONFIG_B_BPC(BPC8) |
MDP4_DMA_CONFIG_PACK(0x21)); 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); mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
} }
......
...@@ -106,6 +106,7 @@ static int mdp4_hw_init(struct msm_kms *kms) ...@@ -106,6 +106,7 @@ static int mdp4_hw_init(struct msm_kms *kms)
if (mdp4_kms->rev >= 2) 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_UPDATE_METHOD, 1);
mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0);
/* disable CSC matrix / YUV by default: */ /* disable CSC matrix / YUV by default: */
mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0); mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0);
......
...@@ -30,6 +30,13 @@ struct mdp4_kms { ...@@ -30,6 +30,13 @@ 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;
...@@ -108,38 +115,50 @@ static inline uint32_t dma2err(enum mdp4_dma dma) ...@@ -108,38 +115,50 @@ static inline uint32_t dma2err(enum mdp4_dma dma)
} }
} }
static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe, static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
enum mdp_mixer_stage_id stage) enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage)
{ {
uint32_t mixer_cfg = 0;
switch (pipe) { switch (pipe) {
case VG1: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
break; break;
case VG2: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
break; break;
case RGB1: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
break; break;
case RGB2: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
break; break;
case RGB3: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
break; break;
case VG3: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
break; break;
case VG4: 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); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
break; break;
default: default:
...@@ -188,7 +207,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, ...@@ -188,7 +207,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); 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_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_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_attach(struct drm_crtc *crtc, struct drm_plane *plane);
void mdp4_crtc_detach(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, struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
......
...@@ -280,7 +280,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) ...@@ -280,7 +280,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
dev->mode_config.max_height = 2048; dev->mode_config.max_height = 2048;
dev->mode_config.funcs = &mode_config_funcs; dev->mode_config.funcs = &mode_config_funcs;
ret = drm_vblank_init(dev, 1); ret = drm_vblank_init(dev, priv->num_crtcs);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n"); dev_err(dev->dev, "failed to initialize vblank\n");
goto fail; goto fail;
......
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