drm: virtio_gpu: add fake timer based vblank handler
authorMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 16 Nov 2023 09:36:32 +0000 (10:36 +0100)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Wed, 22 Nov 2023 12:45:44 +0000 (13:45 +0100)
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
drivers/gpu/drm/virtio/virtgpu_display.c
drivers/gpu/drm/virtio/virtgpu_drv.h

index 9ea7611a9e0fc1eccb0b11036dbcf9c0964b501a..13cfe889b7e5aed571bdfa2dff9baaa804112712 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_vblank.h>
 
 #include "virtgpu_drv.h"
 
 #define XRES_MAX  8192
 #define YRES_MAX  8192
 
+#define VIDI_REFRESH_TIME (1000 / 50)
+
 #define drm_connector_to_virtio_gpu_output(x) \
        container_of(x, struct virtio_gpu_output, conn)
 
+static void vidi_fake_vblank_timer(struct timer_list *t)
+{
+       struct virtio_gpu_device *vgdev = from_timer(vgdev, t, fake_vblank_timer);
+       struct virtio_gpu_output *output = vgdev->outputs + 0; //index;
+       struct drm_crtc *crtc = &output->crtc;
+
+       if (drm_crtc_handle_vblank(crtc))
+               mod_timer(&vgdev->fake_vblank_timer,
+                       jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
+}
+
+static int exynos_drm_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct virtio_gpu_device *vgdev = dev->dev_private;
+
+       mod_timer(&vgdev->fake_vblank_timer,
+               jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1);
+
+       return 0;
+}
+
+static void exynos_drm_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+}
+
+static void exynos_crtc_handle_event(struct drm_crtc *crtc)
+{
+       struct drm_pending_vblank_event *event = crtc->state->event;
+       unsigned long flags;
+
+       if (!event)
+               return;
+       crtc->state->event = NULL;
+
+       WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+       spin_lock_irqsave(&crtc->dev->event_lock, flags);
+       drm_crtc_arm_vblank_event(crtc, event);
+       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+}
+
 static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = {
        .set_config             = drm_atomic_helper_set_config,
        .destroy                = drm_crtc_cleanup,
@@ -55,6 +100,8 @@ static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = {
        .reset                  = drm_atomic_helper_crtc_reset,
        .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
        .atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
+       .enable_vblank          = exynos_drm_crtc_enable_vblank,
+       .disable_vblank         = exynos_drm_crtc_disable_vblank,
 };
 
 static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = {
@@ -98,6 +145,7 @@ static void virtio_gpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
 static void virtio_gpu_crtc_atomic_enable(struct drm_crtc *crtc,
                                          struct drm_atomic_state *state)
 {
+       drm_crtc_vblank_on(crtc);
 }
 
 static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -107,6 +155,16 @@ static void virtio_gpu_crtc_atomic_disable(struct drm_crtc *crtc,
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
 
+       drm_crtc_vblank_off(crtc);
+
+       if (crtc->state->event && !crtc->state->active) {
+               spin_lock_irq(&crtc->dev->event_lock);
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               spin_unlock_irq(&crtc->dev->event_lock);
+
+               crtc->state->event = NULL;
+       }
+
        virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, 0, 0, 0, 0);
        virtio_gpu_notify(vgdev);
 }
@@ -133,6 +191,8 @@ static void virtio_gpu_crtc_atomic_flush(struct drm_crtc *crtc,
        if (drm_atomic_crtc_needs_modeset(crtc_state)) {
                output->needs_modeset = true;
        }
+
+       exynos_crtc_handle_event(crtc);
 }
 
 static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_funcs = {
@@ -334,27 +394,35 @@ static const struct drm_mode_config_funcs virtio_gpu_mode_funcs = {
 
 int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev)
 {
+       struct drm_device *dev = vgdev->ddev;
        int i, ret;
 
-       ret = drmm_mode_config_init(vgdev->ddev);
+       ret = drmm_mode_config_init(dev);
        if (ret)
                return ret;
 
-       vgdev->ddev->mode_config.quirk_addfb_prefer_host_byte_order = true;
-       vgdev->ddev->mode_config.funcs = &virtio_gpu_mode_funcs;
+       timer_setup(&vgdev->fake_vblank_timer, vidi_fake_vblank_timer, 0);
+
+       dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
+       dev->mode_config.funcs = &virtio_gpu_mode_funcs;
 
        /* modes will be validated against the framebuffer size */
-       vgdev->ddev->mode_config.min_width = XRES_MIN;
-       vgdev->ddev->mode_config.min_height = YRES_MIN;
-       vgdev->ddev->mode_config.max_width = XRES_MAX;
-       vgdev->ddev->mode_config.max_height = YRES_MAX;
+       dev->mode_config.min_width = XRES_MIN;
+       dev->mode_config.min_height = YRES_MIN;
+       dev->mode_config.max_width = XRES_MAX;
+       dev->mode_config.max_height = YRES_MAX;
 
        vgdev->ddev->mode_config.fb_modifiers_not_supported = true;
 
        for (i = 0 ; i < vgdev->num_scanouts; ++i)
                vgdev_output_init(vgdev, i);
 
-       drm_mode_config_reset(vgdev->ddev);
+       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+       printk("drm_vblank_init %d\n", ret);
+       if (ret)
+               return ret;
+
+       drm_mode_config_reset(dev);
        return 0;
 }
 
index 9b98470593b0607324dca739f994fa4ca04bb158..6083966a34a6ef875de26a62c24c3edb29c974ea 100644 (file)
@@ -262,6 +262,8 @@ struct virtio_gpu_device {
        spinlock_t resource_export_lock;
        /* protects map state and host_visible_mm */
        spinlock_t host_visible_lock;
+
+       struct timer_list fake_vblank_timer;
 };
 
 struct virtio_gpu_fpriv {