drm/armada: use old_state for update tracking in atomic_update()
authorRussell King <rmk+kernel@armlinux.org.uk>
Mon, 30 Jul 2018 10:52:34 +0000 (11:52 +0100)
committerRussell King <rmk+kernel@armlinux.org.uk>
Mon, 30 Jul 2018 10:52:34 +0000 (11:52 +0100)
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>
drivers/gpu/drm/armada/armada_crtc.c
drivers/gpu/drm/armada/armada_crtc.h
drivers/gpu/drm/armada/armada_overlay.c

index 0566739118187b95ee217ec5692b1de90c4314a2..14339d5bed149478485167d3dab66521f06660ba 100644 (file)
@@ -1114,64 +1114,14 @@ int armada_drm_plane_atomic_check(struct drm_plane *plane,
        return 0;
 }
 
-static unsigned int armada_drm_primary_update_state(
-       struct drm_plane_state *state, struct armada_regs *regs)
-{
-       struct armada_plane *dplane = drm_to_armada_plane(state->plane);
-       struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc);
-       struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb);
-       bool was_disabled;
-       unsigned int idx = 0;
-       u32 val;
-
-       val = CFG_GRA_FMT(dfb->fmt) | CFG_GRA_MOD(dfb->mod);
-       if (dfb->fmt > CFG_420)
-               val |= CFG_PALETTE_ENA;
-       if (state->visible)
-               val |= CFG_GRA_ENA;
-       if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst))
-               val |= CFG_GRA_HSMOOTH;
-       if (dcrtc->interlaced)
-               val |= CFG_GRA_FTOGGLE;
-
-       was_disabled = !(dplane->state.ctrl0 & CFG_GRA_ENA);
-       if (was_disabled)
-               armada_reg_queue_mod(regs, idx,
-                                    0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1);
-
-       dplane->state.ctrl0 = val;
-       dplane->state.src_hw = armada_rect_hw_fp(&state->src);
-       dplane->state.dst_hw = armada_rect_hw(&state->dst);
-       dplane->state.dst_yx = armada_rect_yx(&state->dst);
-
-       idx += armada_drm_crtc_calc_fb(&dfb->fb, state->src.x1 >> 16,
-                                      state->src.y1 >> 16, regs + idx,
-                                      dcrtc->interlaced);
-       armada_reg_queue_set(regs, idx, dplane->state.dst_yx,
-                            LCD_SPU_GRA_OVSA_HPXL_VLN);
-       armada_reg_queue_set(regs, idx, dplane->state.src_hw,
-                            LCD_SPU_GRA_HPXL_VLN);
-       armada_reg_queue_set(regs, idx, dplane->state.dst_hw,
-                            LCD_SPU_GZM_HPXL_VLN);
-       armada_reg_queue_mod(regs, idx, dplane->state.ctrl0, CFG_GRAFORMAT |
-                            CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
-                                        CFG_SWAPYU | CFG_YUV2RGB) |
-                            CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
-                            CFG_GRA_HSMOOTH | CFG_GRA_ENA,
-                            LCD_SPU_DMA_CTRL0);
-
-       dplane->state.vsync_update = !was_disabled;
-       dplane->state.changed = true;
-
-       return idx;
-}
-
 static void armada_drm_primary_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;
+       u32 cfg, cfg_mask, val;
+       unsigned int idx;
 
        DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
 
@@ -1187,13 +1137,69 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
        dcrtc = drm_to_armada_crtc(state->crtc);
        regs = dcrtc->regs + dcrtc->regs_idx;
 
-       dcrtc->regs_idx += armada_drm_primary_update_state(state, regs);
+       idx = 0;
+       if (!old_state->visible && state->visible) {
+               val = CFG_PDWN64x66;
+               if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
+                       val |= CFG_PDWN256x24;
+               armada_reg_queue_mod(regs, idx, 0, val, 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_GRA_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_GRA_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_GZM_HPXL_VLN);
+       if (old_state->src.x1 != state->src.x1 ||
+           old_state->src.y1 != state->src.y1 ||
+           old_state->fb != state->fb) {
+               idx += armada_drm_crtc_calc_fb(state->fb,
+                                              state->src.x1 >> 16,
+                                              state->src.y1 >> 16,
+                                              regs + idx,
+                                              dcrtc->interlaced);
+       }
+       if (old_state->fb != state->fb) {
+               cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
+                     CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod);
+               if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
+                       cfg |= CFG_PALETTE_ENA;
+               if (state->visible)
+                       cfg |= CFG_GRA_ENA;
+               if (dcrtc->interlaced)
+                       cfg |= CFG_GRA_FTOGGLE;
+               cfg_mask = CFG_GRAFORMAT |
+                          CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
+                                      CFG_SWAPYU | CFG_YUV2RGB) |
+                          CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
+                          CFG_GRA_ENA;
+       } else if (old_state->visible != state->visible) {
+               cfg = state->visible ? CFG_GRA_ENA : 0;
+               cfg_mask = CFG_GRA_ENA;
+       } else {
+               cfg = cfg_mask = 0;
+       }
+       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_GRA_HSMOOTH;
+               if (drm_rect_width(&state->src) >> 16 !=
+                   drm_rect_width(&state->dst))
+                       cfg |= CFG_GRA_HSMOOTH;
+       }
+
+       if (cfg_mask)
+               armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
+                                    LCD_SPU_DMA_CTRL0);
+
+       dcrtc->regs_idx += idx;
 }
 
 static void armada_drm_primary_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;
@@ -1208,8 +1214,6 @@ static void armada_drm_primary_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_GRA_ENA;
-
        dcrtc = drm_to_armada_crtc(old_state->crtc);
        regs = dcrtc->regs + dcrtc->regs_idx;
 
index 4da56a171b13e4d886c630e28bb0cdca1fea2065..79ac0db047c9e68395656c9225afb7c37b041a7e 100644 (file)
@@ -45,24 +45,12 @@ struct armada_plane_work {
        struct armada_regs regs[14];
 };
 
-struct armada_plane_state {
-       u16 src_x;
-       u16 src_y;
-       u32 src_hw;
-       u32 dst_hw;
-       u32 dst_yx;
-       u32 ctrl0;
-       bool changed;
-       bool vsync_update;
-};
-
 struct armada_plane {
        struct drm_plane        base;
        wait_queue_head_t       frame_wait;
        bool                    next_work;
        struct armada_plane_work works[2];
        struct armada_plane_work *work;
-       struct armada_plane_state state;
 };
 #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base)
 
index be9de5d85f9f4cddabfce6fc37cb95ceb40e10fd..aa2a12aec3cc58661a4a1e214238bc805a8b0bd7 100644 (file)
@@ -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;
        }