#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 FAKE_VBLANK_TIME (1000 / 50)
+
#define drm_connector_to_virtio_gpu_output(x) \
container_of(x, struct virtio_gpu_output, conn)
+static void virtio_gpu_fake_vblank_timer(struct timer_list *t)
+{
+ struct virtio_gpu_device *vgdev = from_timer(vgdev, t,
+ fake_vblank_timer);
+ /* TODO: use proper output index */
+ struct virtio_gpu_output *output = vgdev->outputs + 0;
+
+ if (drm_crtc_handle_vblank(&output->crtc))
+ mod_timer(&vgdev->fake_vblank_timer,
+ jiffies + msecs_to_jiffies(FAKE_VBLANK_TIME) - 1);
+}
+
+static int virtio_gpu_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(FAKE_VBLANK_TIME) - 1);
+
+ return 0;
+}
+
+static void virtio_gpu_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+}
+
+static void virtio_gpu_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;
+
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ if (drm_crtc_vblank_get(crtc) == 0)
+ drm_crtc_arm_vblank_event(crtc, event);
+ else
+ drm_crtc_send_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,
.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 = virtio_gpu_crtc_enable_vblank,
+ .disable_vblank = virtio_gpu_crtc_disable_vblank,
};
static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = {
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,
struct virtio_gpu_device *vgdev = dev->dev_private;
struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(crtc);
+ spin_lock_irq(&dev->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&dev->event_lock);
+
+ drm_crtc_vblank_off(crtc);
virtio_gpu_cmd_set_scanout(vgdev, output->index, 0, 0, 0, 0, 0);
virtio_gpu_notify(vgdev);
}
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
output->needs_modeset = true;
}
+
+ virtio_gpu_crtc_handle_event(crtc);
}
static const struct drm_crtc_helper_funcs virtio_gpu_crtc_helper_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, virtio_gpu_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);
+ if (ret)
+ return ret;
+
+ drm_mode_config_reset(dev);
return 0;
}