From 830aadceae20c08704562f0b83fdd0f0062d06c6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 30 Jul 2018 11:52:31 +0100 Subject: [PATCH 01/39] drm/armada: Replace drm_dev_unref with drm_dev_put This patch unifies the naming of DRM functions for reference counting of struct drm_device. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 4b11b6b52f1d..d1705d298a39 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -109,7 +109,7 @@ static int armada_drm_bind(struct device *dev) /* * The drm_device structure must be at the start of - * armada_private for drm_dev_unref() to work correctly. + * armada_private for drm_dev_put() to work correctly. */ BUILD_BUG_ON(offsetof(struct armada_private, drm) != 0); @@ -180,7 +180,7 @@ static int armada_drm_bind(struct device *dev) drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); flush_work(&priv->fb_unref_work); - drm_dev_unref(&priv->drm); + drm_dev_put(&priv->drm); return ret; } @@ -200,7 +200,7 @@ static void armada_drm_unbind(struct device *dev) drm_mm_takedown(&priv->linear); flush_work(&priv->fb_unref_work); - drm_dev_unref(&priv->drm); + drm_dev_put(&priv->drm); } static int compare_of(struct device *dev, void *data) From 7794ec7774066eb12af67a0a756bddd66f2d50f8 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Mon, 30 Jul 2018 11:52:31 +0100 Subject: [PATCH 02/39] drm/armada: Adding new typedef vm_fault_t Use new return type vm_fault_t for fault handler in struct vm_operations_struct. For now, this is just documenting that the function returns a VM_FAULT value rather than an errno. Once all instances are converted, vm_fault_t will become a distinct type. commit 1c8f422059ae ("mm: change return type to vm_fault_t") Previously vm_insert_pfn() returns err which driver mapped into VM_FAULT_* type. The new function vmf_insert_pfn() will replace this inefficiency by returning VM_FAULT_* type. Signed-off-by: Souptick Joarder Reviewed-by: Matthew Wilcox Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_gem.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 3fb37c75c065..892c1d9304bb 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -13,25 +13,14 @@ #include #include "armada_ioctlP.h" -static int armada_gem_vm_fault(struct vm_fault *vmf) +static vm_fault_t armada_gem_vm_fault(struct vm_fault *vmf) { struct drm_gem_object *gobj = vmf->vma->vm_private_data; struct armada_gem_object *obj = drm_to_armada_gem(gobj); unsigned long pfn = obj->phys_addr >> PAGE_SHIFT; - int ret; pfn += (vmf->address - vmf->vma->vm_start) >> PAGE_SHIFT; - ret = vm_insert_pfn(vmf->vma, vmf->address, pfn); - - switch (ret) { - case 0: - case -EBUSY: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + return vmf_insert_pfn(vmf->vma, vmf->address, pfn); } const struct vm_operations_struct armada_gem_vm_ops = { From 1729f56010a960f182a36e09ce8d6504fa637d76 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 03/39] drm/armada: clean up armada_drm_crtc_page_flip() drm_mode_page_flip_ioctl() already takes care of checking the framebuffer format, and also assigns primary->fb after a successful call to this handler. These are both redundant, and can be removed. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 42a40daff132..78bb3d51417b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1039,10 +1039,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, unsigned i; int ret; - /* We don't support changing the pixel format */ - if (fb->format != crtc->primary->fb->format) - return -EINVAL; - work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); if (!work) return -ENOMEM; @@ -1068,14 +1064,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } - /* - * Don't take a reference on the new framebuffer; - * drm_mode_page_flip_ioctl() has already grabbed a reference and - * will _not_ drop that reference on successful return from this - * function. Simply mark this new framebuffer as the current one. - */ - dcrtc->crtc.primary->fb = fb; - /* * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. From 0239520e0290e7d5f186f7fb7f7ce307c478a439 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 04/39] drm/armada: add rectangle helpers Add helpers to convert rectangle width/height and x/y to register values. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 8 +++----- drivers/gpu/drm/armada/armada_hw.h | 15 +++++++++++++++ drivers/gpu/drm/armada/armada_overlay.c | 7 +++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 78bb3d51417b..205d5dc7ba81 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1158,11 +1158,9 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); dplane->state.ctrl0 = val; - dplane->state.src_hw = (drm_rect_height(&state->src) & 0xffff0000) | - drm_rect_width(&state->src) >> 16; - dplane->state.dst_hw = drm_rect_height(&state->dst) << 16 | - drm_rect_width(&state->dst); - dplane->state.dst_yx = state->dst.y1 << 16 | state->dst.x1; + 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); armada_drm_gra_plane_regs(regs + idx, &dfb->fb, &dplane->state, state->src.x1 >> 16, state->src.y1 >> 16, diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 345dc4d0851e..277580b36758 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -316,4 +316,19 @@ enum { PWRDN_IRQ_LEVEL = 1 << 0, }; +static inline u32 armada_rect_hw_fp(struct drm_rect *r) +{ + return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16; +} + +static inline u32 armada_rect_hw(struct drm_rect *r) +{ + return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff); +} + +static inline u32 armada_rect_yx(struct drm_rect *r) +{ + return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff); +} + #endif diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index afa7ded3ae31..2347811ccf1b 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -146,22 +146,21 @@ static void armada_ovl_plane_update_state(struct drm_plane_state *state, LCD_SPU_DMA_PITCH_UV); } - val = (drm_rect_height(&state->src) & 0xffff0000) | - drm_rect_width(&state->src) >> 16; + 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 = drm_rect_height(&state->dst) << 16 | drm_rect_width(&state->dst); + 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); } - val = state->dst.y1 << 16 | state->dst.x1; + 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, From f9a13bb3baf6009225e91f2b9748ed27f2db9c2c Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 05/39] drm/armada: move mode set vblank handling and disable/enable Move the mode set vblank handling and controller enable/disable to the prepare() and commit() callbacks. This will be needed when we move to mode_set_nofb() as we should not enable the controller without the plane coordinates and location having been properly updated. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 41 ++++++++++++++-------------- drivers/gpu/drm/armada/armada_crtc.h | 1 + 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 205d5dc7ba81..683b2cec3d55 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -399,6 +399,7 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_plane *plane; + u32 val; /* * If we have an overlay plane associated with this CRTC, disable @@ -411,6 +412,18 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), HZ)); } + + /* Wait for pending flips to complete */ + armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), + MAX_SCHEDULE_TIMEOUT); + + drm_crtc_vblank_off(crtc); + + val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; + if (val != dcrtc->dumb_ctrl) { + dcrtc->dumb_ctrl = val; + writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); + } } /* The mode_config.mutex will be held for this call */ @@ -418,10 +431,12 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - if (dcrtc->dpms != DRM_MODE_DPMS_ON) { - dcrtc->dpms = DRM_MODE_DPMS_ON; - armada_drm_crtc_update(dcrtc); - } + 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 */ @@ -623,6 +638,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, bool interlaced; drm_framebuffer_get(crtc->primary->fb); + dcrtc->old_modeset_fb = old_fb; interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); @@ -656,18 +672,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, adj->crtc_vsync_end, adj->crtc_vtotal, tm, bm); - /* Wait for pending flips to complete */ - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); - - drm_crtc_vblank_off(crtc); - - val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; - if (val != dcrtc->dumb_ctrl) { - dcrtc->dumb_ctrl = val; - writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); - } - /* * If we are blanked, we would have disabled the clock. Re-enable * it so that compute_clock() does the right thing. @@ -739,11 +743,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_drm_primary_set(crtc, crtc->primary, x, y); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - armada_drm_crtc_update(dcrtc); - - drm_crtc_vblank_on(crtc); - armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); - return 0; } diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 445829b8877a..8edcfd1fa75f 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -93,6 +93,7 @@ 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; From cfd1b63af78bfce8161e5f65a1d799a9c33b52c6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 06/39] drm/armada: use core of primary update_plane for mode set Use the core of the update_plane method to configure the primary plane within mode_set() rather than duplicating this code. This moves us closer to the same code structure that the atomic modeset transitional helpers will use. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 137 ++++++++++++--------------- 1 file changed, 59 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 683b2cec3d55..6dd54f1d3ac9 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -613,17 +613,8 @@ static void armada_drm_gra_plane_regs(struct armada_regs *regs, armada_reg_queue_end(regs, i); } -static void armada_drm_primary_set(struct drm_crtc *crtc, - struct drm_plane *plane, int x, int y) -{ - struct armada_plane_state *state = &drm_to_armada_plane(plane)->state; - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_regs regs[8]; - bool interlaced = dcrtc->interlaced; - - armada_drm_gra_plane_regs(regs, plane->fb, state, x, y, interlaced); - armada_drm_crtc_update_regs(dcrtc, regs); -} +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, @@ -637,24 +628,13 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, unsigned i; bool interlaced; - drm_framebuffer_get(crtc->primary->fb); + /* 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); - val = CFG_GRA_ENA; - val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt); - val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod); - - if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420) - val |= CFG_PALETTE_ENA; - - drm_to_armada_plane(crtc->primary)->state.ctrl0 = val; - drm_to_armada_plane(crtc->primary)->state.src_hw = - drm_to_armada_plane(crtc->primary)->state.dst_hw = - adj->crtc_vdisplay << 16 | adj->crtc_hdisplay; - drm_to_armada_plane(crtc->primary)->state.dst_yx = 0; - i = 0; rm = adj->crtc_hsync_start - adj->crtc_hdisplay; lm = adj->crtc_htotal - adj->crtc_hsync_end; @@ -694,9 +674,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, spin_lock_irqsave(&dcrtc->irq_lock, flags); - /* Ensure graphic fifo is enabled */ - armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); - /* Even interlaced/progressive frame */ dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 | adj->crtc_htotal; @@ -739,37 +716,34 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, armada_reg_queue_end(regs, i); armada_drm_crtc_update_regs(dcrtc, regs); - - armada_drm_primary_set(crtc, crtc->primary, x, y); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); - return 0; + 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 armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct armada_regs regs[4]; - unsigned i; + 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, + }; - i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs, - dcrtc->interlaced); - armada_reg_queue_end(regs, i); - - /* Wait for pending flips to complete */ - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); - - /* Take a reference to the new fb as we're using it */ - drm_framebuffer_get(crtc->primary->fb); - - /* Update the base in the CRTC */ - armada_drm_crtc_update_regs(dcrtc, regs); - - /* Drop our previously held reference */ - armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); + armada_drm_do_primary_update(crtc->primary, &state, old_fb); return 0; } @@ -1169,37 +1143,20 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, dplane->state.changed = true; } -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) +static int armada_drm_do_primary_update(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_framebuffer *old_fb) { struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct armada_crtc *dcrtc = drm_to_armada_crtc(state->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, - }; struct drm_crtc_state crtc_state = { - .crtc = crtc, - .enable = crtc->enabled, - .mode = crtc->mode, + .crtc = state->crtc, + .enable = state->crtc->enabled, + .mode = state->crtc->mode, }; int ret; - ret = drm_atomic_helper_check_plane_state(&state, &crtc_state, 0, + ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0, INT_MAX, true, false); if (ret) return ret; @@ -1207,19 +1164,19 @@ static int armada_drm_primary_update(struct drm_plane *plane, work = &dplane->works[dplane->next_work]; work->fn = armada_drm_crtc_complete_frame_work; - if (plane->fb != fb) { + 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(fb); + drm_framebuffer_reference(state->fb); - work->old_fb = plane->fb; + work->old_fb = old_fb; } else { work->old_fb = NULL; } - armada_drm_primary_update_state(&state, work->regs); + armada_drm_primary_update_state(state, work->regs); if (!dplane->state.changed) return 0; @@ -1248,6 +1205,30 @@ static int armada_drm_primary_update(struct drm_plane *plane, return 0; } +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); +} + int armada_drm_plane_disable(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx) { From ecf25d2380313139a2cc5f07e7ac2d910054b478 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 07/39] drm/armada: merge armada_drm_gra_plane_regs() into only caller armada_drm_gra_plane_regs() is now only ever called from within armada_drm_primary_update_state(), so merge it into this function. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 55 ++++++++++++---------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 6dd54f1d3ac9..735abdab9754 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -588,31 +588,6 @@ static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) return val; } -static void armada_drm_gra_plane_regs(struct armada_regs *regs, - struct drm_framebuffer *fb, struct armada_plane_state *state, - int x, int y, bool interlaced) -{ - unsigned int i; - u32 ctrl0; - - i = armada_drm_crtc_calc_fb(fb, x, y, regs, interlaced); - armada_reg_queue_set(regs, i, state->dst_yx, LCD_SPU_GRA_OVSA_HPXL_VLN); - armada_reg_queue_set(regs, i, state->src_hw, LCD_SPU_GRA_HPXL_VLN); - armada_reg_queue_set(regs, i, state->dst_hw, LCD_SPU_GZM_HPXL_VLN); - - ctrl0 = state->ctrl0; - if (interlaced) - ctrl0 |= CFG_GRA_FTOGGLE; - - armada_reg_queue_mod(regs, i, 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); - armada_reg_queue_end(regs, i); -} - static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); @@ -1107,8 +1082,8 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .disable_vblank = armada_drm_crtc_disable_vblank, }; -static void armada_drm_primary_update_state(struct drm_plane_state *state, - struct armada_regs *regs) +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); @@ -1124,6 +1099,8 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, 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) @@ -1135,12 +1112,26 @@ static void armada_drm_primary_update_state(struct drm_plane_state *state, dplane->state.dst_hw = armada_rect_hw(&state->dst); dplane->state.dst_yx = armada_rect_yx(&state->dst); - armada_drm_gra_plane_regs(regs + idx, &dfb->fb, &dplane->state, - state->src.x1 >> 16, state->src.y1 >> 16, - dcrtc->interlaced); + 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 int armada_drm_do_primary_update(struct drm_plane *plane, @@ -1154,6 +1145,7 @@ static int armada_drm_do_primary_update(struct drm_plane *plane, .enable = state->crtc->enabled, .mode = state->crtc->mode, }; + unsigned int idx; int ret; ret = drm_atomic_helper_check_plane_state(state, &crtc_state, 0, @@ -1176,7 +1168,8 @@ static int armada_drm_do_primary_update(struct drm_plane *plane, work->old_fb = NULL; } - armada_drm_primary_update_state(state, work->regs); + idx = armada_drm_primary_update_state(state, work->regs); + armada_reg_queue_end(work->regs, idx); if (!dplane->state.changed) return 0; From 80c63aee8143d83743a9df6d09309d3d15b20680 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 08/39] drm/armada: reset all atomic state during driver initialisation Reset the atomic state of any converted components during driver initialisation to ensure that we have the atomic state initialised for any component converted to atomic modeset. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index d1705d298a39..e47b995b4ce6 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -155,6 +155,8 @@ static int armada_drm_bind(struct device *dev) priv->drm.irq_enabled = true; + drm_mode_config_reset(&priv->drm); + ret = armada_fbdev_init(&priv->drm); if (ret) goto err_comp; From c36045e17a0e9206078a3254385bf9258e32d5b8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 09/39] 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 | 314 +++++++++++++-------------- drivers/gpu/drm/armada/armada_crtc.h | 8 +- 2 files changed, 160 insertions(+), 162 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,93 +1150,69 @@ 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 drm_plane_state *state = plane->state; + struct armada_crtc *dcrtc; + struct armada_regs *regs; + + 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_drm_primary_update_state(state, regs); +} + +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 = 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 armada_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx = 0; - 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 (!old_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] 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); - work->old_fb = old_fb; - } else { - work->old_fb = NULL; - } + dplane->state.ctrl0 &= ~CFG_GRA_ENA; - idx = armada_drm_primary_update_state(state, work->regs); - armada_reg_queue_end(work->regs, idx); + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; - if (!dplane->state.changed) - return 0; + /* 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); - /* Wait for pending work to complete */ - if (armada_drm_plane_work_wait(dplane, HZ / 10) == 0) - armada_drm_plane_work_cancel(dcrtc, dplane); - - if (!dplane->state.vsync_update) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - return 0; - } - - /* 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); - } - - dplane->next_work = !dplane->next_work; - - return 0; + dcrtc->regs_idx += 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); -} +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 From de503ddff86ed31cde5ec5ea74ec7bf60d3fecc5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 10/39] drm/armada: convert page_flip to use primary plane atomic_update() page_flip requests happen asynchronously, so we can't wait on the vblank event before returning to userspace, as the transitional plane update helper would do. Craft our own implementation that keeps the asynchronous behaviour of this request, while making use of the atomic infrastructure for the primary plane update. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 85 +++++++++++++++++++--------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 523e0e8c6962..50b34f5fc97b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -939,53 +940,81 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) * and a mode_set. */ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, - struct drm_modeset_acquire_ctx *ctx) + struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, + uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct drm_plane *plane = crtc->primary; + const struct drm_plane_helper_funcs *plane_funcs; + struct drm_plane_state *state; struct armada_plane_work *work; - unsigned i; int ret; - work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); - if (!work) + /* Construct new state for the primary plane */ + state = drm_atomic_helper_plane_duplicate_state(plane); + if (!state) return -ENOMEM; - work->event = event; - work->old_fb = dcrtc->crtc.primary->fb; + drm_atomic_set_fb_for_plane(state, fb); - i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs, - dcrtc->interlaced); - armada_reg_queue_end(work->regs, i); - - /* - * Ensure that we hold a reference on the new framebuffer. - * This has to match the behaviour in mode_set. - */ - drm_framebuffer_get(fb); - - ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) { - /* Undo our reference above */ - drm_framebuffer_put(fb); - kfree(work); - return ret; + work = armada_drm_crtc_alloc_plane_work(plane); + if (!work) { + ret = -ENOMEM; + goto put_state; } + /* Make sure we can get vblank interrupts */ + ret = drm_crtc_vblank_get(crtc); + if (ret) + goto put_work; + /* - * We are in transition to atomic modeset: update the atomic modeset - * state with the new framebuffer to keep the state consistent. + * If we have another work pending, we can't process this flip. + * The modeset locks protect us from another user queuing a work + * while we're setting up. */ - drm_framebuffer_assign(&dcrtc->crtc.primary->state->fb, fb); + if (drm_to_armada_plane(plane)->work) { + ret = -EBUSY; + goto put_vblank; + } + + work->event = event; + work->old_fb = plane->state->fb; + + /* + * Hold a ref on the new fb while it's being displayed by the + * hardware. The old fb refcount will be released in the worker. + */ + drm_framebuffer_get(state->fb); + + /* Point of no return */ + swap(plane->state, state); + + dcrtc->regs_idx = 0; + dcrtc->regs = work->regs; + + plane_funcs = plane->helper_private; + plane_funcs->atomic_update(plane, state); + armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); + + /* Queue the work - this should never fail */ + WARN_ON(armada_drm_plane_work_queue(dcrtc, work)); + work = NULL; /* * Finally, if the display is blanked, we won't receive an * interrupt, so complete it now. */ if (dpms_blanked(dcrtc->dpms)) - armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); + armada_drm_plane_work_run(dcrtc, plane); - return 0; +put_vblank: + drm_crtc_vblank_put(crtc); +put_work: + kfree(work); +put_state: + drm_atomic_helper_plane_destroy_state(plane, state); + return ret; } static int From 47dc413b0025e96eaa43bdd808233763e4080a10 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 11/39] drm/armada: convert overlay plane to atomic state The overlay plane support updates asynchronously to the request, but the drm_plane_helper_update() transitional helper waits for a vblank event before releasing the framebuffer. Using the transitional helper would make the call block, which would introduce a performance regression. Convert the overlay plane update to use the atomic state structures and methods for the plane, but implement our own legacy update method rather than the transitional helper. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 79 +---------- drivers/gpu/drm/armada/armada_crtc.h | 7 + drivers/gpu/drm/armada/armada_overlay.c | 179 ++++++++++++++++++------ 3 files changed, 145 insertions(+), 120 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 50b34f5fc97b..5bb097b75b44 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -295,19 +295,6 @@ static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -static void armada_drm_crtc_complete_disable_work(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - unsigned long flags; - - if (dcrtc->plane == work->plane) - dcrtc->plane = NULL; - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, work->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - static struct armada_plane_work * armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) { @@ -1080,7 +1067,7 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .disable_vblank = armada_drm_crtc_disable_vblank, }; -static int armada_drm_plane_prepare_fb(struct drm_plane *plane, +int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) { DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n", @@ -1096,7 +1083,7 @@ static int armada_drm_plane_prepare_fb(struct drm_plane *plane, return 0; } -static void armada_drm_plane_cleanup_fb(struct drm_plane *plane, +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", @@ -1107,7 +1094,7 @@ static void armada_drm_plane_cleanup_fb(struct drm_plane *plane, drm_framebuffer_put(old_state->fb); } -static int armada_drm_plane_atomic_check(struct drm_plane *plane, +int armada_drm_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { if (state->fb && !WARN_ON(!state->crtc)) { @@ -1243,66 +1230,6 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { .atomic_disable = armada_drm_primary_plane_atomic_disable, }; -int armada_drm_plane_disable(struct drm_plane *plane, - struct drm_modeset_acquire_ctx *ctx) -{ - struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_crtc *dcrtc; - struct armada_plane_work *work; - unsigned int idx = 0; - u32 sram_para1, enable_mask; - - if (!plane->crtc) - return 0; - - /* - * Arrange to power down most RAMs and FIFOs if this is the primary - * plane, otherwise just the YUV FIFOs for the overlay plane. - */ - if (plane->type == DRM_PLANE_TYPE_PRIMARY) { - sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | - CFG_PDWN32x32 | CFG_PDWN64x66; - enable_mask = CFG_GRA_ENA; - } else { - sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66; - enable_mask = CFG_DMA_ENA; - } - - dplane->state.ctrl0 &= ~enable_mask; - - dcrtc = drm_to_armada_crtc(plane->crtc); - - /* - * Try to disable the plane and drop our ref on the framebuffer - * at the next frame update. If we fail for any reason, disable - * the plane immediately. - */ - work = &dplane->works[dplane->next_work]; - work->fn = armada_drm_crtc_complete_disable_work; - work->cancel = armada_drm_crtc_complete_disable_work; - work->old_fb = plane->fb; - - armada_reg_queue_mod(work->regs, idx, - 0, enable_mask, LCD_SPU_DMA_CTRL0); - armada_reg_queue_mod(work->regs, idx, - sram_para1, 0, LCD_SPU_SRAM_PARA1); - armada_reg_queue_end(work->regs, idx); - - /* Wait for any preceding work to complete, but don't wedge */ - if (WARN_ON(!armada_drm_plane_work_wait(dplane, HZ))) - armada_drm_plane_work_cancel(dcrtc, dplane); - - if (armada_drm_plane_work_queue(dcrtc, work)) { - work->fn(dcrtc, work); - if (work->old_fb) - drm_framebuffer_unreference(work->old_fb); - } - - dplane->next_work = !dplane->next_work; - - return 0; -} - static const struct drm_plane_funcs armada_primary_plane_funcs = { .update_plane = drm_plane_helper_update, .disable_plane = drm_plane_helper_disable, diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 3253947e0d41..4da56a171b13 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -75,6 +75,13 @@ void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, int x, int y); +int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state); +void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state); +int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state); + struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 2347811ccf1b..be9de5d85f9f 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -7,7 +7,9 @@ * published by the Free Software Foundation. */ #include +#include #include +#include #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" @@ -78,7 +80,7 @@ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -static void armada_ovl_plane_update_state(struct drm_plane_state *state, +static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state, struct armada_regs *regs) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(state->plane); @@ -180,67 +182,116 @@ static void armada_ovl_plane_update_state(struct drm_plane_state *state, dplane->base.state.changed = idx != 0; - armada_reg_queue_end(regs, idx); + return 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) +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; + + 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); +} + +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; + + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); + + if (!old_state->crtc) + return; + + 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->state.ctrl0 &= ~CFG_DMA_ENA; + + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + /* Disable plane and power down the YUV FIFOs */ + armada_reg_queue_mod(regs, idx, 0, CFG_DMA_ENA, LCD_SPU_DMA_CTRL0); + armada_reg_queue_mod(regs, idx, CFG_PDWN16x66 | CFG_PDWN32x66, 0, + LCD_SPU_SRAM_PARA1); + + dcrtc->regs_idx += idx; + + if (dcrtc->plane == plane) + dcrtc->plane = NULL; +} + +static const struct drm_plane_helper_funcs armada_overlay_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_overlay_plane_atomic_update, + .atomic_disable = armada_drm_overlay_plane_atomic_disable, +}; + +static int armada_overlay_commit(struct drm_plane *plane, + struct drm_plane_state *state) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + const struct drm_plane_helper_funcs *plane_funcs; + struct armada_crtc *dcrtc = drm_to_armada_crtc(state->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, - }; - struct drm_crtc_state crtc_state = { - .crtc = crtc, - .enable = crtc->enabled, - .mode = crtc->mode, - }; 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_atomic_helper_check_plane_state(&state, &crtc_state, 0, - INT_MAX, true, false); + plane_funcs = plane->helper_private; + ret = plane_funcs->atomic_check(plane, state); if (ret) - return ret; + goto put_state; work = &dplane->base.works[dplane->base.next_work]; - if (plane->fb != fb) { + if (plane->state->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(fb); + drm_framebuffer_reference(state->fb); - work->old_fb = plane->fb; + work->old_fb = plane->state->fb; } else { work->old_fb = NULL; } - armada_ovl_plane_update_state(&state, work->regs); + /* Point of no return */ + swap(plane->state, state); + dcrtc->regs_idx = 0; + dcrtc->regs = work->regs; + + plane_funcs->atomic_update(plane, state); + + /* If nothing was updated, short-circuit */ if (!dplane->base.state.changed) - return 0; + goto put_state; + + armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); /* Wait for pending work to complete */ if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) @@ -249,7 +300,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, /* Just updating the position/size? */ if (!dplane->base.state.vsync_update) { armada_ovl_plane_work(dcrtc, work); - return 0; + goto put_state; } if (!dcrtc->plane) { @@ -259,12 +310,48 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, /* Queue it for update on the next interrupt if we are enabled */ ret = armada_drm_plane_work_queue(dcrtc, work); - if (ret) + if (ret) { DRM_ERROR("failed to queue plane work: %d\n", ret); + ret = 0; + } dplane->base.next_work = !dplane->base.next_work; - return 0; +put_state: + drm_atomic_helper_plane_destroy_state(plane, state); + return ret; +} + +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 drm_plane_state *state; + + trace_armada_ovl_plane_update(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + + /* Construct new state for the overlay plane */ + state = drm_atomic_helper_plane_duplicate_state(plane); + if (!state) + return -ENOMEM; + + state->crtc = crtc; + drm_atomic_set_fb_for_plane(state, fb); + state->crtc_x = crtc_x; + state->crtc_y = crtc_y; + state->crtc_h = crtc_h; + state->crtc_w = crtc_w; + state->src_x = src_x; + state->src_y = src_y; + state->src_h = src_h; + state->src_w = src_w; + + return armada_overlay_commit(plane, state); } static void armada_ovl_plane_destroy(struct drm_plane *plane) @@ -355,9 +442,10 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, static const struct drm_plane_funcs armada_ovl_plane_funcs = { .update_plane = armada_ovl_plane_update, - .disable_plane = armada_drm_plane_disable, + .disable_plane = drm_plane_helper_disable, .destroy = armada_ovl_plane_destroy, .set_property = armada_ovl_plane_set_property, + .reset = drm_atomic_helper_plane_reset, }; static const uint32_t armada_ovl_formats[] = { @@ -450,6 +538,9 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->base.works[0].fn = armada_ovl_plane_work; dplane->base.works[1].fn = armada_ovl_plane_work; + drm_plane_helper_add(&dplane->base.base, + &armada_overlay_plane_helper_funcs); + ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs, &armada_ovl_plane_funcs, armada_ovl_formats, From 9c41467c9aa5b3916ff559b8c2b3725d6290e5ec Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 12/39] drm/armada: remove temporary crtc state Now that we have the CRTC using the atomic modeset transitional helper, there is no need to build a temporary crtc state anymore - we can use the CRTC atomic state directly. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 5bb097b75b44..056673911818 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1099,13 +1099,13 @@ int armada_drm_plane_atomic_check(struct drm_plane *plane, { 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, - }; + struct drm_crtc_state *crtc_state; - return drm_atomic_helper_check_plane_state(state, &crtc_state, + if (state->state) + crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); + else + crtc_state = crtc->state; + return drm_atomic_helper_check_plane_state(state, crtc_state, 0, INT_MAX, true, false); } else { From 3acea7b9b62c282ea3d4d0cd156ca8e35dfa8a8c Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 13/39] 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 --- drivers/gpu/drm/armada/armada_crtc.c | 116 +++++++------- drivers/gpu/drm/armada/armada_crtc.h | 12 -- drivers/gpu/drm/armada/armada_overlay.c | 201 +++++++++++------------- 3 files changed, 150 insertions(+), 179 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 056673911818..14339d5bed14 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -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; diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 4da56a171b13..79ac0db047c9 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -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) 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,117 +81,14 @@ 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) -{ - 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); - } - - 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]; - - 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_reg_queue_set(regs, idx, addrs[0], - LCD_SPU_DMA_START_ADDR_Y0); - armada_reg_queue_set(regs, idx, addrs[1], - LCD_SPU_DMA_START_ADDR_U0); - armada_reg_queue_set(regs, idx, addrs[2], - LCD_SPU_DMA_START_ADDR_V0); - armada_reg_queue_set(regs, idx, addrs[0], - LCD_SPU_DMA_START_ADDR_Y1); - armada_reg_queue_set(regs, idx, addrs[1], - LCD_SPU_DMA_START_ADDR_U1); - 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 = 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); - } - - 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); - } - - 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; - } - - 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; + unsigned int idx; + u32 cfg, cfg_mask, val; DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); @@ -206,13 +104,96 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, dcrtc = drm_to_armada_crtc(state->crtc); regs = dcrtc->regs + dcrtc->regs_idx; - dcrtc->regs_idx += armada_ovl_plane_update_state(state, regs); + 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 (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]; + + 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); + armada_reg_queue_set(regs, idx, addrs[1], + LCD_SPU_DMA_START_ADDR_U0); + armada_reg_queue_set(regs, idx, addrs[2], + LCD_SPU_DMA_START_ADDR_V0); + armada_reg_queue_set(regs, idx, addrs[0], + LCD_SPU_DMA_START_ADDR_Y1); + armada_reg_queue_set(regs, idx, addrs[1], + LCD_SPU_DMA_START_ADDR_U1); + armada_reg_queue_set(regs, idx, addrs[2], + LCD_SPU_DMA_START_ADDR_V1); + + 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); + + 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; + + /* + * 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 (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; + } + + if (cfg_mask) + armada_reg_queue_mod(regs, idx, cfg, cfg_mask, + LCD_SPU_DMA_CTRL0); + + 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; } From d40af7b1ae23da718ba916fcd07f5b064efff921 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 14/39] drm/armada: move primary plane to separate file Split out the primary plane support; this is now entirely separate from the CRTC support. Signed-off-by: Russell King --- drivers/gpu/drm/armada/Makefile | 2 +- drivers/gpu/drm/armada/armada_crtc.c | 273 +--------------------- drivers/gpu/drm/armada/armada_crtc.h | 10 - drivers/gpu/drm/armada/armada_overlay.c | 3 +- drivers/gpu/drm/armada/armada_plane.c | 297 ++++++++++++++++++++++++ drivers/gpu/drm/armada/armada_plane.h | 16 ++ 6 files changed, 318 insertions(+), 283 deletions(-) create mode 100644 drivers/gpu/drm/armada/armada_plane.c create mode 100644 drivers/gpu/drm/armada/armada_plane.h diff --git a/drivers/gpu/drm/armada/Makefile b/drivers/gpu/drm/armada/Makefile index ecf25cf9f9f5..9bc3c3213724 100644 --- a/drivers/gpu/drm/armada/Makefile +++ b/drivers/gpu/drm/armada/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \ - armada_gem.o armada_overlay.o armada_trace.o + armada_gem.o armada_overlay.o armada_plane.o armada_trace.o armada-y += armada_510.o armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 14339d5bed14..b9b0a508793d 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -20,6 +20,7 @@ #include "armada_fb.h" #include "armada_gem.h" #include "armada_hw.h" +#include "armada_plane.h" #include "armada_trace.h" enum csc_mode { @@ -30,23 +31,6 @@ enum csc_mode { CSC_RGB_STUDIO = 2, }; -static const uint32_t armada_primary_formats[] = { - DRM_FORMAT_UYVY, - DRM_FORMAT_YUYV, - DRM_FORMAT_VYUY, - DRM_FORMAT_YVYU, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_RGB888, - DRM_FORMAT_BGR888, - DRM_FORMAT_ARGB1555, - DRM_FORMAT_ABGR1555, - DRM_FORMAT_RGB565, - DRM_FORMAT_BGR565, -}; - /* * A note about interlacing. Let's consider HDMI 1920x1080i. * The timing parameters we have from X are: @@ -160,57 +144,6 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) } } -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y) -{ - const struct drm_format_info *format = fb->format; - unsigned int num_planes = format->num_planes; - u32 addr = drm_fb_obj(fb)->dev_addr; - int i; - - if (num_planes > 3) - num_planes = 3; - - addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + - x * format->cpp[0]; - - y /= format->vsub; - x /= format->hsub; - - for (i = 1; i < num_planes; i++) - addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + - x * format->cpp[i]; - for (; i < 3; i++) - addrs[i] = 0; -} - -static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, - int x, int y, struct armada_regs *regs, bool interlaced) -{ - unsigned pitch = fb->pitches[0]; - u32 addrs[3], addr_odd, addr_even; - unsigned i = 0; - - DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", - pitch, x, y, fb->format->cpp[0] * 8); - - armada_drm_plane_calc_addrs(addrs, fb, x, y); - - addr_odd = addr_even = addrs[0]; - - if (interlaced) { - addr_even += pitch; - pitch *= 2; - } - - /* write offset, base, and pitch */ - armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); - armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); - armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); - - return i; -} - static void armada_drm_plane_work_call(struct armada_crtc *dcrtc, struct armada_plane_work *work, void (*fn)(struct armada_crtc *, struct armada_plane_work *)) @@ -1067,194 +1000,6 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .disable_vblank = armada_drm_crtc_disable_vblank, }; -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; -} - -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); -} - -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; - - if (state->state) - crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); - else - crtc_state = crtc->state; - return drm_atomic_helper_check_plane_state(state, crtc_state, - 0, INT_MAX, - true, false); - } else { - state->visible = false; - } - return 0; -} - -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); - - 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; - - 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_crtc *dcrtc; - struct armada_regs *regs; - unsigned int idx = 0; - - DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); - - if (!old_state->crtc) - return; - - 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); - - dcrtc = drm_to_armada_crtc(old_state->crtc); - regs = dcrtc->regs + dcrtc->regs_idx; - - /* 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, -}; - -static const struct drm_plane_funcs armada_primary_plane_funcs = { - .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) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(plane->works); i++) - plane->works[i].plane = &plane->base; - - init_waitqueue_head(&plane->frame_wait); - - return 0; -} - static const struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { { CSC_AUTO, "Auto" }, { CSC_YUV_CCIR601, "CCIR601" }, @@ -1363,21 +1108,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, goto err_crtc; } - ret = armada_drm_plane_init(primary); - if (ret) { - kfree(primary); - 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, - ARRAY_SIZE(armada_primary_formats), - NULL, - DRM_PLANE_TYPE_PRIMARY, NULL); + ret = armada_drm_primary_plane_init(drm, primary); if (ret) { kfree(primary); goto err_crtc; diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 79ac0db047c9..2672c5cc0e45 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -54,21 +54,11 @@ struct armada_plane { }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) -int armada_drm_plane_init(struct armada_plane *plane); int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, struct armada_plane_work *work); int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout); void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, struct armada_plane *plane); -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y); - -int armada_drm_plane_prepare_fb(struct drm_plane *plane, - struct drm_plane_state *state); -void armada_drm_plane_cleanup_fb(struct drm_plane *plane, - struct drm_plane_state *old_state); -int armada_drm_plane_atomic_check(struct drm_plane *plane, - struct drm_plane_state *state); struct armada_crtc { struct drm_crtc crtc; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index aa2a12aec3cc..214b2171a8f4 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -10,13 +10,14 @@ #include #include #include +#include #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" #include "armada_gem.h" #include "armada_hw.h" -#include #include "armada_ioctlP.h" +#include "armada_plane.h" #include "armada_trace.h" struct armada_ovl_plane_properties { diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c new file mode 100644 index 000000000000..9d1eec1dc720 --- /dev/null +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2012 Russell King + * Rewritten from the dovefb driver, and Armada510 manuals. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include "armada_crtc.h" +#include "armada_drm.h" +#include "armada_fb.h" +#include "armada_gem.h" +#include "armada_hw.h" +#include "armada_plane.h" +#include "armada_trace.h" + +static const uint32_t armada_primary_formats[] = { + DRM_FORMAT_UYVY, + DRM_FORMAT_YUYV, + DRM_FORMAT_VYUY, + DRM_FORMAT_YVYU, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, +}; + +void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, + int x, int y) +{ + const struct drm_format_info *format = fb->format; + unsigned int num_planes = format->num_planes; + u32 addr = drm_fb_obj(fb)->dev_addr; + int i; + + if (num_planes > 3) + num_planes = 3; + + addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + + x * format->cpp[0]; + + y /= format->vsub; + x /= format->hsub; + + for (i = 1; i < num_planes; i++) + addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + + x * format->cpp[i]; + for (; i < 3; i++) + addrs[i] = 0; +} + +static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, + int x, int y, struct armada_regs *regs, bool interlaced) +{ + unsigned pitch = fb->pitches[0]; + u32 addrs[3], addr_odd, addr_even; + unsigned i = 0; + + DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", + pitch, x, y, fb->format->cpp[0] * 8); + + armada_drm_plane_calc_addrs(addrs, fb, x, y); + + addr_odd = addr_even = addrs[0]; + + if (interlaced) { + addr_even += pitch; + pitch *= 2; + } + + /* write offset, base, and pitch */ + armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); + armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); + armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); + + return i; +} + +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; +} + +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); +} + +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; + + if (state->state) + crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); + else + crtc_state = crtc->state; + return drm_atomic_helper_check_plane_state(state, crtc_state, + 0, INT_MAX, + true, false); + } else { + state->visible = false; + } + return 0; +} + +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); + + 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; + + 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_crtc *dcrtc; + struct armada_regs *regs; + unsigned int idx = 0; + + DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name); + + if (!old_state->crtc) + return; + + 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); + + dcrtc = drm_to_armada_crtc(old_state->crtc); + regs = dcrtc->regs + dcrtc->regs_idx; + + /* 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, +}; + +static const struct drm_plane_funcs armada_primary_plane_funcs = { + .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) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(plane->works); i++) + plane->works[i].plane = &plane->base; + + init_waitqueue_head(&plane->frame_wait); + + return 0; +} + +int armada_drm_primary_plane_init(struct drm_device *drm, + struct armada_plane *primary) +{ + int ret; + + ret = armada_drm_plane_init(primary); + if (ret) + return ret; + + 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, + ARRAY_SIZE(armada_primary_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + + return ret; +} diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h new file mode 100644 index 000000000000..3c8316003907 --- /dev/null +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -0,0 +1,16 @@ +#ifndef ARMADA_PLANE_H +#define ARMADA_PLANE_H + +void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, + int x, int y); +int armada_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state); +void armada_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state); +int armada_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state); +int armada_drm_plane_init(struct armada_plane *plane); +int armada_drm_primary_plane_init(struct drm_device *drm, + struct armada_plane *primary); + +#endif From 63b93c0834a0cb7d537b30f8e815a9f63d0da37f Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 15/39] drm/armada: move plane works to overlay Only overlay makes use of these now, so move these to the overlay code. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.h | 2 -- drivers/gpu/drm/armada/armada_overlay.c | 12 ++++++++---- drivers/gpu/drm/armada/armada_plane.c | 6 ------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 2672c5cc0e45..73ddd7d61eb4 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -48,8 +48,6 @@ struct armada_plane_work { 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; }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 214b2171a8f4..40868e485ae8 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -36,6 +36,8 @@ struct armada_ovl_plane_properties { struct armada_ovl_plane { struct armada_plane base; + struct armada_plane_work works[2]; + bool next_work; bool wait_vblank; struct armada_ovl_plane_properties prop; }; @@ -245,7 +247,7 @@ static int armada_overlay_commit(struct drm_plane *plane, if (ret) goto put_state; - work = &dplane->base.works[dplane->base.next_work]; + work = &dplane->works[dplane->next_work]; if (plane->state->fb != state->fb) { /* @@ -295,7 +297,7 @@ static int armada_overlay_commit(struct drm_plane *plane, ret = 0; } - dplane->base.next_work = !dplane->base.next_work; + dplane->next_work = !dplane->next_work; put_state: drm_atomic_helper_plane_destroy_state(plane, state); @@ -515,8 +517,10 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) return ret; } - dplane->base.works[0].fn = armada_ovl_plane_work; - dplane->base.works[1].fn = armada_ovl_plane_work; + dplane->works[0].plane = &dplane->base.base; + dplane->works[0].fn = armada_ovl_plane_work; + dplane->works[1].plane = &dplane->base.base; + dplane->works[1].fn = armada_ovl_plane_work; drm_plane_helper_add(&dplane->base.base, &armada_overlay_plane_helper_funcs); diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 9d1eec1dc720..1cb6a605bda9 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -264,13 +264,7 @@ static const struct drm_plane_funcs armada_primary_plane_funcs = { int armada_drm_plane_init(struct armada_plane *plane) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(plane->works); i++) - plane->works[i].plane = &plane->base; - init_waitqueue_head(&plane->frame_wait); - return 0; } From 61ba252705a6d5b8dd71bd2ccc544d33cb2af623 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 16/39] drm/armada: move CBSH properties into overlay plane state Move the contrast, brightness, and saturation properties to the overlay plane state structure, and call our overlay commit function to update the hardware via the planes atomic_update() method. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.h | 2 +- drivers/gpu/drm/armada/armada_overlay.c | 163 ++++++++++++++++++++---- 2 files changed, 136 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 73ddd7d61eb4..c27435a8776a 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -42,7 +42,7 @@ struct armada_plane_work { struct drm_plane *plane; struct drm_framebuffer *old_fb; struct drm_pending_vblank_event *event; - struct armada_regs regs[14]; + struct armada_regs regs[24]; }; struct armada_plane { diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 40868e485ae8..ec3ce28f162e 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -20,6 +20,10 @@ #include "armada_plane.h" #include "armada_trace.h" +#define DEFAULT_BRIGHTNESS 0 +#define DEFAULT_CONTRAST 0x4000 +#define DEFAULT_SATURATION 0x4000 + struct armada_ovl_plane_properties { uint32_t colorkey_yr; uint32_t colorkey_ug; @@ -27,9 +31,6 @@ struct armada_ovl_plane_properties { #define K2R(val) (((val) >> 0) & 0xff) #define K2G(val) (((val) >> 8) & 0xff) #define K2B(val) (((val) >> 16) & 0xff) - int16_t brightness; - uint16_t contrast; - uint16_t saturation; uint32_t colorkey_mode; uint32_t colorkey_enable; }; @@ -44,6 +45,26 @@ struct armada_ovl_plane { #define drm_to_armada_ovl_plane(p) \ container_of(p, struct armada_ovl_plane, base.base) +struct armada_overlay_state { + struct drm_plane_state base; + s16 brightness; + u16 contrast; + u16 saturation; +}; +#define drm_to_overlay_state(s) \ + container_of(s, struct armada_overlay_state, base) + +static inline u32 armada_spu_contrast(struct drm_plane_state *state) +{ + return drm_to_overlay_state(state)->brightness << 16 | + drm_to_overlay_state(state)->contrast; +} + +static inline u32 armada_spu_saturation(struct drm_plane_state *state) +{ + /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */ + return drm_to_overlay_state(state)->saturation << 16; +} static void armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, @@ -53,13 +74,6 @@ armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U); writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V); - writel_relaxed(prop->brightness << 16 | prop->contrast, - dcrtc->base + LCD_SPU_CONTRAST); - /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */ - writel_relaxed(prop->saturation << 16, - dcrtc->base + LCD_SPU_SATURATION); - writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE); - spin_lock_irq(&dcrtc->irq_lock); armada_updatel(prop->colorkey_mode, CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, @@ -191,6 +205,17 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_mod(regs, idx, cfg, cfg_mask, LCD_SPU_DMA_CTRL0); + val = armada_spu_contrast(state); + if ((!old_state->visible && state->visible) || + armada_spu_contrast(old_state) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_CONTRAST); + val = armada_spu_saturation(state); + if ((!old_state->visible && state->visible) || + armada_spu_saturation(old_state) != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); + if (!old_state->visible && state->visible) + armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); + dcrtc->regs_idx += idx; } @@ -264,6 +289,10 @@ static int armada_overlay_commit(struct drm_plane *plane, /* Point of no return */ swap(plane->state, state); + /* No CRTC, can't update */ + if (!plane->state->crtc) + goto put_state; + dcrtc->regs_idx = 0; dcrtc->regs = work->regs; @@ -300,7 +329,7 @@ static int armada_overlay_commit(struct drm_plane *plane, dplane->next_work = !dplane->next_work; put_state: - drm_atomic_helper_plane_destroy_state(plane, state); + plane->funcs->atomic_destroy_state(plane, state); return ret; } @@ -318,7 +347,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, src_x, src_y, src_w, src_h); /* Construct new state for the overlay plane */ - state = drm_atomic_helper_plane_duplicate_state(plane); + state = plane->funcs->atomic_duplicate_state(plane); if (!state) return -ENOMEM; @@ -404,15 +433,22 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, dplane->prop.colorkey_enable = ADV_GRACOLORKEY; } update_attr = true; - } else if (property == priv->brightness_prop) { - dplane->prop.brightness = val - 256; - update_attr = true; - } else if (property == priv->contrast_prop) { - dplane->prop.contrast = val; - update_attr = true; - } else if (property == priv->saturation_prop) { - dplane->prop.saturation = val; - update_attr = true; + } else { + struct drm_plane_state *state; + int ret; + + state = plane->funcs->atomic_duplicate_state(plane); + if (!state) + return -ENOMEM; + + ret = plane->funcs->atomic_set_property(plane, state, property, + val); + if (ret) { + plane->funcs->atomic_destroy_state(plane, state); + return ret; + } + + return armada_overlay_commit(plane, state); } if (update_attr && dplane->base.base.crtc) @@ -422,12 +458,85 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, return 0; } +static void armada_overlay_reset(struct drm_plane *plane) +{ + struct armada_overlay_state *state; + + if (plane->state) + __drm_atomic_helper_plane_destroy_state(plane->state); + kfree(plane->state); + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state) { + state->base.plane = plane; + state->base.rotation = DRM_MODE_ROTATE_0; + state->brightness = DEFAULT_BRIGHTNESS; + state->contrast = DEFAULT_CONTRAST; + state->saturation = DEFAULT_SATURATION; + } + plane->state = &state->base; +} + +struct drm_plane_state * +armada_overlay_duplicate_state(struct drm_plane *plane) +{ + struct armada_overlay_state *state; + + if (WARN_ON(!plane->state)) + return NULL; + + state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL); + if (state) + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + return &state->base; +} + +static int armada_overlay_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val) +{ + struct armada_private *priv = plane->dev->dev_private; + + if (property == priv->brightness_prop) { + drm_to_overlay_state(state)->brightness = val - 256; + } else if (property == priv->contrast_prop) { + drm_to_overlay_state(state)->contrast = val; + } else if (property == priv->saturation_prop) { + drm_to_overlay_state(state)->saturation = val; + } else { + return -EINVAL; + } + return 0; +} + +static int armada_overlay_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, struct drm_property *property, + uint64_t *val) +{ + struct armada_private *priv = plane->dev->dev_private; + + if (property == priv->brightness_prop) { + *val = drm_to_overlay_state(state)->brightness + 256; + } else if (property == priv->contrast_prop) { + *val = drm_to_overlay_state(state)->contrast; + } else if (property == priv->saturation_prop) { + *val = drm_to_overlay_state(state)->saturation; + } else { + return -EINVAL; + } + return 0; +} + static const struct drm_plane_funcs armada_ovl_plane_funcs = { .update_plane = armada_ovl_plane_update, .disable_plane = drm_plane_helper_disable, .destroy = armada_ovl_plane_destroy, .set_property = armada_ovl_plane_set_property, - .reset = drm_atomic_helper_plane_reset, + .reset = armada_overlay_reset, + .atomic_duplicate_state = armada_overlay_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .atomic_set_property = armada_overlay_set_property, + .atomic_get_property = armada_overlay_get_property, }; static const uint32_t armada_ovl_formats[] = { @@ -542,9 +651,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | CFG_ALPHAM_GRA | CFG_ALPHA(0); dplane->prop.colorkey_enable = ADV_GRACOLORKEY; - dplane->prop.brightness = 0; - dplane->prop.contrast = 0x4000; - dplane->prop.saturation = 0x4000; mobj = &dplane->base.base.base; drm_object_attach_property(mobj, priv->colorkey_prop, @@ -559,11 +665,12 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) 0x000000); drm_object_attach_property(mobj, priv->colorkey_mode_prop, CKMODE_RGB); - drm_object_attach_property(mobj, priv->brightness_prop, 256); + drm_object_attach_property(mobj, priv->brightness_prop, + 256 + DEFAULT_BRIGHTNESS); drm_object_attach_property(mobj, priv->contrast_prop, - dplane->prop.contrast); + DEFAULT_CONTRAST); drm_object_attach_property(mobj, priv->saturation_prop, - dplane->prop.saturation); + DEFAULT_SATURATION); return 0; } From c96103b6c49ff9a8710e580da72c0f116d24a76c Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 17/39] drm/armada: move colorkey properties into overlay plane state Move the overlay plane colorkey properties into the plane state, keeping the existing driver behaviour to avoid breaking userspace. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_overlay.c | 251 +++++++++++++----------- 1 file changed, 132 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index ec3ce28f162e..7f75df4f8390 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -24,29 +24,22 @@ #define DEFAULT_CONTRAST 0x4000 #define DEFAULT_SATURATION 0x4000 -struct armada_ovl_plane_properties { - uint32_t colorkey_yr; - uint32_t colorkey_ug; - uint32_t colorkey_vb; -#define K2R(val) (((val) >> 0) & 0xff) -#define K2G(val) (((val) >> 8) & 0xff) -#define K2B(val) (((val) >> 16) & 0xff) - uint32_t colorkey_mode; - uint32_t colorkey_enable; -}; - struct armada_ovl_plane { struct armada_plane base; struct armada_plane_work works[2]; bool next_work; bool wait_vblank; - struct armada_ovl_plane_properties prop; }; #define drm_to_armada_ovl_plane(p) \ container_of(p, struct armada_ovl_plane, base.base) struct armada_overlay_state { struct drm_plane_state base; + u32 colorkey_yr; + u32 colorkey_ug; + u32 colorkey_vb; + u32 colorkey_mode; + u32 colorkey_enable; s16 brightness; u16 contrast; u16 saturation; @@ -66,25 +59,6 @@ static inline u32 armada_spu_saturation(struct drm_plane_state *state) return drm_to_overlay_state(state)->saturation << 16; } -static void -armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, - struct armada_crtc *dcrtc) -{ - writel_relaxed(prop->colorkey_yr, dcrtc->base + LCD_SPU_COLORKEY_Y); - writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U); - writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V); - - spin_lock_irq(&dcrtc->irq_lock); - armada_updatel(prop->colorkey_mode, - CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, - dcrtc->base + LCD_SPU_DMA_CTRL1); - if (dcrtc->variant->has_spu_adv_reg) - armada_updatel(prop->colorkey_enable, - ADV_GRACOLORKEY | ADV_VIDCOLORKEY, - dcrtc->base + LCD_SPU_ADV_REG); - spin_unlock_irq(&dcrtc->irq_lock); -} - /* === Plane support === */ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, struct armada_plane_work *work) @@ -215,6 +189,30 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); if (!old_state->visible && state->visible) armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); + val = drm_to_overlay_state(state)->colorkey_yr; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_yr != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_Y); + val = drm_to_overlay_state(state)->colorkey_ug; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_ug != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_U); + val = drm_to_overlay_state(state)->colorkey_vb; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_vb != val) + armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_V); + val = drm_to_overlay_state(state)->colorkey_mode; + if ((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_mode != val) + armada_reg_queue_mod(regs, idx, val, CFG_CKMODE_MASK | + CFG_ALPHAM_MASK | CFG_ALPHA_MASK, + LCD_SPU_DMA_CTRL1); + val = drm_to_overlay_state(state)->colorkey_enable; + if (((!old_state->visible && state->visible) || + drm_to_overlay_state(old_state)->colorkey_enable != val) && + dcrtc->variant->has_spu_adv_reg) + armada_reg_queue_mod(regs, idx, val, ADV_GRACOLORKEY | + ADV_VIDCOLORKEY, LCD_SPU_ADV_REG); dcrtc->regs_idx += idx; } @@ -314,10 +312,7 @@ static int armada_overlay_commit(struct drm_plane *plane, goto put_state; } - if (!dcrtc->plane) { - dcrtc->plane = plane; - armada_ovl_update_attr(&dplane->prop, dcrtc); - } + dcrtc->plane = plane; /* Queue it for update on the next interrupt if we are enabled */ ret = armada_drm_plane_work_queue(dcrtc, work); @@ -377,85 +372,20 @@ static void armada_ovl_plane_destroy(struct drm_plane *plane) static int armada_ovl_plane_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t val) { - struct armada_private *priv = plane->dev->dev_private; - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - bool update_attr = false; + struct drm_plane_state *state; + int ret; - if (property == priv->colorkey_prop) { -#define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8) - dplane->prop.colorkey_yr = CCC(K2R(val)); - dplane->prop.colorkey_ug = CCC(K2G(val)); - dplane->prop.colorkey_vb = CCC(K2B(val)); -#undef CCC - update_attr = true; - } else if (property == priv->colorkey_min_prop) { - dplane->prop.colorkey_yr &= ~0x00ff0000; - dplane->prop.colorkey_yr |= K2R(val) << 16; - dplane->prop.colorkey_ug &= ~0x00ff0000; - dplane->prop.colorkey_ug |= K2G(val) << 16; - dplane->prop.colorkey_vb &= ~0x00ff0000; - dplane->prop.colorkey_vb |= K2B(val) << 16; - update_attr = true; - } else if (property == priv->colorkey_max_prop) { - dplane->prop.colorkey_yr &= ~0xff000000; - dplane->prop.colorkey_yr |= K2R(val) << 24; - dplane->prop.colorkey_ug &= ~0xff000000; - dplane->prop.colorkey_ug |= K2G(val) << 24; - dplane->prop.colorkey_vb &= ~0xff000000; - dplane->prop.colorkey_vb |= K2B(val) << 24; - update_attr = true; - } else if (property == priv->colorkey_val_prop) { - dplane->prop.colorkey_yr &= ~0x0000ff00; - dplane->prop.colorkey_yr |= K2R(val) << 8; - dplane->prop.colorkey_ug &= ~0x0000ff00; - dplane->prop.colorkey_ug |= K2G(val) << 8; - dplane->prop.colorkey_vb &= ~0x0000ff00; - dplane->prop.colorkey_vb |= K2B(val) << 8; - update_attr = true; - } else if (property == priv->colorkey_alpha_prop) { - dplane->prop.colorkey_yr &= ~0x000000ff; - dplane->prop.colorkey_yr |= K2R(val); - dplane->prop.colorkey_ug &= ~0x000000ff; - dplane->prop.colorkey_ug |= K2G(val); - dplane->prop.colorkey_vb &= ~0x000000ff; - dplane->prop.colorkey_vb |= K2B(val); - update_attr = true; - } else if (property == priv->colorkey_mode_prop) { - if (val == CKMODE_DISABLE) { - dplane->prop.colorkey_mode = - CFG_CKMODE(CKMODE_DISABLE) | - CFG_ALPHAM_CFG | CFG_ALPHA(255); - dplane->prop.colorkey_enable = 0; - } else { - dplane->prop.colorkey_mode = - CFG_CKMODE(val) | - CFG_ALPHAM_GRA | CFG_ALPHA(0); - dplane->prop.colorkey_enable = ADV_GRACOLORKEY; - } - update_attr = true; - } else { - struct drm_plane_state *state; - int ret; + state = plane->funcs->atomic_duplicate_state(plane); + if (!state) + return -ENOMEM; - state = plane->funcs->atomic_duplicate_state(plane); - if (!state) - return -ENOMEM; - - ret = plane->funcs->atomic_set_property(plane, state, property, - val); - if (ret) { - plane->funcs->atomic_destroy_state(plane, state); - return ret; - } - - return armada_overlay_commit(plane, state); + ret = plane->funcs->atomic_set_property(plane, state, property, val); + if (ret) { + plane->funcs->atomic_destroy_state(plane, state); + return ret; } - if (update_attr && dplane->base.base.crtc) - armada_ovl_update_attr(&dplane->prop, - drm_to_armada_crtc(dplane->base.base.crtc)); - - return 0; + return armada_overlay_commit(plane, state); } static void armada_overlay_reset(struct drm_plane *plane) @@ -470,6 +400,12 @@ static void armada_overlay_reset(struct drm_plane *plane) if (state) { state->base.plane = plane; state->base.rotation = DRM_MODE_ROTATE_0; + state->colorkey_yr = 0xfefefe00; + state->colorkey_ug = 0x01010100; + state->colorkey_vb = 0x01010100; + state->colorkey_mode = CFG_CKMODE(CKMODE_RGB) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + state->colorkey_enable = ADV_GRACOLORKEY; state->brightness = DEFAULT_BRIGHTNESS; state->contrast = DEFAULT_CONTRAST; state->saturation = DEFAULT_SATURATION; @@ -497,7 +433,57 @@ static int armada_overlay_set_property(struct drm_plane *plane, { struct armada_private *priv = plane->dev->dev_private; - if (property == priv->brightness_prop) { +#define K2R(val) (((val) >> 0) & 0xff) +#define K2G(val) (((val) >> 8) & 0xff) +#define K2B(val) (((val) >> 16) & 0xff) + if (property == priv->colorkey_prop) { +#define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8) + drm_to_overlay_state(state)->colorkey_yr = CCC(K2R(val)); + drm_to_overlay_state(state)->colorkey_ug = CCC(K2G(val)); + drm_to_overlay_state(state)->colorkey_vb = CCC(K2B(val)); +#undef CCC + } else if (property == priv->colorkey_min_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0x00ff0000; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 16; + drm_to_overlay_state(state)->colorkey_ug &= ~0x00ff0000; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 16; + drm_to_overlay_state(state)->colorkey_vb &= ~0x00ff0000; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 16; + } else if (property == priv->colorkey_max_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0xff000000; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 24; + drm_to_overlay_state(state)->colorkey_ug &= ~0xff000000; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 24; + drm_to_overlay_state(state)->colorkey_vb &= ~0xff000000; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 24; + } else if (property == priv->colorkey_val_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0x0000ff00; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 8; + drm_to_overlay_state(state)->colorkey_ug &= ~0x0000ff00; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 8; + drm_to_overlay_state(state)->colorkey_vb &= ~0x0000ff00; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 8; + } else if (property == priv->colorkey_alpha_prop) { + drm_to_overlay_state(state)->colorkey_yr &= ~0x000000ff; + drm_to_overlay_state(state)->colorkey_yr |= K2R(val); + drm_to_overlay_state(state)->colorkey_ug &= ~0x000000ff; + drm_to_overlay_state(state)->colorkey_ug |= K2G(val); + drm_to_overlay_state(state)->colorkey_vb &= ~0x000000ff; + drm_to_overlay_state(state)->colorkey_vb |= K2B(val); + } else if (property == priv->colorkey_mode_prop) { + if (val == CKMODE_DISABLE) { + drm_to_overlay_state(state)->colorkey_mode = + CFG_CKMODE(CKMODE_DISABLE) | + CFG_ALPHAM_CFG | CFG_ALPHA(255); + drm_to_overlay_state(state)->colorkey_enable = 0; + } else { + drm_to_overlay_state(state)->colorkey_mode = + CFG_CKMODE(val) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + drm_to_overlay_state(state)->colorkey_enable = + ADV_GRACOLORKEY; + } + } else if (property == priv->brightness_prop) { drm_to_overlay_state(state)->brightness = val - 256; } else if (property == priv->contrast_prop) { drm_to_overlay_state(state)->contrast = val; @@ -515,7 +501,41 @@ static int armada_overlay_get_property(struct drm_plane *plane, { struct armada_private *priv = plane->dev->dev_private; - if (property == priv->brightness_prop) { +#define C2K(c,s) (((c) >> (s)) & 0xff) +#define R2BGR(r,g,b,s) (C2K(r,s) << 0 | C2K(g,s) << 8 | C2K(b,s) << 16) + if (property == priv->colorkey_prop) { + /* Do best-efforts here for this property */ + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 16); + /* If min != max, or min != val, error out */ + if (*val != R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 24) || + *val != R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 8)) + return -EINVAL; + } else if (property == priv->colorkey_min_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 16); + } else if (property == priv->colorkey_max_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 24); + } else if (property == priv->colorkey_val_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 8); + } else if (property == priv->colorkey_alpha_prop) { + *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr, + drm_to_overlay_state(state)->colorkey_ug, + drm_to_overlay_state(state)->colorkey_vb, 0); + } else if (property == priv->colorkey_mode_prop) { + *val = (drm_to_overlay_state(state)->colorkey_mode & + CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK); + } else if (property == priv->brightness_prop) { *val = drm_to_overlay_state(state)->brightness + 256; } else if (property == priv->contrast_prop) { *val = drm_to_overlay_state(state)->contrast; @@ -645,13 +665,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) return ret; } - dplane->prop.colorkey_yr = 0xfefefe00; - dplane->prop.colorkey_ug = 0x01010100; - dplane->prop.colorkey_vb = 0x01010100; - dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | - CFG_ALPHAM_GRA | CFG_ALPHA(0); - dplane->prop.colorkey_enable = ADV_GRACOLORKEY; - mobj = &dplane->base.base.base; drm_object_attach_property(mobj, priv->colorkey_prop, 0x0101fe); From 240cf2b58eb0bdd3c59387ca0cfbd5657708b996 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 18/39] drm/armada: remove crtc YUV colourspace properties Remove the unused CRTC colourspace properties - userspace does not make use of these. In any case, these are not a property of the CRTC, since they demonstrably only affect the video (overlay) plane, irrespective of the format of the graphics (primary) plane. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 118 --------------------------- drivers/gpu/drm/armada/armada_crtc.h | 2 - drivers/gpu/drm/armada/armada_drm.h | 2 - 3 files changed, 122 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index b9b0a508793d..35b2df0fc21c 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -23,14 +23,6 @@ #include "armada_plane.h" #include "armada_trace.h" -enum csc_mode { - CSC_AUTO = 0, - CSC_YUV_CCIR601 = 1, - CSC_YUV_CCIR709 = 2, - CSC_RGB_COMPUTER = 1, - CSC_RGB_STUDIO = 2, -}; - /* * A note about interlacing. Let's consider HDMI 1920x1080i. * The timing parameters we have from X are: @@ -438,42 +430,6 @@ static irqreturn_t armada_drm_irq(int irq, void *arg) return IRQ_NONE; } -static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) -{ - struct drm_display_mode *adj = &dcrtc->crtc.mode; - uint32_t val = 0; - - if (dcrtc->csc_yuv_mode == CSC_YUV_CCIR709) - val |= CFG_CSC_YUV_CCIR709; - if (dcrtc->csc_rgb_mode == CSC_RGB_STUDIO) - val |= CFG_CSC_RGB_STUDIO; - - /* - * In auto mode, set the colorimetry, based upon the HDMI spec. - * 1280x720p, 1920x1080p and 1920x1080i use ITU709, others use - * ITU601. It may be more appropriate to set this depending on - * the source - but what if the graphic frame is YUV and the - * video frame is RGB? - */ - if ((adj->hdisplay == 1280 && adj->vdisplay == 720 && - !(adj->flags & DRM_MODE_FLAG_INTERLACE)) || - (adj->hdisplay == 1920 && adj->vdisplay == 1080)) { - if (dcrtc->csc_yuv_mode == CSC_AUTO) - val |= CFG_CSC_YUV_CCIR709; - } - - /* - * We assume we're connected to a TV-like device, so the YUV->RGB - * conversion should produce a limited range. We should set this - * depending on the connectors attached to this CRTC, and what - * kind of device they report being connected. - */ - if (dcrtc->csc_rgb_mode == CSC_AUTO) - val |= CFG_CSC_RGB_STUDIO; - - return val; -} - /* The mode_config.mutex will be held for this call */ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { @@ -560,9 +516,6 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); - - val = dcrtc->spu_iopad_ctrl | armada_drm_crtc_calculate_csc(dcrtc); - armada_reg_queue_set(regs, i, val, LCD_SPU_IOPAD_CONTROL); armada_reg_queue_end(regs, i); armada_drm_crtc_update_regs(dcrtc, regs); @@ -937,33 +890,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } -static int -armada_drm_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, uint64_t val) -{ - struct armada_private *priv = crtc->dev->dev_private; - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - bool update_csc = false; - - if (property == priv->csc_yuv_prop) { - dcrtc->csc_yuv_mode = val; - update_csc = true; - } else if (property == priv->csc_rgb_prop) { - dcrtc->csc_rgb_mode = val; - update_csc = true; - } - - if (update_csc) { - uint32_t val; - - val = dcrtc->spu_iopad_ctrl | - armada_drm_crtc_calculate_csc(dcrtc); - writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL); - } - - return 0; -} - /* These are called under the vbl_lock. */ static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) { @@ -993,45 +919,12 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .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 const struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { - { CSC_AUTO, "Auto" }, - { CSC_YUV_CCIR601, "CCIR601" }, - { CSC_YUV_CCIR709, "CCIR709" }, -}; - -static const struct drm_prop_enum_list armada_drm_csc_rgb_enum_list[] = { - { CSC_AUTO, "Auto" }, - { CSC_RGB_COMPUTER, "Computer system" }, - { CSC_RGB_STUDIO, "Studio" }, -}; - -static int armada_drm_crtc_create_properties(struct drm_device *dev) -{ - struct armada_private *priv = dev->dev_private; - - if (priv->csc_yuv_prop) - return 0; - - priv->csc_yuv_prop = drm_property_create_enum(dev, 0, - "CSC_YUV", armada_drm_csc_yuv_enum_list, - ARRAY_SIZE(armada_drm_csc_yuv_enum_list)); - priv->csc_rgb_prop = drm_property_create_enum(dev, 0, - "CSC_RGB", armada_drm_csc_rgb_enum_list, - ARRAY_SIZE(armada_drm_csc_rgb_enum_list)); - - if (!priv->csc_yuv_prop || !priv->csc_rgb_prop) - return -ENOMEM; - - return 0; -} - static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, struct resource *res, int irq, const struct armada_variant *variant, struct device_node *port) @@ -1042,10 +935,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, void __iomem *base; int ret; - ret = armada_drm_crtc_create_properties(drm); - if (ret) - return ret; - base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); @@ -1063,8 +952,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, dcrtc->base = base; dcrtc->num = drm->mode_config.num_crtc; dcrtc->clk = ERR_PTR(-EINVAL); - dcrtc->csc_yuv_mode = CSC_AUTO; - dcrtc->csc_rgb_mode = CSC_AUTO; dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0; dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; spin_lock_init(&dcrtc->irq_lock); @@ -1121,11 +1008,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); - drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, - dcrtc->csc_yuv_mode); - drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop, - dcrtc->csc_rgb_mode); - return armada_overlay_plane_create(drm, 1 << dcrtc->num); err_crtc_init: diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index c27435a8776a..21338f7c3d7d 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -72,8 +72,6 @@ struct armada_crtc { } v[2]; bool interlaced; bool cursor_update; - uint8_t csc_yuv_mode; - uint8_t csc_rgb_mode; struct drm_plane *plane; diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index cc4c557c9f66..28087e4b9b81 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -60,8 +60,6 @@ struct armada_private { struct armada_crtc *dcrtc[2]; struct drm_mm linear; /* protected by linear_lock */ struct mutex linear_lock; - struct drm_property *csc_yuv_prop; - struct drm_property *csc_rgb_prop; struct drm_property *colorkey_prop; struct drm_property *colorkey_min_prop; struct drm_property *colorkey_max_prop; From c29277d4e56388e805acc3ba428c9cff7df99fa7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 19/39] drm/armada: add plane colorspace properties Use the DRM standard plane properties for specifying the YUV colour encoding parameter. Our colour range is fixed at limited range. Since we are transitioning to atomic modeset, we need to explicitly add handling of these properties to our atomic_set_property() method, but once the transition is complete, these will be removed. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_overlay.c | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 7f75df4f8390..bc1b5b860141 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -23,6 +23,7 @@ #define DEFAULT_BRIGHTNESS 0 #define DEFAULT_CONTRAST 0x4000 #define DEFAULT_SATURATION 0x4000 +#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601 struct armada_ovl_plane { struct armada_plane base; @@ -59,6 +60,19 @@ static inline u32 armada_spu_saturation(struct drm_plane_state *state) return drm_to_overlay_state(state)->saturation << 16; } +static inline u32 armada_csc(struct drm_plane_state *state) +{ + /* + * The CFG_CSC_RGB_* settings control the output of the colour space + * converter, setting the range of output values it produces. Since + * we will be blending with the full-range graphics, we need to + * produce full-range RGB output from the conversion. + */ + return CFG_CSC_RGB_COMPUTER | + (state->color_encoding == DRM_COLOR_YCBCR_BT709 ? + CFG_CSC_YUV_CCIR709 : CFG_CSC_YUV_CCIR601); +} + /* === Plane support === */ static void armada_ovl_plane_work(struct armada_crtc *dcrtc, struct armada_plane_work *work) @@ -189,6 +203,11 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION); if (!old_state->visible && state->visible) armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE); + val = armada_csc(state); + if ((!old_state->visible && state->visible) || + armada_csc(old_state) != val) + armada_reg_queue_mod(regs, idx, val, CFG_CSC_MASK, + LCD_SPU_IOPAD_CONTROL); val = drm_to_overlay_state(state)->colorkey_yr; if ((!old_state->visible && state->visible) || drm_to_overlay_state(old_state)->colorkey_yr != val) @@ -399,6 +418,8 @@ static void armada_overlay_reset(struct drm_plane *plane) state = kzalloc(sizeof(*state), GFP_KERNEL); if (state) { state->base.plane = plane; + state->base.color_encoding = DEFAULT_ENCODING; + state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; state->base.rotation = DRM_MODE_ROTATE_0; state->colorkey_yr = 0xfefefe00; state->colorkey_ug = 0x01010100; @@ -489,6 +510,9 @@ static int armada_overlay_set_property(struct drm_plane *plane, drm_to_overlay_state(state)->contrast = val; } else if (property == priv->saturation_prop) { drm_to_overlay_state(state)->saturation = val; + } else if (property == plane->color_encoding_property) { + /* transitional only */ + state->color_encoding = val; } else { return -EINVAL; } @@ -685,5 +709,12 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) drm_object_attach_property(mobj, priv->saturation_prop, DEFAULT_SATURATION); - return 0; + ret = drm_plane_create_color_properties(&dplane->base.base, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DEFAULT_ENCODING, + DRM_COLOR_YCBCR_LIMITED_RANGE); + + return ret; } From 3382a6b999415d1f78cee3f483957651d7e1f8a4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 20/39] drm/armada: move armada_drm_mode_config_funcs to armada_drv.c Move the armada_drm_mode_config_funcs to armada_drv.c, since this now has less to do with FBs than it does with general mode configuration. In doing so, we need to make armada_fb_create() visible to armada_drv.c, which reveals a function name clash with armada_fbdev.c. Rename the version in armada_fbdev.c. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_drm.h | 2 -- drivers/gpu/drm/armada/armada_drv.c | 6 ++++++ drivers/gpu/drm/armada/armada_fb.c | 7 +------ drivers/gpu/drm/armada/armada_fb.h | 3 ++- drivers/gpu/drm/armada/armada_fbdev.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 28087e4b9b81..64f1c8836078 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -79,8 +79,6 @@ void __armada_drm_queue_unref_work(struct drm_device *, void armada_drm_queue_unref_work(struct drm_device *, struct drm_framebuffer *); -extern const struct drm_mode_config_funcs armada_drm_mode_config_funcs; - int armada_fbdev_init(struct drm_device *); void armada_fbdev_fini(struct drm_device *); diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index e47b995b4ce6..7517f23bb9cd 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -15,6 +15,7 @@ #include "armada_crtc.h" #include "armada_drm.h" #include "armada_gem.h" +#include "armada_fb.h" #include "armada_hw.h" #include #include "armada_ioctlP.h" @@ -77,6 +78,11 @@ static struct drm_driver armada_drm_driver = { .fops = &armada_drm_fops, }; +static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { + .fb_create = armada_fb_create, + .output_poll_changed = drm_fb_helper_output_poll_changed, +}; + static int armada_drm_bind(struct device *dev) { struct armada_private *priv; diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index edd15126bde9..6bd638a54579 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -84,7 +84,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, return dfb; } -static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, +struct drm_framebuffer *armada_fb_create(struct drm_device *dev, struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode) { struct armada_gem_object *obj; @@ -138,8 +138,3 @@ static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, DRM_ERROR("failed to initialize framebuffer: %d\n", ret); return ERR_PTR(ret); } - -const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { - .fb_create = armada_fb_create, - .output_poll_changed = drm_fb_helper_output_poll_changed, -}; diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h index 5c130ff5da77..476daad0a36a 100644 --- a/drivers/gpu/drm/armada/armada_fb.h +++ b/drivers/gpu/drm/armada/armada_fb.h @@ -19,5 +19,6 @@ struct armada_framebuffer { struct armada_framebuffer *armada_framebuffer_create(struct drm_device *, const struct drm_mode_fb_cmd2 *, struct armada_gem_object *); - +struct drm_framebuffer *armada_fb_create(struct drm_device *dev, + struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode); #endif diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 2a59db0994b2..8d23700848df 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -24,7 +24,7 @@ static /*const*/ struct fb_ops armada_fb_ops = { .fb_imageblit = drm_fb_helper_cfb_imageblit, }; -static int armada_fb_create(struct drm_fb_helper *fbh, +static int armada_fbdev_create(struct drm_fb_helper *fbh, struct drm_fb_helper_surface_size *sizes) { struct drm_device *dev = fbh->dev; @@ -108,7 +108,7 @@ static int armada_fb_probe(struct drm_fb_helper *fbh, int ret = 0; if (!fbh->fb) { - ret = armada_fb_create(fbh, sizes); + ret = armada_fbdev_create(fbh, sizes); if (ret == 0) ret = 1; } From b4df3ba0d76823cb5e548505de104837d89aa5a9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 21/39] drm/armada: pass plane state into armada_drm_plane_calc_addrs() armada_drm_plane_calc_addrs() gets all its information from the plane state, so it makes sense to pass the plane state pointer down into this function, rather than extracting the information in identical ways, sometimes a couple of layers up. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_overlay.c | 6 +++--- drivers/gpu/drm/armada/armada_plane.c | 25 ++++++++++++------------- drivers/gpu/drm/armada/armada_plane.h | 3 +-- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index bc1b5b860141..e8c3bcc09d5c 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -130,11 +130,10 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, 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; + u16 src_x; u32 addrs[3]; - armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y); + armada_drm_plane_calc_addrs(state, addrs); armada_reg_queue_set(regs, idx, addrs[0], LCD_SPU_DMA_START_ADDR_Y0); @@ -166,6 +165,7 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, * the UV swap. */ format = state->fb->format; + src_x = state->src.x1 >> 16; if (format->num_planes == 1 && src_x & (format->hsub - 1)) cfg ^= CFG_DMA_MOD(CFG_SWAPUV); cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT | diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 1cb6a605bda9..c426c92c79d9 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -35,14 +35,19 @@ static const uint32_t armada_primary_formats[] = { DRM_FORMAT_BGR565, }; -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y) +void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]) { + struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; unsigned int num_planes = format->num_planes; + unsigned int x = state->src.x1 >> 16; + unsigned int y = state->src.y1 >> 16; u32 addr = drm_fb_obj(fb)->dev_addr; int i; + DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n", + fb->pitches[0], x, y, format->cpp[0] * 8); + if (num_planes > 3) num_planes = 3; @@ -59,17 +64,14 @@ void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, addrs[i] = 0; } -static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, - int x, int y, struct armada_regs *regs, bool interlaced) +static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, + struct armada_regs *regs, bool interlaced) { - unsigned pitch = fb->pitches[0]; + unsigned pitch = state->fb->pitches[0]; u32 addrs[3], addr_odd, addr_even; unsigned i = 0; - DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", - pitch, x, y, fb->format->cpp[0] * 8); - - armada_drm_plane_calc_addrs(addrs, fb, x, y); + armada_drm_plane_calc_addrs(state, addrs); addr_odd = addr_even = addrs[0]; @@ -175,10 +177,7 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, 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, + idx += armada_drm_crtc_calc_fb(state, regs + idx, dcrtc->interlaced); } if (old_state->fb != state->fb) { diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 3c8316003907..999a0bd3e512 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,8 +1,7 @@ #ifndef ARMADA_PLANE_H #define ARMADA_PLANE_H -void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb, - int x, int y); +void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]); int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); void armada_drm_plane_cleanup_fb(struct drm_plane *plane, From 4aafe00e2f6bb43656d690b6241f80bb8c236168 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 22/39] drm/armada: provide pitches from armada_drm_plane_calc_addrs() Provide the framebuffer pitches from armada_drm_plane_calc_addrs() as well as the base addresses for each plane. Since this is now about more than just addresses, rename to armada_drm_plane_calc(). Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_overlay.c | 8 ++++---- drivers/gpu/drm/armada/armada_plane.c | 22 ++++++++++++++-------- drivers/gpu/drm/armada/armada_plane.h | 3 ++- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index e8c3bcc09d5c..f36f6fb919e7 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -130,10 +130,10 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, old_state->src.y1 != state->src.y1 || old_state->fb != state->fb) { const struct drm_format_info *format; - u16 src_x; + u16 src_x, pitches[3]; u32 addrs[3]; - armada_drm_plane_calc_addrs(state, addrs); + armada_drm_plane_calc(state, addrs, pitches); armada_reg_queue_set(regs, idx, addrs[0], LCD_SPU_DMA_START_ADDR_Y0); @@ -148,9 +148,9 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, armada_reg_queue_set(regs, idx, addrs[2], LCD_SPU_DMA_START_ADDR_V1); - val = state->fb->pitches[0] << 16 | state->fb->pitches[0]; + val = pitches[0] << 16 | pitches[0]; armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC); - val = state->fb->pitches[1] << 16 | state->fb->pitches[2]; + val = pitches[1] << 16 | pitches[2]; armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV); cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) | diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index c426c92c79d9..3c9414c56aca 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -35,7 +35,8 @@ static const uint32_t armada_primary_formats[] = { DRM_FORMAT_BGR565, }; -void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]) +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], + u16 pitches[3]) { struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; @@ -53,37 +54,42 @@ void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]) addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + x * format->cpp[0]; + pitches[0] = fb->pitches[0]; y /= format->vsub; x /= format->hsub; - for (i = 1; i < num_planes; i++) + for (i = 1; i < num_planes; i++) { addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + x * format->cpp[i]; - for (; i < 3; i++) + pitches[i] = fb->pitches[i]; + } + for (; i < 3; i++) { addrs[i] = 0; + pitches[i] = 0; + } } static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, struct armada_regs *regs, bool interlaced) { - unsigned pitch = state->fb->pitches[0]; + u16 pitches[3]; u32 addrs[3], addr_odd, addr_even; unsigned i = 0; - armada_drm_plane_calc_addrs(state, addrs); + armada_drm_plane_calc(state, addrs, pitches); addr_odd = addr_even = addrs[0]; if (interlaced) { - addr_even += pitch; - pitch *= 2; + addr_even += pitches[0]; + pitches[0] *= 2; } /* write offset, base, and pitch */ armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); - armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); + armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH); return i; } diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 999a0bd3e512..98280beaaa44 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,7 +1,8 @@ #ifndef ARMADA_PLANE_H #define ARMADA_PLANE_H -void armada_drm_plane_calc_addrs(struct drm_plane_state *state, u32 addrs[3]); +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], + u16 pitches[3]); int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); void armada_drm_plane_cleanup_fb(struct drm_plane *plane, From b5bae71a79d712681bdf48ee029f1953697924f7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 23/39] drm/armada: push interlace calculation into armada_drm_plane_calc() Push the interlaced frame calculation down into armada_drm_plane_calc() which needs to apply the same correction for both the overlay and primary planes. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_overlay.c | 16 +++++------ drivers/gpu/drm/armada/armada_plane.c | 38 +++++++++++++------------ drivers/gpu/drm/armada/armada_plane.h | 4 +-- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index f36f6fb919e7..7de8b6bd7847 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -131,21 +131,21 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, old_state->fb != state->fb) { const struct drm_format_info *format; u16 src_x, pitches[3]; - u32 addrs[3]; + u32 addrs[2][3]; - armada_drm_plane_calc(state, addrs, pitches); + armada_drm_plane_calc(state, addrs, pitches, false); - armada_reg_queue_set(regs, idx, addrs[0], + armada_reg_queue_set(regs, idx, addrs[0][0], LCD_SPU_DMA_START_ADDR_Y0); - armada_reg_queue_set(regs, idx, addrs[1], + armada_reg_queue_set(regs, idx, addrs[0][1], LCD_SPU_DMA_START_ADDR_U0); - armada_reg_queue_set(regs, idx, addrs[2], + armada_reg_queue_set(regs, idx, addrs[0][2], LCD_SPU_DMA_START_ADDR_V0); - armada_reg_queue_set(regs, idx, addrs[0], + armada_reg_queue_set(regs, idx, addrs[1][0], LCD_SPU_DMA_START_ADDR_Y1); - armada_reg_queue_set(regs, idx, addrs[1], + armada_reg_queue_set(regs, idx, addrs[1][1], LCD_SPU_DMA_START_ADDR_U1); - armada_reg_queue_set(regs, idx, addrs[2], + armada_reg_queue_set(regs, idx, addrs[1][2], LCD_SPU_DMA_START_ADDR_V1); val = pitches[0] << 16 | pitches[0]; diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 3c9414c56aca..1320fec4c386 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -35,8 +35,8 @@ static const uint32_t armada_primary_formats[] = { DRM_FORMAT_BGR565, }; -void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], - u16 pitches[3]) +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3], + u16 pitches[3], bool interlaced) { struct drm_framebuffer *fb = state->fb; const struct drm_format_info *format = fb->format; @@ -52,43 +52,45 @@ void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], if (num_planes > 3) num_planes = 3; - addrs[0] = addr + fb->offsets[0] + y * fb->pitches[0] + - x * format->cpp[0]; + addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] + + x * format->cpp[0]; pitches[0] = fb->pitches[0]; y /= format->vsub; x /= format->hsub; for (i = 1; i < num_planes; i++) { - addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] + - x * format->cpp[i]; + addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] + + x * format->cpp[i]; pitches[i] = fb->pitches[i]; } for (; i < 3; i++) { - addrs[i] = 0; + addrs[0][i] = 0; pitches[i] = 0; } + if (interlaced) { + for (i = 0; i < 3; i++) { + addrs[1][i] = addrs[0][i] + pitches[i]; + pitches[i] *= 2; + } + } else { + for (i = 0; i < 3; i++) + addrs[1][i] = addrs[0][i]; + } } static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state, struct armada_regs *regs, bool interlaced) { u16 pitches[3]; - u32 addrs[3], addr_odd, addr_even; + u32 addrs[2][3]; unsigned i = 0; - armada_drm_plane_calc(state, addrs, pitches); - - addr_odd = addr_even = addrs[0]; - - if (interlaced) { - addr_even += pitches[0]; - pitches[0] *= 2; - } + armada_drm_plane_calc(state, addrs, pitches, interlaced); /* write offset, base, and pitch */ - armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); - armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); + armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0); + armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1); armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH); return i; diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 98280beaaa44..1bd8430992e0 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -1,8 +1,8 @@ #ifndef ARMADA_PLANE_H #define ARMADA_PLANE_H -void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[3], - u16 pitches[3]); +void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3], + u16 pitches[3], bool interlaced); int armada_drm_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state); void armada_drm_plane_cleanup_fb(struct drm_plane *plane, From 155b8290f7635b31faa57ca38cb5ddfe78111c2d Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 24/39] drm/armada: move sync signal polarity to mode_set_nofb() method For atomic modeset, we need to set the sync signal polarities from the CRTC state structure rather than the legacy mode structure stored in CRTC. In any case, we should update this from our mode_set_nofb() method, rather than the commit() method. Move it there, and ensure that armada_drm_crtc_update() will not overwrite these bits. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 47 +++++++++++++--------------- drivers/gpu/drm/armada/armada_crtc.h | 1 - 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 35b2df0fc21c..3cae6587b079 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -115,25 +115,9 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) dumb_ctrl |= DUMB_BLANK; } - /* - * The documentation doesn't indicate what the normal state of - * the sync signals are. Sebastian Hesselbart kindly probed - * these signals on his board to determine their state. - * - * The non-inverted state of the sync signals is active high. - * Setting these bits makes the appropriate signal active low. - */ - if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NCSYNC) - dumb_ctrl |= CFG_INV_CSYNC; - if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NHSYNC) - dumb_ctrl |= CFG_INV_HSYNC; - if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NVSYNC) - dumb_ctrl |= CFG_INV_VSYNC; - - if (dcrtc->dumb_ctrl != dumb_ctrl) { - dcrtc->dumb_ctrl = dumb_ctrl; - writel_relaxed(dumb_ctrl, dcrtc->base + LCD_SPU_DUMB_CTRL); - } + armada_updatel(dumb_ctrl, + ~(CFG_INV_CSYNC | CFG_INV_HSYNC | CFG_INV_VSYNC), + dcrtc->base + LCD_SPU_DUMB_CTRL); } static void armada_drm_plane_work_call(struct armada_crtc *dcrtc, @@ -280,7 +264,6 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_plane *plane; - u32 val; /* * If we have an overlay plane associated with this CRTC, disable @@ -300,11 +283,7 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); - val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; - if (val != dcrtc->dumb_ctrl) { - dcrtc->dumb_ctrl = val; - writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); - } + armada_updatel(0, CFG_DUMB_ENA, dcrtc->base + LCD_SPU_DUMB_CTRL); } /* The mode_config.mutex will be held for this call */ @@ -516,6 +495,24 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); + + /* + * The documentation doesn't indicate what the normal state of + * the sync signals are. Sebastian Hesselbart kindly probed + * these signals on his board to determine their state. + * + * The non-inverted state of the sync signals is active high. + * Setting these bits makes the appropriate signal active low. + */ + val = 0; + if (adj->flags & DRM_MODE_FLAG_NCSYNC) + val |= CFG_INV_CSYNC; + if (adj->flags & DRM_MODE_FLAG_NHSYNC) + val |= CFG_INV_HSYNC; + if (adj->flags & DRM_MODE_FLAG_NVSYNC) + val |= CFG_INV_VSYNC; + armada_reg_queue_mod(regs, i, val, CFG_INV_CSYNC | CFG_INV_HSYNC | + CFG_INV_VSYNC, LCD_SPU_DUMB_CTRL); armada_reg_queue_end(regs, i); armada_drm_crtc_update_regs(dcrtc, regs); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 21338f7c3d7d..775c01c52982 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -85,7 +85,6 @@ struct armada_crtc { int dpms; uint32_t cfg_dumb_ctrl; - uint32_t dumb_ctrl; uint32_t spu_iopad_ctrl; spinlock_t irq_lock; From a61c3922f6293ab5d58f64e2312981cc646c2fd8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 25/39] drm/armada: update debug in armada_drm_crtc_mode_set_nofb() Update debug to use KMS level, and print the mode using the standard format for mode lines, but print the adjusted CRTC parameters as that's what we will be programming for. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 3cae6587b079..9ad966caf08c 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -426,16 +426,15 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) bm = adj->crtc_vsync_start - adj->crtc_vdisplay; tm = adj->crtc_vtotal - adj->crtc_vsync_end; - DRM_DEBUG_DRIVER("H: %d %d %d %d lm %d rm %d\n", - adj->crtc_hdisplay, - adj->crtc_hsync_start, - adj->crtc_hsync_end, - adj->crtc_htotal, lm, rm); - DRM_DEBUG_DRIVER("V: %d %d %d %d tm %d bm %d\n", - adj->crtc_vdisplay, - adj->crtc_vsync_start, - adj->crtc_vsync_end, - adj->crtc_vtotal, tm, bm); + DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n", + crtc->base.id, crtc->name, + adj->base.id, adj->name, adj->vrefresh, adj->clock, + adj->crtc_hdisplay, adj->crtc_hsync_start, + adj->crtc_hsync_end, adj->crtc_htotal, + adj->crtc_vdisplay, adj->crtc_vsync_start, + adj->crtc_vsync_end, adj->crtc_vtotal, + adj->type, adj->flags); + DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); /* * If we are blanked, we would have disabled the clock. Re-enable From 4e4b3563ac006e47761341682de80528e2cf30ab Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 26/39] drm/armada: clean up SPU_ADV_REG Rather than writing all bits of SPU_ADV_REG on modeset, only write what we need to change, and initialise the register in the variant initialisation. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_510.c | 5 ++++- drivers/gpu/drm/armada/armada_crtc.c | 11 ++++------- drivers/gpu/drm/armada/armada_drm.h | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 41a784f5a5e6..9a4fbb6a24b8 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c @@ -27,6 +27,10 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev) /* Lower the watermark so to eliminate jitter at higher bandwidths */ armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); + /* Initialise SPU register */ + writel_relaxed(ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, + dcrtc->base + LCD_SPU_ADV_REG); + return 0; } @@ -77,7 +81,6 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, const struct armada_variant armada510_ops = { .has_spu_adv_reg = true, - .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, .init = armada510_crtc_init, .compute_clock = armada510_crtc_compute_clock, }; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 9ad966caf08c..80d34a4b7d41 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -463,17 +463,15 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) adj->crtc_htotal; dcrtc->v[1].spu_v_porch = tm << 16 | bm; val = adj->crtc_hsync_start; - dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | - dcrtc->variant->spu_adv_reg; + dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; if (interlaced) { /* Odd interlaced frame */ + val -= adj->crtc_htotal / 2; + dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total + (1 << 16); dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; - val = adj->crtc_hsync_start - adj->crtc_htotal / 2; - dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | - dcrtc->variant->spu_adv_reg; } else { dcrtc->v[0] = dcrtc->v[1]; } @@ -486,11 +484,10 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, LCD_SPUT_V_H_TOTAL); - if (dcrtc->variant->has_spu_adv_reg) { + if (dcrtc->variant->has_spu_adv_reg) armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); - } val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 64f1c8836078..a6f919b0084c 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -42,7 +42,6 @@ struct armada_private; struct armada_variant { bool has_spu_adv_reg; - uint32_t spu_adv_reg; int (*init)(struct armada_crtc *, struct device *); int (*compute_clock)(struct armada_crtc *, const struct drm_display_mode *, From dbb4ca8acae100b21946a9c6439af51bd606595e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 27/39] drm/armada: handle atomic modeset crtc events Prepare handling for atomic modeset CRTC events. Currently, using the transition helpers, CRTC events do not exist, but once we switch to proper atomic modeset, they have to be handled. We queue an event for the next vblank in two places: - armada_drm_crtc_atomic_flush() provided we aren't doing an atomic modeset. - armada_drm_crtc_commit() if we are committing a modeset. This ensures that the event is sent at the correct time (after all updates have been written to the hardware and after the following vblank.) Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 33 ++++++++++++++++++++++++++++ drivers/gpu/drm/armada/armada_crtc.h | 1 + 2 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 80d34a4b7d41..a0c67ec892cf 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -232,6 +232,19 @@ static void armada_drm_vblank_off(struct armada_crtc *dcrtc) armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); } +static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct drm_pending_vblank_event *event; + + /* If we have an event, we need vblank events enabled */ + event = xchg(&crtc->state->event, NULL); + if (event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + dcrtc->event = event; + } +} + /* The mode_config.mutex will be held for this call */ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) { @@ -294,6 +307,8 @@ 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); + + armada_drm_crtc_queue_state_event(crtc); } /* The mode_config.mutex will be held for this call */ @@ -337,6 +352,7 @@ static void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask) static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) { + struct drm_pending_vblank_event *event; void __iomem *base = dcrtc->base; struct drm_plane *ovl_plane; @@ -383,6 +399,16 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) if (stat & GRA_FRAME_IRQ) armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); + + if (stat & VSYNC_IRQ) { + event = xchg(&dcrtc->event, NULL); + if (event) { + spin_lock(&dcrtc->crtc.dev->event_lock); + drm_crtc_send_vblank_event(&dcrtc->crtc, event); + spin_unlock(&dcrtc->crtc.dev->event_lock); + drm_crtc_vblank_put(&dcrtc->crtc); + } + } } static irqreturn_t armada_drm_irq(int irq, void *arg) @@ -554,6 +580,13 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock_irqsave(&dcrtc->irq_lock, flags); armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); spin_unlock_irqrestore(&dcrtc->irq_lock, flags); + + /* + * If we aren't doing a full modeset, then we need to queue + * the event here. + */ + if (!drm_atomic_crtc_needs_modeset(crtc->state)) + armada_drm_crtc_queue_state_event(crtc); } static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 775c01c52982..8b1de877cb02 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -90,6 +90,7 @@ struct armada_crtc { spinlock_t irq_lock; uint32_t irq_ena; + struct drm_pending_vblank_event *event; struct armada_regs atomic_regs[32]; struct armada_regs *regs; unsigned int regs_idx; From a0fbb35ecde52aa5abf5975d117d29e3b30f7b91 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 28/39] drm/armada: push responsibility for clock management to backend Push responsibility for managing the clock during DPMS down into the variant backend, rather than the CRTC layer having knowledge of its state. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_510.c | 19 +++++++++++++++++++ drivers/gpu/drm/armada/armada_crtc.c | 19 ++++++------------- drivers/gpu/drm/armada/armada_drm.h | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c index 9a4fbb6a24b8..2f7c048c5361 100644 --- a/drivers/gpu/drm/armada/armada_510.c +++ b/drivers/gpu/drm/armada/armada_510.c @@ -79,8 +79,27 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, return 0; } +static void armada510_crtc_disable(struct armada_crtc *dcrtc) +{ + if (!IS_ERR(dcrtc->clk)) { + clk_disable_unprepare(dcrtc->clk); + dcrtc->clk = ERR_PTR(-EINVAL); + } +} + +static void armada510_crtc_enable(struct armada_crtc *dcrtc, + const struct drm_display_mode *mode) +{ + if (IS_ERR(dcrtc->clk)) { + dcrtc->clk = dcrtc->extclk[0]; + WARN_ON(clk_prepare_enable(dcrtc->clk)); + } +} + const struct armada_variant armada510_ops = { .has_spu_adv_reg = true, .init = armada510_crtc_init, .compute_clock = armada510_crtc_compute_clock, + .disable = armada510_crtc_disable, + .enable = armada510_crtc_enable, }; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index a0c67ec892cf..5d8fdcda27ee 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -253,14 +253,14 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) if (dpms_blanked(dcrtc->dpms) != dpms_blanked(dpms)) { if (dpms_blanked(dpms)) armada_drm_vblank_off(dcrtc); - else if (!IS_ERR(dcrtc->clk)) - WARN_ON(clk_prepare_enable(dcrtc->clk)); + else if (dcrtc->variant->enable) + dcrtc->variant->enable(dcrtc, &crtc->hwmode); dcrtc->dpms = dpms; armada_drm_crtc_update(dcrtc); if (!dpms_blanked(dpms)) drm_crtc_vblank_on(&dcrtc->crtc); - else if (!IS_ERR(dcrtc->clk)) - clk_disable_unprepare(dcrtc->clk); + else if (dcrtc->variant->disable) + dcrtc->variant->disable(dcrtc); } else if (dcrtc->dpms != dpms) { dcrtc->dpms = dpms; } @@ -462,13 +462,6 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) adj->type, adj->flags); DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n", lm, rm, tm, bm); - /* - * If we are blanked, we would have disabled the clock. Re-enable - * it so that compute_clock() does the right thing. - */ - if (!IS_ERR(dcrtc->clk) && dpms_blanked(dcrtc->dpms)) - WARN_ON(clk_prepare_enable(dcrtc->clk)); - /* Now compute the divider for real */ dcrtc->variant->compute_clock(dcrtc, adj, &sclk); @@ -824,8 +817,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) priv->dcrtc[dcrtc->num] = NULL; drm_crtc_cleanup(&dcrtc->crtc); - if (!IS_ERR(dcrtc->clk)) - clk_disable_unprepare(dcrtc->clk); + if (dcrtc->variant->disable) + dcrtc->variant->disable(dcrtc); writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA); diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index a6f919b0084c..9658be917ea1 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -46,6 +46,8 @@ struct armada_variant { int (*compute_clock)(struct armada_crtc *, const struct drm_display_mode *, uint32_t *); + void (*disable)(struct armada_crtc *); + void (*enable)(struct armada_crtc *, const struct drm_display_mode *); }; /* Variant ops */ From a0f75d2468fe4510bb8d0d6c4e1a5fd5e262e7b5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 29/39] drm/armada: unhook dpms state from armada_drm_crtc_update() Explicitly pass in the desired enable/disable state into armada_drm_crtc_update() rather than having it use the DPMS state stored in our crtc structure. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 5d8fdcda27ee..554135062d93 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -94,13 +94,13 @@ armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) #define dpms_blanked(dpms) ((dpms) != DRM_MODE_DPMS_ON) -static void armada_drm_crtc_update(struct armada_crtc *dcrtc) +static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) { uint32_t dumb_ctrl; dumb_ctrl = dcrtc->cfg_dumb_ctrl; - if (!dpms_blanked(dcrtc->dpms)) + if (enable) dumb_ctrl |= CFG_DUMB_ENA; /* @@ -109,8 +109,7 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc) * force LCD_D[23:0] to output blank color, overriding the GPIO or * SPI usage. So leave it as-is unless in DUMB24_RGB888_0 mode. */ - if (dpms_blanked(dcrtc->dpms) && - (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { + if (!enable && (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { dumb_ctrl &= ~DUMB_MASK; dumb_ctrl |= DUMB_BLANK; } @@ -256,7 +255,7 @@ static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) else if (dcrtc->variant->enable) dcrtc->variant->enable(dcrtc, &crtc->hwmode); dcrtc->dpms = dpms; - armada_drm_crtc_update(dcrtc); + armada_drm_crtc_update(dcrtc, !dpms_blanked(dcrtc->dpms)); if (!dpms_blanked(dpms)) drm_crtc_vblank_on(&dcrtc->crtc); else if (dcrtc->variant->disable) @@ -305,7 +304,7 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc) struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); dcrtc->dpms = DRM_MODE_DPMS_ON; - armada_drm_crtc_update(dcrtc); + armada_drm_crtc_update(dcrtc, true); drm_crtc_vblank_on(crtc); armada_drm_crtc_queue_state_event(crtc); From 34e25ed60ae2cdf91b953dd3772ae48a6bffbd4c Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:52:34 +0100 Subject: [PATCH 30/39] drm/armada: implement atomic_enable()/atomic_disable() methods Implement the atomic_enable()/atomic_disable() methods used by the atomic modeset helpers. atomic_disable() will need some transitional code during conversion to ensure proper ordering is maintained. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 554135062d93..e93097d3aa06 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -581,6 +581,75 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, armada_drm_crtc_queue_state_event(crtc); } +static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + struct drm_pending_vblank_event *event; + struct drm_plane *plane; + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + /* + * For transition only - we must wait for completion of our + * untransitioned paths before changing anything. + */ + plane = dcrtc->plane; + if (plane) + WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), + HZ)); + armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), + MAX_SCHEDULE_TIMEOUT); + + dcrtc->dpms = DRM_MODE_DPMS_OFF; + drm_crtc_vblank_off(crtc); + armada_drm_crtc_update(dcrtc, false); + + if (!crtc->state->active) { + /* + * This modeset will be leaving the CRTC disabled, so + * call the backend to disable upstream clocks etc. + */ + if (dcrtc->variant->disable) + dcrtc->variant->disable(dcrtc); + + /* + * We will not receive any further vblank events. + * Send the flip_done event manually. + */ + event = crtc->state->event; + crtc->state->event = NULL; + if (event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } + } +} + +static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + + DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + + dcrtc->dpms = DRM_MODE_DPMS_ON; + if (!old_state->active) { + /* + * This modeset is enabling the CRTC after it having + * been disabled. Reverse the call to ->disable in + * the atomic_disable(). + */ + if (dcrtc->variant->enable) + dcrtc->variant->enable(dcrtc, &crtc->state->adjusted_mode); + } + armada_drm_crtc_update(dcrtc, true); + drm_crtc_vblank_on(crtc); + + armada_drm_crtc_queue_state_event(crtc); +} + static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .dpms = armada_drm_crtc_dpms, .prepare = armada_drm_crtc_prepare, @@ -592,6 +661,8 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { .disable = armada_drm_crtc_disable, .atomic_begin = armada_drm_crtc_atomic_begin, .atomic_flush = armada_drm_crtc_atomic_flush, + .atomic_disable = armada_drm_crtc_atomic_disable, + .atomic_enable = armada_drm_crtc_atomic_enable, }; static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, From 6bd02908836ed00aa7fcdc759d490029137c2b30 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 31/39] drm/armada: enable atomic modeset support Enable atomic modeset helpers, and internal DRM use of atomic modeset with armada-drm. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 7 +++---- drivers/gpu/drm/armada/armada_drv.c | 5 ++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index e93097d3aa06..375a20757561 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -278,13 +278,12 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc) struct drm_plane *plane; /* - * If we have an overlay plane associated with this CRTC, disable - * it before the modeset to avoid its coordinates being outside - * the new mode parameters. + * If we have an overlay plane associated with this CRTC, disable it + * before the modeset to avoid its coordinates being outside the new + * mode parameters. For transitional atomic modeset, we only wait. */ plane = dcrtc->plane; if (plane) { - drm_plane_force_disable(plane); WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), HZ)); } diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 7517f23bb9cd..20661bd9001e 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ static struct drm_driver armada_drm_driver = { .desc = "Armada SoC DRM", .date = "20120730", .driver_features = DRIVER_GEM | DRIVER_MODESET | - DRIVER_PRIME, + DRIVER_PRIME | DRIVER_ATOMIC, .ioctls = armada_ioctls, .fops = &armada_drm_fops, }; @@ -81,6 +82,8 @@ static struct drm_driver armada_drm_driver = { static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = { .fb_create = armada_fb_create, .output_poll_changed = drm_fb_helper_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, }; static int armada_drm_bind(struct device *dev) From 6d2f864fdff5c73cb37069cd17b0f897d7995b62 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 32/39] drm/armada: switch legacy modeset to atomic modeset Switch the legacy set_config() method to use the atomic modeset helper, which allows us to get rid of the legacy dpms, prepare, commit, mode_set, mode_set_base and disable helper methods. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 103 +-------------------------- drivers/gpu/drm/armada/armada_crtc.h | 1 - 2 files changed, 1 insertion(+), 103 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 375a20757561..0cef40ad3a06 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -92,8 +92,6 @@ armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) } } -#define dpms_blanked(dpms) ((dpms) != DRM_MODE_DPMS_ON) - static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) { uint32_t dumb_ctrl; @@ -221,16 +219,6 @@ armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) return work; } -static void armada_drm_vblank_off(struct armada_crtc *dcrtc) -{ - /* - * Tell the DRM core that vblank IRQs aren't going to happen for - * a while. This cleans up any pending vblank events for us. - */ - drm_crtc_vblank_off(&dcrtc->crtc); - armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); -} - static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -244,71 +232,6 @@ static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) } } -/* The mode_config.mutex will be held for this call */ -static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - - if (dpms_blanked(dcrtc->dpms) != dpms_blanked(dpms)) { - if (dpms_blanked(dpms)) - armada_drm_vblank_off(dcrtc); - else if (dcrtc->variant->enable) - dcrtc->variant->enable(dcrtc, &crtc->hwmode); - dcrtc->dpms = dpms; - armada_drm_crtc_update(dcrtc, !dpms_blanked(dcrtc->dpms)); - if (!dpms_blanked(dpms)) - drm_crtc_vblank_on(&dcrtc->crtc); - else if (dcrtc->variant->disable) - dcrtc->variant->disable(dcrtc); - } else if (dcrtc->dpms != dpms) { - dcrtc->dpms = dpms; - } -} - -/* - * Prepare for a mode set. Turn off overlay to ensure that we don't end - * up with the overlay size being bigger than the active screen size. - * We rely upon X refreshing this state after the mode set has completed. - * - * The mode_config.mutex will be held for this call - */ -static void armada_drm_crtc_prepare(struct drm_crtc *crtc) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct drm_plane *plane; - - /* - * If we have an overlay plane associated with this CRTC, disable it - * before the modeset to avoid its coordinates being outside the new - * mode parameters. For transitional atomic modeset, we only wait. - */ - plane = dcrtc->plane; - if (plane) { - WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), - HZ)); - } - - /* Wait for pending flips to complete */ - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); - - drm_crtc_vblank_off(crtc); - - armada_updatel(0, CFG_DUMB_ENA, dcrtc->base + LCD_SPU_DUMB_CTRL); -} - -/* The mode_config.mutex will be held for this call */ -static void armada_drm_crtc_commit(struct drm_crtc *crtc) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - - dcrtc->dpms = DRM_MODE_DPMS_ON; - armada_drm_crtc_update(dcrtc, true); - drm_crtc_vblank_on(crtc); - - armada_drm_crtc_queue_state_event(crtc); -} - /* The mode_config.mutex will be held for this call */ static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adj) @@ -532,15 +455,6 @@ static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } -/* The mode_config.mutex will be held for this call */ -static void armada_drm_crtc_disable(struct drm_crtc *crtc) -{ - armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - - /* Disable our primary plane when we disable the 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) { @@ -600,7 +514,6 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), MAX_SCHEDULE_TIMEOUT); - dcrtc->dpms = DRM_MODE_DPMS_OFF; drm_crtc_vblank_off(crtc); armada_drm_crtc_update(dcrtc, false); @@ -633,7 +546,6 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); - dcrtc->dpms = DRM_MODE_DPMS_ON; if (!old_state->active) { /* * This modeset is enabling the CRTC after it having @@ -650,14 +562,8 @@ static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, } 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 = 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, .atomic_disable = armada_drm_crtc_atomic_disable, @@ -962,13 +868,6 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, WARN_ON(armada_drm_plane_work_queue(dcrtc, work)); work = NULL; - /* - * Finally, if the display is blanked, we won't receive an - * interrupt, so complete it now. - */ - if (dpms_blanked(dcrtc->dpms)) - armada_drm_plane_work_run(dcrtc, plane); - put_vblank: drm_crtc_vblank_put(crtc); put_work: @@ -1005,7 +904,7 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .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, + .set_config = drm_atomic_helper_set_config, .page_flip = armada_drm_crtc_page_flip, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 8b1de877cb02..afc9266bc1e2 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -83,7 +83,6 @@ struct armada_crtc { uint32_t cursor_w; uint32_t cursor_h; - int dpms; uint32_t cfg_dumb_ctrl; uint32_t spu_iopad_ctrl; From 13c94d5349c9c0756131e7bf2e703ab36ea55c73 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 33/39] drm/armada: switch primary plane to atomic modeset Switch the primary plane away from the transitional helpers, and use the atomic helpers instead to implement the legacy set_plane ioctl call for this plane. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 116 +------------------------- drivers/gpu/drm/armada/armada_plane.c | 4 +- 2 files changed, 3 insertions(+), 117 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 0cef40ad3a06..a25094bbeb2c 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -191,34 +191,6 @@ void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, armada_drm_plane_work_call(dcrtc, work, work->cancel); } -static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - unsigned long flags; - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, work->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - -static struct armada_plane_work * -armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) -{ - struct armada_plane_work *work; - int i = 0; - - work = kzalloc(sizeof(*work), GFP_KERNEL); - if (!work) - return NULL; - - work->plane = plane; - work->fn = armada_drm_crtc_complete_frame_work; - work->need_kfree = true; - armada_reg_queue_end(work->regs, i); - - return work; -} - static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -318,9 +290,6 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) spin_unlock(&dcrtc->irq_lock); - if (stat & GRA_FRAME_IRQ) - armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); - if (stat & VSYNC_IRQ) { event = xchg(&dcrtc->event, NULL); if (event) { @@ -459,15 +428,9 @@ 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; } @@ -511,8 +474,6 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, if (plane) WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), HZ)); - armada_drm_plane_work_wait(drm_to_armada_plane(dcrtc->crtc.primary), - MAX_SCHEDULE_TIMEOUT); drm_crtc_vblank_off(crtc); armada_drm_crtc_update(dcrtc, false); @@ -802,81 +763,6 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) kfree(dcrtc); } -/* - * The mode_config lock is held here, to prevent races between this - * and a mode_set. - */ -static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx) -{ - struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); - struct drm_plane *plane = crtc->primary; - const struct drm_plane_helper_funcs *plane_funcs; - struct drm_plane_state *state; - struct armada_plane_work *work; - int ret; - - /* Construct new state for the primary plane */ - state = drm_atomic_helper_plane_duplicate_state(plane); - if (!state) - return -ENOMEM; - - drm_atomic_set_fb_for_plane(state, fb); - - work = armada_drm_crtc_alloc_plane_work(plane); - if (!work) { - ret = -ENOMEM; - goto put_state; - } - - /* Make sure we can get vblank interrupts */ - ret = drm_crtc_vblank_get(crtc); - if (ret) - goto put_work; - - /* - * If we have another work pending, we can't process this flip. - * The modeset locks protect us from another user queuing a work - * while we're setting up. - */ - if (drm_to_armada_plane(plane)->work) { - ret = -EBUSY; - goto put_vblank; - } - - work->event = event; - work->old_fb = plane->state->fb; - - /* - * Hold a ref on the new fb while it's being displayed by the - * hardware. The old fb refcount will be released in the worker. - */ - drm_framebuffer_get(state->fb); - - /* Point of no return */ - swap(plane->state, state); - - dcrtc->regs_idx = 0; - dcrtc->regs = work->regs; - - plane_funcs = plane->helper_private; - plane_funcs->atomic_update(plane, state); - armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); - - /* Queue the work - this should never fail */ - WARN_ON(armada_drm_plane_work_queue(dcrtc, work)); - work = NULL; - -put_vblank: - drm_crtc_vblank_put(crtc); -put_work: - kfree(work); -put_state: - drm_atomic_helper_plane_destroy_state(plane, state); - return ret; -} - /* These are called under the vbl_lock. */ static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) { @@ -905,7 +791,7 @@ static const struct drm_crtc_funcs armada_crtc_funcs = { .cursor_move = armada_drm_crtc_cursor_move, .destroy = armada_drm_crtc_destroy, .set_config = drm_atomic_helper_set_config, - .page_flip = armada_drm_crtc_page_flip, + .page_flip = drm_atomic_helper_page_flip, .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, diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 1320fec4c386..39c9ba3ee57e 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -261,8 +261,8 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = { }; static const struct drm_plane_funcs armada_primary_plane_funcs = { - .update_plane = drm_plane_helper_update, - .disable_plane = drm_plane_helper_disable, + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_primary_helper_destroy, .reset = drm_atomic_helper_plane_reset, .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, From b1ec9ed6aa985be432f9ba29696029dc6779258e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 34/39] drm/armada: switch overlay plane to atomic modeset Switch the overlay plane away from the transitional helpers and legacy methods, and use atomic helpers instead to implement the legacy set_plane ioctl methods. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 89 ------------- drivers/gpu/drm/armada/armada_crtc.h | 19 --- drivers/gpu/drm/armada/armada_overlay.c | 170 +++++------------------- 3 files changed, 31 insertions(+), 247 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index a25094bbeb2c..ebcb99316c94 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -117,80 +117,6 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) dcrtc->base + LCD_SPU_DUMB_CTRL); } -static void armada_drm_plane_work_call(struct armada_crtc *dcrtc, - struct armada_plane_work *work, - void (*fn)(struct armada_crtc *, struct armada_plane_work *)) -{ - struct armada_plane *dplane = drm_to_armada_plane(work->plane); - struct drm_pending_vblank_event *event; - struct drm_framebuffer *fb; - - if (fn) - fn(dcrtc, work); - drm_crtc_vblank_put(&dcrtc->crtc); - - event = work->event; - fb = work->old_fb; - if (event || fb) { - struct drm_device *dev = dcrtc->crtc.dev; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - if (event) - drm_crtc_send_vblank_event(&dcrtc->crtc, event); - if (fb) - __armada_drm_queue_unref_work(dev, fb); - spin_unlock_irqrestore(&dev->event_lock, flags); - } - - if (work->need_kfree) - kfree(work); - - wake_up(&dplane->frame_wait); -} - -static void armada_drm_plane_work_run(struct armada_crtc *dcrtc, - struct drm_plane *plane) -{ - struct armada_plane *dplane = drm_to_armada_plane(plane); - struct armada_plane_work *work = xchg(&dplane->work, NULL); - - /* Handle any pending frame work. */ - if (work) - armada_drm_plane_work_call(dcrtc, work, work->fn); -} - -int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - struct armada_plane *plane = drm_to_armada_plane(work->plane); - int ret; - - ret = drm_crtc_vblank_get(&dcrtc->crtc); - if (ret) - return ret; - - ret = cmpxchg(&plane->work, NULL, work) ? -EBUSY : 0; - if (ret) - drm_crtc_vblank_put(&dcrtc->crtc); - - return ret; -} - -int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout) -{ - return wait_event_timeout(plane->frame_wait, !plane->work, timeout); -} - -void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, - struct armada_plane *dplane) -{ - struct armada_plane_work *work = xchg(&dplane->work, NULL); - - if (work) - armada_drm_plane_work_call(dcrtc, work, work->cancel); -} - static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); @@ -247,7 +173,6 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) { struct drm_pending_vblank_event *event; void __iomem *base = dcrtc->base; - struct drm_plane *ovl_plane; if (stat & DMA_FF_UNDERFLOW) DRM_ERROR("video underflow on crtc %u\n", dcrtc->num); @@ -257,10 +182,6 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) if (stat & VSYNC_IRQ) drm_crtc_handle_vblank(&dcrtc->crtc); - ovl_plane = dcrtc->plane; - if (ovl_plane) - armada_drm_plane_work_run(dcrtc, ovl_plane); - spin_lock(&dcrtc->irq_lock); if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { int i = stat & GRA_FRAME_IRQ0 ? 0 : 1; @@ -462,19 +383,9 @@ static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct drm_pending_vblank_event *event; - struct drm_plane *plane; DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); - /* - * For transition only - we must wait for completion of our - * untransitioned paths before changing anything. - */ - plane = dcrtc->plane; - if (plane) - WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane), - HZ)); - drm_crtc_vblank_off(crtc); armada_drm_crtc_update(dcrtc, false); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index afc9266bc1e2..5b607d45f469 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -35,29 +35,12 @@ struct armada_crtc; struct armada_plane; struct armada_variant; -struct armada_plane_work { - void (*fn)(struct armada_crtc *, struct armada_plane_work *); - void (*cancel)(struct armada_crtc *, struct armada_plane_work *); - bool need_kfree; - struct drm_plane *plane; - struct drm_framebuffer *old_fb; - struct drm_pending_vblank_event *event; - struct armada_regs regs[24]; -}; - struct armada_plane { struct drm_plane base; wait_queue_head_t frame_wait; - struct armada_plane_work *work; }; #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) -int armada_drm_plane_work_queue(struct armada_crtc *dcrtc, - struct armada_plane_work *work); -int armada_drm_plane_work_wait(struct armada_plane *plane, long timeout); -void armada_drm_plane_work_cancel(struct armada_crtc *dcrtc, - struct armada_plane *plane); - struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; @@ -73,8 +56,6 @@ struct armada_crtc { bool interlaced; bool cursor_update; - struct drm_plane *plane; - struct armada_gem_object *cursor_obj; int cursor_x; int cursor_y; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 7de8b6bd7847..ec2043b6f61f 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -27,9 +27,6 @@ struct armada_ovl_plane { struct armada_plane base; - struct armada_plane_work works[2]; - bool next_work; - bool wait_vblank; }; #define drm_to_armada_ovl_plane(p) \ container_of(p, struct armada_ovl_plane, base.base) @@ -74,18 +71,6 @@ static inline u32 armada_csc(struct drm_plane_state *state) } /* === Plane support === */ -static void armada_ovl_plane_work(struct armada_crtc *dcrtc, - struct armada_plane_work *work) -{ - unsigned long flags; - - trace_armada_ovl_plane_work(&dcrtc->crtc, work->plane); - - spin_lock_irqsave(&dcrtc->irq_lock, flags); - armada_drm_crtc_update_regs(dcrtc, work->regs); - spin_unlock_irqrestore(&dcrtc->irq_lock, flags); -} - static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -109,8 +94,6 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, 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, @@ -173,8 +156,6 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane, 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; @@ -262,9 +243,6 @@ static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane, LCD_SPU_SRAM_PARA1); dcrtc->regs_idx += idx; - - if (dcrtc->plane == plane) - dcrtc->plane = NULL; } static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = { @@ -275,108 +253,50 @@ static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = { .atomic_disable = armada_drm_overlay_plane_atomic_disable, }; -static int armada_overlay_commit(struct drm_plane *plane, - struct drm_plane_state *state) -{ - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - const struct drm_plane_helper_funcs *plane_funcs; - struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc); - struct armada_plane_work *work; - int ret; - - plane_funcs = plane->helper_private; - ret = plane_funcs->atomic_check(plane, state); - if (ret) - goto put_state; - - work = &dplane->works[dplane->next_work]; - - if (plane->state->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); - - work->old_fb = plane->state->fb; - } else { - work->old_fb = NULL; - } - - /* Point of no return */ - swap(plane->state, state); - - /* No CRTC, can't update */ - if (!plane->state->crtc) - goto put_state; - - dcrtc->regs_idx = 0; - dcrtc->regs = work->regs; - - plane_funcs->atomic_update(plane, state); - - /* If nothing was updated, short-circuit */ - if (dcrtc->regs_idx == 0) - goto put_state; - - armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); - - /* Wait for pending work to complete */ - if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) - armada_drm_plane_work_cancel(dcrtc, &dplane->base); - - /* Just updating the position/size? */ - if (!dplane->wait_vblank) { - armada_ovl_plane_work(dcrtc, work); - goto put_state; - } - - dcrtc->plane = plane; - - /* 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); - ret = 0; - } - - dplane->next_work = !dplane->next_work; - -put_state: - plane->funcs->atomic_destroy_state(plane, state); - return ret; -} - static int -armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, +armada_overlay_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 drm_plane_state *state; + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + int ret = 0; trace_armada_ovl_plane_update(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); - /* Construct new state for the overlay plane */ - state = plane->funcs->atomic_duplicate_state(plane); + state = drm_atomic_state_alloc(plane->dev); if (!state) return -ENOMEM; - state->crtc = crtc; - drm_atomic_set_fb_for_plane(state, fb); - state->crtc_x = crtc_x; - state->crtc_y = crtc_y; - state->crtc_h = crtc_h; - state->crtc_w = crtc_w; - state->src_x = src_x; - state->src_y = src_y; - state->src_h = src_h; - state->src_w = src_w; + state->acquire_ctx = ctx; + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } - return armada_overlay_commit(plane, state); + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (ret != 0) + goto fail; + + drm_atomic_set_fb_for_plane(plane_state, fb); + plane_state->crtc_x = crtc_x; + plane_state->crtc_y = crtc_y; + plane_state->crtc_h = crtc_h; + plane_state->crtc_w = crtc_w; + plane_state->src_x = src_x; + plane_state->src_y = src_y; + plane_state->src_h = src_h; + plane_state->src_w = src_w; + + ret = drm_atomic_nonblocking_commit(state); +fail: + drm_atomic_state_put(state); + return ret; } static void armada_ovl_plane_destroy(struct drm_plane *plane) @@ -388,25 +308,6 @@ static void armada_ovl_plane_destroy(struct drm_plane *plane) kfree(dplane); } -static int armada_ovl_plane_set_property(struct drm_plane *plane, - struct drm_property *property, uint64_t val) -{ - struct drm_plane_state *state; - int ret; - - state = plane->funcs->atomic_duplicate_state(plane); - if (!state) - return -ENOMEM; - - ret = plane->funcs->atomic_set_property(plane, state, property, val); - if (ret) { - plane->funcs->atomic_destroy_state(plane, state); - return ret; - } - - return armada_overlay_commit(plane, state); -} - static void armada_overlay_reset(struct drm_plane *plane) { struct armada_overlay_state *state; @@ -510,9 +411,6 @@ static int armada_overlay_set_property(struct drm_plane *plane, drm_to_overlay_state(state)->contrast = val; } else if (property == priv->saturation_prop) { drm_to_overlay_state(state)->saturation = val; - } else if (property == plane->color_encoding_property) { - /* transitional only */ - state->color_encoding = val; } else { return -EINVAL; } @@ -572,10 +470,9 @@ static int armada_overlay_get_property(struct drm_plane *plane, } static const struct drm_plane_funcs armada_ovl_plane_funcs = { - .update_plane = armada_ovl_plane_update, - .disable_plane = drm_plane_helper_disable, + .update_plane = armada_overlay_plane_update, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = armada_ovl_plane_destroy, - .set_property = armada_ovl_plane_set_property, .reset = armada_overlay_reset, .atomic_duplicate_state = armada_overlay_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, @@ -670,11 +567,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) return ret; } - dplane->works[0].plane = &dplane->base.base; - dplane->works[0].fn = armada_ovl_plane_work; - dplane->works[1].plane = &dplane->base.base; - dplane->works[1].fn = armada_ovl_plane_work; - drm_plane_helper_add(&dplane->base.base, &armada_overlay_plane_helper_funcs); From 3cb13ac97bdfda5b301609256e3e0b59bc94f10a Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 35/39] drm/armada: update planes after the dumb frame is complete Write out the plane updates after the dumb frame has completed, but just before the blank period. This allows all the plane updates to be performed in a flicker-free non-tearing manner. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 46 ++++++++++++++++------------ drivers/gpu/drm/armada/armada_crtc.h | 1 + 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index ebcb99316c94..bb1e13b4516b 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -197,21 +197,27 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) writel_relaxed(val, base + LCD_SPU_ADV_REG); } - if (stat & DUMB_FRAMEDONE && dcrtc->cursor_update) { - writel_relaxed(dcrtc->cursor_hw_pos, - base + LCD_SPU_HWC_OVSA_HPXL_VLN); - writel_relaxed(dcrtc->cursor_hw_sz, - base + LCD_SPU_HWC_HPXL_VLN); - armada_updatel(CFG_HWC_ENA, - CFG_HWC_ENA | CFG_HWC_1BITMOD | CFG_HWC_1BITENA, - base + LCD_SPU_DMA_CTRL0); - dcrtc->cursor_update = false; + if (stat & dcrtc->irq_ena & DUMB_FRAMEDONE) { + if (dcrtc->update_pending) { + armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); + dcrtc->update_pending = false; + } + if (dcrtc->cursor_update) { + writel_relaxed(dcrtc->cursor_hw_pos, + base + LCD_SPU_HWC_OVSA_HPXL_VLN); + writel_relaxed(dcrtc->cursor_hw_sz, + base + LCD_SPU_HWC_HPXL_VLN); + armada_updatel(CFG_HWC_ENA, + CFG_HWC_ENA | CFG_HWC_1BITMOD | + CFG_HWC_1BITENA, + base + LCD_SPU_DMA_CTRL0); + dcrtc->cursor_update = false; + } armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); } - spin_unlock(&dcrtc->irq_lock); - if (stat & VSYNC_IRQ) { + if (stat & VSYNC_IRQ && !dcrtc->update_pending) { event = xchg(&dcrtc->event, NULL); if (event) { spin_lock(&dcrtc->crtc.dev->event_lock); @@ -360,22 +366,26 @@ 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); - /* * If we aren't doing a full modeset, then we need to queue * the event here. */ - if (!drm_atomic_crtc_needs_modeset(crtc->state)) + if (!drm_atomic_crtc_needs_modeset(crtc->state)) { + dcrtc->update_pending = true; armada_drm_crtc_queue_state_event(crtc); + spin_lock_irq(&dcrtc->irq_lock); + armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA); + spin_unlock_irq(&dcrtc->irq_lock); + } else { + spin_lock_irq(&dcrtc->irq_lock); + armada_drm_crtc_update_regs(dcrtc, dcrtc->regs); + spin_unlock_irq(&dcrtc->irq_lock); + } } static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, @@ -532,7 +542,6 @@ static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload) if (!dcrtc->cursor_obj || !h || !w) { spin_lock_irq(&dcrtc->irq_lock); - armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); dcrtc->cursor_update = false; armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); spin_unlock_irq(&dcrtc->irq_lock); @@ -556,7 +565,6 @@ static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload) if (dcrtc->cursor_hw_sz != (h << 16 | w)) { spin_lock_irq(&dcrtc->irq_lock); - armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA); dcrtc->cursor_update = false; armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0); spin_unlock_irq(&dcrtc->irq_lock); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 5b607d45f469..b95ea13d0705 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -70,6 +70,7 @@ struct armada_crtc { spinlock_t irq_lock; uint32_t irq_ena; + bool update_pending; struct drm_pending_vblank_event *event; struct armada_regs atomic_regs[32]; struct armada_regs *regs; From dae2155bb07bb2063ce604049e9aa4e862b6db0a Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 36/39] drm/armada: update primary framebuffer parameters on mode change The framebuffer base address and toggling mode needs to be updated when the interlaced flag for mode changes is updated. Arrange to reprogram these parameters when only the mode has changed. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_plane.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index 39c9ba3ee57e..bed2dca83a37 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -184,11 +184,13 @@ static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane, 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) { + old_state->fb != state->fb || + state->crtc->state->mode_changed) { idx += armada_drm_crtc_calc_fb(state, regs + idx, dcrtc->interlaced); } - if (old_state->fb != state->fb) { + if (old_state->fb != state->fb || + state->crtc->state->mode_changed) { 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) From d701278ada5115c40cd4d58ce0fb1169479c0bf6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 37/39] drm/armada: remove unnecessary armada_ovl_plane structure We no longer need a private plane structure, so get rid of it. Use the drm_plane structure directly. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_overlay.c | 34 +++++++------------------ 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index ec2043b6f61f..eb7dfb65ef47 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -25,12 +25,6 @@ #define DEFAULT_SATURATION 0x4000 #define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601 -struct armada_ovl_plane { - struct armada_plane base; -}; -#define drm_to_armada_ovl_plane(p) \ - container_of(p, struct armada_ovl_plane, base.base) - struct armada_overlay_state { struct drm_plane_state base; u32 colorkey_yr; @@ -301,11 +295,8 @@ armada_overlay_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, static void armada_ovl_plane_destroy(struct drm_plane *plane) { - struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); - drm_plane_cleanup(plane); - - kfree(dplane); + kfree(plane); } static void armada_overlay_reset(struct drm_plane *plane) @@ -550,38 +541,31 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) { struct armada_private *priv = dev->dev_private; struct drm_mode_object *mobj; - struct armada_ovl_plane *dplane; + struct drm_plane *overlay; int ret; ret = armada_overlay_create_properties(dev); if (ret) return ret; - dplane = kzalloc(sizeof(*dplane), GFP_KERNEL); - if (!dplane) + overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); + if (!overlay) return -ENOMEM; - ret = armada_drm_plane_init(&dplane->base); - if (ret) { - kfree(dplane); - return ret; - } + drm_plane_helper_add(overlay, &armada_overlay_plane_helper_funcs); - drm_plane_helper_add(&dplane->base.base, - &armada_overlay_plane_helper_funcs); - - ret = drm_universal_plane_init(dev, &dplane->base.base, crtcs, + ret = drm_universal_plane_init(dev, overlay, crtcs, &armada_ovl_plane_funcs, armada_ovl_formats, ARRAY_SIZE(armada_ovl_formats), NULL, DRM_PLANE_TYPE_OVERLAY, NULL); if (ret) { - kfree(dplane); + kfree(overlay); return ret; } - mobj = &dplane->base.base.base; + mobj = &overlay->base; drm_object_attach_property(mobj, priv->colorkey_prop, 0x0101fe); drm_object_attach_property(mobj, priv->colorkey_min_prop, @@ -601,7 +585,7 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) drm_object_attach_property(mobj, priv->saturation_prop, DEFAULT_SATURATION); - ret = drm_plane_create_color_properties(&dplane->base.base, + ret = drm_plane_create_color_properties(overlay, BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709), BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), From 82c702cb0c041a9a1c69f489d1517235a633fc77 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 38/39] drm/armada: remove unnecessary armada_plane structure We no longer require a private armada_plane structure, so eliminate it, and use the drm_plane structure directly. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_crtc.c | 6 +++--- drivers/gpu/drm/armada/armada_crtc.h | 7 ------- drivers/gpu/drm/armada/armada_plane.c | 17 +++-------------- drivers/gpu/drm/armada/armada_plane.h | 3 +-- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index bb1e13b4516b..da9360688b55 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -723,7 +723,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, { struct armada_private *priv = drm->dev_private; struct armada_crtc *dcrtc; - struct armada_plane *primary; + struct drm_plane *primary; void __iomem *base; int ret; @@ -793,7 +793,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, goto err_crtc; } - ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, &primary->base, NULL, + ret = drm_crtc_init_with_planes(drm, &dcrtc->crtc, primary, NULL, &armada_crtc_funcs, NULL); if (ret) goto err_crtc_init; @@ -803,7 +803,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, return armada_overlay_plane_create(drm, 1 << dcrtc->num); err_crtc_init: - primary->base.funcs->destroy(&primary->base); + primary->funcs->destroy(primary); err_crtc: kfree(dcrtc); diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index b95ea13d0705..7ebd337b60af 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -32,15 +32,8 @@ struct armada_regs { armada_reg_queue_mod(_r, _i, 0, 0, ~0) struct armada_crtc; -struct armada_plane; struct armada_variant; -struct armada_plane { - struct drm_plane base; - wait_queue_head_t frame_wait; -}; -#define drm_to_armada_plane(p) container_of(p, struct armada_plane, base) - struct armada_crtc { struct drm_crtc crtc; const struct armada_variant *variant; diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index bed2dca83a37..9f36423dd394 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -271,25 +271,14 @@ static const struct drm_plane_funcs armada_primary_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -int armada_drm_plane_init(struct armada_plane *plane) -{ - init_waitqueue_head(&plane->frame_wait); - return 0; -} - int armada_drm_primary_plane_init(struct drm_device *drm, - struct armada_plane *primary) + struct drm_plane *primary) { int ret; - ret = armada_drm_plane_init(primary); - if (ret) - return ret; + drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs); - drm_plane_helper_add(&primary->base, - &armada_primary_plane_helper_funcs); - - ret = drm_universal_plane_init(drm, &primary->base, 0, + ret = drm_universal_plane_init(drm, primary, 0, &armada_primary_plane_funcs, armada_primary_formats, ARRAY_SIZE(armada_primary_formats), diff --git a/drivers/gpu/drm/armada/armada_plane.h b/drivers/gpu/drm/armada/armada_plane.h index 1bd8430992e0..ff4281ba7fad 100644 --- a/drivers/gpu/drm/armada/armada_plane.h +++ b/drivers/gpu/drm/armada/armada_plane.h @@ -9,8 +9,7 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state); int armada_drm_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state); -int armada_drm_plane_init(struct armada_plane *plane); int armada_drm_primary_plane_init(struct drm_device *drm, - struct armada_plane *primary); + struct drm_plane *primary); #endif From aa595c00bcf5b6f2f394a98217f82c9402952ea9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: [PATCH 39/39] drm/armada: remove obsolete fb unreferencing kfifo and workqueue Remove the obsolete fb unreferencing system that is no longer used since we've transitioned to atomic modeset. Signed-off-by: Russell King --- drivers/gpu/drm/armada/armada_drm.h | 7 ------ drivers/gpu/drm/armada/armada_drv.c | 35 ----------------------------- 2 files changed, 42 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index 9658be917ea1..f09083ff15d3 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -55,8 +55,6 @@ extern const struct armada_variant armada510_ops; struct armada_private { struct drm_device drm; - struct work_struct fb_unref_work; - DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8); struct drm_fb_helper *fbdev; struct armada_crtc *dcrtc[2]; struct drm_mm linear; /* protected by linear_lock */ @@ -75,11 +73,6 @@ struct armada_private { #endif }; -void __armada_drm_queue_unref_work(struct drm_device *, - struct drm_framebuffer *); -void armada_drm_queue_unref_work(struct drm_device *, - struct drm_framebuffer *); - int armada_fbdev_init(struct drm_device *); void armada_fbdev_fini(struct drm_device *); diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 20661bd9001e..fa31589b4fc0 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -21,36 +21,6 @@ #include #include "armada_ioctlP.h" -static void armada_drm_unref_work(struct work_struct *work) -{ - struct armada_private *priv = - container_of(work, struct armada_private, fb_unref_work); - struct drm_framebuffer *fb; - - while (kfifo_get(&priv->fb_unref, &fb)) - drm_framebuffer_put(fb); -} - -/* Must be called with dev->event_lock held */ -void __armada_drm_queue_unref_work(struct drm_device *dev, - struct drm_framebuffer *fb) -{ - struct armada_private *priv = dev->dev_private; - - WARN_ON(!kfifo_put(&priv->fb_unref, fb)); - schedule_work(&priv->fb_unref_work); -} - -void armada_drm_queue_unref_work(struct drm_device *dev, - struct drm_framebuffer *fb) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - __armada_drm_queue_unref_work(dev, fb); - spin_unlock_irqrestore(&dev->event_lock, flags); -} - static struct drm_ioctl_desc armada_ioctls[] = { DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0), DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0), @@ -134,9 +104,6 @@ static int armada_drm_bind(struct device *dev) dev_set_drvdata(dev, &priv->drm); - INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); - INIT_KFIFO(priv->fb_unref); - /* Mode setting support */ drm_mode_config_init(&priv->drm); priv->drm.mode_config.min_width = 320; @@ -190,7 +157,6 @@ static int armada_drm_bind(struct device *dev) err_kms: drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); - flush_work(&priv->fb_unref_work); drm_dev_put(&priv->drm); return ret; } @@ -209,7 +175,6 @@ static void armada_drm_unbind(struct device *dev) drm_mode_config_cleanup(&priv->drm); drm_mm_takedown(&priv->linear); - flush_work(&priv->fb_unref_work); drm_dev_put(&priv->drm); }