From c36045e17a0e9206078a3254385bf9258e32d5b8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH] drm/armada: convert primary plane to atomic state Convert the primary plane as a whole to use its atomic state and the transitional helpers. The CRTC is also switched to use the transitional helpers for mode_set() and mode_set_base(). Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 308 +++++++++++++-------------- drivers/gpu/drm/armada/armada_crtc.h | 8 +- 2 files changed, 157 insertions(+), 159 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 735abdab9754..523e0e8c6962 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -325,38 +325,6 @@ armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) return work; } -static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, - struct drm_framebuffer *fb, bool force) -{ - struct armada_plane_work *work; - - if (!fb) - return; - - if (force) { - /* Display is disabled, so just drop the old fb */ - drm_framebuffer_put(fb); - return; - } - - work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); - if (work) { - work->old_fb = fb; - - if (armada_drm_plane_work_queue(dcrtc, work) == 0) - return; - - kfree(work); - } - - /* - * Oops - just drop the reference immediately and hope for - * the best. The worst that will happen is the buffer gets - * reused before it has finished being displayed. - */ - drm_framebuffer_put(fb); -} - static void armada_drm_vblank_off(struct armada_crtc *dcrtc) { /* @@ -434,9 +402,6 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) dcrtc->dpms = DRM_MODE_DPMS_ON; armada_drm_crtc_update(dcrtc); drm_crtc_vblank_on(crtc); - - if (dcrtc->old_modeset_fb) - armada_drm_crtc_finish_fb(dcrtc, dcrtc->old_modeset_fb, false); } /* The mode_config.mutex will be held for this call */ @@ -588,27 +553,16 @@ static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) return val; } -static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb); - /* The mode_config.mutex will be held for this call */ -static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, struct drm_display_mode *adj, - int x, int y, struct drm_framebuffer *old_fb) +static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { + struct drm_display_mode *adj = &crtc->state->adjusted_mode; struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_regs regs[17]; uint32_t lm, rm, tm, bm, val, sclk; unsigned long flags; unsigned i; - bool interlaced; - - /* Take a reference on the old fb for armada_drm_crtc_commit() */ - if (old_fb) - drm_framebuffer_get(old_fb); - dcrtc->old_modeset_fb = old_fb; - - interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); + bool interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); i = 0; rm = adj->crtc_hsync_start - adj->crtc_hdisplay; @@ -692,35 +646,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_drm_crtc_update_regs(dcrtc, regs); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - - return armada_drm_crtc_mode_set_base(crtc, x, y, old_fb); -} - -static int armada_drm_do_primary_update(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_framebuffer *old_fb); - -/* The mode_config.mutex will be held for this call */ -static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct drm_plane_state state = { - .plane = crtc->primary, - .crtc = crtc, - .fb = crtc->primary->fb, - .crtc_x = 0, - .crtc_y = 0, - .crtc_w = crtc->mode.hdisplay, - .crtc_h = crtc->mode.vdisplay, - .src_x = x << 16, - .src_y = y << 16, - .src_w = crtc->mode.hdisplay << 16, - .src_h = crtc->mode.vdisplay << 16, - .rotation = DRM_MODE_ROTATE_0, - }; - - armada_drm_do_primary_update(crtc->primary, &state, old_fb); - - return 0; } /* The mode_config.mutex will be held for this call */ @@ -732,14 +657,49 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc) crtc->primary->funcs->disable_plane(crtc->primary, NULL); } +static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct armada_plane *dplane; + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + /* Wait 100ms for any plane works to complete */ + dplane = drm_to_armada_plane(crtc->primary); + if (WARN_ON(armada_drm_plane_work_wait(dplane, HZ / 10) == 0)) + armada_drm_plane_work_cancel(dcrtc, dplane); + + dcrtc->regs_idx = 0; + dcrtc->regs = dcrtc->atomic_regs; +} + +static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + unsigned long flags; + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); + + spin_lock_irqsave(&dcrtc->irq_lock, flags); + armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); +} + static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .dpms = armada_drm_crtc_dpms, .prepare = armada_drm_crtc_prepare, .commit = armada_drm_crtc_commit, .mode_fixup = armada_drm_crtc_mode_fixup, - .mode_set = armada_drm_crtc_mode_set, - .mode_set_base = armada_drm_crtc_mode_set_base, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = armada_drm_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, .disable = armada_drm_crtc_disable, + .atomic_begin = armada_drm_crtc_atomic_begin, + .atomic_flush = armada_drm_crtc_atomic_flush, }; static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, @@ -1012,6 +972,12 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } + /* + * We are in transition to atomic modeset: update the atomic modeset + * state with the new framebuffer to keep the state consistent. + */ + drm_framebuffer_assign(&dcrtc->crtc.primary->state->fb, fb); + /* * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. @@ -1072,16 +1038,66 @@ static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc) } static const struct drm_crtc_funcs armada_crtc_funcs = { + .reset = drm_atomic_helper_crtc_reset, .cursor_set = armada_drm_crtc_cursor_set, .cursor_move = armada_drm_crtc_cursor_move, .destroy = armada_drm_crtc_destroy, .set_config = drm_crtc_helper_set_config, .page_flip = armada_drm_crtc_page_flip, .set_property = armada_drm_crtc_set_property, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .enable_vblank = armada_drm_crtc_enable_vblank, .disable_vblank = armada_drm_crtc_disable_vblank, }; +static int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state) +{ + DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", + plane->base.id, plane->name, + state->fb ? state->fb->base.id : 0); + + /* + * Take a reference on the new framebuffer - we want to + * hold on to it while the hardware is displaying it. + */ + if (state->fb) + drm_framebuffer_get(state->fb); + return 0; +} + +static void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", + plane->base.id, plane->name, + old_state->fb ? old_state->fb->base.id : 0); + + if (old_state->fb) + drm_framebuffer_put(old_state->fb); +} + +static int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + if (state->fb && !WARN_ON(!state->crtc)) { + struct drm_crtc *crtc = state->crtc; + struct drm_crtc_state crtc_state = { + .crtc = crtc, + .enable = crtc->enabled, + .mode = crtc->mode, + }; + + return drm_atomic_helper_check_plane_state(state, &crtc_state, + 0, INT_MAX, + true, false); + } else { + state->visible = false; + } + return 0; +} + static unsigned int armada_drm_primary_update_state( struct drm_plane_state *state, struct armada_regs *regs) { @@ -1134,94 +1150,70 @@ static unsigned int armada_drm_primary_update_state( return idx; } -static int armada_drm_do_primary_update(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_framebuffer *old_fb) +static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) { - struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); - struct armada_plane_work *work; - struct drm_crtc_state crtc_state = { - .crtc = state->crtc, - .enable = state->crtc->enabled, - .mode = state->crtc->mode, - }; - unsigned int idx; - int ret; + struct drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; - ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0, - INT_MAX, true, false); - if (ret) - return ret; + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - work = &dplane->works[dplane->next_work]; - work->fn = armada_drm_crtc_complete_frame_work; + if (!state->fb || WARN_ON(!state->crtc)) + return; - if (old_fb != state->fb) { - /* - * Take a reference on the new framebuffer - we want to - * hold on to it while the hardware is displaying it. - */ - drm_framebuffer_reference(state->fb); + 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); - work->old_fb = old_fb; - } else { - work->old_fb = NULL; - } + dcrtc = drm_to_armada_crtc(state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; - idx = armada_drm_primary_update_state(state, work->regs); - armada_reg_queue_end(work->regs, idx); + dcrtc->regs_idx += armada_drm_primary_update_state(state, regs); +} - if (!dplane->state.changed) - return 0; +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; - /* Wait for pending work to complete */ - if (armada_drm_plane_work_wait(dplane, HZ / 10) == 0) - armada_drm_plane_work_cancel(dcrtc, dplane); + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - if (!dplane->state.vsync_update) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - return 0; - } + if (!old_state->crtc) + return; - /* Queue it for update on the next interrupt if we are enabled */ - ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - } + DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n", + plane->base.id, plane->name, + old_state->crtc->base.id, old_state->crtc->name, + old_state->fb->base.id); - dplane->next_work = !dplane->next_work; + dplane->state.ctrl0 &= ~CFG_GRA_ENA; - return 0; -} + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; -static int armada_drm_primary_update(struct drm_plane *plane, - struct drm_crtc *crtc, struct drm_framebuffer *fb, - int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int 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 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, - }; - - return armada_drm_do_primary_update(plane, &state, plane->fb); + /* Disable plane and power down most RAMs and FIFOs */ + armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0); + armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 | + CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66, + 0, LCD_SPU_SRAM_PARA1); + + dcrtc->regs_idx += idx; } +static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { + .prepare_fb = armada_drm_plane_prepare_fb, + .cleanup_fb = armada_drm_plane_cleanup_fb, + .atomic_check = armada_drm_plane_atomic_check, + .atomic_update = armada_drm_primary_plane_atomic_update, + .atomic_disable = armada_drm_primary_plane_atomic_disable, +}; + int armada_drm_plane_disable(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx) { @@ -1283,9 +1275,12 @@ int armada_drm_plane_disable(struct drm_plane *plane, } static const struct drm_plane_funcs armada_primary_plane_funcs = { - .update_plane = armada_drm_primary_update, - .disable_plane = armada_drm_plane_disable, + .update_plane = drm_plane_helper_update, + .disable_plane = drm_plane_helper_disable, .destroy = drm_primary_helper_destroy, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; int armada_drm_plane_init(struct armada_plane *plane) @@ -1414,6 +1409,9 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, goto err_crtc; } + drm_plane_helper_add(&primary->base, + &armada_primary_plane_helper_funcs); + ret = drm_universal_plane_init(drm, &primary->base, 0, &armada_primary_plane_funcs, armada_primary_formats, diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 8edcfd1fa75f..3253947e0d41 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -93,7 +93,6 @@ struct armada_crtc { uint8_t csc_rgb_mode; struct drm_plane *plane; - struct drm_framebuffer *old_modeset_fb; struct armada_gem_object *cursor_obj; int cursor_x; @@ -110,14 +109,15 @@ struct armada_crtc { spinlock_t irq_lock; uint32_t irq_ena; + + struct armada_regs atomic_regs[32]; + struct armada_regs *regs; + unsigned int regs_idx; }; #define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); -int armada_drm_plane_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx); - extern struct platform_driver armada_lcd_platform_driver; #endif -- 2.30.2