Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/gma500: Add page flip support on psb/cdv

Legacy (non-atomic) page flip support is added to the driver by using the
mode_set_base CRTC function, that allows configuring a new framebuffer for
display. Since the function requires the primary plane's fb to be set
already, this is done prior to calling the function in the page flip helper
and reverted if the flip fails.

The vblank interrupt handler is also refactored to support passing an event.
The PIPE_TE_STATUS bit is also considered to indicate vblank on medfield
only, as explained in psb_enable_vblank.

It was tested by running weston on both poulsbo and cedartrail.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
Reviewed-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191106094400.445834-3-paul.kocialkowski@bootlin.com

authored by

Paul Kocialkowski and committed by
Patrik Jakobsson
f76c22ce b20e9afb

+72 -3
+1
drivers/gpu/drm/gma500/cdv_intel_display.c
··· 979 979 .gamma_set = gma_crtc_gamma_set, 980 980 .set_config = gma_crtc_set_config, 981 981 .destroy = gma_crtc_destroy, 982 + .page_flip = gma_crtc_page_flip, 982 983 }; 983 984 984 985 const struct gma_clock_funcs cdv_clock_funcs = {
+46
drivers/gpu/drm/gma500/gma_display.c
··· 503 503 kfree(gma_crtc); 504 504 } 505 505 506 + int gma_crtc_page_flip(struct drm_crtc *crtc, 507 + struct drm_framebuffer *fb, 508 + struct drm_pending_vblank_event *event, 509 + uint32_t page_flip_flags, 510 + struct drm_modeset_acquire_ctx *ctx) 511 + { 512 + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 513 + struct drm_framebuffer *current_fb = crtc->primary->fb; 514 + struct drm_framebuffer *old_fb = crtc->primary->old_fb; 515 + const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 516 + struct drm_device *dev = crtc->dev; 517 + unsigned long flags; 518 + int ret; 519 + 520 + if (!crtc_funcs->mode_set_base) 521 + return -EINVAL; 522 + 523 + /* Using mode_set_base requires the new fb to be set already. */ 524 + crtc->primary->fb = fb; 525 + 526 + if (event) { 527 + spin_lock_irqsave(&dev->event_lock, flags); 528 + 529 + WARN_ON(drm_crtc_vblank_get(crtc) != 0); 530 + 531 + gma_crtc->page_flip_event = event; 532 + 533 + /* Call this locked if we want an event at vblank interrupt. */ 534 + ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb); 535 + if (ret) { 536 + gma_crtc->page_flip_event = NULL; 537 + drm_crtc_vblank_put(crtc); 538 + } 539 + 540 + spin_unlock_irqrestore(&dev->event_lock, flags); 541 + } else { 542 + ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb); 543 + } 544 + 545 + /* Restore previous fb in case of failure. */ 546 + if (ret) 547 + crtc->primary->fb = current_fb; 548 + 549 + return ret; 550 + } 551 + 506 552 int gma_crtc_set_config(struct drm_mode_set *set, 507 553 struct drm_modeset_acquire_ctx *ctx) 508 554 {
+6
drivers/gpu/drm/gma500/gma_display.h
··· 11 11 #define _GMA_DISPLAY_H_ 12 12 13 13 #include <linux/pm_runtime.h> 14 + #include <drm/drm_vblank.h> 14 15 15 16 struct drm_encoder; 16 17 struct drm_mode_set; ··· 72 71 extern void gma_crtc_commit(struct drm_crtc *crtc); 73 72 extern void gma_crtc_disable(struct drm_crtc *crtc); 74 73 extern void gma_crtc_destroy(struct drm_crtc *crtc); 74 + extern int gma_crtc_page_flip(struct drm_crtc *crtc, 75 + struct drm_framebuffer *fb, 76 + struct drm_pending_vblank_event *event, 77 + uint32_t page_flip_flags, 78 + struct drm_modeset_acquire_ctx *ctx); 75 79 extern int gma_crtc_set_config(struct drm_mode_set *set, 76 80 struct drm_modeset_acquire_ctx *ctx); 77 81
+1
drivers/gpu/drm/gma500/psb_intel_display.c
··· 432 432 .gamma_set = gma_crtc_gamma_set, 433 433 .set_config = gma_crtc_set_config, 434 434 .destroy = gma_crtc_destroy, 435 + .page_flip = gma_crtc_page_flip, 435 436 }; 436 437 437 438 const struct gma_clock_funcs psb_clock_funcs = {
+3
drivers/gpu/drm/gma500/psb_intel_drv.h
··· 12 12 #include <drm/drm_crtc_helper.h> 13 13 #include <drm/drm_encoder.h> 14 14 #include <drm/drm_probe_helper.h> 15 + #include <drm/drm_vblank.h> 15 16 #include <linux/gpio.h> 16 17 #include "gma_display.h" 17 18 ··· 183 182 struct psb_intel_crtc_state *crtc_state; 184 183 185 184 const struct gma_clock_funcs *clock_funcs; 185 + 186 + struct drm_pending_vblank_event *page_flip_event; 186 187 }; 187 188 188 189 #define to_gma_crtc(x) \
+15 -3
drivers/gpu/drm/gma500/psb_irq.c
··· 165 165 "%s, can't clear status bits for pipe %d, its value = 0x%x.\n", 166 166 __func__, pipe, PSB_RVDC32(pipe_stat_reg)); 167 167 168 - if (pipe_stat_val & PIPE_VBLANK_STATUS) 168 + if (pipe_stat_val & PIPE_VBLANK_STATUS || 169 + (IS_MFLD(dev) && pipe_stat_val & PIPE_TE_STATUS)) { 170 + struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); 171 + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 172 + unsigned long flags; 173 + 169 174 drm_handle_vblank(dev, pipe); 170 175 171 - if (pipe_stat_val & PIPE_TE_STATUS) 172 - drm_handle_vblank(dev, pipe); 176 + spin_lock_irqsave(&dev->event_lock, flags); 177 + if (gma_crtc->page_flip_event) { 178 + drm_crtc_send_vblank_event(crtc, 179 + gma_crtc->page_flip_event); 180 + gma_crtc->page_flip_event = NULL; 181 + drm_crtc_vblank_put(crtc); 182 + } 183 + spin_unlock_irqrestore(&dev->event_lock, flags); 184 + } 173 185 } 174 186 175 187 /*