diff options
author | jilai wang <jilaiw@codeaurora.org> | 2015-06-25 17:37:42 -0400 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2015-08-15 18:27:15 -0400 |
commit | 129877819c0a5f8d419fe67ae08a8a7c811afa5e (patch) | |
tree | dc093d220897efd68d1beecf5aed0078a45aff05 /drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | |
parent | 4ff696eafaa50d6d649d256d20528b475104a500 (diff) |
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>
Diffstat (limited to 'drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c')
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 110 |
1 files changed, 76 insertions, 34 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 5a00f9fed8cb..572f57927595 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | |||
@@ -160,7 +160,7 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) | |||
160 | 160 | ||
161 | if (mdp5_crtc->ctl && !crtc->state->enable) { | 161 | if (mdp5_crtc->ctl && !crtc->state->enable) { |
162 | /* set STAGE_UNUSED for all layers */ | 162 | /* set STAGE_UNUSED for all layers */ |
163 | mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000); | 163 | mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, NULL, 0, 0); |
164 | mdp5_ctl_release(mdp5_crtc->ctl); | 164 | mdp5_ctl_release(mdp5_crtc->ctl); |
165 | mdp5_crtc->ctl = NULL; | 165 | mdp5_crtc->ctl = NULL; |
166 | } | 166 | } |
@@ -196,13 +196,9 @@ static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc, | |||
196 | /* | 196 | /* |
197 | * blend_setup() - blend all the planes of a CRTC | 197 | * blend_setup() - blend all the planes of a CRTC |
198 | * | 198 | * |
199 | * When border is enabled, the border color will ALWAYS be the base layer. | 199 | * If no base layer is available, border will be enabled as the base layer. |
200 | * Therefore, the first plane (private RGB pipe) will start at STAGE0. | 200 | * Otherwise all layers will be blended based on their stage calculated |
201 | * If disabled, the first plane starts at STAGE_BASE. | 201 | * in mdp5_crtc_atomic_check. |
202 | * | ||
203 | * Note: | ||
204 | * Border is not enabled here because the private plane is exactly | ||
205 | * the CRTC resolution. | ||
206 | */ | 202 | */ |
207 | static void blend_setup(struct drm_crtc *crtc) | 203 | static void blend_setup(struct drm_crtc *crtc) |
208 | { | 204 | { |
@@ -210,9 +206,14 @@ static void blend_setup(struct drm_crtc *crtc) | |||
210 | struct mdp5_kms *mdp5_kms = get_kms(crtc); | 206 | struct mdp5_kms *mdp5_kms = get_kms(crtc); |
211 | struct drm_plane *plane; | 207 | struct drm_plane *plane; |
212 | const struct mdp5_cfg_hw *hw_cfg; | 208 | const struct mdp5_cfg_hw *hw_cfg; |
213 | uint32_t lm = mdp5_crtc->lm, blend_cfg = 0; | 209 | struct mdp5_plane_state *pstate, *pstates[STAGE_MAX + 1] = {NULL}; |
210 | const struct mdp_format *format; | ||
211 | uint32_t lm = mdp5_crtc->lm; | ||
212 | uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0; | ||
214 | unsigned long flags; | 213 | unsigned long flags; |
215 | #define blender(stage) ((stage) - STAGE_BASE) | 214 | uint8_t stage[STAGE_MAX + 1]; |
215 | int i, plane_cnt = 0; | ||
216 | #define blender(stage) ((stage) - STAGE0) | ||
216 | 217 | ||
217 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); | 218 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); |
218 | 219 | ||
@@ -222,33 +223,73 @@ static void blend_setup(struct drm_crtc *crtc) | |||
222 | if (!mdp5_crtc->ctl) | 223 | if (!mdp5_crtc->ctl) |
223 | goto out; | 224 | goto out; |
224 | 225 | ||
226 | /* Collect all plane information */ | ||
225 | drm_atomic_crtc_for_each_plane(plane, crtc) { | 227 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
226 | enum mdp_mixer_stage_id stage = | 228 | pstate = to_mdp5_plane_state(plane->state); |
227 | to_mdp5_plane_state(plane->state)->stage; | 229 | pstates[pstate->stage] = pstate; |
230 | stage[pstate->stage] = mdp5_plane_pipe(plane); | ||
231 | plane_cnt++; | ||
232 | } | ||
228 | 233 | ||
229 | /* | 234 | /* |
230 | * Note: This cannot happen with current implementation but | 235 | * If there is no base layer, enable border color. |
231 | * we need to check this condition once z property is added | 236 | * Although it's not possbile in current blend logic, |
232 | */ | 237 | * put it here as a reminder. |
233 | BUG_ON(stage > hw_cfg->lm.nb_stages); | 238 | */ |
239 | if (!pstates[STAGE_BASE] && plane_cnt) { | ||
240 | ctl_blend_flags |= MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT; | ||
241 | DBG("Border Color is enabled"); | ||
242 | } | ||
234 | 243 | ||
235 | /* LM */ | 244 | /* The reset for blending */ |
236 | mdp5_write(mdp5_kms, | 245 | for (i = STAGE0; i <= STAGE_MAX; i++) { |
237 | REG_MDP5_LM_BLEND_OP_MODE(lm, blender(stage)), | 246 | if (!pstates[i]) |
238 | MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) | | 247 | continue; |
239 | MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST)); | 248 | |
249 | format = to_mdp_format( | ||
250 | msm_framebuffer_format(pstates[i]->base.fb)); | ||
251 | plane = pstates[i]->base.plane; | ||
252 | blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) | | ||
253 | MDP5_LM_BLEND_OP_MODE_BG_ALPHA(BG_CONST); | ||
254 | fg_alpha = pstates[i]->alpha; | ||
255 | bg_alpha = 0xFF - pstates[i]->alpha; | ||
256 | DBG("Stage %d fg_alpha %x bg_alpha %x", i, fg_alpha, bg_alpha); | ||
257 | |||
258 | if (format->alpha_enable && pstates[i]->premultiplied) { | ||
259 | blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) | | ||
260 | MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL); | ||
261 | if (fg_alpha != 0xff) { | ||
262 | bg_alpha = fg_alpha; | ||
263 | blend_op |= | ||
264 | MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA | | ||
265 | MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA; | ||
266 | } else { | ||
267 | blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA; | ||
268 | } | ||
269 | } else if (format->alpha_enable) { | ||
270 | blend_op = MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_PIXEL) | | ||
271 | MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL); | ||
272 | if (fg_alpha != 0xff) { | ||
273 | bg_alpha = fg_alpha; | ||
274 | blend_op |= | ||
275 | MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA | | ||
276 | MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA | | ||
277 | MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA | | ||
278 | MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA; | ||
279 | } else { | ||
280 | blend_op |= MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(lm, | ||
285 | blender(i)), blend_op); | ||
240 | mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm, | 286 | mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(lm, |
241 | blender(stage)), 0xff); | 287 | blender(i)), fg_alpha); |
242 | mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm, | 288 | mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm, |
243 | blender(stage)), 0x00); | 289 | blender(i)), bg_alpha); |
244 | /* CTL */ | ||
245 | blend_cfg |= mdp_ctl_blend_mask(mdp5_plane_pipe(plane), stage); | ||
246 | DBG("%s: blending pipe %s on stage=%d", mdp5_crtc->name, | ||
247 | pipe2name(mdp5_plane_pipe(plane)), stage); | ||
248 | } | 290 | } |
249 | 291 | ||
250 | DBG("%s: lm%d: blend config = 0x%08x", mdp5_crtc->name, lm, blend_cfg); | 292 | mdp5_ctl_blend(mdp5_crtc->ctl, lm, stage, plane_cnt, ctl_blend_flags); |
251 | mdp5_ctl_blend(mdp5_crtc->ctl, lm, blend_cfg); | ||
252 | 293 | ||
253 | out: | 294 | out: |
254 | spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags); | 295 | spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags); |
@@ -339,7 +380,8 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, | |||
339 | struct mdp5_kms *mdp5_kms = get_kms(crtc); | 380 | struct mdp5_kms *mdp5_kms = get_kms(crtc); |
340 | struct drm_plane *plane; | 381 | struct drm_plane *plane; |
341 | struct drm_device *dev = crtc->dev; | 382 | struct drm_device *dev = crtc->dev; |
342 | struct plane_state pstates[STAGE3 + 1]; | 383 | struct plane_state pstates[STAGE_MAX + 1]; |
384 | const struct mdp5_cfg_hw *hw_cfg; | ||
343 | int cnt = 0, i; | 385 | int cnt = 0, i; |
344 | 386 | ||
345 | DBG("%s: check", mdp5_crtc->name); | 387 | DBG("%s: check", mdp5_crtc->name); |
@@ -354,10 +396,10 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, | |||
354 | /* verify that there are not too many planes attached to crtc | 396 | /* verify that there are not too many planes attached to crtc |
355 | * and that we don't have conflicting mixer stages: | 397 | * and that we don't have conflicting mixer stages: |
356 | */ | 398 | */ |
399 | hw_cfg = mdp5_cfg_get_hw_config(mdp5_kms->cfg); | ||
357 | drm_atomic_crtc_state_for_each_plane(plane, state) { | 400 | drm_atomic_crtc_state_for_each_plane(plane, state) { |
358 | struct drm_plane_state *pstate; | 401 | struct drm_plane_state *pstate; |
359 | 402 | if (cnt >= (hw_cfg->lm.nb_stages)) { | |
360 | if (cnt >= ARRAY_SIZE(pstates)) { | ||
361 | dev_err(dev->dev, "too many planes!\n"); | 403 | dev_err(dev->dev, "too many planes!\n"); |
362 | return -EINVAL; | 404 | return -EINVAL; |
363 | } | 405 | } |
@@ -369,13 +411,13 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, | |||
369 | */ | 411 | */ |
370 | if (!pstate) | 412 | if (!pstate) |
371 | pstate = plane->state; | 413 | pstate = plane->state; |
372 | |||
373 | pstates[cnt].plane = plane; | 414 | pstates[cnt].plane = plane; |
374 | pstates[cnt].state = to_mdp5_plane_state(pstate); | 415 | pstates[cnt].state = to_mdp5_plane_state(pstate); |
375 | 416 | ||
376 | cnt++; | 417 | cnt++; |
377 | } | 418 | } |
378 | 419 | ||
420 | /* assign a stage based on sorted zpos property */ | ||
379 | sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); | 421 | sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); |
380 | 422 | ||
381 | for (i = 0; i < cnt; i++) { | 423 | for (i = 0; i < cnt; i++) { |