diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2018-07-30 13:52:34 +0300 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2018-07-30 13:52:34 +0300 |
commit | 3acea7b9b62c282ea3d4d0cd156ca8e35dfa8a8c (patch) | |
tree | 79bb02ca5105290ee7a8f440fe34522b846403fe /drivers/gpu/drm/armada/armada_overlay.c | |
parent | 9c41467c9aa5b3916ff559b8c2b3725d6290e5ec (diff) | |
download | linux-3acea7b9b62c282ea3d4d0cd156ca8e35dfa8a8c.tar.xz |
drm/armada: use old_state for update tracking in atomic_update()
Rather than tracking the register state, we can now check the previous
state and decide which registers need updating from that since the old
plane state indicates the previous state which was programmed into the
hardware.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'drivers/gpu/drm/armada/armada_overlay.c')
-rw-r--r-- | drivers/gpu/drm/armada/armada_overlay.c | 189 |
1 files changed, 84 insertions, 105 deletions
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index be9de5d85f9f..aa2a12aec3cc 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -35,6 +35,7 @@ struct armada_ovl_plane_properties { struct armada_ovl_plane { struct armada_plane base; + bool wait_vblank; struct armada_ovl_plane_properties prop; }; #define drm_to_armada_ovl_plane(p) \ @@ -80,52 +81,55 @@ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, - struct armada_regs *regs) +static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(state->plane); - struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb); - const struct drm_format_info *format; - unsigned int idx = 0; - bool fb_changed; - u32 val, ctrl0; - u16 src_x, src_y; - - ctrl0 = CFG_DMA_FMT(dfb->fmt) | CFG_DMA_MOD(dfb->mod) | CFG_CBSH_ENA; - if (state->visible) - ctrl0 |= CFG_DMA_ENA; - if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst)) - ctrl0 |= CFG_DMA_HSMOOTH; - - /* - * Shifting a YUV packed format image by one pixel causes the U/V - * planes to swap. Compensate for it by also toggling the UV swap. - */ - format = dfb->fb.format; - if (format->num_planes == 1 && state->src.x1 >> 16 & (format->hsub - 1)) - ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV); - - if (~dplane->base.state.ctrl0 & ctrl0 & CFG_DMA_ENA) { - /* Power up the Y/U/V FIFOs on ENA 0->1 transitions */ - armada_reg_queue_mod(regs, idx, - 0, CFG_PDWN16x66 | CFG_PDWN32x66, - LCD_SPU_SRAM_PARA1); - } + struct drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx; + u32 cfg, cfg_mask, val; - fb_changed = dplane->base.base.fb != &dfb->fb || - dplane->base.state.src_x != state->src.x1 >> 16 || - dplane->base.state.src_y != state->src.y1 >> 16; + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - dplane->base.state.vsync_update = fb_changed; + if (!state->fb || WARN_ON(!state->crtc)) + return; + DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", + plane->base.id, plane->name, + state->crtc->base.id, state->crtc->name, + state->fb->base.id, + old_state->visible, state->visible); + + dcrtc = drm_to_armada_crtc(state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + drm_to_armada_ovl_plane(plane)->wait_vblank = false; + + idx = 0; + if (!old_state->visible && state->visible) + armada_reg_queue_mod(regs, idx, + 0, CFG_PDWN16x66 | CFG_PDWN32x66, + LCD_SPU_SRAM_PARA1); + val = armada_rect_hw_fp(&state->src); + if (armada_rect_hw_fp(&old_state->src) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN); + val = armada_rect_yx(&state->dst); + if (armada_rect_yx(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN); + val = armada_rect_hw(&state->dst); + if (armada_rect_hw(&old_state->dst) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN); /* FIXME: overlay on an interlaced display */ - if (fb_changed) { + if (old_state->src.x1 != state->src.x1 || + old_state->src.y1 != state->src.y1 || + old_state->fb != state->fb) { + const struct drm_format_info *format; + u16 src_x = state->src.x1 >> 16; + u16 src_y = state->src.y1 >> 16; u32 addrs[3]; - dplane->base.state.src_y = src_y = state->src.y1 >> 16; - dplane->base.state.src_x = src_x = state->src.x1 >> 16; - - armada_drm_plane_calc_addrs(addrs, &dfb->fb, src_x, src_y); + armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y); armada_reg_queue_set(regs, idx, addrs[0], LCD_SPU_DMA_START_ADDR_Y0); @@ -140,79 +144,56 @@ static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, armada_reg_queue_set(regs, idx, addrs[2], LCD_SPU_DMA_START_ADDR_V1); - val = dfb->fb.pitches[0] << 16 | dfb->fb.pitches[0]; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_PITCH_YC); - val = dfb->fb.pitches[1] << 16 | dfb->fb.pitches[2]; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_PITCH_UV); - } - - val = armada_rect_hw_fp(&state->src); - if (dplane->base.state.src_hw != val) { - dplane->base.state.src_hw = val; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_HPXL_VLN); - } + val = state->fb->pitches[0] << 16 | state->fb->pitches[0]; + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); + val = state->fb->pitches[1] << 16 | state->fb->pitches[2]; + armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); - val = armada_rect_hw(&state->dst); - if (dplane->base.state.dst_hw != val) { - dplane->base.state.dst_hw = val; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DZM_HPXL_VLN); - } + cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | + CFG_DMA_MOD(drm_fb_to_armada_fb(state->fb)->mod) | + CFG_CBSH_ENA; + if (state->visible) + cfg |= CFG_DMA_ENA; - val = armada_rect_yx(&state->dst); - if (dplane->base.state.dst_yx != val) { - dplane->base.state.dst_yx = val; - armada_reg_queue_set(regs, idx, val, - LCD_SPU_DMA_OVSA_HPXL_VLN); + /* + * Shifting a YUV packed format image by one pixel causes the + * U/V planes to swap. Compensate for it by also toggling + * the UV swap. + */ + format = state->fb->format; + if (format->num_planes == 1 && src_x & (format->hsub - 1)) + cfg ^= CFG_DMA_MOD(CFG_SWAPUV); + cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | + CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | + CFG_SWAPYU | CFG_YUV2RGB) | + CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE | + CFG_DMA_ENA; + + drm_to_armada_ovl_plane(plane)->wait_vblank = true; + } else if (old_state->visible != state->visible) { + cfg = state->visible ? CFG_DMA_ENA : 0; + cfg_mask = CFG_DMA_ENA; + } else { + cfg = cfg_mask = 0; } - - if (dplane->base.state.ctrl0 != ctrl0) { - dplane->base.state.ctrl0 = ctrl0; - armada_reg_queue_mod(regs, idx, ctrl0, - CFG_CBSH_ENA | CFG_DMAFORMAT | CFG_DMA_FTOGGLE | - CFG_DMA_HSMOOTH | CFG_DMA_TSTMODE | - CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_SWAPYU | - CFG_YUV2RGB) | CFG_DMA_ENA, - LCD_SPU_DMA_CTRL0); - dplane->base.state.vsync_update = true; + if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) || + drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) { + cfg_mask |= CFG_DMA_HSMOOTH; + if (drm_rect_width(&state->src) >> 16 != + drm_rect_width(&state->dst)) + cfg |= CFG_DMA_HSMOOTH; } - dplane->base.state.changed = idx != 0; - - return idx; -} - -static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *old_state) -{ - struct drm_plane_state *state = plane->state; - struct armada_crtc *dcrtc; - struct armada_regs *regs; + if (cfg_mask) + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, + LCD_SPU_DMA_CTRL0); - DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - - if (!state->fb || WARN_ON(!state->crtc)) - return; - - DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n", - plane->base.id, plane->name, - state->crtc->base.id, state->crtc->name, - state->fb->base.id, - old_state->visible, state->visible); - - dcrtc = drm_to_armada_crtc(state->crtc); - regs = dcrtc->regs + dcrtc->regs_idx; - - dcrtc->regs_idx += armada_ovl_plane_update_state(state, regs); + dcrtc->regs_idx += idx; } static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct armada_plane *dplane = drm_to_armada_plane(plane); struct armada_crtc *dcrtc; struct armada_regs *regs; unsigned int idx = 0; @@ -227,8 +208,6 @@ static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, old_state->crtc->base.id, old_state->crtc->name, old_state->fb->base.id); - dplane->state.ctrl0 &= ~CFG_DMA_ENA; - dcrtc = drm_to_armada_crtc(old_state->crtc); regs = dcrtc->regs + dcrtc->regs_idx; @@ -288,7 +267,7 @@ static int armada_overlay_commit(struct drm_plane *plane, plane_funcs->atomic_update(plane, state); /* If nothing was updated, short-circuit */ - if (!dplane->base.state.changed) + if (dcrtc->regs_idx == 0) goto put_state; armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); @@ -298,7 +277,7 @@ static int armada_overlay_commit(struct drm_plane *plane, armada_drm_plane_work_cancel(dcrtc, &dplane->base); /* Just updating the position/size? */ - if (!dplane->base.state.vsync_update) { + if (!dplane->wait_vblank) { armada_ovl_plane_work(dcrtc, work); goto put_state; } |