summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imx/dcss/dcss-kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imx/dcss/dcss-kms.c')
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
new file mode 100644
index 000000000000..dce1858268ae
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+
+#include "imx-drm.h"
+#include "dcss-crtc.h"
+
+static void dcss_drm_output_poll_changed(struct drm_device *drm)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+}
+
+static int dcss_drm_atomic_check(struct drm_device *drm,
+ struct drm_atomic_state *state)
+{
+ int ret;
+
+ ret = drm_atomic_helper_check_modeset(drm, state);
+ if (ret)
+ return ret;
+
+ ret = drm_atomic_helper_check_planes(drm, state);
+ if (ret)
+ return ret;
+
+ /*
+ * Check modeset again in case crtc_state->mode_changed is
+ * updated in plane's ->atomic_check callback.
+ */
+ return drm_atomic_helper_check_modeset(drm, state);
+}
+
+static int dcss_drm_atomic_commit(struct drm_device *drm,
+ struct drm_atomic_state *state,
+ bool nonblock)
+{
+ struct drm_plane_state *plane_state;
+ struct drm_plane *plane;
+ struct dma_buf *dma_buf;
+ int i;
+
+ /*
+ * If the plane fb has an dma-buf attached, fish out the exclusive
+ * fence for the atomic helper to wait on.
+ */
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
+ dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
+ 0)->base.dma_buf;
+ if (!dma_buf)
+ continue;
+ plane_state->fence =
+ reservation_object_get_excl_rcu(dma_buf->resv);
+ }
+ }
+
+ return drm_atomic_helper_commit(drm, state, nonblock);
+}
+
+static void dcss_kms_setup_output_pipe(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *di;
+ int i;
+
+ for_each_connector_in_state(state, connector, conn_state, i) {
+ if (!connector->state->best_encoder)
+ continue;
+
+ if (!connector->state->crtc->state->active ||
+ !drm_atomic_crtc_needs_modeset(connector->state->crtc->state))
+ continue;
+
+ crtc = connector->state->crtc;
+ di = &connector->display_info;
+
+ dcss_crtc_setup_opipe(crtc, connector, di->hdmi.colorimetry,
+ di->hdmi.hdr_panel_metadata.eotf,
+ HDMI_QUANTIZATION_RANGE_FULL);
+ }
+}
+
+static void dcss_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ dcss_kms_setup_output_pipe(state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ drm_atomic_helper_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = dcss_drm_output_poll_changed,
+ .atomic_check = dcss_drm_atomic_check,
+ .atomic_commit = dcss_drm_atomic_commit,
+};
+
+struct drm_mode_config_helper_funcs dcss_drm_mode_config_helpers = {
+ .atomic_commit_tail = dcss_drm_atomic_commit_tail,
+};