diff options
| author | Stephane Viau <sviau@codeaurora.org> | 2015-03-13 15:49:33 -0400 |
|---|---|---|
| committer | Rob Clark <robdclark@gmail.com> | 2015-04-01 19:29:34 -0400 |
| commit | 389b09a1822db2bf5050060acc63611ea6c4670d (patch) | |
| tree | 04e47e953e1695fe8a45955ff9d431a1a67be5cd /drivers/gpu/drm/msm/mdp | |
| parent | d145dd78d7e72ac07c84f6919283569e6b45a5c3 (diff) | |
drm/msm/mdp5: Add START signal to kick off certain pipelines
Some interfaces (WB, DSI Command Mode) need to be kicked off
through a START Signal. This signal needs to be sent at the right
time and requests in some cases to keep track of the pipeline
status (eg: whether pipeline registers are flushed AND output WB
buffers are ready, in case of WB interface).
Signed-off-by: Stephane Viau <sviau@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/msm/mdp')
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 31 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c | 247 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h | 72 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 1 |
7 files changed, 276 insertions, 97 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index b0a44310cf2a..1eacea72c5eb 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | |||
| @@ -31,6 +31,7 @@ const struct mdp5_cfg_hw msm8x74_config = { | |||
| 31 | .ctl = { | 31 | .ctl = { |
| 32 | .count = 5, | 32 | .count = 5, |
| 33 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, | 33 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, |
| 34 | .flush_hw_mask = 0x0003ffff, | ||
| 34 | }, | 35 | }, |
| 35 | .pipe_vig = { | 36 | .pipe_vig = { |
| 36 | .count = 3, | 37 | .count = 3, |
| @@ -78,6 +79,7 @@ const struct mdp5_cfg_hw apq8084_config = { | |||
| 78 | .ctl = { | 79 | .ctl = { |
| 79 | .count = 5, | 80 | .count = 5, |
| 80 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, | 81 | .base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 }, |
| 82 | .flush_hw_mask = 0x003fffff, | ||
| 81 | }, | 83 | }, |
| 82 | .pipe_vig = { | 84 | .pipe_vig = { |
| 83 | .count = 4, | 85 | .count = 4, |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h index 4e90740c9749..69e35aca80a7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.h | |||
| @@ -44,6 +44,11 @@ struct mdp5_lm_block { | |||
| 44 | uint32_t nb_stages; /* number of stages per blender */ | 44 | uint32_t nb_stages; /* number of stages per blender */ |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | struct mdp5_ctl_block { | ||
| 48 | MDP5_SUB_BLOCK_DEFINITION; | ||
| 49 | uint32_t flush_hw_mask; /* FLUSH register's hardware mask */ | ||
| 50 | }; | ||
| 51 | |||
| 47 | struct mdp5_smp_block { | 52 | struct mdp5_smp_block { |
| 48 | int mmb_count; /* number of SMP MMBs */ | 53 | int mmb_count; /* number of SMP MMBs */ |
| 49 | int mmb_size; /* MMB: size in bytes */ | 54 | int mmb_size; /* MMB: size in bytes */ |
| @@ -55,7 +60,7 @@ struct mdp5_cfg_hw { | |||
| 55 | char *name; | 60 | char *name; |
| 56 | 61 | ||
| 57 | struct mdp5_smp_block smp; | 62 | struct mdp5_smp_block smp; |
| 58 | struct mdp5_sub_block ctl; | 63 | struct mdp5_ctl_block ctl; |
| 59 | struct mdp5_sub_block pipe_vig; | 64 | struct mdp5_sub_block pipe_vig; |
| 60 | struct mdp5_sub_block pipe_rgb; | 65 | struct mdp5_sub_block pipe_rgb; |
| 61 | struct mdp5_sub_block pipe_dma; | 66 | struct mdp5_sub_block pipe_dma; |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 15136f17f8ce..9527ad112446 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | |||
| @@ -82,8 +82,6 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending) | |||
| 82 | mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank); | 82 | mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | #define mdp5_lm_get_flush(lm) mdp_ctl_flush_mask_lm(lm) | ||
| 86 | |||
| 87 | static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask) | 85 | static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask) |
| 88 | { | 86 | { |
| 89 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); | 87 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); |
| @@ -110,8 +108,8 @@ static void crtc_flush_all(struct drm_crtc *crtc) | |||
| 110 | drm_atomic_crtc_for_each_plane(plane, crtc) { | 108 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
| 111 | flush_mask |= mdp5_plane_get_flush(plane); | 109 | flush_mask |= mdp5_plane_get_flush(plane); |
| 112 | } | 110 | } |
| 113 | flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); | 111 | |
| 114 | flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm); | 112 | flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm); |
| 115 | 113 | ||
| 116 | crtc_flush(crtc, flush_mask); | 114 | crtc_flush(crtc, flush_mask); |
| 117 | } | 115 | } |
| @@ -442,13 +440,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 442 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); | 440 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); |
| 443 | struct drm_device *dev = crtc->dev; | 441 | struct drm_device *dev = crtc->dev; |
| 444 | struct mdp5_kms *mdp5_kms = get_kms(crtc); | 442 | struct mdp5_kms *mdp5_kms = get_kms(crtc); |
| 445 | struct drm_gem_object *cursor_bo, *old_bo; | 443 | struct drm_gem_object *cursor_bo, *old_bo = NULL; |
| 446 | uint32_t blendcfg, cursor_addr, stride; | 444 | uint32_t blendcfg, cursor_addr, stride; |
| 447 | int ret, bpp, lm; | 445 | int ret, bpp, lm; |
| 448 | unsigned int depth; | 446 | unsigned int depth; |
| 449 | enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL; | 447 | enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL; |
| 450 | uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0); | 448 | uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0); |
| 451 | uint32_t roi_w, roi_h; | 449 | uint32_t roi_w, roi_h; |
| 450 | bool cursor_enable = true; | ||
| 452 | unsigned long flags; | 451 | unsigned long flags; |
| 453 | 452 | ||
| 454 | if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { | 453 | if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { |
| @@ -461,7 +460,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 461 | 460 | ||
| 462 | if (!handle) { | 461 | if (!handle) { |
| 463 | DBG("Cursor off"); | 462 | DBG("Cursor off"); |
| 464 | return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false); | 463 | cursor_enable = false; |
| 464 | goto set_cursor; | ||
| 465 | } | 465 | } |
| 466 | 466 | ||
| 467 | cursor_bo = drm_gem_object_lookup(dev, file, handle); | 467 | cursor_bo = drm_gem_object_lookup(dev, file, handle); |
| @@ -502,11 +502,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, | |||
| 502 | 502 | ||
| 503 | spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); | 503 | spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); |
| 504 | 504 | ||
| 505 | ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true); | 505 | set_cursor: |
| 506 | if (ret) | 506 | ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, 0, cursor_enable); |
| 507 | if (ret) { | ||
| 508 | dev_err(dev->dev, "failed to %sable cursor: %d\n", | ||
| 509 | cursor_enable ? "en" : "dis", ret); | ||
| 507 | goto end; | 510 | goto end; |
| 511 | } | ||
| 508 | 512 | ||
| 509 | flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl); | ||
| 510 | crtc_flush(crtc, flush_mask); | 513 | crtc_flush(crtc, flush_mask); |
| 511 | 514 | ||
| 512 | end: | 515 | end: |
| @@ -628,11 +631,13 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf) | |||
| 628 | int mdp5_crtc_get_lm(struct drm_crtc *crtc) | 631 | int mdp5_crtc_get_lm(struct drm_crtc *crtc) |
| 629 | { | 632 | { |
| 630 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); | 633 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); |
| 634 | return WARN_ON(!crtc) ? -EINVAL : mdp5_crtc->lm; | ||
| 635 | } | ||
| 631 | 636 | ||
| 632 | if (WARN_ON(!crtc)) | 637 | struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc) |
| 633 | return -EINVAL; | 638 | { |
| 634 | 639 | struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); | |
| 635 | return mdp5_crtc->lm; | 640 | return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl; |
| 636 | } | 641 | } |
| 637 | 642 | ||
| 638 | /* initialize crtc */ | 643 | /* initialize crtc */ |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index a548113a8f68..7c0adf54e3e5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. | 2 | * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. |
| 3 | * | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 and | 5 | * it under the terms of the GNU General Public License version 2 and |
| @@ -35,18 +35,16 @@ | |||
| 35 | 35 | ||
| 36 | struct op_mode { | 36 | struct op_mode { |
| 37 | struct mdp5_interface intf; | 37 | struct mdp5_interface intf; |
| 38 | /* | 38 | |
| 39 | * TODO: add a state variable to control the pipeline | 39 | bool encoder_enabled; |
| 40 | * | 40 | uint32_t start_mask; |
| 41 | * eg: WB interface needs both buffer addresses to be committed + | ||
| 42 | * output buffers ready to be written into, before we can START. | ||
| 43 | */ | ||
| 44 | }; | 41 | }; |
| 45 | 42 | ||
| 46 | struct mdp5_ctl { | 43 | struct mdp5_ctl { |
| 47 | struct mdp5_ctl_manager *ctlm; | 44 | struct mdp5_ctl_manager *ctlm; |
| 48 | 45 | ||
| 49 | u32 id; | 46 | u32 id; |
| 47 | int lm; | ||
| 50 | 48 | ||
| 51 | /* whether this CTL has been allocated or not: */ | 49 | /* whether this CTL has been allocated or not: */ |
| 52 | bool busy; | 50 | bool busy; |
| @@ -58,8 +56,8 @@ struct mdp5_ctl { | |||
| 58 | spinlock_t hw_lock; | 56 | spinlock_t hw_lock; |
| 59 | u32 reg_offset; | 57 | u32 reg_offset; |
| 60 | 58 | ||
| 61 | /* flush mask used to commit CTL registers */ | 59 | /* when do CTL registers need to be flushed? (mask of trigger bits) */ |
| 62 | u32 flush_mask; | 60 | u32 pending_ctl_trigger; |
| 63 | 61 | ||
| 64 | bool cursor_on; | 62 | bool cursor_on; |
| 65 | 63 | ||
| @@ -73,6 +71,9 @@ struct mdp5_ctl_manager { | |||
| 73 | u32 nlm; | 71 | u32 nlm; |
| 74 | u32 nctl; | 72 | u32 nctl; |
| 75 | 73 | ||
| 74 | /* to filter out non-present bits in the current hardware config */ | ||
| 75 | u32 flush_hw_mask; | ||
| 76 | |||
| 76 | /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */ | 77 | /* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */ |
| 77 | spinlock_t pool_lock; | 78 | spinlock_t pool_lock; |
| 78 | struct mdp5_ctl ctls[MAX_CTL]; | 79 | struct mdp5_ctl ctls[MAX_CTL]; |
| @@ -174,6 +175,9 @@ int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf) | |||
| 174 | 175 | ||
| 175 | memcpy(&ctl->pipeline.intf, intf, sizeof(*intf)); | 176 | memcpy(&ctl->pipeline.intf, intf, sizeof(*intf)); |
| 176 | 177 | ||
| 178 | ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) | | ||
| 179 | mdp_ctl_flush_mask_encoder(intf); | ||
| 180 | |||
| 177 | /* Virtual interfaces need not set a display intf (e.g.: Writeback) */ | 181 | /* Virtual interfaces need not set a display intf (e.g.: Writeback) */ |
| 178 | if (!mdp5_cfg_intf_is_virtual(intf->type)) | 182 | if (!mdp5_cfg_intf_is_virtual(intf->type)) |
| 179 | set_display_intf(mdp5_kms, intf); | 183 | set_display_intf(mdp5_kms, intf); |
| @@ -183,14 +187,90 @@ int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf) | |||
| 183 | return 0; | 187 | return 0; |
| 184 | } | 188 | } |
| 185 | 189 | ||
| 186 | int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable) | 190 | static bool start_signal_needed(struct mdp5_ctl *ctl) |
| 191 | { | ||
| 192 | struct op_mode *pipeline = &ctl->pipeline; | ||
| 193 | |||
| 194 | if (!pipeline->encoder_enabled || pipeline->start_mask != 0) | ||
| 195 | return false; | ||
| 196 | |||
| 197 | switch (pipeline->intf.type) { | ||
| 198 | case INTF_WB: | ||
| 199 | return true; | ||
| 200 | case INTF_DSI: | ||
| 201 | return pipeline->intf.mode == MDP5_INTF_DSI_MODE_COMMAND; | ||
| 202 | default: | ||
| 203 | return false; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 208 | * send_start_signal() - Overlay Processor Start Signal | ||
| 209 | * | ||
| 210 | * For a given control operation (display pipeline), a START signal needs to be | ||
| 211 | * executed in order to kick off operation and activate all layers. | ||
| 212 | * e.g.: DSI command mode, Writeback | ||
| 213 | */ | ||
| 214 | static void send_start_signal(struct mdp5_ctl *ctl) | ||
| 215 | { | ||
| 216 | unsigned long flags; | ||
| 217 | |||
| 218 | spin_lock_irqsave(&ctl->hw_lock, flags); | ||
| 219 | ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1); | ||
| 220 | spin_unlock_irqrestore(&ctl->hw_lock, flags); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void refill_start_mask(struct mdp5_ctl *ctl) | ||
| 224 | { | ||
| 225 | struct op_mode *pipeline = &ctl->pipeline; | ||
| 226 | struct mdp5_interface *intf = &ctl->pipeline.intf; | ||
| 227 | |||
| 228 | pipeline->start_mask = mdp_ctl_flush_mask_lm(ctl->lm); | ||
| 229 | |||
| 230 | /* | ||
| 231 | * Writeback encoder needs to program & flush | ||
| 232 | * address registers for each page flip.. | ||
| 233 | */ | ||
| 234 | if (intf->type == INTF_WB) | ||
| 235 | pipeline->start_mask |= mdp_ctl_flush_mask_encoder(intf); | ||
| 236 | } | ||
| 237 | |||
| 238 | /** | ||
| 239 | * mdp5_ctl_set_encoder_state() - set the encoder state | ||
| 240 | * | ||
| 241 | * @enable: true, when encoder is ready for data streaming; false, otherwise. | ||
| 242 | * | ||
| 243 | * Note: | ||
| 244 | * This encoder state is needed to trigger START signal (data path kickoff). | ||
| 245 | */ | ||
| 246 | int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled) | ||
| 247 | { | ||
| 248 | if (WARN_ON(!ctl)) | ||
| 249 | return -EINVAL; | ||
| 250 | |||
| 251 | ctl->pipeline.encoder_enabled = enabled; | ||
| 252 | DBG("intf_%d: %s", ctl->pipeline.intf.num, enabled ? "on" : "off"); | ||
| 253 | |||
| 254 | if (start_signal_needed(ctl)) { | ||
| 255 | send_start_signal(ctl); | ||
| 256 | refill_start_mask(ctl); | ||
| 257 | } | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | /* | ||
| 263 | * Note: | ||
| 264 | * CTL registers need to be flushed after calling this function | ||
| 265 | * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask) | ||
| 266 | */ | ||
| 267 | int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable) | ||
| 187 | { | 268 | { |
| 188 | struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; | 269 | struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; |
| 189 | unsigned long flags; | 270 | unsigned long flags; |
| 190 | u32 blend_cfg; | 271 | u32 blend_cfg; |
| 191 | int lm; | 272 | int lm = ctl->lm; |
| 192 | 273 | ||
| 193 | lm = mdp5_crtc_get_lm(ctl->crtc); | ||
| 194 | if (unlikely(WARN_ON(lm < 0))) { | 274 | if (unlikely(WARN_ON(lm < 0))) { |
| 195 | dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d", | 275 | dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d", |
| 196 | ctl->id, lm); | 276 | ctl->id, lm); |
| @@ -210,12 +290,12 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable) | |||
| 210 | 290 | ||
| 211 | spin_unlock_irqrestore(&ctl->hw_lock, flags); | 291 | spin_unlock_irqrestore(&ctl->hw_lock, flags); |
| 212 | 292 | ||
| 293 | ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id); | ||
| 213 | ctl->cursor_on = enable; | 294 | ctl->cursor_on = enable; |
| 214 | 295 | ||
| 215 | return 0; | 296 | return 0; |
| 216 | } | 297 | } |
| 217 | 298 | ||
| 218 | |||
| 219 | int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg) | 299 | int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg) |
| 220 | { | 300 | { |
| 221 | unsigned long flags; | 301 | unsigned long flags; |
| @@ -229,37 +309,133 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg) | |||
| 229 | ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg); | 309 | ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg); |
| 230 | spin_unlock_irqrestore(&ctl->hw_lock, flags); | 310 | spin_unlock_irqrestore(&ctl->hw_lock, flags); |
| 231 | 311 | ||
| 312 | ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm); | ||
| 313 | |||
| 232 | return 0; | 314 | return 0; |
| 233 | } | 315 | } |
| 234 | 316 | ||
| 317 | u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf) | ||
| 318 | { | ||
| 319 | /* these are dummy bits for now, but will appear in next chipsets: */ | ||
| 320 | #define MDP5_CTL_FLUSH_TIMING_0 0x80000000 | ||
| 321 | #define MDP5_CTL_FLUSH_TIMING_1 0x40000000 | ||
| 322 | #define MDP5_CTL_FLUSH_TIMING_2 0x20000000 | ||
| 323 | #define MDP5_CTL_FLUSH_TIMING_3 0x10000000 | ||
| 324 | #define MDP5_CTL_FLUSH_WB 0x00010000 | ||
| 325 | |||
| 326 | if (intf->type == INTF_WB) | ||
| 327 | return MDP5_CTL_FLUSH_WB; | ||
| 328 | |||
| 329 | switch (intf->num) { | ||
| 330 | case 0: return MDP5_CTL_FLUSH_TIMING_0; | ||
| 331 | case 1: return MDP5_CTL_FLUSH_TIMING_1; | ||
| 332 | case 2: return MDP5_CTL_FLUSH_TIMING_2; | ||
| 333 | case 3: return MDP5_CTL_FLUSH_TIMING_3; | ||
| 334 | default: return 0; | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | u32 mdp_ctl_flush_mask_cursor(int cursor_id) | ||
| 339 | { | ||
| 340 | /* these are dummy bits for now, but will appear in next chipsets: */ | ||
| 341 | #define MDP5_CTL_FLUSH_CURSOR_0 0x00400000 | ||
| 342 | #define MDP5_CTL_FLUSH_CURSOR_1 0x00800000 | ||
| 343 | |||
| 344 | switch (cursor_id) { | ||
| 345 | case 0: return MDP5_CTL_FLUSH_CURSOR_0; | ||
| 346 | case 1: return MDP5_CTL_FLUSH_CURSOR_1; | ||
| 347 | default: return 0; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe) | ||
| 352 | { | ||
| 353 | switch (pipe) { | ||
| 354 | case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0; | ||
| 355 | case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1; | ||
| 356 | case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2; | ||
| 357 | case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0; | ||
| 358 | case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1; | ||
| 359 | case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2; | ||
| 360 | case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0; | ||
| 361 | case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1; | ||
| 362 | case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3; | ||
| 363 | case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3; | ||
| 364 | default: return 0; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | u32 mdp_ctl_flush_mask_lm(int lm) | ||
| 369 | { | ||
| 370 | switch (lm) { | ||
| 371 | case 0: return MDP5_CTL_FLUSH_LM0; | ||
| 372 | case 1: return MDP5_CTL_FLUSH_LM1; | ||
| 373 | case 2: return MDP5_CTL_FLUSH_LM2; | ||
| 374 | case 5: return MDP5_CTL_FLUSH_LM5; | ||
| 375 | default: return 0; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask) | ||
| 380 | { | ||
| 381 | struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; | ||
| 382 | u32 sw_mask = 0; | ||
| 383 | #define BIT_NEEDS_SW_FIX(bit) \ | ||
| 384 | (!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit)) | ||
| 385 | |||
| 386 | /* for some targets, cursor bit is the same as LM bit */ | ||
| 387 | if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0)) | ||
| 388 | sw_mask |= mdp_ctl_flush_mask_lm(ctl->lm); | ||
| 389 | |||
| 390 | return sw_mask; | ||
| 391 | } | ||
| 392 | |||
| 393 | /** | ||
| 394 | * mdp5_ctl_commit() - Register Flush | ||
| 395 | * | ||
| 396 | * The flush register is used to indicate several registers are all | ||
| 397 | * programmed, and are safe to update to the back copy of the double | ||
| 398 | * buffered registers. | ||
| 399 | * | ||
| 400 | * Some registers FLUSH bits are shared when the hardware does not have | ||
| 401 | * dedicated bits for them; handling these is the job of fix_sw_flush(). | ||
| 402 | * | ||
| 403 | * CTL registers need to be flushed in some circumstances; if that is the | ||
| 404 | * case, some trigger bits will be present in both flush mask and | ||
| 405 | * ctl->pending_ctl_trigger. | ||
| 406 | */ | ||
| 235 | int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask) | 407 | int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask) |
| 236 | { | 408 | { |
| 237 | struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; | 409 | struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; |
| 410 | struct op_mode *pipeline = &ctl->pipeline; | ||
| 238 | unsigned long flags; | 411 | unsigned long flags; |
| 239 | 412 | ||
| 240 | if (flush_mask & MDP5_CTL_FLUSH_CURSOR_DUMMY) { | 413 | pipeline->start_mask &= ~flush_mask; |
| 241 | int lm = mdp5_crtc_get_lm(ctl->crtc); | ||
| 242 | 414 | ||
| 243 | if (unlikely(WARN_ON(lm < 0))) { | 415 | VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask, |
| 244 | dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d", | 416 | pipeline->start_mask, ctl->pending_ctl_trigger); |
| 245 | ctl->id, lm); | ||
| 246 | return -EINVAL; | ||
| 247 | } | ||
| 248 | 417 | ||
| 249 | /* for current targets, cursor bit is the same as LM bit */ | 418 | if (ctl->pending_ctl_trigger & flush_mask) { |
| 250 | flush_mask |= mdp_ctl_flush_mask_lm(lm); | 419 | flush_mask |= MDP5_CTL_FLUSH_CTL; |
| 420 | ctl->pending_ctl_trigger = 0; | ||
| 251 | } | 421 | } |
| 252 | 422 | ||
| 253 | spin_lock_irqsave(&ctl->hw_lock, flags); | 423 | flush_mask |= fix_sw_flush(ctl, flush_mask); |
| 254 | ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask); | ||
| 255 | spin_unlock_irqrestore(&ctl->hw_lock, flags); | ||
| 256 | 424 | ||
| 257 | return 0; | 425 | flush_mask &= ctl_mgr->flush_hw_mask; |
| 258 | } | ||
| 259 | 426 | ||
| 260 | u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl) | 427 | if (flush_mask) { |
| 261 | { | 428 | spin_lock_irqsave(&ctl->hw_lock, flags); |
| 262 | return ctl->flush_mask; | 429 | ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask); |
| 430 | spin_unlock_irqrestore(&ctl->hw_lock, flags); | ||
| 431 | } | ||
| 432 | |||
| 433 | if (start_signal_needed(ctl)) { | ||
| 434 | send_start_signal(ctl); | ||
| 435 | refill_start_mask(ctl); | ||
| 436 | } | ||
| 437 | |||
| 438 | return 0; | ||
| 263 | } | 439 | } |
| 264 | 440 | ||
| 265 | void mdp5_ctl_release(struct mdp5_ctl *ctl) | 441 | void mdp5_ctl_release(struct mdp5_ctl *ctl) |
| @@ -280,6 +456,11 @@ void mdp5_ctl_release(struct mdp5_ctl *ctl) | |||
| 280 | DBG("CTL %d released", ctl->id); | 456 | DBG("CTL %d released", ctl->id); |
| 281 | } | 457 | } |
| 282 | 458 | ||
| 459 | int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl) | ||
| 460 | { | ||
| 461 | return WARN_ON(!ctl) ? -EINVAL : ctl->id; | ||
| 462 | } | ||
| 463 | |||
| 283 | /* | 464 | /* |
| 284 | * mdp5_ctl_request() - CTL dynamic allocation | 465 | * mdp5_ctl_request() - CTL dynamic allocation |
| 285 | * | 466 | * |
| @@ -307,8 +488,10 @@ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr, | |||
| 307 | 488 | ||
| 308 | ctl = &ctl_mgr->ctls[c]; | 489 | ctl = &ctl_mgr->ctls[c]; |
| 309 | 490 | ||
| 491 | ctl->lm = mdp5_crtc_get_lm(crtc); | ||
| 310 | ctl->crtc = crtc; | 492 | ctl->crtc = crtc; |
| 311 | ctl->busy = true; | 493 | ctl->busy = true; |
| 494 | ctl->pending_ctl_trigger = 0; | ||
| 312 | DBG("CTL %d allocated", ctl->id); | 495 | DBG("CTL %d allocated", ctl->id); |
| 313 | 496 | ||
| 314 | unlock: | 497 | unlock: |
| @@ -339,7 +522,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, | |||
| 339 | void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg) | 522 | void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg) |
| 340 | { | 523 | { |
| 341 | struct mdp5_ctl_manager *ctl_mgr; | 524 | struct mdp5_ctl_manager *ctl_mgr; |
| 342 | const struct mdp5_sub_block *ctl_cfg = &hw_cfg->ctl; | 525 | const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl; |
| 343 | unsigned long flags; | 526 | unsigned long flags; |
| 344 | int c, ret; | 527 | int c, ret; |
| 345 | 528 | ||
| @@ -361,6 +544,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, | |||
| 361 | ctl_mgr->dev = dev; | 544 | ctl_mgr->dev = dev; |
| 362 | ctl_mgr->nlm = hw_cfg->lm.count; | 545 | ctl_mgr->nlm = hw_cfg->lm.count; |
| 363 | ctl_mgr->nctl = ctl_cfg->count; | 546 | ctl_mgr->nctl = ctl_cfg->count; |
| 547 | ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask; | ||
| 364 | spin_lock_init(&ctl_mgr->pool_lock); | 548 | spin_lock_init(&ctl_mgr->pool_lock); |
| 365 | 549 | ||
| 366 | /* initialize each CTL of the pool: */ | 550 | /* initialize each CTL of the pool: */ |
| @@ -376,7 +560,6 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, | |||
| 376 | ctl->ctlm = ctl_mgr; | 560 | ctl->ctlm = ctl_mgr; |
| 377 | ctl->id = c; | 561 | ctl->id = c; |
| 378 | ctl->reg_offset = ctl_cfg->base[c]; | 562 | ctl->reg_offset = ctl_cfg->base[c]; |
| 379 | ctl->flush_mask = MDP5_CTL_FLUSH_CTL; | ||
| 380 | ctl->busy = false; | 563 | ctl->busy = false; |
| 381 | spin_lock_init(&ctl->hw_lock); | 564 | spin_lock_init(&ctl->hw_lock); |
| 382 | } | 565 | } |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h index 271d5ac429be..7a62000994a1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h | |||
| @@ -33,20 +33,13 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm); | |||
| 33 | * which is then used to call the other mdp5_ctl_*(ctl, ...) functions. | 33 | * which is then used to call the other mdp5_ctl_*(ctl, ...) functions. |
| 34 | */ | 34 | */ |
| 35 | struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc); | 35 | struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc); |
| 36 | int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl); | ||
| 36 | 37 | ||
| 37 | struct mdp5_interface; | 38 | struct mdp5_interface; |
| 38 | int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf); | 39 | int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf); |
| 40 | int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled); | ||
| 39 | 41 | ||
| 40 | int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable); | 42 | int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable); |
| 41 | |||
| 42 | /* @blend_cfg: see LM blender config definition below */ | ||
| 43 | int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg); | ||
| 44 | |||
| 45 | /* @flush_mask: see CTL flush masks definitions below */ | ||
| 46 | int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask); | ||
| 47 | u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl); | ||
| 48 | |||
| 49 | void mdp5_ctl_release(struct mdp5_ctl *ctl); | ||
| 50 | 43 | ||
| 51 | /* | 44 | /* |
| 52 | * blend_cfg (LM blender config): | 45 | * blend_cfg (LM blender config): |
| @@ -73,51 +66,32 @@ static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe, | |||
| 73 | } | 66 | } |
| 74 | 67 | ||
| 75 | /* | 68 | /* |
| 76 | * flush_mask (CTL flush masks): | 69 | * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM) |
| 70 | * | ||
| 71 | * @blend_cfg: see LM blender config definition below | ||
| 77 | * | 72 | * |
| 78 | * The following functions allow each DRM entity to get and store | 73 | * Note: |
| 79 | * their own flush mask. | 74 | * CTL registers need to be flushed after calling this function |
| 80 | * Once stored, these masks will then be accessed through each DRM's | 75 | * (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask) |
| 81 | * interface and used by the caller of mdp5_ctl_commit() to specify | ||
| 82 | * which block(s) need to be flushed through @flush_mask parameter. | ||
| 83 | */ | 76 | */ |
| 77 | int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg); | ||
| 84 | 78 | ||
| 85 | #define MDP5_CTL_FLUSH_CURSOR_DUMMY 0x80000000 | 79 | /** |
| 80 | * mdp_ctl_flush_mask...() - Register FLUSH masks | ||
| 81 | * | ||
| 82 | * These masks are used to specify which block(s) need to be flushed | ||
| 83 | * through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask). | ||
| 84 | */ | ||
| 85 | u32 mdp_ctl_flush_mask_lm(int lm); | ||
| 86 | u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe); | ||
| 87 | u32 mdp_ctl_flush_mask_cursor(int cursor_id); | ||
| 88 | u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf); | ||
| 86 | 89 | ||
| 87 | static inline u32 mdp_ctl_flush_mask_cursor(int cursor_id) | 90 | /* @flush_mask: see CTL flush masks definitions below */ |
| 88 | { | 91 | int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask); |
| 89 | /* TODO: use id once multiple cursor support is present */ | ||
| 90 | (void)cursor_id; | ||
| 91 | 92 | ||
| 92 | return MDP5_CTL_FLUSH_CURSOR_DUMMY; | 93 | void mdp5_ctl_release(struct mdp5_ctl *ctl); |
| 93 | } | ||
| 94 | 94 | ||
| 95 | static inline u32 mdp_ctl_flush_mask_lm(int lm) | ||
| 96 | { | ||
| 97 | switch (lm) { | ||
| 98 | case 0: return MDP5_CTL_FLUSH_LM0; | ||
| 99 | case 1: return MDP5_CTL_FLUSH_LM1; | ||
| 100 | case 2: return MDP5_CTL_FLUSH_LM2; | ||
| 101 | case 5: return MDP5_CTL_FLUSH_LM5; | ||
| 102 | default: return 0; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | 95 | ||
| 106 | static inline u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe) | ||
| 107 | { | ||
| 108 | switch (pipe) { | ||
| 109 | case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0; | ||
| 110 | case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1; | ||
| 111 | case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2; | ||
| 112 | case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0; | ||
| 113 | case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1; | ||
| 114 | case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2; | ||
| 115 | case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0; | ||
| 116 | case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1; | ||
| 117 | case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3; | ||
| 118 | case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3; | ||
| 119 | default: return 0; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | 96 | ||
| 123 | #endif /* __MDP5_CTL_H__ */ | 97 | #endif /* __MDP5_CTL_H__ */ |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c index b18b381502a3..2ef6d1b0a218 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c | |||
| @@ -217,12 +217,15 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, | |||
| 217 | mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3); /* frame+line? */ | 217 | mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3); /* frame+line? */ |
| 218 | 218 | ||
| 219 | spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); | 219 | spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); |
| 220 | |||
| 221 | mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf); | ||
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | static void mdp5_encoder_disable(struct drm_encoder *encoder) | 224 | static void mdp5_encoder_disable(struct drm_encoder *encoder) |
| 223 | { | 225 | { |
| 224 | struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); | 226 | struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); |
| 225 | struct mdp5_kms *mdp5_kms = get_kms(encoder); | 227 | struct mdp5_kms *mdp5_kms = get_kms(encoder); |
| 228 | struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc); | ||
| 226 | int lm = mdp5_crtc_get_lm(encoder->crtc); | 229 | int lm = mdp5_crtc_get_lm(encoder->crtc); |
| 227 | struct mdp5_interface *intf = &mdp5_encoder->intf; | 230 | struct mdp5_interface *intf = &mdp5_encoder->intf; |
| 228 | int intfn = mdp5_encoder->intf.num; | 231 | int intfn = mdp5_encoder->intf.num; |
| @@ -231,9 +234,12 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder) | |||
| 231 | if (WARN_ON(!mdp5_encoder->enabled)) | 234 | if (WARN_ON(!mdp5_encoder->enabled)) |
| 232 | return; | 235 | return; |
| 233 | 236 | ||
| 237 | mdp5_ctl_set_encoder_state(ctl, false); | ||
| 238 | |||
| 234 | spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); | 239 | spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); |
| 235 | mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0); | 240 | mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0); |
| 236 | spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); | 241 | spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); |
| 242 | mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf)); | ||
| 237 | 243 | ||
| 238 | /* | 244 | /* |
| 239 | * Wait for a vsync so we know the ENABLE=0 latched before | 245 | * Wait for a vsync so we know the ENABLE=0 latched before |
| @@ -254,18 +260,21 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder) | |||
| 254 | { | 260 | { |
| 255 | struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); | 261 | struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); |
| 256 | struct mdp5_kms *mdp5_kms = get_kms(encoder); | 262 | struct mdp5_kms *mdp5_kms = get_kms(encoder); |
| 263 | struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc); | ||
| 264 | struct mdp5_interface *intf = &mdp5_encoder->intf; | ||
| 257 | int intfn = mdp5_encoder->intf.num; | 265 | int intfn = mdp5_encoder->intf.num; |
| 258 | unsigned long flags; | 266 | unsigned long flags; |
| 259 | 267 | ||
| 260 | if (WARN_ON(mdp5_encoder->enabled)) | 268 | if (WARN_ON(mdp5_encoder->enabled)) |
| 261 | return; | 269 | return; |
| 262 | 270 | ||
| 263 | mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf); | ||
| 264 | |||
| 265 | bs_set(mdp5_encoder, 1); | 271 | bs_set(mdp5_encoder, 1); |
| 266 | spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); | 272 | spin_lock_irqsave(&mdp5_encoder->intf_lock, flags); |
| 267 | mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1); | 273 | mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1); |
| 268 | spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); | 274 | spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags); |
| 275 | mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf)); | ||
| 276 | |||
| 277 | mdp5_ctl_set_encoder_state(ctl, true); | ||
| 269 | 278 | ||
| 270 | mdp5_encoder->enabled = true; | 279 | mdp5_encoder->enabled = true; |
| 271 | } | 280 | } |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 1a6aa494d92f..690edfde4ba1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | |||
| @@ -230,6 +230,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, | |||
| 230 | uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc); | 230 | uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc); |
| 231 | 231 | ||
| 232 | int mdp5_crtc_get_lm(struct drm_crtc *crtc); | 232 | int mdp5_crtc_get_lm(struct drm_crtc *crtc); |
| 233 | struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc); | ||
| 233 | void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); | 234 | void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); |
| 234 | void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf); | 235 | void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf); |
| 235 | struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, | 236 | struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, |
