---
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));