[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 7/9] drm/xen-front: Implement KMS/connector handling



From: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>

Implement kernel modesetiing/connector handling using
DRM simple KMS helper pipeline:

- implement KMS part of the driver with the help of DRM
  simple pipepline helper which is possible due to the fact
  that the para-virtualized driver only supports a single
  (primary) plane:
  - initialize connectors according to XenStore configuration
  - handle frame done events from the backend
  - generate vblank events
  - create and destroy frame buffers and propagate those
    to the backend
  - propagate set/reset mode configuration to the backend on display
    enable/disable callbacks
  - send page flip request to the backend and implement logic for
    reporting backend IO errors on prepare fb callback

- implement virtual connector handling:
  - support only pixel formats suitable for single plane modes
  - make sure the connector is always connected
  - support a single video mode as per para-virtualized driver
    configuration

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
---
 drivers/gpu/drm/xen/Makefile             |   2 +
 drivers/gpu/drm/xen/xen_drm_front_conn.c | 125 +++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_conn.h |  35 ++++
 drivers/gpu/drm/xen/xen_drm_front_drv.c  |  15 ++
 drivers/gpu/drm/xen/xen_drm_front_drv.h  |  12 ++
 drivers/gpu/drm/xen/xen_drm_front_kms.c  | 299 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/xen/xen_drm_front_kms.h  |  30 ++++
 7 files changed, 518 insertions(+)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_conn.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_conn.h
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_kms.c
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front_kms.h

diff --git a/drivers/gpu/drm/xen/Makefile b/drivers/gpu/drm/xen/Makefile
index d3068202590f..4fcb0da1a9c5 100644
--- a/drivers/gpu/drm/xen/Makefile
+++ b/drivers/gpu/drm/xen/Makefile
@@ -2,6 +2,8 @@
 
 drm_xen_front-objs := xen_drm_front.o \
                      xen_drm_front_drv.o \
+                     xen_drm_front_kms.o \
+                     xen_drm_front_conn.o \
                      xen_drm_front_evtchnl.o \
                      xen_drm_front_shbuf.o \
                      xen_drm_front_cfg.o
diff --git a/drivers/gpu/drm/xen/xen_drm_front_conn.c 
b/drivers/gpu/drm/xen/xen_drm_front_conn.c
new file mode 100644
index 000000000000..d9986a2e1a3b
--- /dev/null
+++ b/drivers/gpu/drm/xen/xen_drm_front_conn.c
@@ -0,0 +1,125 @@
+/*
+ *  Xen para-virtual DRM device
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <video/videomode.h>
+
+#include "xen_drm_front_conn.h"
+#include "xen_drm_front_drv.h"
+
+static struct xen_drm_front_drm_pipeline *
+to_xen_drm_pipeline(struct drm_connector *connector)
+{
+       return container_of(connector, struct xen_drm_front_drm_pipeline, conn);
+}
+
+static const uint32_t plane_formats[] = {
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_XRGB4444,
+       DRM_FORMAT_ARGB4444,
+       DRM_FORMAT_XRGB1555,
+       DRM_FORMAT_ARGB1555,
+};
+
+const uint32_t *xen_drm_front_conn_get_formats(int *format_count)
+{
+       *format_count = ARRAY_SIZE(plane_formats);
+       return plane_formats;
+}
+
+static enum drm_connector_status connector_detect(
+               struct drm_connector *connector, bool force)
+{
+       if (drm_dev_is_unplugged(connector->dev))
+               return connector_status_disconnected;
+
+       return connector_status_connected;
+}
+
+#define XEN_DRM_NUM_VIDEO_MODES                1
+#define XEN_DRM_CRTC_VREFRESH_HZ       60
+
+static int connector_get_modes(struct drm_connector *connector)
+{
+       struct xen_drm_front_drm_pipeline *pipeline =
+               to_xen_drm_pipeline(connector);
+       struct drm_display_mode *mode;
+       struct videomode videomode;
+       int width, height;
+
+       mode = drm_mode_create(connector->dev);
+       if (!mode)
+               return 0;
+
+       memset(&videomode, 0, sizeof(videomode));
+       videomode.hactive = pipeline->width;
+       videomode.vactive = pipeline->height;
+       width = videomode.hactive + videomode.hfront_porch +
+               videomode.hback_porch + videomode.hsync_len;
+       height = videomode.vactive + videomode.vfront_porch +
+               videomode.vback_porch + videomode.vsync_len;
+       videomode.pixelclock = width * height * XEN_DRM_CRTC_VREFRESH_HZ;
+       mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+
+       drm_display_mode_from_videomode(&videomode, mode);
+       drm_mode_probed_add(connector, mode);
+       return XEN_DRM_NUM_VIDEO_MODES;
+}
+
+static int connector_mode_valid(struct drm_connector *connector,
+               struct drm_display_mode *mode)
+{
+       struct xen_drm_front_drm_pipeline *pipeline =
+                       to_xen_drm_pipeline(connector);
+
+       if (mode->hdisplay != pipeline->width)
+               return MODE_ERROR;
+
+       if (mode->vdisplay != pipeline->height)
+               return MODE_ERROR;
+
+       return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+       .get_modes = connector_get_modes,
+       .mode_valid = connector_mode_valid,
+};
+
+static const struct drm_connector_funcs connector_funcs = {
+       .detect = connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = drm_connector_cleanup,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+int xen_drm_front_conn_init(struct xen_drm_front_drm_info *drm_info,
+               struct drm_connector *connector)
+{
+       drm_connector_helper_add(connector, &connector_helper_funcs);
+
+       return drm_connector_init(drm_info->drm_dev, connector,
+               &connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
+}
diff --git a/drivers/gpu/drm/xen/xen_drm_front_conn.h 
b/drivers/gpu/drm/xen/xen_drm_front_conn.h
new file mode 100644
index 000000000000..708e80d45985
--- /dev/null
+++ b/drivers/gpu/drm/xen/xen_drm_front_conn.h
@@ -0,0 +1,35 @@
+/*
+ *  Xen para-virtual DRM device
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
+ */
+
+#ifndef __XEN_DRM_FRONT_CONN_H_
+#define __XEN_DRM_FRONT_CONN_H_
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+
+#include <linux/wait.h>
+
+struct xen_drm_front_drm_info;
+
+const uint32_t *xen_drm_front_conn_get_formats(int *format_count);
+
+int xen_drm_front_conn_init(struct xen_drm_front_drm_info *drm_info,
+               struct drm_connector *connector);
+
+#endif /* __XEN_DRM_FRONT_CONN_H_ */
diff --git a/drivers/gpu/drm/xen/xen_drm_front_drv.c 
b/drivers/gpu/drm/xen/xen_drm_front_drv.c
index b3764d5ed0f6..e8862d26ba27 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_drv.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_drv.c
@@ -23,6 +23,7 @@
 #include "xen_drm_front.h"
 #include "xen_drm_front_cfg.h"
 #include "xen_drm_front_drv.h"
+#include "xen_drm_front_kms.h"
 
 static int dumb_create(struct drm_file *filp,
                struct drm_device *dev, struct drm_mode_create_dumb *args)
@@ -41,6 +42,13 @@ static void free_object(struct drm_gem_object *obj)
 static void on_frame_done(struct platform_device *pdev,
                int conn_idx, uint64_t fb_cookie)
 {
+       struct xen_drm_front_drm_info *drm_info = platform_get_drvdata(pdev);
+
+       if (unlikely(conn_idx >= drm_info->cfg->num_connectors))
+               return;
+
+       xen_drm_front_kms_on_frame_done(&drm_info->pipeline[conn_idx],
+                       fb_cookie);
 }
 
 static void lastclose(struct drm_device *dev)
@@ -157,6 +165,12 @@ int xen_drm_front_drv_probe(struct platform_device *pdev,
                return ret;
        }
 
+       ret = xen_drm_front_kms_init(drm_info);
+       if (ret) {
+               DRM_ERROR("Failed to initialize DRM/KMS, ret %d\n", ret);
+               goto fail_modeset;
+       }
+
        dev->irq_enabled = 1;
 
        ret = drm_dev_register(dev, 0);
@@ -172,6 +186,7 @@ int xen_drm_front_drv_probe(struct platform_device *pdev,
 
 fail_register:
        drm_dev_unregister(dev);
+fail_modeset:
        drm_mode_config_cleanup(dev);
        return ret;
 }
diff --git a/drivers/gpu/drm/xen/xen_drm_front_drv.h 
b/drivers/gpu/drm/xen/xen_drm_front_drv.h
index aaa476535c13..563318b19f34 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_drv.h
+++ b/drivers/gpu/drm/xen/xen_drm_front_drv.h
@@ -20,14 +20,24 @@
 #define __XEN_DRM_FRONT_DRV_H_
 
 #include <drm/drmP.h>
+#include <drm/drm_simple_kms_helper.h>
 
 #include "xen_drm_front.h"
 #include "xen_drm_front_cfg.h"
+#include "xen_drm_front_conn.h"
 
 struct xen_drm_front_drm_pipeline {
        struct xen_drm_front_drm_info *drm_info;
 
        int index;
+
+       struct drm_simple_display_pipe pipe;
+
+       struct drm_connector conn;
+       /* these are only for connector mode checking */
+       int width, height;
+       /* last backend error seen on page flip */
+       int pgflip_last_error;
 };
 
 struct xen_drm_front_drm_info {
@@ -35,6 +45,8 @@ struct xen_drm_front_drm_info {
        struct xen_drm_front_ops *front_ops;
        struct drm_device *drm_dev;
        struct xen_drm_front_cfg *cfg;
+
+       struct xen_drm_front_drm_pipeline pipeline[XEN_DRM_FRONT_MAX_CRTCS];
 };
 
 static inline uint64_t xen_drm_front_fb_to_cookie(
diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c 
b/drivers/gpu/drm/xen/xen_drm_front_kms.c
new file mode 100644
index 000000000000..ad94c28835cd
--- /dev/null
+++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c
@@ -0,0 +1,299 @@
+/*
+ *  Xen para-virtual DRM device
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
+ */
+
+#include "xen_drm_front_kms.h"
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+
+#include "xen_drm_front.h"
+#include "xen_drm_front_conn.h"
+#include "xen_drm_front_drv.h"
+
+static struct xen_drm_front_drm_pipeline *
+to_xen_drm_pipeline(struct drm_simple_display_pipe *pipe)
+{
+       return container_of(pipe, struct xen_drm_front_drm_pipeline, pipe);
+}
+
+static void fb_destroy(struct drm_framebuffer *fb)
+{
+       struct xen_drm_front_drm_info *drm_info = fb->dev->dev_private;
+
+       drm_info->front_ops->fb_detach(drm_info->front_info,
+                       xen_drm_front_fb_to_cookie(fb));
+       drm_gem_fb_destroy(fb);
+}
+
+static struct drm_framebuffer_funcs fb_funcs = {
+       .destroy = fb_destroy,
+};
+
+static struct drm_framebuffer *fb_create(struct drm_device *dev,
+               struct drm_file *filp, const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct xen_drm_front_drm_info *drm_info = dev->dev_private;
+       static struct drm_framebuffer *fb;
+       struct drm_gem_object *gem_obj;
+       int ret;
+
+       fb = drm_gem_fb_create_with_funcs(dev, filp, mode_cmd, &fb_funcs);
+       if (IS_ERR_OR_NULL(fb))
+               return fb;
+
+       gem_obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+       if (!gem_obj) {
+               DRM_ERROR("Failed to lookup GEM object\n");
+               ret = -ENOENT;
+               goto fail;
+       }
+
+       drm_gem_object_unreference_unlocked(gem_obj);
+
+       ret = drm_info->front_ops->fb_attach(
+                       drm_info->front_info,
+                       xen_drm_front_dbuf_to_cookie(gem_obj),
+                       xen_drm_front_fb_to_cookie(fb),
+                       fb->width, fb->height, fb->format->format);
+       if (ret < 0) {
+               DRM_ERROR("Back failed to attach FB %p: %d\n", fb, ret);
+               goto fail;
+       }
+
+       return fb;
+
+fail:
+       drm_gem_fb_destroy(fb);
+       return ERR_PTR(ret);
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+       .fb_create = fb_create,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = drm_atomic_helper_commit,
+};
+
+static int display_set_config(struct drm_simple_display_pipe *pipe,
+       struct drm_framebuffer *fb)
+{
+       struct xen_drm_front_drm_pipeline *pipeline =
+                       to_xen_drm_pipeline(pipe);
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct xen_drm_front_drm_info *drm_info = pipeline->drm_info;
+       int ret;
+
+       if (fb)
+               ret = drm_info->front_ops->mode_set(pipeline,
+                               crtc->x, crtc->y,
+                               fb->width, fb->height, fb->format->cpp[0] * 8,
+                               xen_drm_front_fb_to_cookie(fb));
+       else
+               ret = drm_info->front_ops->mode_set(pipeline,
+                               0, 0, 0, 0, 0,
+                               xen_drm_front_fb_to_cookie(NULL));
+
+       if (ret)
+               DRM_ERROR("Failed to set mode to back: %d\n", ret);
+
+       return ret;
+}
+
+static void display_enable(struct drm_simple_display_pipe *pipe,
+               struct drm_crtc_state *crtc_state)
+{
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct drm_framebuffer *fb = pipe->plane.state->fb;
+
+       if (display_set_config(pipe, fb) == 0)
+               drm_crtc_vblank_on(crtc);
+       else
+               DRM_ERROR("Failed to enable display\n");
+}
+
+static void display_disable(struct drm_simple_display_pipe *pipe)
+{
+       struct drm_crtc *crtc = &pipe->crtc;
+
+       display_set_config(pipe, NULL);
+       drm_crtc_vblank_off(crtc);
+       /* final check for stalled events */
+       if (crtc->state->event && !crtc->state->active) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+               drm_crtc_send_vblank_event(crtc, crtc->state->event);
+               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+               crtc->state->event = NULL;
+       }
+}
+
+void xen_drm_front_kms_on_frame_done(
+               struct xen_drm_front_drm_pipeline *pipeline,
+               uint64_t fb_cookie)
+{
+       drm_crtc_handle_vblank(&pipeline->pipe.crtc);
+}
+
+static void display_send_page_flip(struct drm_simple_display_pipe *pipe,
+               struct drm_plane_state *old_plane_state)
+{
+       struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(
+                       old_plane_state->state, &pipe->plane);
+
+       /*
+        * If old_plane_state->fb is NULL and plane_state->fb is not,
+        * then this is an atomic commit which will enable display.
+        * If old_plane_state->fb is not NULL and plane_state->fb is,
+        * then this is an atomic commit which will disable display.
+        * Ignore these and do not send page flip as this framebuffer will be
+        * sent to the backend as a part of display_set_config call.
+        */
+       if (old_plane_state->fb && plane_state->fb) {
+               struct xen_drm_front_drm_pipeline *pipeline =
+                               to_xen_drm_pipeline(pipe);
+               struct xen_drm_front_drm_info *drm_info = pipeline->drm_info;
+               int ret;
+
+               ret = drm_info->front_ops->page_flip(drm_info->front_info,
+                               pipeline->index,
+                               xen_drm_front_fb_to_cookie(plane_state->fb));
+               pipeline->pgflip_last_error = ret;
+               if (ret) {
+                       DRM_ERROR("Failed to send page flip request to backend: 
%d\n", ret);
+                       /*
+                        * As we are at commit stage the DRM core will anyways
+                        * wait for the vblank and knows nothing about our
+                        * failure. The best we can do is to handle
+                        * vblank now, so there is no vblank/flip_done
+                        * time outs
+                        */
+                       drm_crtc_handle_vblank(&pipeline->pipe.crtc);
+               }
+       }
+}
+
+static int display_prepare_fb(struct drm_simple_display_pipe *pipe,
+               struct drm_plane_state *plane_state)
+{
+       struct xen_drm_front_drm_pipeline *pipeline =
+                       to_xen_drm_pipeline(pipe);
+
+       if (pipeline->pgflip_last_error) {
+               int ret;
+
+               /* if previous page flip didn't succeed then report the error */
+               ret = pipeline->pgflip_last_error;
+               /* and let us try to page flip next time */
+               pipeline->pgflip_last_error = 0;
+               return ret;
+       }
+       return drm_gem_fb_prepare_fb(&pipe->plane, plane_state);
+}
+
+static void display_update(struct drm_simple_display_pipe *pipe,
+               struct drm_plane_state *old_plane_state)
+{
+       struct drm_crtc *crtc = &pipe->crtc;
+       struct drm_pending_vblank_event *event;
+
+       event = crtc->state->event;
+       if (event) {
+               struct drm_device *dev = crtc->dev;
+               unsigned long flags;
+
+               crtc->state->event = NULL;
+
+               spin_lock_irqsave(&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(&dev->event_lock, flags);
+       }
+       /*
+        * Send page flip request to the backend *after* we have event armed/
+        * sent above, so on page flip done event from the backend we can
+        * deliver it while handling vblank.
+        */
+       display_send_page_flip(pipe, old_plane_state);
+}
+
+static const struct drm_simple_display_pipe_funcs display_funcs = {
+       .enable = display_enable,
+       .disable = display_disable,
+       .prepare_fb = display_prepare_fb,
+       .update = display_update,
+};
+
+static int display_pipe_init(struct xen_drm_front_drm_info *drm_info,
+               int index, struct xen_drm_front_cfg_connector *cfg,
+               struct xen_drm_front_drm_pipeline *pipeline)
+{
+       struct drm_device *dev = drm_info->drm_dev;
+       const uint32_t *formats;
+       int format_count;
+       int ret;
+
+       pipeline->drm_info = drm_info;
+       pipeline->index = index;
+       pipeline->height = cfg->height;
+       pipeline->width = cfg->width;
+
+       ret = xen_drm_front_conn_init(drm_info, &pipeline->conn);
+       if (ret)
+               return ret;
+
+       formats = xen_drm_front_conn_get_formats(&format_count);
+
+       return drm_simple_display_pipe_init(dev, &pipeline->pipe,
+                       &display_funcs, formats, format_count,
+                       NULL, &pipeline->conn);
+}
+
+int xen_drm_front_kms_init(struct xen_drm_front_drm_info *drm_info)
+{
+       struct drm_device *dev = drm_info->drm_dev;
+       int i, ret;
+
+       drm_mode_config_init(dev);
+
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+       dev->mode_config.max_width = 4095;
+       dev->mode_config.max_height = 2047;
+       dev->mode_config.funcs = &mode_config_funcs;
+
+       for (i = 0; i < drm_info->cfg->num_connectors; i++) {
+               struct xen_drm_front_cfg_connector *cfg =
+                               &drm_info->cfg->connectors[i];
+               struct xen_drm_front_drm_pipeline *pipeline =
+                               &drm_info->pipeline[i];
+
+               ret = display_pipe_init(drm_info, i, cfg, pipeline);
+               if (ret) {
+                       drm_mode_config_cleanup(dev);
+                       return ret;
+               }
+       }
+
+       drm_mode_config_reset(dev);
+       return 0;
+}
diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.h 
b/drivers/gpu/drm/xen/xen_drm_front_kms.h
new file mode 100644
index 000000000000..65a50033bb9b
--- /dev/null
+++ b/drivers/gpu/drm/xen/xen_drm_front_kms.h
@@ -0,0 +1,30 @@
+/*
+ *  Xen para-virtual DRM device
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
+ */
+
+#ifndef __XEN_DRM_FRONT_KMS_H_
+#define __XEN_DRM_FRONT_KMS_H_
+
+#include "xen_drm_front_drv.h"
+
+int xen_drm_front_kms_init(struct xen_drm_front_drm_info *drm_info);
+
+void xen_drm_front_kms_on_frame_done(
+               struct xen_drm_front_drm_pipeline *pipeline,
+               uint64_t fb_cookie);
+
+#endif /* __XEN_DRM_FRONT_KMS_H_ */
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.