drm/armada: move overlay plane register update generation
authorRussell King <rmk+kernel@armlinux.org.uk>
Sat, 8 Jul 2017 09:22:33 +0000 (10:22 +0100)
committerRussell King <rmk+kernel@armlinux.org.uk>
Fri, 8 Dec 2017 12:21:53 +0000 (12:21 +0000)
Move the overlay plane register update generation to a separate function
as this is independent of the legacy or atomic update.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
drivers/gpu/drm/armada/armada_crtc.h
drivers/gpu/drm/armada/armada_overlay.c

index 0c7b519..445829b 100644 (file)
@@ -52,6 +52,8 @@ struct armada_plane_state {
        u32 dst_hw;
        u32 dst_yx;
        u32 ctrl0;
+       bool changed;
+       bool vsync_update;
 };
 
 struct armada_plane {
index 00da2c5..e5fa346 100644 (file)
@@ -75,153 +75,172 @@ static void armada_ovl_plane_work(struct armada_crtc *dcrtc,
        spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
 }
 
-static int
-armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
-       struct drm_framebuffer *fb,
-       int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h,
-       uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
-       struct drm_modeset_acquire_ctx *ctx)
+static void armada_ovl_plane_update_state(struct drm_plane_state *state,
+       struct armada_regs *regs)
 {
-       struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
-       struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
-       struct armada_plane_work *work;
+       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;
-       struct drm_plane_state state = {
-               .plane = plane,
-               .crtc = crtc,
-               .fb = fb,
-               .src_x = src_x,
-               .src_y = src_y,
-               .src_w = src_w,
-               .src_h = src_h,
-               .crtc_x = crtc_x,
-               .crtc_y = crtc_y,
-               .crtc_w = crtc_w,
-               .crtc_h = crtc_h,
-               .rotation = DRM_MODE_ROTATE_0,
-       };
-       const struct drm_rect clip = {
-               .x2 = crtc->mode.hdisplay,
-               .y2 = crtc->mode.vdisplay,
-       };
-       uint32_t val, ctrl0;
-       unsigned idx = 0;
+       unsigned int idx = 0;
        bool fb_changed;
-       int ret;
+       u32 val, ctrl0;
+       u16 src_x, src_y;
 
-       trace_armada_ovl_plane_update(plane, crtc, fb,
-                                crtc_x, crtc_y, crtc_w, crtc_h,
-                                src_x, src_y, src_w, src_h);
-
-       ret = drm_plane_helper_check_state(&state, &clip, 0, INT_MAX, true,
-                                           false);
-       if (ret)
-               return ret;
-
-       work = &dplane->base.works[dplane->base.next_work];
-
-       ctrl0 = CFG_DMA_FMT(drm_fb_to_armada_fb(fb)->fmt) |
-               CFG_DMA_MOD(drm_fb_to_armada_fb(fb)->mod) |
-               CFG_CBSH_ENA;
-       if (state.visible)
+       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))
+       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 = fb->format;
-       if (format->num_planes == 1 && state.src.x1 >> 16 & (format->hsub - 1))
+       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(work->regs, idx,
+               armada_reg_queue_mod(regs, idx,
                                     0, CFG_PDWN16x66 | CFG_PDWN32x66,
                                     LCD_SPU_SRAM_PARA1);
        }
 
-       fb_changed = plane->fb != fb ||
-                    dplane->base.state.src_x != state.src.x1 >> 16 ||
-                    dplane->base.state.src_y != state.src.y1 >> 16;
+       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;
+
+       dplane->base.state.vsync_update = fb_changed;
 
        /* FIXME: overlay on an interlaced display */
        if (fb_changed) {
                u32 addrs[3];
 
-               /*
-                * Take a reference on the new framebuffer - we want to
-                * hold on to it while the hardware is displaying it.
-                */
-               drm_framebuffer_get(fb);
-
-               work->old_fb = plane->fb;
+               dplane->base.state.src_y = src_y = state->src.y1 >> 16;
+               dplane->base.state.src_x = src_x = state->src.x1 >> 16;
 
-               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, fb, src_x, src_y);
-
-               armada_reg_queue_set(work->regs, idx, addrs[0],
+               armada_reg_queue_set(regs, idx, addrs[0],
                                     LCD_SPU_DMA_START_ADDR_Y0);
-               armada_reg_queue_set(work->regs, idx, addrs[1],
+               armada_reg_queue_set(regs, idx, addrs[1],
                                     LCD_SPU_DMA_START_ADDR_U0);
-               armada_reg_queue_set(work->regs, idx, addrs[2],
+               armada_reg_queue_set(regs, idx, addrs[2],
                                     LCD_SPU_DMA_START_ADDR_V0);
-               armada_reg_queue_set(work->regs, idx, addrs[0],
+               armada_reg_queue_set(regs, idx, addrs[0],
                                     LCD_SPU_DMA_START_ADDR_Y1);
-               armada_reg_queue_set(work->regs, idx, addrs[1],
+               armada_reg_queue_set(regs, idx, addrs[1],
                                     LCD_SPU_DMA_START_ADDR_U1);
-               armada_reg_queue_set(work->regs, idx, addrs[2],
+               armada_reg_queue_set(regs, idx, addrs[2],
                                     LCD_SPU_DMA_START_ADDR_V1);
 
-               val = fb->pitches[0] << 16 | fb->pitches[0];
-               armada_reg_queue_set(work->regs, idx, val,
+               val = dfb->fb.pitches[0] << 16 | dfb->fb.pitches[0];
+               armada_reg_queue_set(regs, idx, val,
                                     LCD_SPU_DMA_PITCH_YC);
-               val = fb->pitches[1] << 16 | fb->pitches[2];
-               armada_reg_queue_set(work->regs, idx, val,
+               val = dfb->fb.pitches[1] << 16 | dfb->fb.pitches[2];
+               armada_reg_queue_set(regs, idx, val,
                                     LCD_SPU_DMA_PITCH_UV);
-       } else {
-               work->old_fb = NULL;
        }
 
-       val = (drm_rect_height(&state.src) & 0xffff0000) |
-              drm_rect_width(&state.src) >> 16;
+       val = (drm_rect_height(&state->src) & 0xffff0000) |
+              drm_rect_width(&state->src) >> 16;
        if (dplane->base.state.src_hw != val) {
                dplane->base.state.src_hw = val;
-               armada_reg_queue_set(work->regs, idx, val,
+               armada_reg_queue_set(regs, idx, val,
                                     LCD_SPU_DMA_HPXL_VLN);
        }
 
-       val = drm_rect_height(&state.dst) << 16 | drm_rect_width(&state.dst);
+       val = drm_rect_height(&state->dst) << 16 | drm_rect_width(&state->dst);
        if (dplane->base.state.dst_hw != val) {
                dplane->base.state.dst_hw = val;
-               armada_reg_queue_set(work->regs, idx, val,
+               armada_reg_queue_set(regs, idx, val,
                                     LCD_SPU_DZM_HPXL_VLN);
        }
 
-       val = state.dst.y1 << 16 | state.dst.x1;
+       val = state->dst.y1 << 16 | state->dst.x1;
        if (dplane->base.state.dst_yx != val) {
                dplane->base.state.dst_yx = val;
-               armada_reg_queue_set(work->regs, idx, val,
+               armada_reg_queue_set(regs, idx, val,
                                     LCD_SPU_DMA_OVSA_HPXL_VLN);
        }
 
        if (dplane->base.state.ctrl0 != ctrl0) {
                dplane->base.state.ctrl0 = ctrl0;
-               armada_reg_queue_mod(work->regs, idx, 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;
        }
 
+       dplane->base.state.changed = idx != 0;
+
+       armada_reg_queue_end(regs, idx);
+}
+
+static int
+armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
+       struct drm_framebuffer *fb,
+       int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h,
+       uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
+       struct drm_modeset_acquire_ctx *ctx)
+{
+       struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
+       struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
+       struct armada_plane_work *work;
+       struct drm_plane_state state = {
+               .plane = plane,
+               .crtc = crtc,
+               .fb = fb,
+               .src_x = src_x,
+               .src_y = src_y,
+               .src_w = src_w,
+               .src_h = src_h,
+               .crtc_x = crtc_x,
+               .crtc_y = crtc_y,
+               .crtc_w = crtc_w,
+               .crtc_h = crtc_h,
+               .rotation = DRM_MODE_ROTATE_0,
+       };
+       const struct drm_rect clip = {
+               .x2 = crtc->mode.hdisplay,
+               .y2 = crtc->mode.vdisplay,
+       };
+       int ret;
+
+       trace_armada_ovl_plane_update(plane, crtc, fb,
+                                crtc_x, crtc_y, crtc_w, crtc_h,
+                                src_x, src_y, src_w, src_h);
+
+       ret = drm_plane_helper_check_state(&state, &clip, 0, INT_MAX, true,
+                                           false);
+       if (ret)
+               return ret;
+
+       work = &dplane->base.works[dplane->base.next_work];
+
+       if (plane->fb != fb) {
+               /*
+                * Take a reference on the new framebuffer - we want to
+                * hold on to it while the hardware is displaying it.
+                */
+               drm_framebuffer_reference(fb);
+
+               work->old_fb = plane->fb;
+       } else {
+               work->old_fb = NULL;
+       }
+
+       armada_ovl_plane_update_state(&state, work->regs);
+
+       if (!dplane->base.state.changed)
+               return 0;
+
        /* Just updating the position/size? */
-       if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) {
-               armada_reg_queue_end(work->regs, idx);
+       if (!dplane->base.state.vsync_update) {
                armada_ovl_plane_work(dcrtc, work);
                return 0;
        }
@@ -235,15 +254,13 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                armada_ovl_update_attr(&dplane->prop, dcrtc);
        }
 
-       if (idx) {
-               armada_reg_queue_end(work->regs, idx);
-               /* Queue it for update on the next interrupt if we are enabled */
-               ret = armada_drm_plane_work_queue(dcrtc, work);
-               if (ret)
-                       DRM_ERROR("failed to queue plane work: %d\n", ret);
+       /* Queue it for update on the next interrupt if we are enabled */
+       ret = armada_drm_plane_work_queue(dcrtc, work);
+       if (ret)
+               DRM_ERROR("failed to queue plane work: %d\n", ret);
+
+       dplane->base.next_work = !dplane->base.next_work;
 
-               dplane->base.next_work = !dplane->base.next_work;
-       }
        return 0;
 }